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
Hallo, ah ja, Entschuldigung. Ich arbeite hier mit einem AtXMega128A1 und mit der aktuellen Version vom AVRGCC und der AVR-LibC. Bis dann, netb
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 :)
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
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.
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.
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:
1 | 00000316 <__bad_interruptx>: |
2 | 316: 8f 93 push r24 |
3 | 318: 80 e0 ldi r24, 0x00 ; 0 |
4 | 31a: 0c 94 db 01 jmp 0x3b6 ; 0x3b6 <__vectors_pop> |
5 | |
6 | 0000031e <__vector_2>: |
7 | 31e: 8f 93 push r24 |
8 | 320: 81 e0 ldi r24, 0x01 ; 1 |
9 | 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.
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.
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
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.