Forum: Mikrocontroller und Digitale Elektronik LPC 17xx Interruptverhalten


von Nima (Gast)


Lesenswert?

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.

von Krapao (Gast)


Lesenswert?

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

von Nima (Gast)


Lesenswert?

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 ;)

von (prx) A. K. (prx)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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
Noch kein Account? Hier anmelden.