Forum: Mikrocontroller und Digitale Elektronik CMSIS und die Interrupt-Prioritäten


von (prx) A. K. (prx)


Lesenswert?

Der Designer der NVIC Architektur der Cortex-Reihe dürfte sich 
vermutlich etwas dabei gedacht haben, als der die Prioritäten 
linksbündig definierte. Mir kam das recht geschickt vor, weil dadurch 
die Prioritäten definiert werden können, ohne zwingend die Anzahl real 
implementierter Prioritäten im Auge behalten zu müssen.

Wenn man also die Prioritäten 0x40 und 0x50 definiert, dann sind das 
beim STM32 (4 Bits) verschiedene Ebenen, beim CM0 gleiche (3 Bits). Aber 
der Level 0xC0 hat nie höhere Priorität als der Level 0x20, egal wieviel 
Bits implementiert sind.

Warum gibt sich also CMSIS erkennbar Mühe, diesem IMHO sinnvollen Design 
des NVIC entgegenzuwirken, indem der Parameter von NVIC_SetPriority den 
Parameter rechtsbündig definiert und intern in die linksbündige 
Definition der Hardware umrechnet?

Ich erkenne zwar in den Encode/Decode-Funktionen den Versuch, die Teile 
der Hardware-Specifikation sichtbar und entschlüssel/verschlüsselbar zu 
machen. Aber muss es wirklich sein, dass man nach der Lektüre der 
Hardware-Spezifikation so klug ist wie vorher, weil CMSIS eine völlig 
andere Konvention verwendet als die Hardware?

Einmal mehr mein Problem mit solchen Libs. Der Designer der Lib hat ein 
anderes Verständnis als der Designer der Hardware und der 
Entwicklungsaufwand verdoppelt sich, statt sich zu reduzieren, weil man 
spätestens beim Debugging ohnehin beide Konventionen kennen muss. Mit 
dem Risiko, das gelegentlich zu verwechseln.

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Da sonst keiner antwortet: Du hast meine volle Zustimmung zu dieser 
Beobachtung. Ich weiß jetzt, dass ich nicht alleine bin :-) Die aktuelle 
CMSIS Methode erzeugt sogar das potentielle Problem einer 
Prioritätsinversion.

Gruß
Marcus
http://www.doulos.com/arm/

von (prx) A. K. (prx)


Lesenswert?

Jedenfalls hat nun ein weiteres Element der mitgelieferten Libs den Weg 
in meinen Papierkorb gefunden und wurde durch eigene Implementierungen 
ersetzt.

Nix gegen diese Encode/Decode-Ansätze. Aber das Format für die 
NVIC_SetPriority Funktion sollte der Hardware-Konvention entsprechen, 
allein schon um nicht zusätzlich Verwirrung zu stiften.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> Warum gibt sich also CMSIS erkennbar Mühe, diesem IMHO sinnvollen Design
> des NVIC entgegenzuwirken, indem der Parameter von NVIC_SetPriority den
> Parameter rechtsbündig definiert und intern in die linksbündige
> Definition der Hardware umrechnet?

Hi,

das ist gemacht, um die Programmierung des NVIC einfacher zu gestalten. 
Ausserdem ist das sogar portierbarer, als wenn man die Prioritäten in 
seiner SW gleich linksbündig definiert. Es erhöht zudem die lesbarkeit.

Der NVIC ist ohnehin schon ein sehr komplexes Peripheral, was die 
wenigsten verstehen. Und jemand, der die komplette Prioritätsverwaltung 
beim NVIC selbst macht, wird auch nicht auf die CMSIS zurückgreifen.

Nehmen wir z.B. jmd. aus der AVR oder 8051 Welt. Der kratzt sich am 
Kopf, was der Kram alles soll. Und genau der freut sich über die schön 
einfachen Funktionen.


> Encode/Decode-Funktionen
Die sind nach mir dazugekommen, muss ich mir mal ansehen.

> Die aktuelle CMSIS Methode erzeugt sogar das potentielle Problem einer
> Prioritätsinversion.
konkretes Beispiel? Lösungsansatz?

Ok, Problem besteht, wenn jmd. Prioritäten zuweist, die ausserhalb der 
unterstützten Bandbreite liegen. Werde mir dazu noch mal Gedanken 
machen.



VG,
/th.

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:
>> Warum gibt sich also CMSIS erkennbar Mühe, diesem IMHO sinnvollen Design

> das ist gemacht, um die Programmierung des NVIC einfacher zu gestalten.
> Ausserdem ist das sogar portierbarer, als wenn man die Prioritäten in
> seiner SW gleich linksbündig definiert. Es erhöht zudem die lesbarkeit.

Ansichtssache. Für mich besteht der Ansatz des NVIC darin, 256 
Prioritäten zu definieren, die je nach Implementierung unterschiedlich 
fein aufgelöst werden. Da kann es mal vorkommen, dass zwei bei STM32 
verschiedene Prioritäten beim LPC1100 gleich sind, aber jedenfalls sind 
sie garantiert nie verkehrt herum ...

>> Prioritätsinversion.
> konkretes Beispiel?

... was bei den CMSIS Prioritäten 4 und 10 durchaus vorkommen wird. Beim 
STM32 sind das intern 4=>0x40 und 10=>0xA0, beim LPC1100 4=>0x80 und 
10=>0x40, also invers.

> Lösungsansatz?

NVIC_SetPriority reicht die 8-Bit Prioritäten der Hardware-Konvention 
direkt durch. Die Bastelei mit Ebenen, Gruppen usw. ist dann Aufgabe der 
Encode-Funktion.

Der Sinn von NVIC_SetPriority sollte m.E. nicht darin bestehen, die 
Hardware-Konvention umzucodieren, sondern den Wert ins richtige Register 
zu schreiben.

Unterschiedliche Konventionen in CMSIS und Hardware erschweren zudem das 
Debugging, weil man beim Blick ins Register die Hardware-Konvention 
sieht, im Parameter und im Quellcode die CMSIS-Konvention. Irgendwann 
bringt man das mal durcheinander. Und kennen muss man dann beide 
Konventionen.

von (prx) A. K. (prx)


Lesenswert?

Etwas inkonsequent ist es übrigens, in NVIC_SetPriority die 
System-Exceptions mit aufzunehmen, in den Pendants für Einzelbits aber 
nicht, obwohl es auch dafür teilweise Bits im SCB gibt.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Hier gibt es weiterhin ein generelles Problem. Als die Lib (ich rede nur 
von der core_cm3.h, V1) entworfen wurde, war der Ansatz, einem Liebhaber 
der Registerprogrammierung die Arbeit zu erleichtern.

Um den Layer möglichst schmal und trotzdem universal zu halten, war der 
Ansatz, pro Funktion nur ein Register zu abstrahieren. Das wurde für den 
NVIC auch so durchgezogen (Die SysTick Funktion ist eigentlich nur für 
RTOS gedacht).

Hinzu kommt, dass man dem Programmierer etwas an Intelligenz zuschreiben 
muss, d.h. er sollte zumindest wissen, was sein System kann (also Zahl 
der Prio Bits).

Wenn ich weiss, ich habe 4 Prio Bits, ist es ein leichtes, sich die 
Prios 0...15 auszudenken, aber schon ziemlich komplex, die 
lückenbehafteten Werte von (0<<4) ... (1<<4) umzusetzen (oder denken wir 
an 3, 5 Bits).


Die aufwendige Berechnung von der Interrupt Nummer zu irgendeinem Bit in 
einem riesen Haufen übernimmt dann die Funktion:
1
static __INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
2
{
3
  NVIC->ISER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* enable interrupt */
4
}
5
6
...
7
8
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
9
{
10
  if(IRQn < 0) {
11
    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */
12
  else {
13
    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */
14
}

Dass man einen Inliner nicht für alle Fälle wasserdicht bekommen kann, 
ist klar. Man kann den Programmierer nur bedingt vor seiner eigenen 
Blödheit schützen. Auf jeden Fall geht das immer zu Lasten der 
Codegrösse und Geschwindigkeit.

Dieser Layer nimmt dem Programmierer lediglich diese komplexe Berechnung 
ab, nicht aber das denken. Dafür ist dann die ST Library oder die 
LumiLib da.



VG,
/th.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> NVIC_SetPriority reicht die 8-Bit Prioritäten der Hardware-Konvention
> direkt durch. Die Bastelei mit Ebenen, Gruppen usw. ist dann Aufgabe der
> Encode-Funktion.

Falsch!

Auch bei der CMSIS muss der Benutzer sich die Gruppen selbst 
ausdenken. Die CMSIS kümmert sich nur um den richtigen shift, _mehr 
nicht_.

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> Der NVIC ist ohnehin schon ein sehr komplexes Peripheral, was die
> wenigsten verstehen. Und jemand, der die komplette Prioritätsverwaltung
> beim NVIC selbst macht, wird auch nicht auf die CMSIS zurückgreifen.

Wenn man sich nicht mit Prioritäten befasst, braucht man 
NVIC_SetPriority nicht. Und wenn man sich damit befasst, dann hat man 
die Controller- oder Cortex-Doku gelesen, evtl. noch den Definitive 
Guide und/oder den Hitex-Wälzer, kämpft dann mit zwei verschiedenen 
Konventionen und tut deshalb gut daran, sich den entsprechenden 
CMSIS-Zirkus zu ersparen. Folglich vereinfacht CMSIS hier garnichts.

Ich halte es für sinnvoll, mit solchen Funktionen die Verteilung von 
Bits und Bytes auf die NFIC-Register abzuwickeln. Die Prioritäten 
umzucodieren irritiert mehr als es hilft.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> Etwas inkonsequent ist es übrigens, in NVIC_SetPriority die
> System-Exceptions mit aufzunehmen, in den Pendants für Einzelbits aber
> nicht, obwohl es auch dafür teilweise Bits im SCB gibt.

Würde die Funktion nur unnötig aufblähen, da sich die Bits überall in 
verschiedenen Registern verstecken. Man müsste jeden Fall abfangen...

---
Nochmal:
Die CMSIS ist keine eierlegende Wollmilchsau, sie ist eine 
vereinfachte Library für den Core, richtet sich an Um- und Einsteiger, 
und dient weiterhin super dazu, den komplexen NVIC zu verstehen, ohne 
sich in der DL erst durch tonnenweise Funktionen und #defines wühlen zu 
müssen.

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> Würde die Funktion nur unnötig aufblähen, da sich die Bits überall in
> verschiedenen Registern verstecken. Man müsste jeden Fall abfangen...

Yep, aber weshalb ist das in NVIC_SetPriority drin?

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> Ich halte es für sinnvoll, mit solchen Funktionen die Verteilung von
> Bits und Bytes auf die NFIC-Register abzuwickeln. Die Prioritäten
> umzucodieren irritiert mehr als es hilft.

Man könnte überlegen, ob man die MSB Shifts der Prios in eine eigene 
Funktion packt. Somit bleibt für die einen die Positionierung anhand der 
INT Nr., für die anderen als geschachtelten Funktionsaufruf eine Hilfe.


VG,
/th.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> Yep, aber weshalb ist das in NVIC_SetPriority drin?

Wie lange hast du gebraucht, um zu verstehen, wie der NVIC funktioniert?
Hattest du dazu dieses Beispiel vor der Nase?
:-)

Es bleibt bei einer Hilfestellung, keiner nimmt dir das Denken ab!

---
Wenn du so argumentierst, kannste die ganze CMSIS killen **g**

---
Ich seh schon, damit haben wir uns ganz schön in die Nesseln gesetzt :-)
Eigentlich sollte das Zeug etwas Licht in den chaotischen Wald der 
Vendors bringen (die structs auf Register), und ein klein wenig 
Einstiegs-/Codinghilfe dazu...

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> Man könnte überlegen, ob man die MSB Shifts der Prios in eine eigene
> Funktion packt. Somit bleibt für die einen die Positionierung anhand der
> INT Nr., für die anderen als geschachtelten Funktionsaufruf eine Hilfe.

Ja, exakt dies hatte ich oben gemeint. NVIC_SetPriority reicht die Prio 
1:1 durch, und eine andere Funktion beliebigen Namens codiert eine 
Darstellung von Prio,Gruppe,wassweissich in die Hardware-Konvention um.

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> Wie lange hast du gebraucht, um zu verstehen, wie der NVIC funktioniert?

Ich bin schon ein paar Jahrzehnte im Geschäft und habe einiges gesehen, 
so krass war's für mich nicht. Die Sache mit den Prios selbst hat mir 
kein Kopfzerbrechen bereitet, im Gegenteil, ich fand den Ansatz sehr 
gut.

Interessanter fand ich den Zusammenhang zwischen aktuellem Level und den 
Core-Exceptions, also ob und wann man in einer Memexception oder gleich 
im Hardfault landet. Das ist eher selten anzutreffen.

> Hattest du dazu dieses Beispiel vor der Nase?

Die Doku von Architektur, vom Core und den Definitive Guide. Das einzige 
Beispiel nach dem ich explizit suchte betraf PendSV.

> Wenn du so argumentierst, kannste die ganze CMSIS killen **g**

Nein. Wie schon gesagt, die Abbildung der IRQ-Nummer auf die Register 
ist sehr sinnvoll. Aber Verständnis wächst mit Konsequenz, so zumindest 
bei mir. Entweder man handhabt alle NVIC-Funktionen gleich, indem man 
Prioritäten und Exceptions auf Bytes und Bits verteilt, oder man lässt 
die Exceptions ganz draussen.

Aber es mal so mal so zu machen dient m.E. niemandem. Denn das kapiert 
nur derjenige, der diese Info aus dem Quellcode der CMSIS in Verbindung 
mit der Kenntnis vom Core rauszieht. Und genau der ist davon laut deiner 
Erklärung nach nicht adressiert.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

ungetestet:
1
static __INLINE uint32_t NVIC_ConvertPrioToHW(uint32_t prio)
2
{
3
  return(((prio & ((1<<__NVIC_PRIO_BITS)-1)) << (8 - __NVIC_PRIO_BITS)) & 0xff);
4
}
5
6
7
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
8
{
9
  if(IRQn < 0) {
10
    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = (priority); } /* set Priority for Cortex-M3 System Interrupts */
11
  else {
12
    NVIC->IP[(uint32_t)(IRQn)] = (priority);    }        /* set Priority for device specific Interrupts  */
13
}

Man beachte den kleinen, aber feinen Unterschied (den man auch in die 
jetztige Fkt. mit einbauen könnte, dann wäre das PrioInv problem vom 
Tisch).
Die prio wird jetzt auf die max. mögliche Prio begrenzt, bevor sie 
zurückgegeben und geschrieben werden kann.



VG,
/th.

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> Man beachte den kleinen, aber feinen Unterschied (den man auch in die
> jetztige Fkt. mit einbauen könnte, dann wäre das PrioInv problem vom
> Tisch).

Keineswegs, denn mit der Maskierung machst du nur genau das, was die 
Hardware auch tut. Wer 10 übergibt kriegt beim CM0 so oder so effektiv 
2, egal ob die Maskierung in der Funktion oder beim Schreiben ins 
Register erfolgt. Erst mit einer min() Operation ist die Inversion 
tatsächlich vom Tisch.

Nur ist das in der neuen Form kein Problem mehr, denn 
NVIC_ConvertPrioToHW bezieht sich nun explizit auf die Prioritäten der 
jeweiligen Implementierung (sollte man dokumentieren) und wer dort bei 
Prios 0..7 den Wert 10 übergibt ist selbst schuld.

NVIC_SetPriority entspricht nun dem, was ich selbst verwende. Ich habe 
allerdings getrennte Funktionen für die System Interrupts und die NVIC 
Interrupts.

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> Wenn ich weiss, ich habe 4 Prio Bits, ist es ein leichtes, sich die
> Prios 0...15 auszudenken, aber schon ziemlich komplex, die
> lückenbehafteten Werte von (0<<4) ... (1<<4) umzusetzen (oder denken wir
> an 3, 5 Bits).

Nicht wenn man das von vorneherein nicht dezimal sondern Hex macht. Dann 
habe ich einen Bereich 00-FF und weiss, dass ich bei jedem Cortex in 
jeder Implementierung den gesamten Bereich verwenden kann ohne 
invertierende Maskierungen zu riskieren. Kann sein, dass rechts was 
verloren geht, aber das ist weit weniger kritisch als links.

D.h. ich verteile die Prios nicht per
 #define UART1_Prio (4<<4)
 #define UART2_Prio (5<<4)
sondern per
 #define UART1_Prio 0x40
 #define UART2_Prio 0x50
und wenn's dann auf einem CM0 auf's Gleiche rausläuft, dann stört mich 
das erstmal nicht, ist vielleicht sogar gewollt.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Stimmt, das Problem ist damit trotzdem nicht vom Tisch ...

Man müsste variabel shiften, sozusagen ein MSB alignment manuell 
vornehmen, wenn man dem User das Berechnen der Prio Werte abnehmen will.

VG,
/th.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

solange du in Hex bist und prios von 4bit hast, ists leicht. Aber nehme 
mal 3, 5, 7 ...

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> Man müsste variabel shiften, sozusagen ein MSB alignment manuell
> vornehmen, wenn man dem User das Berechnen der Prio Werte abnehmen will.

Dann kommt nur noch der Bereich 0x80-0xFF raus, alles drunter wird auf 
0x80 abgebildet ;-).

Die Inversion vermeidet man eher mit
  min(prio,(1<<__NVIC_PRIO_BITS)-1)

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Ich könnte mir jetzt eine Fkt. ausdenken, die ein MSB Alignment macht, 
die restlichen Stellen abschneidet, und die Fkt. hinzufügen.

Aber: Ich garantiere dir, ich krieg trotzdem wieder Haue :-)

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> solange du in Hex bist und prios von 4bit hast, ists leicht. Aber nehme
> mal 3, 5, 7 ...

Ich schrieb oben, dass ich schon etwas länger im Geschäft bin. Also auf 
Maschinen angefangen habe, bei denen man an der Konsole nur Hex zu sehen 
kriegte. Keine Sorge, sowas kann ich im Schlaf. ;-)

Aber darum geht es nicht unbedingt. Wenn man explizit verschiedene Prios 
braucht, dann muss man drauf achten. Wenn man eine Lösung auf die zur 
Verfügung stehenden Prios verteilen muss, dann ist man 
implementierungsabhängig und nehme die Convert.. Funktion. Wenn's nicht 
ganz so knackig ist, dann kann man das auf den Bereich 00-FF abbilden 
und muss nur das realistische Minimum von 3 Bits um Auge behalten. Der 
Rest ist dann Zugabe.

Man kann auch beim STM32 1 Bit für die Gruppe kassieren, dann sind 
dieser und ein CM0 mit seinen 3 Bits im Verhalten fast gleich und man 
kann den gleichen Bereich nutzen.

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> Aber: Ich garantiere dir, ich krieg trotzdem wieder Haue :-)

Versprochen! Bei sowas ganz sicher! ;-)

von Henry (Gast)


Lesenswert?

Ich muss jetzt diesen alten Thread nochmal rauskramen. Bin ein STM32 
Späteinsteiger und habe mich jetzt mal durch die STM32F103 NVIC-Specs 
und die CMSIS Libs durchgewühlt.
Diese ganzen Prioritäts-Gruppierungen in CMSIS sind m.E. Unfug.
Letztendlich läuft es doch einfach auf 15 Prioritäten raus, die im High 
Nibble vom PR[n]stehen. Es zählen doch nur die ogenannten Pre-emption 
Levels. Diese Subprioritäten haben doch gar keien Einfluss.
Im CortexM3 Programming-manual ist das zum Glück viel einfacher 
beschrieben.

Beim STM32F103 sieht daher meine NVIC Prioritätsfestlegung z.B. so aus:
1
PR[0] = 0x00;  // Prioritäten sind 0x00(hoch)  bis 0xF0 (niedrig)
2
PR[1] = 0x00;
3
PR[2] = 0x10;
4
PR[3] = 0xF0;
5
PR[4] = 0x30;
6
.....
7
PR[40] = 0x00;
8
PR[41] = 0xF0;
9
PR[42] = 0xF0;

Oder sehe ich da was falsch ?

von Henry (Gast)


Lesenswert?

Sorry hatte das NVIC vergessen:
1
NVIC->PR[0] = 0x00;  // Prioritäten sind 0x00(hoch)  bis 0xF0 (niedrig)
2
NVIC->PR[1] = 0x00;
3
NVIC->PR[2] = 0x10;
4
NVIC->PR[3] = 0xF0;
5
NVIC->PR[4] = 0x30;
6
.....
7
NVIC->PR[40] = 0x00;
8
NVIC->PR[41] = 0xF0;
9
NVIC->PR[42] = 0xF0;

von (prx) A. K. (prx)


Lesenswert?

Klar - die Preemption-Prioritäten sind die wichtigeren. Aber die 
Subprioritäten haben die nützliche Eigenheit, dass Interrupts innerhalb 
einer jeweiligen Gruppe sich garantiert nicht gegenseitig unterbrechen 
können. Und dennoch definierbar ist, welcher davon vorrangig dran kommt. 
Diese Subprioritäten sind ungefähr das, was bei AVR die Prioritäten 
durch Vektor-Reihenfolge darstellen, aber wählbar.

von MCUA (Gast)


Lesenswert?

Diese Subprioritäten (innerhalb eine INT-prio-Gruppe) muss es immer 
geben, da ja nicht (wenn mehrere auslösen) per Zufall irgent ein Vector 
angesprungen werden kann.

von (prx) A. K. (prx)


Lesenswert?

MCUA schrieb:
> Diese Subprioritäten (innerhalb eine INT-prio-Gruppe) muss es immer
> geben, da ja nicht (wenn mehrere auslösen) per Zufall irgent ein Vector
> angesprungen werden kann.

Weshalb eigentlich nicht? ;-)

Aber der Knackpunkt hier ist, dass sie frei wählbar sind.

von Henry (Gast)


Lesenswert?

Jetzt habe ichs hoffentlich verstanden: In der misc.c Funktion steht die 
Funktion NVIC_PriorityGroupConfig. Die Trennungslinie (Binary 
point)zwischen Group-Priority(PreEmption) und Sub-Priority wird dort 
einmalig festgelegt.
Ich hatte mich gefragt, wie die Aufteilung mit 4 Bit funktionieren soll.

Auszug aus der misc.c
[c]
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
  /* Check the parameters */
  assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));

  /* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value 
*/
  SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}
[\c]

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.