Forum: Mikrocontroller und Digitale Elektronik Wie sicher erkennen, ob Funktion innerhalb einer ISR aufgerufen wird?


von A. S. (ferraith)


Lesenswert?

Hallo!

Ich programmiere einen ARM Cortex M3 (NXP LPC1769) und bin auf der Suche 
nach einer Möglichkeit (höchstwahrscheinlich ein Register rauslesen), 
wie ich innerhalb einer Funktion erkennen kann, ob ich mich gerade in 
einer ISR befinde oder nicht. Abhängig davon würden verschiedene Befehle 
ausgeführt werden.

Ich habe nun schon etwas herumexperimentiert und auch das Reference 
Manual zum LPC1769 gewesen, welches Register mir die passende 
Information liefert.

Z.B. habe ich versucht wenn ich mich in der SysTick-ISR befinde, ob das 
"Interrupt Active Bit Register" (IABR) einen Wert != 0 hat. Dies ist 
nicht der Fall. Es hat den Wert 0x00000000. Dies bedeutet, dass kein 
Interrupt aktiv ist. Auch ansonsten habe ich bisher kein Register finden 
können (weder in den NVIC noch in den SC Registern) mit dem ich sicher 
kennen kann, ob ich in einer ISR bin.

Hat jemand von euch eine Idee?

Danke und Grüße,
ferraith

von amateur (Gast)


Lesenswert?

Wird die Funktion von einer ISR UND außerhalb aufgerufen?

Wenn nicht versuchst du den Kreis eckig zu machen.

Selbst deine Testsequenz wird ja nur dann durchlaufen, wenn gerade keine 
ISR aktiv ist. Sogar eine zwischenzeitliche Unterbrechung wird nicht 
bemerkt - soll ja auch so sein.

von Floh (Gast)


Lesenswert?

Verschiedene Möglichkeiten:
1.
Zwei verschiedene Funktionen, eine für ISR, eine für allgemeinen Aufruf.

2.
Der Funktion beim Aufruf durch einen Parameter mitteilen, was zu tun 
ist.

3.
Am Anfang der ISR ein globales Flag setzen, das in der funktion 
ausgewertet wird.

Die Reihenfolge gibt meine Empfehlung wieder :-)

von A. S. (ferraith)


Lesenswert?

@Floh & amateur

das ist exakt was es bereits gibt:

Ich habe zwei Funktionen:
1
int GetTickCountFromISR()
2
int GetTickCount()

Diese beiden kommen mit FreeRTOS mit. Ich habe um die gesamte 
Basisfunktionalität von FreeRTOS (Task Verwaltung) einen C++ Wrapper 
geschrieben.

Nun möchte ich nicht mehr in der Klasse die zwei oben genannten Methoden 
anbieten, sondern nur noch:
1
int GetTickCountNew();
Diese soll wie folgt implementiert sein:
1
int GetTickCountNew() {
2
  if(calledFromISR() == TRUE) {
3
    return GetTickCountFromISR();
4
  else {
5
    return GetTickCount();
6
  }
7
}

Ich versuche sozusaggen von der ISR zu abstrahieren.

von (prx) A. K. (prx)


Lesenswert?

A. S. schrieb:
> Z.B. habe ich versucht wenn ich mich in der SysTick-ISR befinde, ob das
> "Interrupt Active Bit Register" (IABR) einen Wert != 0 hat. Dies ist
> nicht der Fall.

Der SysTick ist ein interner Interrupt. Die IABRs sind nur für externe 
Interrupts zuständig.

von amateur (Gast)


Lesenswert?

Wird eine Funktion innerhalb einer ISR UND außerhalb aufgerufen, so 
solltest Du Dich mal mit der Problematik des reentranten Aufrufs 
beschäftigen.
Da geht’s um den gleichzeitigen Aufruf einer Funktion von mehreren 
Stellen aus. Nicht jede Funktion kann das bzw. verträgt das.

von (prx) A. K. (prx)


Lesenswert?

PS: Extern aus Sicht des Cores, nicht des Controllers.

von (prx) A. K. (prx)


Lesenswert?

amateur schrieb:
> Da geht’s um den gleichzeitigen Aufruf einer Funktion von mehreren
> Stellen aus. Nicht jede Funktion kann das bzw. verträgt das.

Im Prinzip richtig, aber ein Cortex M3 ist kein 8-Bit Controller.

A. S. schrieb:
> Hat jemand von euch eine Idee?

Im speziellen Fall vom SysTick: SCB_SHCSR.SYSTICKACT

von amateur (Gast)


Lesenswert?

Die Problematik des reentranten Aufrufs ist unabhängig vom Prozessor und 
der internen Datenwortbreite. Nutzt Du aber ein RT-OS so sollte man 
davon ausgehen können, dass die <<mitgelieferten>> Funktionen damit 
keine Probleme haben.
Ich gehe mal davon aus, dass Du am schnellsten glücklich wirst, wenn Du 
ein globales Flag, beim Eintritt in die ISR setzt und beim Austritt 
zurücksetzt. Und das natürlich abfragst. Auch dürfte dies ein 
Mechanismus sein, der sich in 5 Jahren noch identifizieren lässt.

von (prx) A. K. (prx)


Lesenswert?

Weshalb muss GetTickCount überhaupt diesen Unterschied machen? Geht es 
darum, in dieser Routine sicherzustellen, dass sie nicht vom SysTick 
Interrupt unterbrochen wird? Dafür liesse sich beispielsweise 
BASEPRI_MAX einsetzen. Vorher so setzen, dass der SysTick nicht 
durchkommt, nachher auf alten Wert zurück. Das darf man dann auch in 
ISRs.

von A. S. (ferraith)


Lesenswert?

@ A.K.

Danke für den Hinweis. Gerade eben habe ich auch das SHCRS Register 
entdeckt. Mein Fehler war, dass ich nicht gewusst habe, dass eine ISR 
sowohl von einem Interrupt als auch von einer Exception aufgerufen 
werden kann.

Somit könnte ich nun mit Hilfe von SHCRS, IABR0 und IABR1 erkennen ob 
eine ISR gerade aktiv ist oder nicht.

Nun habt ihr soviel kritische Fragen aufgeworfen, dass ich mir im Moment 
garnicht sicher bin, ob ich so einen Mechansimus einbauen möchte oder 
nicht ;-)

von A. S. (ferraith)


Lesenswert?

A. K.

auf GetSysTick habe ich keinen Einfluss da die Funktion von FreeRTOS zur 
Verfügung gestellt wird.

von (prx) A. K. (prx)


Lesenswert?

A. S. schrieb:
> Diese beiden kommen mit FreeRTOS mit.

Dafür dass sie bei FreeRTOS dabei sind ist schon beachtlich, dass Google 
sie nicht findet. ;-)

Wäre schon interessant, worin der Unterschied besteht. Ich werde das 
Gefühl nicht los, dass da was auf dem Kopf steht, so überflüssig viel 
Komplexität eingebracht wird.

von Dr. Sommer (Gast)


Lesenswert?

Zig Antworten und keine enthält die offensichtliche Lösung: Register 
IPSR auslesen. Seite 624 im ARMv7M Reference Manual. Ist 0 oder Nummer 
der aktuellen Exception. Löst natürlich nicht das Reentrant-Problem

von (prx) A. K. (prx)


Lesenswert?

Dr. Sommer schrieb:
> Zig Antworten und keine enthält die offensichtliche Lösung:

Dazu muss man erst einmal wissen, wo man suchen muss. Ich hatte danach 
im Cortex M3 Manual gesucht, nicht in der Architektur.

von Marcan (Gast)


Lesenswert?

Schreib eine zusätzliche Auswertung!

ISRCall = 0;

wenn in der ISR die Routine ausgeführt werden soll:

ISRCall = 1;
Routine_Start;


ISRCall kannst Du dann auf 1 prüfen wann und so oft du willst...

von A. S. (ferraith)


Lesenswert?

Ich werde mein Problem mit dem IPSR-Register lösen. Das ist super 
elegant. Werde den Register-Check noch abstrahieren, damit nicht in 
meiner Klasse direkt Register geprüft werden. Evtl. finde ich noch in 
der CMSIS etwas passendes.

Aktuell sehe ich kein Reentrant-Problem mit folgender (prototypischer) 
Umsetzung:
1
int GetTickCountNew() {
2
  if(SCB_ICSR != 0) {
3
    return GetTickCountFromISR();
4
  else {
5
    return GetTickCount();
6
  }
7
}

Ich habe keine globale Variable in der Methode, die während der normalen 
Programmausführung bzw. in der ISR manipuliert werden könnte, und somit 
zu einem Fehlverhalten führen würde.

von Dr. Sommer (Gast)


Lesenswert?

A. K. schrieb:
> Ich hatte danach
> im Cortex M3 Manual gesucht, nicht in der Architektur.
Die Architecture Reference ist enorm hilfreich für alles, die sollte man 
auf jeden Fall kennen...!

A. S. schrieb:
> Evtl. finde ich noch in der CMSIS etwas passendes.
Ja enthält die __get_IPSR () Funktion dafür.

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.