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?
- Dein Manual zum Compiler - Dein Manula zum Assembler - Dein Datenblatt des uC - Dein Datenblatt des Befehlssatzes - Dein Professor - Deine Glaskugel
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...
Schau auch mal unter Clobber List und eventuell volatile nach: http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
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
Worin liegt eigentlich der Charme vom User-Mode? Ohne MMU ist dessen Nutzen m.E. sehr begrenzt.
@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
Ich mache das mit folgenden Funktionen: __disable_irq(); __enable_irq(); Hoffe dies klärt die Angelegenheit Gruss
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.