Forum: Mikrocontroller und Digitale Elektronik STM32F2xx: Global Interrupt abfragen


von Michael (Gast)


Lesenswert?

Hallo!

Ich entwickle gerade FW für einen STM32F2xx von ST unter IAR.
Hier würde ich gerne CriticalSection-Funktionen verwenden.
Bei dem gefundenen Beispielcode wird der Global Interrupt mit
1
asm("CPSID i");
 deaktiviert und mit
1
asm("CPSIE i");
 wieder aktiviert.

Bei einem STM32F0XX sah der Beispielcode anders aus:
1
#define IRQ_FLAG        0x80
2
#define FIQ_FLAG        0x40
3
4
inline __arm uint32 EntrCritSection(void)
5
{
6
unsigned long tmp;
7
  tmp = __get_CPSR();
8
  __set_CPSR(tmp | IRQ_FLAG);
9
  return(tmp);
10
}
11
12
inline __arm void ExtCritSection(uint32 Save)
13
{
14
unsigned long tmp;
15
  tmp = __get_CPSR();
16
  __set_CPSR(tmp & (Save | ~IRQ_FLAG));
17
}
18
19
inline __arm uint32 EntrCritSectionFiq(void)
20
{
21
unsigned long tmp;
22
  tmp = __get_CPSR();
23
  __set_CPSR(tmp | (IRQ_FLAG | FIQ_FLAG));
24
  return(tmp);
25
}
26
27
inline __arm void ExtCritSectionFiq(uint32 Save)
28
{
29
unsigned long tmp;
30
  tmp = __get_CPSR();
31
  __set_CPSR(tmp & (Save | ~(IRQ_FLAG | FIQ_FLAG)));
32
}

Mich interessiert das "__get_CPSR".
Wenn mein Prozessor STM32F2xx gibt es die Befehle __get_CPSR und 
__set_CPSR nicht.

Gibt es eine Alternative zum __get_CPSR?

Danke und Grüß
Michael

von (prx) A. K. (prx)


Lesenswert?

Michael schrieb:
> Wenn mein Prozessor STM32F2xx gibt es die Befehle __get_CPSR und
> __set_CPSR nicht.

Interessant. Das sind direkte Umsetzungen von Prozessorbefehlen und es 
ist der gleiche Prozessor. Veraltete CMSIS oder falsche Funktion 
verwendet?

: Bearbeitet durch User
von Michael (Gast)


Angehängte Dateien:

Lesenswert?

Das kommt aus einem Code-Beispiel von IAR direkt zu meinem 
STM32F2xx-Prozessor.
Ich glaube ich mache nichts verbotenes, wenn ich ihn im Original 
anfüge...

von (prx) A. K. (prx)


Lesenswert?

Michael schrieb:
> Das kommt aus einem Code-Beispiel von IAR direkt zu meinem
> STM32F2xx-Prozessor.

Nur ist die Version vom Core in beiden Fällen gleich. Der Kram für die 
Core-Version unterhalb von 7 bezieht sich auf ARM7/ARM9, kann also mit 
dem STM32F0xx eigentlich auch nicht funktioniert haben.

Such mal in der CMSIS, was dort der richtige oder auch nicht richtige 
aber von dir gesuchte Weg ist. Ein sinnvoller Weg geht beispielsweise 
über das BASEPRI/BASEPRI_MAX Register.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Michael schrieb:
> Hier würde ich gerne CriticalSection-Funktionen verwenden.

Und was stört dich an den dort enthaltenen Makros?
#define ENTR_CRT_SECTION() EntrCritSection()
#define EXT_CRT_SECTION()  ExtCritSection()

von Michael (Gast)


Lesenswert?

A. K. schrieb:
> Such mal in der CMSIS, ...

Guter Tipp, aber dazu muss ich mich bei ARM registrieren.
und keine Ahnung wie oft ich jetzt da Captcha eingeben habe (Mit 
Großbuchstaben oder Kleinbuchstaben; nur die die Buchstaben ohne Zahlen 
(da characters)) ... Er sagt jedes mal, dass ich das Captcha falsch 
eingegeben habe. Und die Audio-Funktion geht auch nicht!

A. K. schrieb:
> Und was stört dich an den dort enthaltenen Makros?
Also das Makro ist ja nicht das Problem, sondern "die Art" der 
umgesetzten CriticalSections....

von (prx) A. K. (prx)


Lesenswert?

Michael schrieb:
> Also das Makro ist ja nicht das Problem, sondern "die Art" der
> umgesetzten CriticalSections....

Weshalb? Das Include setzt diese Makros für ARMv7 in CPSID/E Befehle um, 
genau wie es sein soll.

von (prx) A. K. (prx)


Lesenswert?

Michael schrieb:
> Guter Tipp, aber dazu muss ich mich bei ARM registrieren.

Normalerweise sollten wahlweise Hersteller des Compilers oder des 
Controllers da weiterhelfen. Die CMSIS findet sich beispielsweise 
zusammen mit dem STM32-Kram in der STM Library.

von Michael (Gast)


Lesenswert?

A. K. schrieb:
> Weshalb? Das Include setzt diese Makros für ARMv7 in CPSID/E Befehle um,
> genau wie es sein soll.

Eben! - Die Makros bewirken nur, dass dann das da steht:
1
inline void EntrCritSection(void)
2
{
3
  if(CriticalSecCntr == 0)
4
  {
5
    asm("CPSID i");
6
  }
7
  // avoid lost of one count in case of simultaneously calling from both places
8
  ++CriticalSecCntr;
9
}
bzw.
1
inline void ExtCritSection(void)
2
{
3
  if(--CriticalSecCntr == 0)
4
  {
5
    asm("CPSIE i");
6
  }
7
}

Und da steht auch das in meinem ersten Beitrag erwähnte
1
asm("CPSIE i");
Ich will aber zusätzlich noch wissen, ob das Interrupt Flag beim 
Betreten der Critical Section -also vorher- schon gesetzt war, oder 
nicht.

Ich bräuchte also so was:
#define IRQ_FLAG        0x80
1
uint32 flag = __get_CPSR() & IRQ_FLAG;

von (prx) A. K. (prx)


Lesenswert?

Michael schrieb:
> Ich will aber zusätzlich noch wissen, ob das Interrupt Flag beim
> Betreten der Critical Section -also vorher- schon gesetzt war, oder
> nicht.

Wozu? Wie sähe dein Code dann aus?

Such mal nach dem PRIMASK Register.

: Bearbeitet durch User
von Michael (Gast)


Lesenswert?

Für mich gibt es nicht nur einen Typus "sicheren Bereich", sondern drei:
1. Innerhalb des sicheren Bereiches sind Globale Interrupts nicht 
erlaubt => Critical Section
2. Innerhalb des sicheren Bereiches in dem Globale Interrupts aktiv sein 
müssen => Mutex
Für das Betreten und Verlassen einer Mutex ist ein Sicherer Bereich von 
Typ 1 = Critical Section von Nöten, in der das jeweilige 
Mutex-Locked-Flag gesetzt wird.
3. Innerhalb des sicheren Bereiches sind Globale Interrupts nur 
zugelassen, wenn sie es vorher auch waren

von Michael (Gast)


Lesenswert?

Typ 3 wird durch die Critical Section auch erfüllt.

Was nicht geklärt ist:
Was ist, wenn innerhalb eines sicheren Bereichs von Typ 1 einer von Typ 
2 aufgerufen wird.
Dann passt es beim nächsten Aufruf einer Typ 3 Zone nicht mehr!

von (prx) A. K. (prx)


Lesenswert?

Wenn ausschliesslich der obige Code im Include für Critical Sections 
genutzt wird, dann dürfen die Critical Sections auch schachteln, da der 
Code einen Level-Counter mitführt.

EntrCritSection => CriticalSecCntr==1 / CPSID I
EntrCritSection => CriticalSecCntr==2 / nix
ExtCritSection  => CriticalSecCntr==1 / nix
ExtCritSection  => CriticalSecCntr==0 / CPSIE I

von (prx) A. K. (prx)


Lesenswert?

Michael schrieb:
> Für das Betreten und Verlassen einer Mutex ist ein Sicherer Bereich von
> Typ 1 = Critical Section von Nöten

Das ist ein Weg. Und zwar der bei den Cortex M schlechtere.

Der bessere trennt die Interrupt-Prioritäten in zwei Bereiche, 
unterschieden durch die RTOS-Priorität N. Interrupts, die RTOS nutzen, 
erhalten eine geringere Priorität als das RTOS in seinen kritischen 
Bereichen. Interrupts ohne RTOS Nutzung können einen höhere Priorität 
haben (funktionell betrachtet, nicht numerisch).

Eine kritische Sektion, die alle funktional geringeren Interrupts als K 
ausschliesst, kann man völlig ohne CPSID/E so definieren:
  enter: var old = BASEPRI
         BASEPRI_MAX = K
  ...
  exit:  BASEPRI = old
Eine Zuweisung an BASEPRI_MAX hat die Eigenheit, die Priorität nie zu 
verschlechtern, daher ist dieses Prinzip risikofrei anwendbar.

Für RTOS-Lockouts, wie beispielsweise für eine Mutex, lässt sich die 
kritische Sektion also mit ebendieser BASEPRI Aktion implementieren, mit 
K=N.

Vorteil: Zeitkritische Interrupts, die keine RTOS APIs verwenden, werden 
vom RTOS nicht blockiert, also auch nicht verzögert.

: Bearbeitet durch User
von Michael (Gast)


Lesenswert?

Eine ausführliche und interessante Antwort! - Verstehen tue ich dennoch 
nur Bahnhof!

von (prx) A. K. (prx)


Lesenswert?

Michael schrieb:
> Eine ausführliche und interessante Antwort! - Verstehen tue ich dennoch
> nur Bahnhof!

Du bist dir ganz sicher, dass du mit Level=Bahnhof unbedingt einen 
RTOS-Kernel bauen willst (wg. Mutex)?

: Bearbeitet durch User
von Michael (Gast)


Lesenswert?

Sagen wir es mal so. Ich weiß, dass der Cortex Priolevels hat.
Aber die benötige mich nicht und deswegen weiß ich darüber auch nicht 
viel, weil ich mich damit nicht befasst habe.
Der Grund ist, dass die FW parallel auch auf einem Prozessor läuft, der 
wesentlich schwächer als ein Cortex ist und diese Funktionen nicht hat.
Deswegen muss ich bei einer portierbaren Holzhammer-'Methode bleiben.

Mit RTOS, insbesondere OS, hat das alles recht wenig zu tun, aber mit 
Nested Interrupts.

von (prx) A. K. (prx)


Lesenswert?

Michael schrieb:
> Mit RTOS, insbesondere OS, hat das alles recht wenig zu tun, aber mit
> Nested Interrupts.

In welcher Umgebung gibt es Mutexe? In Interrupts ist eine Mutex 
ziemlich sinnarm und eine kritische Sektion zum Schutz vor Interrupts 
ist keine Mutex. Und die Mutext hattest du eingeführt.

Also: Wo hast du ein Problem? Die Makros/Funktionen im Include 
jedenfalls führen - richtig eingesetzt - nicht zu einem Problem.

von W.S. (Gast)


Lesenswert?

Entweder hat er ein Problem mit seinem eigentlichen Systementwurf (weil 
er seine Algorithmen so organisiert hat, daß mehrere Instanzen zugleich 
schreibend auf Daten zugreifen) oder er hat Spaß daran, etwas zu 
verwenden, was er an anderer Stelle schon mal benutzt hatte:

Michael schrieb:
> Hier würde ich gerne CriticalSection-Funktionen verwenden.

Gerne! Und wozu genau? Ich würde die Sache so aufbauen, daß man 
derartiges überhaupt nicht benötigt. Wer das nicht kann oder will, 
stolpert später drüber.

W.S.

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.