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__armuint32EntrCritSection(void)
5
{
6
unsignedlongtmp;
7
tmp=__get_CPSR();
8
__set_CPSR(tmp|IRQ_FLAG);
9
return(tmp);
10
}
11
12
inline__armvoidExtCritSection(uint32Save)
13
{
14
unsignedlongtmp;
15
tmp=__get_CPSR();
16
__set_CPSR(tmp&(Save|~IRQ_FLAG));
17
}
18
19
inline__armuint32EntrCritSectionFiq(void)
20
{
21
unsignedlongtmp;
22
tmp=__get_CPSR();
23
__set_CPSR(tmp|(IRQ_FLAG|FIQ_FLAG));
24
return(tmp);
25
}
26
27
inline__armvoidExtCritSectionFiq(uint32Save)
28
{
29
unsignedlongtmp;
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
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?
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...
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.
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()
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....
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.
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.
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
inlinevoidEntrCritSection(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
inlinevoidExtCritSection(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
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.
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
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!
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
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.
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)?
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.
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.
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.