Hi,
Ich brauche einen Timer für die Geschwindigkeitsregelung eines Motors
auf einem STM32F4 und das ganze klappt auch wunderbar über die ganze
Bandbreite des Motors (60rpm bis 5000rpm) auf +- 0.1 rpm genau, aber nur
wenn ich den Timer mit dem Faktor 1.07 multipliziere. Es sind im übrigen
alle Timer betroffen.
Da der Faktor ziemlich neutral ist (nicht so 1.7348922, sondern nur
1.07) dachte ich an einen falschen prescaler oder so, aber dem ist nicht
so:
-uC läuft mit 100Mhz mit einem externen 16Mhz Quarz.
-Timer:
Ich kann mir das wirklich nicht erklären und in einer älteren
Programmversion ging es auch noch ohne Faktor. Jemand eine Idee? Der
Quarz kann nicht falsch sein, da UART und CO noch Fehlerfrei laufen.
Lass doch mal die ganze Motorregelung weg und lass dir in der ISR des
Timers einen Pin togglen und messe mit dem Oszilloskop, ob die Frequenz
stimmt.
Bert S. schrieb:> -Messung Cyclic Zeit für Geschwindigkeitsmessung:
Du fragst den Timer-Stand also manuell ab? Dann kann das Ergebnis dank
variierender Programmlaufzeit doch beliebig abweichen.
Dr. Sommer schrieb:> Du fragst den Timer-Stand also manuell ab? Dann kann das Ergebnis dank> variierender Programmlaufzeit doch beliebig abweichen.
Ja, ich habe das mal auch noch so probiert:
1
floatt;
2
startTimeMeasureing(HTIM1);
3
HAL_Delay(5);
4
stopTimeMeasureing(&t,HTIM1);
5
sprintf(data_buf,"t:%d\n",(int)t);
6
usart_tx_dma(256,data_buf,USB_UART);
Das gibt mir 59832 aus, statt den 50000 die ich bräuchte, auch wenn
alles andere deaktiviert ist (keine Interrupts). Wie würdest du denn die
Zeit auslesen, mit dem DMA oder gleich Interrupt?
Dr. Sommer schrieb:> Lass doch mal die ganze Motorregelung weg und lass dir in der ISR des> Timers einen Pin togglen und messe mit dem Oszilloskop, ob die Frequenz> stimmt.
Jo, das mache ich mal.
Bert S. schrieb:> Wie würdest du denn die> Zeit auslesen, mit dem DMA?
Ich würde den Input Capture / PWM Input Mode des Timers nehmen, damit
dieser exakt in Hardware die Zeit misst und man lediglich das Ergebnis
aus dem Register lesen muss. Dazu muss das Encoder-Signal auf einen Pin
des Timers gelegt werden.
Dr. Sommer schrieb:> Ich würde den Input Capture / PWM Input Mode des Timers nehmen, damit> dieser exakt in Hardware die Zeit misst und man lediglich das Ergebnis> aus dem Register lesen muss. Dazu muss das Encoder-Signal auf einen Pin> des Timers gelegt werden.
Ok, das macht natürlich schon mehr Sinn, IC wird sowiso verwendet für
den Encoder, die Zeitmessung war aber für den Luenberg Observer zur
Geschwindigkeitsschätzung. Aber trotzdem kann ich mir nicht erklären,
warum die Zeitmessung so extrem daneben liegt, Interrupts treten nicht
wirklich viele auf. Ich denke der Fehler muss irgendwo anders liegen,
zumindest scheint der Timer mit dem Oszi genau.
Benutzt du denn die FPU, oder werden deine Floating-Point-Operationen in
Software berechnet (langsam)? Braucht es unbedingt float?
Wenn du CNT auf 0 setzt, wird der Prescaler-Zähler nicht auf 0 gesetzt.
Schreibe stattdessen in das EGR, dann wird beides automatisch auf 0
gesetzt. Timer im laufenden Betrieb zu setzen und abzufragen ist ungenau
und macht nur Ärger...
Dr. Sommer schrieb:> Benutzt du denn die FPU, oder werden deine Floating-Point-Operationen in> Software berechnet (langsam)?
FPU müsste aktiviert sein:
SCB->CPACR|=((3UL<<10*2)|(3UL<<11*2));/* set CP10 and CP11 Full Access */
6
#endif
7
/* Reset the RCC clock configuration to the default reset state ------------*/
8
/* Set HSION bit */
9
RCC->CR|=(uint32_t)0x00000001;
10
11
/* Reset CFGR register */
12
RCC->CFGR=0x00000000;
13
14
/* Reset HSEON, CSSON and PLLON bits */
15
RCC->CR&=(uint32_t)0xFEF6FFFF;
16
17
/* Reset PLLCFGR register */
18
RCC->PLLCFGR=0x24003010;
19
20
/* Reset HSEBYP bit */
21
RCC->CR&=(uint32_t)0xFFFBFFFF;
22
23
/* Disable all interrupts */
24
RCC->CIR=0x00000000;
25
26
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
27
SystemInit_ExtMemCtl();
28
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
29
30
/* Configure the Vector Table location add offset address ------------------*/
31
#ifdef VECT_TAB_SRAM
32
SCB->VTOR=SRAM_BASE|VECT_TAB_OFFSET;/* Vector Table Relocation in Internal SRAM */
33
#else
34
SCB->VTOR=FLASH_BASE|VECT_TAB_OFFSET;/* Vector Table Relocation in Internal FLASH */
35
#endif
36
}
Dr. Sommer schrieb:> Wenn du CNT auf 0 setzt, wird der Prescaler-Zähler nicht auf 0 gesetzt.> Schreibe stattdessen in das EGR, dann wird beides automatisch auf 0> gesetzt. Timer im laufenden Betrieb zu setzen und abzufragen ist ungenau> und macht nur Ärger...
Ok danke, ich probiere das mal.
Bert S. schrieb:> FPU müsste aktiviert sein:
Erzeugt der Compiler denn auch Instruktionen für die FPU? Die FPU bringt
nichts wenn eine Soft-Float-Library aufgerufen wird...
Dr. Sommer schrieb:> Erzeugt der Compiler denn auch Instruktionen für die FPU? Die FPU bringt> nichts wenn eine Soft-Float-Library aufgerufen wird...
Ich verwende Atollic Truestudio, soweit ich das gelesen habe,
unterstützt das der Compiler.
Die Compiler Optionen sind folgende:
Bert S. schrieb:> -mfloat-abi=hard -mfpu=fpv4-sp-d16
Ja, das sieht gut aus. Schau mal im disassemblierten Code, ob da Dinge
wie "vmul" oder "vadd" auftauchen, das sind FPU-Anweisungen.
Bert S. schrieb:> Ja, ich habe das mal auch noch so probiert: float t;> startTimeMeasureing(HTIM1);> HAL_Delay(5);> stopTimeMeasureing(&t,HTIM1);> sprintf(data_buf,"t:%d\n",(int)t);> usart_tx_dma(256,data_buf,USB_UART);>> Das gibt mir 59832 aus, statt den 50000 die ich bräuchte, auch wenn> alles andere deaktiviert ist (keine Interrupts).
Achtung: HAL_Delay() baut auf dem SysTick-IRQ auf, der nur 1x ms
auslöst. Je nachdem wann du startest kann dein Delay also um 1ms
abweichen. Die 59832 wären damit im normalen Rahmen.
Hermann K. schrieb:> Achtung: HAL_Delay() baut auf dem SysTick-IRQ auf, der nur 1x ms> auslöst. Je nachdem wann du startest kann dein Delay also um 1ms> abweichen. Die 59832 wären damit im normalen Rahmen.
Stimmt, da hast du recht, der ist immer um 1ms verschoben, daher passt
der Timer also und auch das Auslesen. Der Fehler muss also woanders
liegen.
Dr. Sommer schrieb:> Ja, das sieht gut aus. Schau mal im disassemblierten Code, ob da Dinge> wie "vmul" oder "vadd" auftauchen, das sind FPU-Anweisungen.
Ja, das taucht auf im .list file, dann passt das schon.