Moin, Moin, ich hab eine Frage bzgl. der LPC17xx Reihe zwecks Interrupts. Beispiel: volatile unsigned int counter; void TIMER0_IRQHandler(void) { if (TIM_GetIntStatus(LPC_TIM0,TIM_MR0_INT) == SET) { counter++; } } wie kann ich ausserhalb des int's sicherstellen, dass während ich in die variable counter reinschreibe, dort kein interrupt aktiv ist ? bei den avr's muss man ja cli() und sei() verwenden, beim lpc hab ich auf die schnelle nichts gefunden.
> bei den avr's muss man ja cli() und sei() verwenden
Muss man nicht. Man kann es verwenden, um den Zugriff innerhalb des
Nicht-IRQ-Codes atomar zu machen. Es gibt auch bequeme Makros dafür in
der avr-libc. Es ist aber eine Brachialmethode, weil alle IRQs und nicht
nur der Timer-IRQ betroffen sind.
Eine Methode unter anderen wäre, mit einen Software-Flag (=> Semaphor)
zu arbeiten. Im Nicht-IRQ Programmteil wird ein Software-Flag gesetzt,
bevor die gemeinsame Variable verändert wird und das Software-Flag wird
gelöscht, wenn das Update abgeschlossen ist. Das Software-Flag wird in
der ISR entsprechend beachtet z.B. indem die ISR mit/ohne Quittieren des
IRQ-Auslösers verlassen wird, wenn das Software-Flag gesetzt ist oder
indem das counter++ dann nicht ausgeführt wird. Was sinnvoll ist, hängt
von der Programmlogik ab.
hm, die idee mit dem semaphor ist gut. ich hatte die bisher immer verworfen, weil ich davon ausging, dass ich im nicht-IRQ Teil auf die Variable zugreifen würde, während der IRQ aktiv ist, aber dieser Fall ist ja garnicht möglich. Kurz und schmerzlos: Danke ;)
Der Tipp mit der Semaphore wird bei einem Cortex-M3 wohl krachend in die Hose gehen, denn diese Prozessoren dürften eine ISR, die ihre Ursache nicht zurücksetzt, als Dauerschleife betreiben, ohne auch nur einen einzigen Befehl des Hauptprogramms weiter zu kommen. Mit Semaphoren blockiert man Tasks gegenseitig. Nicht Interrupt-Handler. Es hilft nix. Wenn die betreffenden Operationen nicht atomar sind, dann muss der betreffende Interrupt abgeschaltet werden. Sei es direkt per NVIC, sei es per temporärer kontrollierem Priority-Level. Alternativ kann man auch mit LDREX/STREX/CLREX arbeiten. Letzteres hat den Vorteil, die Latenz nicht negativ zu beeinflussen. Einfaches Schreiben in eine wortgrosse Variable ist bei einem CM3 allerdings atomar, da brennt nichts an.
Nima schrieb: > bei den avr's muss man ja cli() und sei() verwenden, beim lpc hab ich > auf die schnelle nichts gefunden. Im NVIC kann man jeden Interrupt einzeln aus- und einschalten. Siehe NVIC_ISERx, NVIC_ICERx sowie BASEPRI. Oder deren Zugriffsfunktionen im CMSIS.
Beispiel für die o.A. Alternative: Inkrementieren im Interrupt-Handler:
1 | counter++; |
2 | __CLREX(); |
Dekrementieren im Hauptprogramm:
1 | unsigned value; |
2 | do { |
3 | value = __LDREXW(&counter) - 1; |
4 | } while (__STREXW(value, &counter); |
Die __xxxxx Funktionen sind Teil vom CMSIS.
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.