Hallo
Da ich ein ziemlicher Neuling bin was die Programmierung von
Microkontrollern(ARM Cortex M3) angeht hab ich mich folgendes gefragt:
Was genau ist ein Nested Vectored Interrupt Controller, wofür ist er
zuständig, wofür genau benötige ich ihn und was ist das besondere an
ihm?
Ich habe mir die Beschreibung auf Wikipedia und hier schon durchgelesen
finde aber auf diese Fragen keine konkreten Antworten.
MfG neuling
Wenn du vorher z.B. mit AVR programmiert hast, ist es schon ein
riesengroßer Unterschied. Beim AVR wird in einer ISR (üblicherweise) als
erstes cli() aufgerufen und als letztes sei(). Damit kann man dann
sicher sein, daß innerhalb einer laufenden ISR keine weitere ISR
dazwischenhaun kann. Das hat man als AVR-Nutzer schnell und tief
verinnerlicht, da es das Programmieren (besonders der ISRen) deutlich
vereinfacht.
Der NVIC mit seinem ersten Buchstaben haut allerdings (üblicherweise)
jederzeit (proritätenabhängig) dazwischen. Da muß man schon enorm mehr
beim Programmieren berücksichtigen, besonders wenn man es ganz anders
gewohnt war/ist. Bin ich am Anfang auch schön mit auf die Schnauze
gefallen, zumal Interruptprogrammierung (z.B. bei EXTIs) meistens nicht
so schön reproduzierbar ist.
Lutz schrieb:> Beim AVR wird in einer ISR (üblicherweise) als> erstes cli() aufgerufen und als letztes sei().
Quark. Das macht die Hardware selbst. sei() unmittelbar am Ende der ISR
hat sogar die gegenteilige Wirkung und kann zum Stack-Overflow führen.
> Damit kann man dann> sicher sein, daß innerhalb einer laufenden ISR keine weitere ISR> dazwischenhaun kann.
Was beim NVIC nicht wesentlich anders ist, bezogen auf Interrups
gleicher oder geringerer Priorität.
A. K. schrieb:>> Beim AVR wird in einer ISR (üblicherweise) als>> erstes cli() aufgerufen und als letztes sei().>> Quark. Das macht die Hardware selbst. sei() unmittelbar am Ende der ISR> hat sogar die gegenteilige Wirkung und kann zum Stack-Overflow führen.
Nun hätte ich ja geschworen, daß das mal anders war? Schön zu Fuß SREG
sichern, cli(), wasauchimmer, SREG zurück (und damit den Status des I).
Pauschal sei() am Ende ist natütlich quatsch; haste recht. Die avr-libc
hat das ja irgendwann auch so gemacht (meine ich zumindest). Hat Atmel
das mal geändert?
A. K. schrieb:>> Damit kann man dann>> sicher sein, daß innerhalb einer laufenden ISR keine weitere ISR>> dazwischenhaun kann.>> Was beim NVIC nicht wesentlich anders ist, bezogen auf Interrups> gleicher oder geringerer Priorität.
Genau deshalb schrieb ich
Lutz schrieb:> Der NVIC mit seinem ersten Buchstaben haut allerdings (üblicherweise)> jederzeit (proritätenabhängig) dazwischen.
Wobei im NVIC allerdings die Prioritäten (neben der
defaultpriorisierung) einstellbar sind, was man dann ja auch gerne tut.
Und genau das kann dann noch zu weiteren Quereffekten führen, die man
berücksichtigen muß.
Lutz schrieb:> Nun hätte ich ja geschworen, daß das mal anders war? Schön zu Fuß SREG> sichern, cli(), wasauchimmer, SREG zurück (und damit den Status des I).> Pauschal sei() am Ende ist natütlich quatsch; haste recht. Die avr-libc> hat das ja irgendwann auch so gemacht (meine ich zumindest). Hat Atmel> das mal geändert?
Nein, das war schon immer so, bereits beim wohl ersten AVR, dem
AT90S1200. Bereits der Aufruf des Handlers schaltet mit dem I Flag die
Interrupts ab und der Return-From-Interrupt Befehl schaltet sie mit dem
I Flag wieder ein.
SREG muss gesichert werden, wenn der Handler selbst irgendwelche Flags
verändert. Nicht aber wegen des I Flags. Das I Flag des in einer ISR
gesicherten SREG enthält aufgrund des beschriebenen Verhaltens eine 0
und entspricht daher nicht dem SREG des unterbrochenen Codes.
Möglicherweise verwechselst du das mit anderen Prozessoren, die bei
einem Interrupt automatisch das ursprüngliche Statusregister sichern und
bei denen der Return den vorherigen Zustand der Interruptsteuerung über
ebendiese Verarbeitung des Statusregisters beim Return wiederherstellt.
So ist es meistens. AVR ist da etwas exotisch.
Lutz schrieb:> Beim AVR wird in einer ISR (üblicherweise) als> erstes cli() aufgerufen und als letztes sei().
Quark mit Soße. Sieht man allerdings bei Anfängern öfters.
Irgendwie scheint man sich immer nur die Fehler von anderen abzugucken.
Lutz schrieb:> Der NVIC mit seinem ersten Buchstaben haut allerdings (üblicherweise)> jederzeit (proritätenabhängig) dazwischen.
Nö.
Prioritäten würfelt man ja nicht aus, sondern vergibt sie mit Absicht.
D.h. man benötigt es, daß ein schneller Interrupt einen langsamen
unterbrechen soll. Und nur dann programmiert man es so.
Ich habe das schon öfter beim AVR vermißt. Man muß deshalb erhebliche
Klimmzüge beim Programmieren machen.
Sogar der uralte 8051 konnte das schon besser (2/4 Prioritäten). Warum
dieser Rückschritt beim AVR gemacht wurde, ist mir unverständlich.
Das NVIC ist allerdings deutlich komplexer als die Interruptlogik beim
8051.
Beim 8051 konnte man auch die Priorität auch innerhalb des Interrupts
hochsetzen. Ich hab das mal für einen Frequenzmesser benötigt.
Ob das NVIC auch solche Tricks erlaubt, weiß ich nicht.
Peter
Peter Dannegger schrieb:> Beim 8051 konnte man auch die Priorität auch innerhalb des Interrupts> hochsetzen. Ich hab das mal für einen Frequenzmesser benötigt.> Ob das NVIC auch solche Tricks erlaubt, weiß ich nicht.
Da man mit BASEPRI die aktuell vom NVIC ausgewertete Priorität gezielt
hochsetzen kann ist das kein Problem.
Interessant scheint mir aber auch der umgekehrte Fall. Man teilt
Interrupt-Handler in einen kurzen eiligen und einen längeren weniger
eiligen Teil auf. Der eilige läuft mit hoher Prio sofort, triggert
abschliessend den weniger eiligen Teil, der auf niedrige Prio
konfiguriert ist und beendet sich.
Der weniger eilige Teil behindert so keine wichtigeren Handler und wird
dennoch alsbald ausgeführt. Die AVR-Regel, im Handler nur das
Allernotwendigste zu tun und ansonsten ein Flags zu setzen, das in der
Mainloop gepollt wird, darf in diesem Top/Bottom-Half Schema
durchbrochen werden.
Peter Dannegger schrieb:> Lutz schrieb:>> Beim AVR wird in einer ISR (üblicherweise) als>> erstes cli() aufgerufen und als letztes sei().>> Quark mit Soße. Sieht man allerdings bei Anfängern öfters.> Irgendwie scheint man sich immer nur die Fehler von anderen abzugucken.
Das mit dem falschen sei() hatten wir ja schon geklärt.
Peter Dannegger schrieb:> Lutz schrieb:>> Der NVIC mit seinem ersten Buchstaben haut allerdings (üblicherweise)>> jederzeit (proritätenabhängig) dazwischen.>> Nö.> Prioritäten würfelt man ja nicht aus, sondern vergibt sie mit Absicht.> D.h. man benötigt es, daß ein schneller Interrupt einen langsamen> unterbrechen soll. Und nur dann programmiert man es so.
1.) Was ist an der Aussage falsch?
2.) Na klar, wenn man alles richtig macht, kann man per Definition auch
keinen Fehler machen. Mit der Betrachtungsweise kann man so ziemlich
jede Diskussion abwürgen.
Nur steigt mit der Zahl der Stellschrauben auch die Wahrscheinlichkeit,
etwas falsch zu machen. Und gerade Interrupts bieten sich dazu an. Und
das ganz besonders, wenn das ganze Interruptkonstrukt auch noch anders
funktioniert, als man es verinnerlicht hat.
Gerade beim Interruptkonzept ist der Unterschied zum AVR enorm und der
NVIC ist weitaus komplexer und hat viel mehr Möglichekiten, als man auf
den ersten oder sogar zweiten Blick erkennt. Da ist letztendlich fast
die Phantasie des Programmierers der limitierende Faktor. Vorgenanntes
Beispiel mit dynamischer Priorisierung veranschaulicht das ganz gut.
Beim AVR läuft die ISR durch und Ende. Es sei denn, man ist so verwegen,
und zündet zwischendrin mit sei() die Lunte an. Na klar, wenn man weiß,
was man macht ...
So kann man beim AVR sicher sein, daß eine autonome Peripherie (z.B.
Timer) in der ISR nur das macht, was vorher schon eingestellt war oder
in dieser ISR geändert wird. Schön einfacher, linearer Gedankengang. Der
NVIC kann da aber, je nach Einstellung, zwischenhaun. Und aus der Traum.
Beispiel: Man nutzt in einer ISR einen Timer. Sofern da nicht vorher
schon was eingestellt war, können nur meine Änderungen in der ISR was
verändern. Kommt nun aber ein höher priorisierter Interrupt dazwischen,
der über weißnichwas für Umwege auch diesen Timer beeinflußt, ist schon
Essig. Und diese möglichen Querbeziehungen werden schnell sehr komplex
und natürlich wird da ein vernüftiges Softwaredesign viel wichtiger als
beim AVR. Insofern ist es natürlich richtig, daß Prios nicht
ausgewürfelt werden.
Übrigens stimme ich der Aussage
> D.h. man benötigt es, daß ein schneller Interrupt einen langsamen> unterbrechen soll. Und nur dann programmiert man es so.
so nicht zu. Die Dauer einer ISR ist ein wichtiges Kriterium für die
Prioritätenvergabe, die Bedeutung des Prozesses aber eine weitere,
mindestens genauso wichtige. Beides zusammen muß zur Bestimmung der
Priorität herangezogen werden. Keine Ahnung: Eine 3 Sekunde lange
shutdown-ISR für Notfälle würde ich nun kaum von einer banalen 1 ms "I'm
still alive"-ISR unterbrechen lassen.
Lutz schrieb:> Übrigens stimme ich der Aussage>> D.h. man benötigt es, daß ein schneller Interrupt einen langsamen>> unterbrechen soll. Und nur dann programmiert man es so.> so nicht zu.
Wenn man "schnell" im Sinn von "eilig" interpretiert, also auf die
Latenz statt auf die Dauer bezieht, dann wird ein Schuh draus.
Der NVIC ist allerdings schon so ein Gerät, dessentwegen ich Neulingen
eher AVR als z.B. STM32 nahelege.
Lutz schrieb:> Keine Ahnung: Eine 3 Sekunde lange> shutdown-ISR für Notfälle würde ich nun kaum von einer banalen 1 ms "I'm> still alive"-ISR unterbrechen lassen.
Wenn aus Ausbleiben der 1ms ISR nach 3ms dazu führt, dass der Wachhund
zubeisst, dann wärs besser wenn doch. ;-)