www.mikrocontroller.net

Forum: Compiler & IDEs __bad_interrupt und der dazugehörige Interrupt-Vektor


Autor: netb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

man kann ja eine ISR erstellen, welche die Standard-ISR 
"__bad_interrupt" ersetzt. Das kann dann dafür benutzt werden, um einen 
ausgelösten Interrupt, welcher aber keine ISR besitzt, abzufangen.

Ich frage mich, ob es eine Möglichkeit gibt innerhalb dieser 
__bad_interrupt ISR herauszufinden, welcher Interrupt ursprünglich 
ausgelöst wurde?

Mein Gedanke war zuerst, dass man die Standard-Vektor-Tabelle ersetzt 
und hier statt einem jmp auf __bad_interrupt ein call benutzt. Dann 
könnte man sich den dazugehörigen Vektor vom Stack holen. Man muss eben 
nur aufpassen, dass der Wert vor dem reti vom Stack wieder runter ist.

Das wäre dann aber mit einem größeren Aufwand verbunden. Kennt jemand 
eine bessere Lösung?

Bis dann,
netb

Autor: nix_könner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
STM32? oder welcher einer?

Autor: netb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ah ja, Entschuldigung. Ich arbeite hier mit einem AtXMega128A1 und mit 
der aktuellen Version vom AVRGCC und der AVR-LibC.

Bis dann,
netb

Autor: netb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch eine kleine Verbesserung: Ich meinte nicht die aktuelle Version vom 
AVRGCC sondern vielmehr die aktuelle Version vom WINAVR, falls es jemand 
so genau wissen will :)

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
netb schrieb:
> Ich frage mich, ob es eine Möglichkeit gibt innerhalb dieser
> __bad_interrupt ISR herauszufinden, welcher Interrupt ursprünglich
> ausgelöst wurde?

So etwas fragt man am besten das Datenblatt.

Oliver

Autor: Floh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also der gcc wird dir den vector jmp nicht durch einen call ersetzen.
Was man aber machen kann ist im Interrupt die Flags abfragen, bei 
einigen Interruptquellen bleiben diese eben erhalten.

Aber das ist eigentlich extremer Pfusch, wenn die Interrupts eingestellt 
sind, sollte auch eine entsprechende ISR da sein.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
netb schrieb:
> Mein Gedanke war zuerst, dass man die Standard-Vektor-Tabelle ersetzt
> und hier statt einem jmp auf __bad_interrupt ein call benutzt.

Müsste gehen, ich wüsste halt nur nicht, wie man das gcrt1.S selbst
so umschreiben kann, dass die Vektortabelle in dieser Form generiert
wird.  Die "richtig belegten" Interruptvektoren müssen ja nach wie
vor über JMP/RJMP erreicht werden, da andernfalls nach der ISR der
Programmfluss beim nächsten Interruptvektor fortgesetzt würde oder
aber jede ISR selbst zuerst die Adresse aus dem Bereich der
Vektortabelle entfernen müsste.

Wenn man natürlich genau weiß, welche Vektoren man wirklich belegt
hat und welche nicht, kann man eine passend zurecht geschnittene
Tabelle implementieren.

Floh schrieb:
> Aber das ist eigentlich extremer Pfusch, wenn die Interrupts eingestellt
> sind, sollte auch eine entsprechende ISR da sein.

Beim Debuggen kommt es trotzdem schon hin und wieder mal vor, dass
man gar nicht weiß, warum man jetzt eigentlich dahin geschmissen
wird, weil vielleicht das Aktivieren des entsprechenden Interrupts
nicht bewusst vorgenommen worden ist oder gar durch einen "wild
laufenden Zeiger" oder sowas erfolgt ist.  Dann hilft es in der ISR
für __bad_interrupt schon ein wenig, wenn man erst einmal weiß,
welcher Interrupt denn zugeschlagen hat, denn dann kann man
rückwärts aufdröseln, warum das entsprechende Bit gesetzt worden
ist (ggf. über einen "data breakpoint" im Debugger).  BTDT.

Ich habe mir übrigens in diesem Falle einfach mittels eines Scripts
ISR-Stubs schreiben lassen für jede ISR, die auf __bad_interrupt
rauskam.  Jede dieser ISRs hat eine Zahl in eine globale Variable
eingetragen und ist danach auf eine zentrale Stelle gesprungen, auf
die man im Debugger einen Breakpoint setzen konnte.

Autor: netb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

danke erst einmal für eure Ideen, dank dieser Ansätze bin ich nun schon 
ein Stück weiter.

@Floh: Das hatte ich mir auch schon überlegt, doch das endet bei einem 
großen AVR halt sehr schnell in tausenden von if-Abfragen.

@Jörg: Der Hinweis mit der gcrt1.S hat mir einen neuen "Lösungsansatz" 
gegeben. Ich habe mir die Datei mal genauer angesehen. Da alle 
Vektor-Symbole das "weak" Attribut besitzen, wird die Sprungadresse, 
welche als Initialisierung den Wert "__bad_interrupt" besitzt, mit der 
richtigen Adresse einer ISR überschrieben, wenn eine solche ISR 
definiert wurde.

Zu dem Zeitpunkt, an dem der Assembler die gcrt1.S jedoch "bearbeitet" 
besitzt das jeweilige Vektor-Symbol noch den Initialisierungswert und 
daher kann im Macro keine Unterscheidung getroffen werden, ob es sich um 
einen tatsächlichen __bad_interrupt handelt oder nur um ein 
Vektor-Symbol, welches später noch überschrieben wird. Damit kann man 
entweder allen Vektor-Symbolen ein Call geben oder gar keinem.

Allerdings bin ich auf eine andere Idee gekommen: Wenn ich keine 
Informationen aus der Adresse ziehen kann, von der aus gesprungen wird 
(weil ich kein Call benutze), so kann ich jedoch Informationen aus der 
Adresse ziehen, zu der gesprungen wird.

Anstatt jedes Vektor-Symbol also stur mit __bad_interrupt zu 
initialisieren, kann man ja auch einen Offeset hinzurechnen.

Also der Vektor 1 springt dann auf __bad_interrupt + 0, Vektor 2 auf 
__bad_interrupt + 8 u.s.w. Das Makro lässt sich ja dahingehend leicht 
modifizieren.

Die Funktion __bad_interrupt wird dann mit Hilfe eines Makros 
folgendermaßen aufgebaut:
00000316 <__bad_interruptx>:
 316:  8f 93         push  r24
 318:  80 e0         ldi  r24, 0x00  ; 0
 31a:  0c 94 db 01   jmp  0x3b6  ; 0x3b6 <__vectors_pop>

0000031e <__vector_2>:
 31e:  8f 93         push  r24
 320:  81 e0         ldi  r24, 0x01  ; 1
 322:  0c 94 db 01   jmp  0x3b6  ; 0x3b6 <__vectors_pop>

u.s.w.

Also Vektor 1 springt hier auf Adresse 0x316, wo das Register 24 
gerettet und anschließend ein Interrupt-Code dort rein geschrieben wird. 
Danach springt er weiter zu __vectors_pop.

In __vectors_pop wird das Register r24 wieder vom Stack geholt und 
danach springt er zur Reset-Adresse.

Wenn man nun eine ISR mit den Vektor "BADISR_vect" anlegt, springt er 
anstatt auf __vectors_pop zu dieser ISR. Diese sollte dann "naked" sein 
und man findet hier im Register r24 den Interrupt, der den Sprung 
verursacht hat. Bevor man nun die ISR mit reti verlässt, muss man nur 
noch das Register r24 manuell vom Stack holen.

r24 habe ich hier einfach aus dem Bauch heraus gewählt, es kann 
natürlich jedes beliebige andere Register sein.

Ok, das ist jetzt allerdings doch recht kompliziert und es verursacht 
einiges an Code-Overhead. Zudem wäre es mir am liebsten, dass man eine 
solch veränderte Interrupt-Tabelle in ein Projekt integriert, ohne dass 
man etwas an der WinAVR oder AVR-LibC Installation ändern muss. 
Allerdings legt die AVR-LibC die Tabelle ja automatisch an, was man erst 
einmal verhindern muss.

Ich bin also noch nicht ganz zufrieden damit, vielleicht fällt mir oder 
euch noch was besseres ein.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
netb schrieb:

> Also Vektor 1 springt hier auf Adresse 0x316, wo das Register 24
> gerettet und anschließend ein Interrupt-Code dort rein geschrieben wird.
> Danach springt er weiter zu __vectors_pop.
>
> In __vectors_pop wird das Register r24 wieder vom Stack geholt und
> danach springt er zur Reset-Adresse.

1) Wenn ein Reset das Ziel ist, brauch R24 weder gesichert noch 
restauriert zu werden.

2) Wenn du eh zu RESET springst, wozu das alles? Das macht 
__bad_interrupt eh schon.

3) Zum RESET-Vektor zu springen ist keine gute Idee. Die Hardware wird 
dadurch nicht neu initialisiert. Besser: WDT aufziehen und warten bis 
der einen RESET auslöst. Danach steht dann auch die Hardware wieder auf 
"neu": Timer, UART, ...

4) R24 kannst du in einer statischen noinit-Variablen sichern. In MCUSR 
erkennst du die RESET-Ursache. Bei WDT liest du die Variable aus und 
kannst sie verfügbar machen (UART, Display, ...) und damit den Vektor 
rausfinden.

Autor: netb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Johann,

natürlich hast du recht. Wenn man nur zum Resetvektor springt ist das 
ganze alles egal. Das Wiederherstellen von r24 habe ich eher der 
Vollständigkeit halber hier integriert.

Das Ziel ist ja eher eine eigene ISR mit dem BADISR_vect zu erstellen 
und in dieser mit Hilfe der Information "welcher Interrupt war für den 
Sprung verantwortlich" etwas anzufangen.

Beispielsweise eine Debug-Ausgabe, oder das Heraussuchen einer eventuell 
gespeicherten Sprungadresse im SRAM.

Bis dann,
netb

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.