Hallo zusammen,
ich habe ein Verständnisproblem und hoffe hier Hilfe zu erhalten.
Wenn ich ein Probgramm in Assembler schreibe und gucke mir den Code mit
der Disassembler Funktion unter AVR Studio an, dann sieht das wunderbar
aus.
(Ganz einfaches Programm!)
Wenn ich es aber in C schreibe (gleicher Sinn) und mir dann den
Assembler code ansehe fängt der schon gar nicht bei Adresse Null an!
Das sieht irgendwie total durcheinander aus. Kann das vielleicht mit der
Optimierung zu tuen haben? Wobei die auf -Os steht.
Hab mal die ersten Zeilen eingefügt
----UNKNOWN_FILE--------------------------------------------------------
-----
0: File not found
+00000000: 940C0038 JMP 0x00000038 Jump
Kann mir jemand was dazu sagen?
Vielen Dank im voraus.
Vermutlich verwendest Du keine Interrupts, dann beginnt
Dein Code wahrscheinlich bei 0x0000. Der Compiler setzt bei Adresse
0x0000 einen Sprung der über die Interrupt-Sprungtabelle hinwegführt.
(Mache bei Asm-Programmen aus Prinzip schon immer so...)
Bei unbenutzen Interrupts steht dann halt ein Reti.
Nur für verständnis.
Es stimmt es sind keine Interrupts vorhanden. Heißt das, dass in C der
Compiler gleich einen Offset für eventuelle Interrupts einfügt?
Keinen Offset, sondern eine Sprungtabelle, also einen Block von Code,
der aus jmps besteht, für jeden Interruptvektor einen. Auch danach
beginnt nicht Dein Programm, sondern es folgen die Flash-Konstanten
(Dinge, die im Programm mit PROGMEM festgelegt wurden). Dann kommt der
C-Startup-Code, und erst danach folgt Dein Programm.
> Aber er scheint ja etliche Male am Anfang immer zur gleichen Stelle zu> springen! Warum macht er das denn?
Interrupts, die im Programm nicht belegt sind, werden mit einem Sprung
zu einem Default-Handler vorbelegt, um nicht in der Wüste zu landen.
Der Default-Handler macht nichts als einen Soft-Reset (Sprung zu dem
Vektor auf Adresse 0 -- den Default-Handler hast Du bei Dir auf Adresse
0x55).
Tommy schrieb:> Aber er scheint ja etliche Male am Anfang immer zur gleichen Stelle zu> springen! Warum macht er das denn?
Er überspringt die Interupt Tabelle.
Okay ich glaube so langsam schnall ichs!
Die Interrupteinspring Tabelle steht ja am Anfang des Flash und wird im
C Programm übersprungen. Das ist doch soweit richtig. Aber was ich jetzt
nicht verstehe, ist das in der Assemblerversion das Programm keine
Adressen am Anfang überspringt. Also doch nicht geschnalt. Oder ist das
so, dass die Assembler Version gar nicht die Interrupt Tabelle einfügt,
wenn sie nicht genutzt wird. Kann man sich das so vorstellen? Wenn das
so ist, wäre für kleine Programme Assembler immer platzsparender als C
oder?
Nein. In der Assembler-Version musst Du die Interrupttabelle
schreiben (so Du eine haben willst), denn die Laufzeitumgebung bestimmst
alleine Du. In Assembler wird kein vorgefertigter Code hinzugefügt,
solange Du es nicht befiehlst.
Ah okay! Aber wenn ich einen bestimmten Interrupt bentzen will, dann
muss ich darauf achten, wo er im Flash hingeschrieben werden muss, da
sie an fest definierten Adressen stehen müssen.
Tommy schrieb:> Ah okay! Aber wenn ich einen bestimmten Interrupt bentzen will, dann> muss ich darauf achten, wo er im Flash hingeschrieben werden muss,
Richtig
> da> sie an fest definierten Adressen stehen müssen.
Genau. Und diese Adressen sind quasi eine Vereinbarung zwischen
Controller-Hersteller und Programmierer (oder Compilerbauer). Genaue
Informationen dazu findest Du im Datenblatt des betreffenden
Controllers, denn jeder AVR ist anders mit (interruptauslösenden)
Features ausgestattet, braucht also eine andere Sprungtabelle.
MfG, Consulter
Und ich hätte noch eine Frage:
Mein Default Handler springt ja an Adresse 0x0000000.
Ist das dann nicht eine Endlosschleife?
+00000000: 940C0038 JMP 0x00000038 Jump
+00000002: 940C0055 JMP 0x00000055 Jump
+00000004: 940C0055 JMP 0x00000055 Jump
Kommt er zur Adresse +00000002 springt der zur Adresse 0x00000055 die
ihm sagt spring nach Adresse +000000000. Fängt das dann nicht wieder von
vorne an?
Vielen Dank an alle!
Jetzt hab ichs geschnallt!
Wirklich letzte Frage:
Dann kann ich doch anhand der Junps am Anfang feststellen, wie viele
Interrupts der MC hat, oder? Ich weiß zwar nicht was für welche aber die
Anzahl weiß ich.
Hc Zimmerer schrieb:> Oder ist das> so, dass die Assembler Version gar nicht die Interrupt Tabelle einfügt,> wenn sie nicht genutzt wird.
Das ist dem Aessemler egal, ob Du die Interrupt Tabelle benutzt oder
nicht. Er schreibt sie so wie Du sie schreibst, schreibst Du keine
schreibt er auch keine.
Tommy schrieb:> Ah okay! Aber wenn ich einen bestimmten Interrupt bentzen will, dann> muss ich darauf achten, wo er im Flash hingeschrieben werden muss, da> sie an fest definierten Adressen stehen müssen.
Wenn ein bestimmter Interrupt ausgelöst wird springt der Programmcounter
an die bestimmte Adresse von diesem Interrupt, da muß die Sprungadresse
stehen, wo der Code für diesen Interrupt steht.
Tommy schrieb:> Kommt er zur Adresse +00000002 springt der zur Adresse 0x00000055 die> ihm sagt spring nach Adresse +000000000. Fängt das dann nicht wieder von> vorne an?
Ja! und dann nach 0x00000038 wo dein Programm anfängt.
Hc Zimmerer schrieb:>> Hc Zimmerer schrieb:> Das schrieb ich nicht. Bitte korrekt zitieren.
Muß natürlich heißen "Tommy schrieb:"
(Wenn man Text markiert und dann rechts klickt "Markierten Text
Zitieren" und man erwischt einen anderen passiert dies.) war keine
Absicht.
Tommy schrieb:> Dann kann ich doch anhand der Junps am Anfang feststellen, wie viele> Interrupts der MC hat, oder? Ich weiß zwar nicht was für welche aber die> Anzahl weiß ich.
Sehe mal hier mit dem Editor ganz unten
C:\Programme\Atmel\AVR Tools\AvrAssembler\Appnotes\m162def.inc
MarioT schrieb:> Tommy schrieb:>> Kommt er zur Adresse +00000002 springt der zur Adresse 0x00000055 die>> ihm sagt spring nach Adresse +000000000. Fängt das dann nicht wieder von>> vorne an?>> Ja! und dann nach 0x00000038 wo dein Programm anfängt.
@Tommy
Ganz genau.
Das Problem ist: Auf einem µC muss immer irgendwas passieren. Ein Aufruf
eines Interrupts, für den es keinen Handler gibt, ist natürlich ein
Fehler. Aber was soll denn der Default Handler machen? Er weiß ja nichts
von deiner Hardware. Also sind die gcc Leute den Weg des geringsten
Widerstands gegangen und haben das einzig Sinnvolle getan, was sie tun
können: Sie lassen das komplette Programm neu starten. Das gibt dir zum
einen die Chance, den Fehler während der Entwicklung festzustellen und
führt auf der andern Seite dazu dass in einer Produktionsumgebung
zumindest die Chance besteht, dass dein µC nach dem Fehler wieder seine
Arbeit aufnimmt.
Denkbar wäre auch gewesen:
den µC in einer Endlosschleife gefangen zu halten. Das hat aber den
Nachteil, dass dann mit Sicherheit dein µC hängt.
den Interrupt einfach zu ignorieren, gar nichts zu tun und zu returnen.
Das hat aber wieder den Nachteil, dass du in der Entwicklungsphase es
nicht bemerkst, dass du einen Interrupt freigegeben hast, der nicht
behandelt wird.
Zu guter letzt: Es gibt auch noch die Möglichkeit sich selbst einen
Default-Handler zu schreiben, der sich dann so verhält, wie du dir das
vorstellst.