Forum: Mikrocontroller und Digitale Elektronik Interrupts ein-/ausschalten beim ARM cortex-M3


von Anak (Gast)


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?

von Holzweg (Gast)


Lesenswert?

- Dein Manual zum Compiler
- Dein Manula zum Assembler
- Dein Datenblatt des uC
- Dein Datenblatt des Befehlssatzes
- Dein Professor
- Deine Glaskugel

von Anak (Gast)


Lesenswert?

Welch hilfreicher Beitrag. Bravo!!

von Reinhard B. (brainstorm)


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

von Anak (Gast)


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?!

von Unbekannter (Gast)


Lesenswert?

Doku zum Interrupt-Controller lesen.

von Reinhard B. (brainstorm)


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

von Andy (Gast)


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...

von Thomas (Gast)


Lesenswert?

Schau auch mal unter Clobber List und eventuell volatile nach:
http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html

von Marcus H. (mharnisch) Benutzerseite


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/

von Berndd (Gast)


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?

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

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/

von Berndd (Gast)


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?

von Marcus H. (mharnisch) Benutzerseite


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 :-)

von STM32User (Gast)


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ß

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

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

von Hannes S. (Gast)


Lesenswert?

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.

von STM32User (Gast)


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

von (prx) A. K. (prx)


Lesenswert?

Worin liegt eigentlich der Charme vom User-Mode? Ohne MMU ist dessen 
Nutzen m.E. sehr begrenzt.

von STM32User (Gast)


Lesenswert?

@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.

von Matthias (Gast)


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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Hannes S. (Gast)


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?

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

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

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

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

von (prx) A. K. (prx)


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.

von Marcus H. (mharnisch) Benutzerseite


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

von STM32User (Gast)


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 ?

von CodeFinder (Gast)


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

von Boris S. (rosch7777)


Lesenswert?

Ich mache das mit folgenden Funktionen:

__disable_irq();

__enable_irq();

Hoffe dies klärt die Angelegenheit

Gruss

von (prx) A. K. (prx)


Lesenswert?

Wer das nach 3 Jahren noch nicht spitzkriegte...

von Didi S. (kokisan2000)


Lesenswert?

Wie Roger schon schrieb ....
Falls Du CMSIS verwendest ....

__disable_irq();
__enable_irq();

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Cihcajhj.html

Falls nicht, findest Du hier die Codeschnipsel

http://openwsn.berkeley.edu/svn/trunk/firmware/openos/kernel/FreeRTOS/CMSISv2p00_LPC17xx/inc/core_cmFunc.h

Gruss
Didi

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.