Hallo,
ich arbeite mich zur Zeit als blutiger Programmieranfänger durch das
AVR-Assembler-Tutorial. Soweit habe ich eigentlich alles gut verstanden
und auch schon erste kleine eigene Programme zur Led-Ansteuerung
ausgetüftelt.
Allerdings hänge ich jetzt schon seit gestern Abend an folgender Stelle:
Zitat:
Der Befehl lpm dient zum Laden einzelner Bytes aus dem Programmspeicher.
Das ist vor allem für Tabellen mit konstanten Werten sehr nützlich
(7-Segmentdekoder, Zeichensätze, Kennlinien, Parameter Texte, etc.) Doch
wie kommt man nun in dem wortweise adressierten Programmspeicher an
einzelne Bytes? Ganz einfach. Der AVR "mogelt" hier und erwartet im
Z-Register eine Byte-Adresse. Von dieser Adresse bilden die Bits 15..1
die Wortadresse, welche zur Adressierung des Programmspeichers verwendet
wird. Bit 0 entscheidet dann, ob das hoch- oder niederwertige Byte in
das Zielregister kopiert werden soll (0=niederwertiges Byte;
1=höherwertiges Byte).
Darum muss bei Verwendung des Befehls lpm die Anfangsadresse immer mit
zwei multipliziert werden.
Zitat Ende.
Wieso man die eigentliche Programmspeicheradresse mit 2 multiplizieren
muss verstehe ich (alle Bits werden 1 nach links geshiftet, sodass die
eigentlich Programmspeicheradresse (die ja eh nur 12 Bit lang ist) auf
den Bits 15-1 liegt). Was mir allerdings unklar ist, ist wie jetzt
bestimmt wird, welches Byte denn jetzt geladen werden soll. Denn das
unterste Bit ist nach einer Multiplikation mit 2 doch immer 0 oder
nicht?
Oder ist es so, dass man generell erst das low Byte lädt, dann den
Z-Pointer mit lpm r16,Z+ auf das high Byte setzt und anschliesend das
lädt?
Verstehe ich es richtig, dass der Z-Pointer nur im Zusammenhang mit dem
lpm Befehlt Byte-Weise positioniert wird und ansonsten immer auf eine
komplette 16bit Programmspeicheradresse zeigt die dann in ZL und ZH
aufgeteilt ist und z.b. mit ijmp angesprungen werden kann?
Vielen Dank!
Gruß,
Timo
Timo schrieb:> den Bits 15-1 liegt). Was mir allerdings unklar ist, ist wie jetzt> bestimmt wird, welches Byte denn jetzt geladen werden soll. Denn das> unterste Bit ist nach einer Multiplikation mit 2 doch immer 0 oder> nicht?
2 Dinge
* wenn du mittels eines Labels irgendetwas im Programmspeicher
unterbringst, dann sorgt der Assembler schon dafür, dass es auf
die gerade Adresse zu liegen kommt.
d.h. in dem Fall brauchst du einfach nur die Adresse (in Form des
Labels) beim Laden des Z-Pointers mal 2 nehmen und alles passt.
* zweitens.
Auch der Z-Pointer ist im Grunde nur eni Register (eigentlich
Registerpärchen) wie jedes andere. Alle Befehle, die auf
Register anwendbar sind, funktionieren selbstverständlich
auch für das Registerpärchen R30/R31 (welche ja den Z-Pointer
darstellen). Insbesondere kann man selbstverständlich nach dem
Laden noch 1 dazuzählen oder man kann das selbstverständlich
auch direkt beim Laden des Z-Pointers schon angeben. Der Assembler
kann ja rechnen. Er hat ja auch die Adresse (die durch das
Label gegeben ist) mal 2 rechnen können. Da kann er dann auch
ruhig noch 1 dazuzählen.
>> Oder ist es so, dass man generell erst das low Byte lädt, dann den> Z-Pointer mit lpm r16,Z+ auf das high Byte setzt und anschliesend das> lädt?
Das macht jetzt aber was anderes., mittels
lpm r16, Z+
lpm r17
lädst du ja 2 hintereinanderliegende Bytes aus dem Flash.
> Verstehe ich es richtig, dass der Z-Pointer nur im Zusammenhang mit dem> lpm Befehlt Byte-Weise positioniert wird und ansonsten immer auf eine> komplette 16bit Programmspeicheradresse zeigt die dann in ZL und ZH> aufgeteilt ist
Der Z-Pointer ist immer in ZH und ZL aufgeteilt (volgo R30/R31)
>Was mir allerdings unklar ist, ist wie jetzt bestimmt wird, welches Byte >denn
jetzt geladen werden soll. Denn das unterste Bit ist nach einer >Multiplikation
mit 2 doch immer 0 oder nicht?
Was hindert Dich daran unmittelbar nach der Multiplikation noch eine
weitere Operation anzufügen, die das zu ladende Byte bestimmt?
Stimmt. Nichts.
>Oder ist es so, dass man generell erst das low Byte lädt, dann den>Z-Pointer mit lpm r16,Z+ auf das high Byte setzt und anschliesend das>lädt?
Nein. Mit lpm r16,Z+ wird sowohl ein Byte geladen und Z erhöht.
Es wäre sinnlos, generell erst das low Byte laden. Es mag z.B. sein, das
man nur das Byte an der ungeraden Adresse braucht. Wozu dann noch das an
der geraden Adresse laden?
>Verstehe ich es richtig, dass der Z-Pointer nur im Zusammenhang mit dem>lpm Befehl Byte-Weise positioniert ...
Nicht nur. Aber beim lpm Befehl schon.
> ... und ansonsten immer auf eine
komplette 16bit Programmspeicheradresse zeigt die dann in ZL und ZH
aufgeteilt ist und z.b. mit ijmp angesprungen werden kann?
Nein. Nicht "ansonsten". Was Du beschreibst ist die Interpretation des
Wertes in Z im Falle des ijmp. Es gibt andere Interpretationen. In der
Befehlsbeschreibung stehen die weiteren.
Vielen Dank erst mal ihr Beiden!! :) Das bringt mich weiter.
Karl Heinz Buchegger schrieb:> Das macht jetzt aber was anderes., mittels>> lpm r16, Z+> lpm r17>> lädst du ja 2 hintereinanderliegende Bytes aus dem Flash.Kali schrieb:> Nein. Mit lpm r16,Z+ wird sowohl ein Byte geladen und Z erhöht.
Stimmt... da hab ich wohl einmal zu viel geladen
Kali schrieb:> Nein. Nicht "ansonsten". Was Du beschreibst ist die Interpretation des> Wertes in Z im Falle des ijmp. Es gibt andere Interpretationen. In der> Befehlsbeschreibung stehen die weiteren.
Ah natürlich.. ich verstehe. Der Z-Pointer enthält einfach eine Adresse
des Programmspeichers. Die Befehle können damit dann natürlich machen
was sie wollen :) (lpm sieht einfach die obersten 15 Bits als
Programmspeicheradresse von der geladen werden soll an)
Kali schrieb:> Was hindert Dich daran unmittelbar nach der Multiplikation noch eine> weitere Operation anzufügen, die das zu ladende Byte bestimmt?> Stimmt. Nichts.
Stimmt.. jetzt wo du es sagst. Frage mich, wieso ich mich damit jetzt so
schwer getan habe. Ist doch eigentlich alles nur logisch :)
Warscheinlich muss sich mein Hirn erst mal an die neue Denkweise mit den
ganzen Registern und Speicheradressen gewöhnen, ist doch recht viel
neuer Stoff den es zu verarbeiten gilt.
Timo schrieb:> Ah natürlich.. ich verstehe. Der Z-Pointer enthält einfach eine Adresse> des Programmspeichers. Die Befehle können damit dann natürlich machen> was sie wollen :) (lpm sieht einfach die obersten 15 Bits als> Programmspeicheradresse von der geladen werden soll an)
Du magst jetzt vielleicht lächeln, aber das, genau das, ist eine ganz
wichtige Erkentniss in so gut wie allen Programmiersprachen, ganz
speziell aber in Assembler. Die Kombination von Befehlen macht das
Rennen. Die Befehle selbst sind eigentlich ganz einfach.