Hallo Forum, ich versuche derzeit den STM32F407VGT6, der auf dem STM32F4 Discovery ist, dazu bringen in regelmäßigen Zeitabständen etwas zu tun; zu Testzwecken zunächst den GPIO-Pin D14 mit LED dran togglen, sodass sie mit 1Hz blinkt. Der Code im Anhang tut das auch. Die LED am Pin D12 blinkt synchron dazu. Wenn ich nun das __WFI in Zeile 56 lösche, um zu simulieren dass die Mainloop etwas tut (LED an D12 quasi PWM-gedimmt), blinkt die LED an D14 plötzlich unregelmäßig (so ala 3 interrupts kommen nach Wunsch, einer wird ausgelassen) bzw. nach einem seltsamen Muster, das definitiv keinem 1Hz Rechteck entspricht. Ich habe noch einiges andres rumprobiert, selbst kleine änderungen an der Mainloop (mehr blinken) ändert die Signalform an D14 - wie ein chaotisches System... ( https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy.st.com%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex_mx_stm32%2fTimer%20Interrupt%20frequency%20influenced%20by%20WFE&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=11 ) gefragt, aber nur mit dem Ergebnis dass man das UIF Flag möglichst früh löschen soll - das hab ich zwar getan, bringt aber auch nicht wirklich was. Das ganze scheint mir irgendeine Form von Hardware-Bug zu sein. Gibt es irgendeine Dokumentation dazu, wie man einen Workaround baut, der sicher funktioniert? Ich kann ja nicht der einzige sein, der Timer-Interrupts verwenden will...! Ich verwende die gcc-arm-embedded Toolchain ( https://launchpad.net/gcc-arm-embedded ), aber daran kann's eigentlich auch nicht liegen - der Assemblercode schaut sinnvoll aus. Über Hilfe wäre ich sehr glücklich, so ein Timer ist doch relativ wichtig...
Das hier
1 | GPIOD->ODR ^= (1 << 12); |
ist bei ARM nicht atomar. Wenn der Timer-Interrupt das ungünstig unterbricht, dann geht das im Interrupt getoggelte Bit "verloren". Abhilfe wäre Bitbanding - hier wird der Read-Modify-Write nicht vom Interrupt unterbrochen - oder BSRR.
ersetze diese Zeile:
1 | TIM10->SR = (uint16_t)~TIM_IT_Update; |
Durch diese Zeile:
1 | while( (TIM10->SR & (1<<0)) > 0 ) TIM10->SR &= ~(1<<0); // clear flag |
wenn es dann immernoch nicht geht, kontrolliere ob die Code Optimization in deinem Compiler aktiv ist und aktiviere sie wenn nicht. Dürfte das Problem beheben. PS: statt das so zu schreiben:
1 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; |
2 | GPIO_Init(GPIOD, &GPIO_InitStructure); |
3 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; |
4 | GPIO_Init(GPIOD, &GPIO_InitStructure); |
5 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; |
6 | GPIO_Init(GPIOD, &GPIO_InitStructure); |
7 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; |
8 | GPIO_Init(GPIOD, &GPIO_InitStructure); |
würde ich das so schreiben (übersichtlicher):
1 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; |
2 | GPIO_Init(GPIOD, &GPIO_InitStructure); |
Gruß Jo
Jo discovery schrieb: > Dürfte das Problem beheben. Nein. Das Problem des OP ist das der Interrupt und main() auf demselben Port arbeiten und das nicht-atomar. Mit _WFI tritt das Problem nur deswegen nicht auf, weil dann der Interrupt an genau dieser Stelle auslöst - und so nicht den kritischen Teil unterbrechen kann.
Jim Meba schrieb: > Jo discovery schrieb: >> Dürfte das Problem beheben. > > Nein. Das Problem des OP ist das der Interrupt und main() auf demselben > Port arbeiten und das nicht-atomar. > > Mit _WFI tritt das Problem nur deswegen nicht auf, weil dann der > Interrupt an genau dieser Stelle auslöst - und so nicht den kritischen > Teil unterbrechen kann. Da hast du Recht. Allerdings kommen hier zwei unterschiedliche Probleme zusammen: Zum einen könnte es sein, (das war meine Vermutung) dass das Interruptflag nach Verlassen der Interruptroutine noch aktiv ist und somit der Interrupt noch ein zweites Mal ausgeführt wird (bekanntes Problem, welches ich auch schonmal hatte) und zum zweiten das Problem das du genannt hast (Das ist sogar zu 100% ein Problem, da stimme ich dir zu). Gruß Jo
Jim Meba schrieb: > ist bei ARM nicht atomar. Wenn der Timer-Interrupt das ungünstig > unterbricht, dann geht das im Interrupt getoggelte Bit "verloren". Das wars tatsächlich... So ein Mist, das Programm hat die ganze Zeit funktioniert, nur die Anzeige war falsch :o Jim Meba schrieb: > Abhilfe wäre Bitbanding - hier wird der Read-Modify-Write nicht vom > Interrupt unterbrochen - oder BSRR. Nicht ganz, leider - toggeln/xor geht damit nicht. mit __disable_irq und __enable_irq drumherum tuts allerdings... Jo discovery schrieb: > Durch diese Zeile: > while( (TIM10->SR & (1<<0)) > 0 ) TIM10->SR &= ~(1<<0); // clear flag SR = ~1; sollte schon reichen, die Flags ignorieren das Schreiben von "1". Die Schleife ist allerdings eine schlaue Idee... > wenn es dann immernoch nicht geht, kontrolliere ob die Code Optimization > in deinem Compiler aktiv ist und aktiviere sie wenn nicht. Die bewirkt eher dass es nicht geht weil dann alles in komischer Reihenfolge ist ;-) Jo discovery schrieb: > Zum einen könnte es sein, (das war meine Vermutung) dass das > Interruptflag nach Verlassen der Interruptroutine noch aktiv ist und > somit der Interrupt noch ein zweites Mal ausgeführt wird (bekanntes > Problem, welches ich auch schonmal hatte) Das Problem hatte ich am Anfang, wir ja durch das Löschen des Flags gelöst. Jo discovery schrieb: > würde ich das so schreiben (übersichtlicher): > GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; > GPIO_Init(GPIOD, &GPIO_InitStructure); Oha, wusste nicht dass das geht...
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.