Hallo Leute,
folgendes Phänomen beschäftigt mich seit heute Vormittag auf einem
STM32F030:
Ich versuche eine Library für die Timer der uC zu schreiben, der
Interrupt wird jedoch viel zu schnell ausgelöst (bei CNT=24 statt 300).
Der Fehler tritt bereits mit folgendem Code auf:
1
voidConfig_TIM16(void){
2
3
RCC->APB2RSTR|=RCC_APB2RSTR_TIM16RST;
4
5
__NOP();__NOP();__NOP();
6
7
RCC->APB2RSTR&=~RCC_APB2RSTR_TIM16RST;
8
9
RCC->APB2ENR|=RCC_APB2ENR_TIM16EN;
10
11
TIM16->ARR=(unsignedshort)300;
12
13
TIM16->PSC=0;
14
15
TIM16->DIER=TIM_DIER_UIE;
16
17
TIM16->CR1|=TIM_CR1_CEN;
18
19
Timer_NVIC_control(TIM16,TIMER_IRQ_ENABLE);
20
21
}
Hat jemand eine Idee, was da genau passiert bzw. was ich falsch mache?
Louis schrieb:> Interrupt wird jedoch viel zu schnell ausgelöst (bei CNT=24 statt 300)
Und wie kommst Du darauf? Eine ISR ist ja nicht zu sehen.
Sind es vielleicht 324, mit der fehlenden 100er Stelle?
[Beim AVR funktioniert das immer einwandfrei ;-)]
Man muß Code nicht mit Leerzeilen aufblähen.
Man sollte aber Code kommentieren, den man anderen zeigt oder wenn man
später selber noch durchsehen will.
Allgemein:
- Timer stoppen
- Einstellungen vornehmen
- Pending Flag(s) löschen
- Interrupt(s) freigeben
- Timer starten
m.n. schrieb:> Und wie kommst Du darauf? Eine ISR ist ja nicht zu sehen.
Ich habe einfach einen Breakpoint im ISR gesetzt und den CNT des Timers
angesehen. Der Timer bleibt beim Erreichen des Breakpoints stehen wegen
folgendem Code:
1
RCC->APB2ENR|=RCC_APB2ENR_DBGMCUEN;
2
DBGMCU->APB2FZ|=DBGMCU_APB2_FZ_DBG_TIM16_STOP;
m.n. schrieb:> Sind es vielleicht 324, mit der fehlenden 100er Stelle?
Leider nicht.
Peter D. schrieb:> Man muß Code nicht mit Leerzeilen aufblähen.> Man sollte aber Code kommentieren, den man anderen zeigt oder wenn man> später selber noch durchsehen will.
Sorry, habe es korrigiert.
Horst schrieb:> Wie ist 'unsigned short' definiert?
Sind 2 Bytes lang, also 16bit.
Peter D. schrieb:> Allgemein:> - Timer stoppen> - Einstellungen vornehmen> - Pending Flag(s) löschen> - Interrupt(s) freigeben> - Timer starten
Code wie oben geändert, leider keine Verbesserung
da1l6 schrieb:> Du solltest das Timer-Interrupt-Flag löschen bevor du den Interrupt> aktivierst.
Zeile eingefügt, leider trotzdem keine Besserung. Ich lande dauerhaft
bei CNT = 24 statt 300 im Interrupt.
Das ist nur eine Vermutung, aber vielleicht geht es um den Zeitablauf.
Es gibt einen Zeitpunkt zu dem die Überstimmung zwischen Timer und
Register eintritt und einen zweiten, späteren Zeitpunkt, zu dem der
Breakpoint in der ISR aktiv wird.
Soweit ich das verstehe, wird das DBGMCU erst wirksam, wenn der
Breakpoint aktiv wird (unter Vorbehalt).
Kann ja sein, dass das im Vergleich zur Timerfrequenz sehr lang ist.
Ansonsten würde ich vorschlagen, einmal einen kompletten, kompilierbaren
Code zu posten, bei dem das Problem auftritt. Ausserdem Angaben darüber
wie der STM seinen Takt bekommt und woher.
Theor schrieb:> Ansonsten würde ich vorschlagen, einmal einen kompletten, kompilierbaren> Code zu posten, bei dem das Problem auftritt. Ausserdem Angaben darüber> wie der STM seinen Takt bekommt und woher.
Alles klar, bin dabei es zusammenzustellen.
Du kannst nicht erwarten, dass das Timer CNT Register auf 0 steht, wenn
der Breakpoint im Interrupt greift. Da hängt zum einen die Timerfrequenz
mit drin, zum anderen dauert es bis die Interrupt Routine ausgeführt
wird oder es muss im Worst Case noch ein andere Interrupt Routine vorher
abgearbeitet werden.
Mache doch mal folgenden Versuch: Belasse den Breakpoint dort wo er ist
und lass das Programm ein paar mal laufen, bis es wieder auf den
Breakpoint läuft. Wenn das CNT Register am Breakpoint mehrfach auf 0x12
steht, weißt du das es die Latenz zwischen Interrupt Request und
Ansprechen des Breakpoints ist.
Louis schrieb:> Ich habe einfach einen Breakpoint im ISR gesetzt und den CNT des Timers> angesehen. Der Timer bleibt beim Erreichen des Breakpoints stehen wegen> folgendem Code:
Der Timer bleibt beim Eintritt in die ISR nicht stehen. Wie vermutet
sind es 324 bzw. 318 mit gelöschtem Überlauf.
Wenn ich das richtig sehe, läuft der Timer mit vollem CPU-Takt, d.h. die
18 Zyklen sind einfach die Zeit, um in den Interrupt zu springen.
Und Autoreload dürfte bedeuten, nach 300 fängt er wieder bei 0 an.
Nimm mal einen Vorteiler 1:64.
Nanu?
Das habe ich doch oben geschrieben. Louis: Hast Du das nicht nach
geprüft, bevor Du den Code gepostet hast?
Zitat:
Das ist nur eine Vermutung, aber vielleicht geht es um den Zeitablauf.
Es gibt einen Zeitpunkt zu dem die Überstimmung zwischen Timer und
Register eintritt und einen zweiten, späteren Zeitpunkt, zu dem der
Breakpoint in der ISR aktiv wird.
Soweit ich das verstehe, wird das DBGMCU erst wirksam, wenn der
Breakpoint aktiv wird (unter Vorbehalt).
Kann ja sein, dass das im Vergleich zur Timerfrequenz sehr lang ist.
Hallo Leute,
anscheinend sah ich keinen Wald vor lauter Bäumen...
Aus irgendeinem verdrehtem Grund habe ich erwartet die 300 in der CNT
sehen zu können. Somit habe ich wohl den Titel "Depp des Tages" sicher.
Danke Euch für die Hilfe!
Beigefügt ein Bild vom Oszi mit dem Code unten. Die 38us ergeben mit
8MHz Takt genau 304, das scheint zu passen.
1
#include"stm32f0xx.h"
2
3
externvoidConfig_TIM16(void);
4
5
intmain(void){
6
7
RCC->APB2ENR|=RCC_APB2ENR_DBGMCUEN;
8
DBGMCU->APB2FZ|=DBGMCU_APB2_FZ_DBG_TIM16_STOP;
9
10
RCC->AHBENR|=(RCC_AHBENR_GPIOAEN);// activate clk for GPIOA
11
12
GPIOA->OTYPER&=~(1UL<<4);// set pin push-pull
13
GPIOA->OSPEEDR|=(3UL<<((4)*2));// set pin high-speed
Peter D. schrieb:> Nimm mal einen Vorteiler 1:64.
Habe ich in das PSC geschrieben, doch es zeigte leider keine Wirkung.
Gibt es da was Besonderes zu beachten?
Theor schrieb:> Nanu?>> Das habe ich doch oben geschrieben. Louis: Hast Du das nicht nach> geprüft, bevor Du den Code gepostet hast?
Sorry, ich habe anscheinend den ganzen Tag einem nicht existenten Fehler
nachgejagt... Brett vorm Kopf halt.
Moin,
zum PSC: Ich kenne den F030 jetzt nicht so (hab F407).
Aber es sieht fuer mich so aus, als ob du den Timer in der ISR
sofort wieder stoppst. Also nur 1 mal laufen laesst.
Ich hatte das Problem, das der PSC Wert erst nach dem ersten
Update Event wirksam wird. Das war der erste ueberlauf (bei mir).
Da schaltest du in der ISR aber den Timer wieder ab.
Meine Einstellung sah dann so aus:
__TIM5_CLK_ENABLE();
/* TIM5 counts up in steps of 10us to provide a 32bit time stamp
value */
TIM5->PSC = 839;
TIM5->CR1 = TIM_CR1_CEN;
TIM5->EGR = TIM_EGR_UG;
Dann ging es. Ich habe keine ISR weil der Timer einfach frei laeuft.
Koennte das bei dir mit dem PSC auch so sein?