mikrocontroller.net

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


Autor: Anak (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Holzweg (Gast)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
- Dein Manual zum Compiler
- Dein Manula zum Assembler
- Dein Datenblatt des uC
- Dein Datenblatt des Befehlssatzes
- Dein Professor
- Deine Glaskugel

Autor: Anak (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Welch hilfreicher Beitrag. Bravo!!

Autor: Reinhard B. (brainstorm)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Anak (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?!

Autor: Unbekannter (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Doku zum Interrupt-Controller lesen.

Autor: Reinhard B. (brainstorm)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau auch mal unter Clobber List und eventuell volatile nach:
http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assemb...

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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/

Autor: Berndd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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/

Autor: Berndd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: STM32User (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hannes S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: STM32User (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A. K. (prx)
Datum:

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

Autor: STM32User (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hannes S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: STM32User (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: CodeFinder (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Roger S. (rosch7777)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich mache das mit folgenden Funktionen:

__disable_irq();

__enable_irq();

Hoffe dies klärt die Angelegenheit

Gruss

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wer das nach 3 Jahren noch nicht spitzkriegte...

Autor: Didi S. (kokisan2000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie Roger schon schrieb ....
Falls Du CMSIS verwendest ....

__disable_irq();
__enable_irq();

http://infocenter.arm.com/help/index.jsp?topic=/co...

Falls nicht, findest Du hier die Codeschnipsel

http://openwsn.berkeley.edu/svn/trunk/firmware/ope...

Gruss
Didi

Antwort schreiben

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

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.