Hallo, ich brauche zwei C-Routinen (oder kurzer ASM-Schnipsel), mit
denen ich alle Interrupts ausschalten und einschalten kann.
Bisher gefunden habe ich:
unsigned long __attribute__((naked)) CPUcpsie(void)
{
unsigned long ulRet;
//
// Read PRIMASK and enable interrupts.
//
__asm(" mrs %0, PRIMASK\n"
" cpsie i\n"
" bx lr\n"
: "=r" (ulRet));
return(ulRet);
}
unsigned long __attribute__((naked)) CPUcpsid(void)
{
unsigned long ulRet;
//
// Read PRIMASK and disable interrupts.
//
__asm(" mrs %0, PRIMASK\n"
" cpsid i\n"
" bx lr\n"
: "=r" (ulRet));
return(ulRet);
}
Das funktioniert aber nicht so, wie ich das möchte. Da kommen Interrupts
der Timer immer noch durch. Wer kann mir bitte helfen?
Ich weiß zwar nicht warum, aber ST erwähnt die NVIC Register im
Usermanual zum STM32 nicht.
Bei ARM gibts das Reference Manual zum Cortex M3. Die benötigten
Register zum maskieren bzw. freischalten heißen "Interrupt-Clear-Enable"
und "Interrupt-Set-Enable". Schreiben von 1 an entsprechende Position im
Enable-Register schaltet IRQ frei, schreiben von 1 im Clear-Register
maskiert den IRQ.
In der FWLib von ST sind die Register aber zumindest im NVIC struct
deklariert (Array mit 2x vu32). Bit-Position entspricht Position in der
Vector-Table vom STM32.
mfg
Reinhard
@Reinhard
Ich habe 7 Interrput-Quellen, die ich kurz ausschalten muss, um ein bzw.
2 Variablen zu ändern. Danach muss ich die Interrupts wieder
einschalten. Wie ich das einzeln machen kann, ist mir klar. Ich habe
gehofft, es gibt einen "globalen" Befehl, mit dem ich einfach alle
Interrupts ein/ausschalten kann. Beim 8051 gabs EA=0 und EA=1. Beim ARM
scheint es sowas wohl nicht zugeben?!
@Anak:
AFAIK gibts die Möglichkeit in der Form nicht. Aber mach dir doch
einfach ein define mit der Maske der betroffenen Interrupts, dann ist
ein/ausschalten auch nur noch jeweils 1 Befehl.
@Unbekannter:
ST hat keine eigene Doku zum Interrupt-Controller (nur eine Auflistung
der Vektoren). Es wird sogar aufs ARM Reference Manual verwiesen. Ich
finde nur bei dem Umfang, den das ST Manual hat, wärs auf die paar
Seiten auch nicht mehr angekommen.
mfg
Punkt1: Auch andere Hersteller verweisen auf die ARM Dokus. Wäre ja auch
blöd, das jedes Mal neu zuschreiben, wo der Kern doch derselbe ist...
Punkt2: RTFM!
Also hier für Doofe:
MOV R0, #1
MSR PRIMASK, R0
Und für ganz Harte dasselbe mit FAULTMASK.
Und hinterher:
MOV R0, #0
MSR PRIMASK, R0
Klar sollte sein, daß das nicht im Usermode geht.
So, und jetzt ab zum Manual Lesen, auch wenn das ein paar Hundert Seiten
sind...
Andy wrote:
> Also hier für Doofe:> MOV R0, #1> MSR PRIMASK, R0> Und für ganz Harte dasselbe mit FAULTMASK.>> Und hinterher:> MOV R0, #0> MSR PRIMASK, R0
Besser wäre allerdings die beschriebene Lösung mit CPSIE/CPSID. Nur eine
16bit Instruktion statt eine 16bit und eine 32bit Instruktion. Dazu
wird hier noch ein Register benötigt.
Die Instruktionen, die der OP uns zeigt, sehen erstmal in Ordnung aus.
Da ich mich mit der GCC Syntax nicht auskenne, weiß ich allerdings
nicht, ob Anak einen Formfehler eingebaut hat. Außerdem wissen wir
nicht, wie die Funktionen bei ihm eingesetzt werden. Die Definition
allein hilft ja noch nicht.
Gruß
Marcus
http://www.doulos.com/arm/
das Prinzip , so wie Anak es gemacht hat, sollte doch stimmen denk ich.
Das globale Interrupt Flag scheint beim Cortex M3 im PRIMASK zu sitzen.
Weis jemand wie man den aktuellen Zustand abfragt, ob globale INTs
gesperrt sind oder ebend nicht?
D.h. kann ich z.B. PRIMASK lesen und vom Rückgabewert 1 oder 0 darauf
schließen?
Berndd schrieb:
> Weis jemand wie man den aktuellen Zustand abfragt, ob globale INTs> gesperrt sind oder ebend nicht?> D.h. kann ich z.B. PRIMASK lesen und vom Rückgabewert 1 oder 0 darauf> schließen?
Ja. Und FAULTMASK nicht vergessen. Könnte ja auch gesetzt sein.
Gruß
Marcus
http://www.doulos.com/arm/
Danke.
Bevor ich
CPSID I
ausführen kann, muss ich in den Supervisor mode wechseln, wenn ich es
richtig verstehe.
Mit CPS geht es aber nicht. Das Ref.Manual sagt hier was anderes als das
Quick Instruction Set zum Thumb2. Wie versetze ich ihn denn diesen
State?
Berndd schrieb:
> Mit CPS geht es aber nicht. Das Ref.Manual sagt hier was anderes als das> Quick Instruction Set zum Thumb2. Wie versetze ich ihn denn diesen> State?
Entweder Du bist schon privilegiert, da die Software diesen Modus nie
verlassen hat, oder Du kannst einen SVC verwenden, um in den
privilegierten Modus zu wechseln. Oder einen Software-Triggered
Interrupt.
Gruß
Marcus
http://www.doulos.com/arm/
PS: Vergiss die Quick Reference. Das was draufsteht hast Du in kürzester
Zeit verinnerlicht, und das was Dich dann noch interessiert steht nicht
drauf :-)
nun,
in einem Forum fand ich diese Worte:
"svc" cannot be executed between a "cpsid i" and a "cpsie i", it is a
common error.
If you execute a "svc" while the interrupts are disabled using "cpsid i"
you will end up in the hard fault handler because the svc priority can
be only lower or equal to zero, "cpsid i" masks all interrupts with
priorities up to zero (highest).
Das deckt sich mit meinen Untersuchungen, Spring in den Hard-Fault
Handler !
Was sagen hierzu die Cortex M3 Experten ? Gibt es eine andere
Möglichkeit?
Gruß
STM32User schrieb:> "svc" cannot be executed between a "cpsid i" and a "cpsie i", it is a> common error.>> Was sagen hierzu die Cortex M3 Experten ?
Ja.
> Gibt es eine andere Möglichkeit?
Für was genau? Bisher hast Du noch nicht beschrieben, was Du eigentlich
machst, bzw. machen möchtest.
--
Marcus
Also ich hab dafür einfach mal ohne groß nachzudenken
__disable_irq/__enable_irq aus der CMSIS verwendet. Aber du kannst ja
mal nachschauen, was da für assembler code erzeugt wird.
@Marcus Harnisch:
nachfolgend mal ein Paar Code-Auszüge:
startup.s
- switch to 2 stack model and user mode (CONTROL=3)
svc.c
int svc_0 disable_interrupts ()
{
int irq_status = ___get_PRIMASK();
___set_PRIMASK(0);
return irq_status;
}
void svc_1 restore_interrupts (int old_irq_status)
{
___set_PRIMASK(old_irq_status);
}
app.c
myfunc()
{
// we are in user mode (no proviledged)
int irg_status = disable_interrupts();
..
// do somthing with all interrupts disabled:
..
restore_interrupts (irg_status);
}
@hannes:
__disable_irq/__enable_irq aus der CMSIS, geht nicht im user mode
@A.K.:
Ich denke mittlerweile auch, das es eher eine akademische Frage ist, da
man
das 2 Stack-Model auch im Priviligierten Modus betreiben kann, was mir
vorher nicht so klar war.
Auch wenn keine MMU da ist, hat der Cortex-M3 eine MPU drin.
Damit könnte man einen "Amok laufenden Task" davon abhalten,
einen Speicherbereich des Kernels (Echtzeit OS) zu zerlegen.
Aber wenn man nur ein einfaches Programm hat, ist das natürlich
sinnfrei, die Modi zu wechseln.
Matthias schrieb:> Auch wenn keine MMU da ist, hat der Cortex-M3 eine MPU drin.
Das ist eine optionale Komponente, die in etlichen Implementierungen
nicht enthalten ist. Bei den STM32 beispielsweise nur in den 200ern, bei
NXP wohl nur in den 1700ern.
Mir scheint dies eher im Hinblick auf Systeme wie µcLinux konzipiert zu
sein, nicht so sehr für Standalone-Programme.
@Matthias: Nicht jeder M3 hat eine MPU, bei NXP und TI meines Wissens
fast alle. Aber bei ST gibts die erst bei den neueren größeren Devices
(XL).
Und die Frage mit dem User Mode: Damit habe ich ja automatisch
zwangsweise zu tun, wenn ich ein OS verwenden würde. Allerdings sollte
man da ja auch für IRQ Geschichten dann die OS Funktionen verwenden.
Oder gibt es Gründe, auch seine eigene Applikation OS-los im User Mode
zu betreiben? Letztendlich ist man ja dann wieder dabei sein Mini-OS zu
schreiben?
STM32User schrieb:> void svc_1 restore_interrupts (int old_irq_status)> {> ___set_PRIMASK(old_irq_status);> }>> myfunc()> {> // we are in user mode (no proviledged)> int irg_status = disable_interrupts();> ..> // do somthing with all interrupts disabled:> ..> restore_interrupts (irg_status);> }
Es gibt zwei Möglichkeiten:
1. Du verwendest schaltest die Interrupts eben nicht komplett aus,
sondern nur bis zu einem bestimmten Level. Den SVC konfigurierst Du
dann mit höherer Priorität.
2. Du schaust im HardFault handler nach der Ursache und falls es sich
um einen steckengebliebenen SVC zur Reaktivierung der IRQ handelt
rufst Du die Instruktion direkt aus dem HardFault Handler auf. Sagt
ja keiner, dass HF fatal sein muss.
--
Marcus
A. K. schrieb:> Worin liegt eigentlich der Charme vom User-Mode?
Vorwärtskompatibilität.
> Ohne MMU ist dessen Nutzen m.E. sehr begrenzt.
In der Tat. Aber es gibt genügend Systeme die eine MPU (auch MMU)
außerhalb des Cores im L2-Subsystem haben. Oder Devices, die
privilegierten Zugriff bereits in der Hardware voraussetzen.
--
Marcus
Marcus Harnisch schrieb:> In der Tat. Aber es gibt genügend Systeme die eine MPU (auch MMU)> außerhalb des Cores im L2-Subsystem haben. Oder Devices, die> privilegierten Zugriff bereits in der Hardware voraussetzen.
Bei einem betriebssystemlosen Controllerprogramm im User-Mode kann man
zwar beispielsweise den NVIC damit absichern. Aber da man wohl
unweigerlich sämtliche IO-Devices offen lassen wird, bringt das
praktisch keinen Sicherheitsgewinn, aber zusätzlichem Aufwand für
Interrupt-Steuerung.
Die Interrupt-Steuerung über SVCs abzuwickeln hat überdies zur Folge,
dass die worst case interrupt latency um ein Vielfaches anwächst, weil
dann die Laufzeit der SVCs mit eingeht.
Mit einem Betriebssystem, das getrennte Prozesse mit getrennten
Adressräumen und den Device-Support im Kernel hat, sieht das anders aus.
Dann sehe ich Sinn darin, diesen Prozessen nur ihren Speicher und keinen
direkten IO-Zugriff zuzugestehen.
Marcus Harnisch schrieb:> Es gibt zwei Möglichkeiten:> [...]
Und noch die dritte, wahrscheinlich beste: Überdenke Dein
Softwarekonzept. Wenn Du Dir schon die Mühe machst, eine Trennung
zwischen privilegiertem und unprivilegiertem Teil Deiner SW vorzunehmen,
dann ist es ziemlich unsinnig, dem unprivilegiertem Teil zu erlauben,
die Interrupts zu deaktivieren.
--
Marcus
@Marcus Harnisch:
> Überdenke Dein Softwarekonzept.
Ich war von der falschen Voraussetzung ausgegangen, das
man das 2 Stack-Model nur mit Trennung zwischen privilegiertem und
unprivilegiertem Teil verwenden kann. Ich verwende das 2 Stack-Model
nun nur im priv. Modus und somit benötige ich keinen SVC-Handler mehr.
-- snip --
Zwischendurch habe ich mal mit die Auswirkungen des BASIPRI Registers
untersuchen wollen.
Dabei zeigte sich das ich unter Verwendung von MCBSTM32 + ULINK2 + MDK
4.14
der Wert des BASEPRI Register beim Debuggen nicht ändert, es stand immer
fest auf dem Wert 0. Im Simulator änderte sich dagegen den Wert in
BASEPRI (gleicher Code).
Setzt der (UlINK2-) Debugger den BASEPRI Wert immer zurück ?
Hi,
also wenn ich das richtig sehe, kannst Du den Timer-Interrupt nicht
abschalten:
"[...] PendSV1 is a permanently enabled interrupt, controlled using
ICSR.PENDSVSET and ICSR.PENDSVCLR (see Interrupt Control State Register
(ICSR) on page B3-12). ***SysTick can not be disabled.***"
(Quelle: "ARMv7-M Architecture Reference Manual", S. 433/B1-15)
Bin aber nicht der Experte -- vielleicht ist das also auch Müll.
Hope it helps!
MfG
CodeFinder
Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.
Wichtige Regeln - erst lesen, dann posten!
Groß- und Kleinschreibung verwenden
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang