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...
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.
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:
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...