AVR: warum jeder Unterbrechungsvektor zwei Befehlswörter belegt

Während meines Studiums des Atmega328-Datenblatts fand ich heraus, dass jeder Interrupt-Vektor zwei Adressen belegt, und nach der Suche kann ich nicht finden, warum das so ist.

Das ist ein Screenshot von atmega328p Datenblatt Seite 82

Geben Sie hier die Bildbeschreibung ein

Ich habe die Spezifikation nicht vor mir, aber es ist ziemlich üblich, dass Adressen größer als ein einzelnes Speicherwort sind. Jeder Interrupt-Vektor speichert eine Adresse, sodass eine Adresse wahrscheinlich zwei Speicherwörter belegt.

Antworten (1)

Die Einheitsgröße der Vektortabelle hängt davon ab, welchen Chip Sie verwenden. Beispielsweise verwenden ATTiny-Chips 2 Bytes (1 Befehl) für jeden Vektor in der Tabelle.

Der Grund für das Zulassen mehrerer Befehle auf den größeren Prozessoren besteht darin, die Verwendung größerer Befehle zu ermöglichen.

Für einen AVR RJMPist der Befehl ein 2-Byte-Befehl für einen relativen Sprung – er kann jedoch nur auf eine Verschiebung von +/-4 kB aus der Vektortabelle zugreifen. Dies ist bei kleineren Prozessoren mit <8 kB Flash in Ordnung, da ISRs (Interrupt Service Routines) überall im Flash-Speicher platziert werden können. Für größere AVRs wie den 32kB Flash ATMega328 ist dies jedoch nicht genug (*).

Um auf den vollen Flash-Speicher zuzugreifen, müssen Sie die Anweisung verwenden JMP. Dies ist ein direkter Sprung, mit dem Sie auf bis zu 4 MB Flash zugreifen können. JMPDer Befehl ist jedoch tatsächlich ein 4-Byte-Befehl. Um diese in der Vektortabelle zu verwenden, müssen Sie für jeden Vektor 2 Befehlswörter zulassen. Und genau das tun sie.

Es ist immer noch durchaus möglich, RJMPoder jeden anderen Einzelwortbefehl innerhalb einer Zweiwort-Vektortabelle zu verwenden. Alles, was Sie tun, ist, ein weiteres hinzuzufügen, NOPum die Anweisung auf zwei Wörter aufzufüllen.

Außerdem müssen Sie nicht unbedingt irgendwohin springen. Stellen Sie sich vor, Ihr ISR müsste nichts weiter tun, als ein Bit in einem IO-Register zu setzen. SBIAuf einem AVR können Sie, wenn sich das Register in Reichweite befindet, die Anweisung oder verwenden, CBIum dies zu tun. Da dies keine Nebenwirkungen auf die ALU-Flags hat, können Sie innerhalb einer Vektortabelle mit zwei Anweisungen Ihre gesamte ISR ( SBIAnweisung gefolgt von RETIAnweisung) erstellen und den gesamten Overhead des Springens zu einer ISR sparen.


(*) Es ist tatsächlich möglich, wenn auch langsamer, sogenannte "Trampoline" zu benutzen. Dies ist im Grunde ein Fall des Platzierens einer einzelnen JMPAnweisung im Flash innerhalb einer +/-4k-Verschiebung von der Vektortabelle. Die Vektortabelle enthält eine RJMPAnweisung, die zu der nahe gelegenen JMPAnweisung springt, die wiederum zu einer beliebigen Stelle im Flash springt.

Gemäß Ihrer Notiz (*) kann es in unserem Fall sein, dass die erste Adresse zum Speichern des Interrupt-Vektors und die zweite Adresse zum Speichern der tatsächlichen Adresse der Interrupt Service Routine ?
@mostafayasin Nein, wenn eine JMPAnweisung verwendet wird, ist die Adresse des ISR in die Anweisung eingebettet, es ist nur so, dass die Anweisung 4 Bytes belegt. Wenn ein Trampolin auf Geräten mit 2 Byte/Vektor in der Tabelle verwendet wird, dann RJMPbefindet sich die Anweisung in der Vektortabelle, die die relative Adresse der JMPAnweisung speichert, die woanders im Speicher platziert ist. Die JMPAnweisung hat immer noch die Adresse der darin eingebetteten ISR.