Hallo zusammen, ich habe einen STM32F100RB µC. Ich möchte die Timer-Overflow-Interrupt Funktion testen. Zu diesem Zweck habe ich Code in der Coocox-IDE kompiliert und getestet. Wie erwartet wird auch ein Interrupt zur erwarteten Zeit ausgelöst, wie ich mit Hilfe eines getoggleten Pins erkennen konnte. Allerdings tritt immer nach dem erwarteten Interrupt nach etwa 1µS ein weiterer Interrupt auf. Warum dieser zweite Interrupt ausgelöst wird habe ich nicht verstanden. Wenn ich in der Interrupt Routine das UIF flag zweimal nacheinander lösche, tritt der zweite Interrupt nicht mehr auf. Vermutlich handelt es sich um etwas wirklich Triviales, aber dies sind meine ersten Versuche mit diesem µC. Vielleicht kann mich jemand mit einem Hinweis in die richtige Richtung stupsen ;-) Dies ist der Code: /////////////////////////////////////////////////////////////////////// #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include "stm32f10x_usart.h" #include "stm32f10x_tim.h" #include "misc.h" GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; int main(void) { int i; SetSysClockTo24(); // Setzt den System-CLK auf 24 MHz RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 ; GPIO_Init(GPIOA, &GPIO_InitStructure); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2,DISABLE); /* Time base configuration */ TIM_TimeBaseStructure.TIM_Period = 0x1000; TIM_TimeBaseStructure.TIM_Prescaler = 2; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM2->DIER |= TIM_DIER_UIE; // (1<<0); // UPDATE INTERRUPT ENABLE NVIC_InitTypeDef NVIC_InitStructure; //create NVIC structure NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // Enable timer counting TIM_Cmd(TIM2,ENABLE); while(1){ } } void TIM2_IRQHandler() { GPIOA->BSRR = GPIO_Pin_8; GPIOA->BRR = GPIO_Pin_8; TIM2->SR &= ~(1<<0); // clear UIF flag } /////////////////////////////////////////////////////////////////////// Danke und Grüße stm32_beginner
Könnte sein, dass die Zeit zwischen dem Rücksetzen des Interrupt-Flags in der ISR und dem Return der ISR so kurz ist, dass der Interrupt mit dem Return noch als aktiv gesehen und die ISR postwendend nochmal aufgerufen wird. Probier also mal
1 | void TIM2_IRQHandler() |
2 | {
|
3 | TIM2->SR = ~(1<<0); // clear UIF flag (=> rc_w0) |
4 | GPIOA->BSRR = GPIO_Pin_8; |
5 | GPIOA->BRR = GPIO_Pin_8; |
6 | }
|
PS: Das SR ist rc_w0, man kann das Bit löschen ohne vorher zu lesen.
@A.K Danke für den Hinweis! Ich habe es mal getestet. Nun wird tatsächlich nur noch ein Interrupt ausgelöst. Ich verstehe dennoch nicht, warum solch ein Effekt auftreten kann. Wenn ich mir das streng sequentiell vorstelle, wird doch erst mal das UIF-Flag gelöscht und danach erst die Interrupt-Funktion verlassen. Weshalb wird das Löschen des Flags erst verspätet wirksam? Zweite Frage: Der Puls, welchen ich durch das Setzen und Zurücksetzen des PORT-PINS erzeuge dauert 80nS. Dies entspricht bei einer Frequenz von 24MHz 2 Takten. Warum dauert das nicht nur einen Takt? Ist es prinzipiell möglich den Puls einen Takt lang zu machen? Gruß stm32_beginner
stm32_beginner schrieb: > Ich verstehe dennoch nicht, warum solch ein Effekt auftreten kann. Wenn > ich mir das streng sequentiell vorstelle, wird doch erst mal das > UIF-Flag gelöscht und danach erst die Interrupt-Funktion verlassen. > Weshalb wird das Löschen des Flags erst verspätet wirksam? Der exakte Ablauf überlappt sich etwas. Wenn der Return-Befehl direkt auf den Store-Befehl folgt, dann findet das Rücksetzen des Flags effektiv zur gleichen Zeit wie der Return-Befehl statt. Selbst wenn da 1-2 Takte dazwischen liegen, dann können chipinterne Register evtl. immer noch für eine entsprechende Verzögerung des Interrupt-Signals zwischen Timersignal und Auswertung durch den Prozessor sorgen. > Takten. Warum dauert das nicht nur einen Takt? Weil da ein Store-Befehl dazwischen liegt und der mindestens 2 Takte benötigt.
Super! Danke für die Antwort. Jetzt bin ich schon wieder etwas schlauer. Ich werde mir bezüglich der Verzögerungszeiten nochmal das Datenblatt vornehmen. Grüße!
Um sicher zu gehen, dass er das Flag auch garantiert gelöscht hat, habe ich nun eine while-Schleife eingefügt, damit das Ganze definierter abläuft: while( (TIM2->SR & (1<<0)) > 0 ) TIM2->SR &= ~(1<<0); // clear UIF flag
Kannst du natürlich machen, aber wenn einige Takte zwischen dem Löschen vom Flag und dem Ende des Handlers sind, dann reicht das auch. Als Daumenregel sollte man also das Interrupt-Flag nicht am Schluss löschen, sondern eher vorne. Ausserdem würde ich empfehlen, mit SR = ~(1<<n); exakt nur das gewünschte Bit zurück zu setzen. Andernfalls riskierst du, dass bei mehreren möglichen Timer-Events welche verloren gehen können. Das passiert nämlich, wenn während der Ausführung von SR &= ~(1<<n): (a) register = SR (b) clear bit in register (c) SR = register ein Interrupt-Flag in (a) noch als 0 geladen, während (b) durch das Event im SR gesetzt, und durch (c) gleich wieder zurückgesetzt wird.
Danke für den Tip! SR = ~(1<<n); ------------------ Blöde Frage: Ich setze damit zwar das eine Bit zurück, aber die anderen Bits werden dann auf '1' gesetzt. Was wäre denn wenn die auf 0 liegen? Damit würde ich doch ungewollt Bits setzen, die ich gar nicht manipulieren will. Oder habe ich da einen Denkfehler?
stm32_beginner schrieb: > Blöde Frage: Ich setze damit zwar das eine Bit zurück, aber die anderen > Bits werden dann auf '1' gesetzt. Was wäre denn wenn die auf 0 liegen? Die Bits im SR sind in der Referenz als rc_w0 gekennzeichnet. Und was diese Bezeichnung bedeutet ist an anderer Stelle erklärt: Eine 1 zu schreiben hat keine Auswirkung.
Danke! Deine Tips haben mir sehr weiter geholfen. Das Referenzdatenblatt habe ich schon begonnen mir zu Gemüte zu führen. Die meisten Unklarheiten basieren ja häufig auf Details, die man einfach übersieht. So war es auch in diesem Fall. Insgesamt bin ich sehr angetan vom STM32. In Kombination mit der freien CooCox IDE ist das schon eine feine Sache. Zumal der µC nicht besonders viel kostet und um Welten leistungsfähiger ist als zb. ein ATMEGA (bei weniger Preis).
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.