Interrupts ein-/ausschalten beim ARM cortex-M3

Gast #1124744
Lesenswert?

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?
#1125045
Lesenswert?

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
Gast #1125081
Lesenswert?

@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?!
#1125117
Lesenswert?

@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
Gast #1125134
Lesenswert?

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...
Persönliche Seite #1126597
Lesenswert?

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/
Gast #1259729
Lesenswert?

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?
Gast #1260106
Lesenswert?

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?
Persönliche Seite #1260179
Lesenswert?

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 :-)
Gast #2033569
Lesenswert?

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ß
Gast #2033743
Lesenswert?

@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
Gast #2033762
Lesenswert?

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.
Gast #2033833
Lesenswert?

@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?
Persönliche Seite #2034002
Lesenswert?

STM32User schrieb im Beitrag #2033743:
> 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
#2034037
Lesenswert?

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.
Persönliche Seite #2035439
Lesenswert?

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
Gast #2035915
Lesenswert?

@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 ?
Gast #2144422
Lesenswert?

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren