Moin,
ich hatte gestern bei einem Projekt komische Probleme. Ab und zu, nach
diverser Zeit, lief der µC nicht mehr weiter (wie im Betreff angedeutet
ein XMega).
Gerade bin ich im Datenblatt auf etwas gestoßen: Der XMEGA ja einen
neuen Interrupt-Controller, der mehrere Prioritäten erlaubt. Bisher war
ich davon ausgegangen, dass dies dazu dient mehrere Interrupts bei
gesetztem Flag in eine Reihenfolge zu bringen. Im Datenblatt steht jetzt
allerdings, dass Interrupts mit höherer Priorität solche mit niedriger
Priorität unterbrechen können.
Da könnte die Ursache der Fehler liegen, die ich habe. Ich war
eigentlich davon ausgegangen, dass andere Interrupts wenn ich mit
ISR(..) arbeite automatisch deaktiviert sind. Nachdem ich ins
Assembler-Listing geguckt habe, habe ich allerdings keine Stelle
gefunden, wo die Interrupts deaktiviert würden. Das scheint beim halben
"Anpassen" des GCC auf den XMEGA übersehen worden zu sein. Die
Verhaltensweise von SIGNAL (war das dabei?) ist ja, die Interrupts nach
aufruf der ISR speziell wieder frei zu geben; beim XMEGA ist es jetzt ja
genau andersrum - die Interrupts müssen explizit gesperrt werden wenn
man "für sich" sein will.
Kann jemand bestätigen, dass die Interrupts beim XMEGA im der mit "ISR"
deklarierten Interrupt-Routine weiter an bleiben? Kann man da ohne
Bedenken mit cli() arbeiten? Das I-Bit müsste doch nur für den initialen
Aufruf der ISR von Bedeutung sein, oder?
Danke für die Anregungen,
Tobi
Moin Tobi,
Tobias Hagemeier schrieb:> ...habe ich allerdings keine Stelle> gefunden, wo die Interrupts deaktiviert würden. Das scheint beim halben> "Anpassen" des GCC auf den XMEGA übersehen worden zu sein.
Nein, das ist bestimmt nicht uebersehen worde, sondern bestimmt so
gewollt.
Der PMIC kann nur dann eine ISR mit niedriger Prioritaet von einer ISR
mit hoeherer Prioritaet unterbrechen lassen, wenn die Interrupts auch
aktiviert sind.
> Kann jemand bestätigen, dass die Interrupts beim XMEGA im der mit "ISR"> deklarierten Interrupt-Routine weiter an bleiben? Kann man da ohne> Bedenken mit cli() arbeiten? Das I-Bit müsste doch nur für den initialen> Aufruf der ISR von Bedeutung sein, oder?
Kann ich weder besaetigen, noch dementieren.
Ich bin aber auch noch nicht in die Situation gekommen alle Interrupts
ausschalten zu muessen.
Mit geschickter (sinnvoller) Auswahl der Prioritaeten und des
Schedulings der ISRs mit niedrigster Prioritaet bin ich immer gut
zurecht gekommen.
Und wenn Du eine ISR hast, die nicht unterbrochen werden darf, gib ihr
die hoechste Prioritaet. Dann wird sie nicht unterbrochen, selbst wenn
die anderen Interrupts noch aktiviert sind.
(Wenn Du erst bei einem Problem ueber den PMIC gestolpert bist, ....
kennst Du das Eventsystem des XMega? Das hat bei mir viele ISRs
ueberfluessig gemacht.)
MfG,
Balze aka AVR Noob
Hi Balze,
ich bin im Moment auf der Arbeit und kann das alles hier nicht
ausprobieren. Meine Vermutung war, dass einige meiner Interrupts mehr
oder weniger gleichzeitig auftreten und ich wollte durch die
unterschiedlichen Prioritäten erreichen dass gleichzeitige Events (USART
als SPI-Master mit RXC und TXC, die ja gleichzeitig eintreffen sollten)
in der richtigen Reihenfolge abgearbeitet werden. Das macht in meinem
Code keinen wirklichen Unterschied, hätte nur eventuell die
Kommunikation etwas beschleunigt.
Das Eventsystem habe ich selbst noch nicht benutzt sondern darüber nur
im Datenblatt gelesen. Meine "große Sache" für die ich die vielen
(insgesamt 5 pro Seite) Interrupts benutze ist das Abspielen einer
Wavedatei von einer SD-Karte. Um da auf Geschwindigkeit zu kommen und
trotzdem möglichst flexibel zu sein lese und schreibe ich nur über die
Interrupts - benutze parallel aber für größere Datenmengen auch noch den
DMA-Controller (= noch mehr Interrupts). Die sollten sich eigentlich
alle gegenseitig aktivieren/deaktivieren, wenn dann aber sobald ein
Interrupt enabled wird der aufgrund höherer Priorität den laufenden
Interrupt "abwürgt" kriege ich natürlich Race Conditions rein..
Ich habe jetzt mal alle Interrupts auf die gleiche (niedrige -> round
robin) Priorität gesetzt und werde das heute abend mal testen.
Da ich es mit unterschiedlichen Prioritäten getestet habe und es damit
ja eine Zeit lang lief kann ich mir eigentlich keine andere Ursache für
die Probleme vorstellen. Solange das Entzahnt ist, sollte dann auch
alles laufen - hoffe ich ;-)
Sonst muss ich da noch mit dem Debuggen anfangen. Das ist bei 375 Zyklen
pro Sekunde auf Seite der SD-Karte noch machbar, spätestens bei den 6kHz
auf Seite des Audio-Chips wirds dann aber mit Debug-Output über UART
recht schwierig, da der Fehler ja von solchen weiteren laufenden
Interrupts auch noch beeinflusst wird.
Gruß,
Tobi
Hallo Tobi,
nix fuer ungut, (ich bin ja der AVR Noob ;-) aber wenn Du mit Deinen
Interrupts "Race Conditions" erzeugen kannst, solltest Du vielleicht
nochmal uber das Konzept nachdenken !?
Wie gibst Du denn die WAV Datei aus ? Per Port an einen Audio-DAC, oder
per internem DAC ? vielleicht sogar Timer gesteuert ?
Falls ja, solltest Du Dich unbedingt mit dem Eventsystem beschaeftigen.
Das kann Dir das schreiben per DMA an den DAC getriggert vom Timer
komplett abnehmen!!!
Das Eventsystem ist echt cool.
Ich habe einen Incrementalgeber-Simulator geschrieben.
Dabei lese ich per DMA (getriggert von einem Timer) den zu
simulierenden Geberzustand und schreibe den gelesenen Wert an einen
Port. Der Timer ist auf PWM gestellt, die PWM auf einen Puls pro
Zaehlerdurchgang.
So habe ich mir eine Incrementalgeber gebaut, der OHNE Software (nur die
Initialisierungen des Timers, DMA, Port und Eventsystems) auskommt.
Nur auf zwei Taster wird per ISR reagiert um die "simulierte" Drehzahl
zu incrementiern oder decrementieren.
So schaffe ich die drei Signale A, B und N mit 4096 Teilungen und
Drehzahlen von ueber 5000 min-1.
Alles ohne die CPU zu benutzen.
Also meine Empfehlung: Eventsystem. Und Du bist einige Probleme los.
MfG,
Balze aka AVR Noob
Moin Balze,
leider ist es nicht so einfach. Ich kann benutze den VLSI 1053 für die
Analogschnittstelle - später soll der Player auch mal MP3s abspielen
können (die große Datenmenge der Waves ist aber hier eher eine
Herausforderung, deshalb der Fokus zunächst mal darauf).
Der VLSI-Chip signalisiert mir per High-Pegel auf einem Pin das ich
weitere Daten senden soll, das erledigt dann der DMA-Controller. Die
Adresse für die nächsten 32 Bytes (leider nicht mehr..) muss ich dann
jedes mal konfigurieren und das ganze auch noch im Single-Shot-Modus
übertragen. Da der USART.DATA-Buffer leer sein muss (DRE-Flag) UND der
Pin hoch gezogen komme ich mit dem Eventsystem da leider nicht weiter;
eine UND-Verknüpfung kriegt man damit soweit ich weiß nicht hin.
Wenn die Datenblöcke dann raus geschickt sind, muss ich auf den Transfer
Complete-Interrupt warten, um Chip select abzuschalten. Das ginge zwar
per Eventsystem (Port auf High setzen), gleichzeitig muss aber auch der
DRE-Interrupt wieder an, damit die nächsten Daten geschickt werden
können.
Alles etwas haarig und für "simpel" mit Eventsystem mMn nicht geeignet.
Und ja, Race Conditions kriegt man recht schnell hin wenn man die
gleichen (teils auch 32-Bit-)Variablen in den Interrupts verwendet, aber
nicht damit rechnet das die Interrupt-Routine von einer anderen
unterbrochen werden kann, die auf der gleichen Variable rumgurkt. Da
müsste man dann kritische Bereiche einbauen, woran ich halt bei den
"normalen" ATMega-Interruptroutinen nicht gewöhnt war.
Ich habe jetzt wie gesagt alle Prioritäten auf LOW gesetzt und werde
dann mal probieren wie es läuft. Ich erwarte da eigentlich keine
Probleme - meine gestern im Test erreichten 400 KByte/Sekunde sollte ich
ja trotzdem schaffen.
Die Laufzeit des Gesamtsystems ändert sich ja nicht dadurch, dass die
Interrupts jetzt nicht mehr verschachtelt ablaufen.
Daumen drücken ;)
Gruß,
Tobi
Kurze Rückmeldung: Es hat funktioniert. Läuft jetzt seit 30 Minuten ohne
Probleme. Zur Sicherheit wird die Schaltung die nächste Nacht durch
Musik spielen ;-)
Danke für deine Anregungen,
Tobi