Forum: Mikrocontroller und Digitale Elektronik 16 Bit RAM-Zugriff beim AVR Assembler


von Holler (Gast)


Lesenswert?

Hallo zusammen,
alle Jubeljahre beschäftige ich mich mit Mini-Controller-Projekten, so 
dass ich nicht wirklich tief in der Materie stecke.

Momentan habe ich einen kleinen Temperatur- und Spannungswächter auf dem 
Tisch, soll mit einem ATTiny45 realisiert werden (habe ich gerade in der 
Bastelkiste, ist schon überdimmensioniert).

Zum Punkt: ich möchte 16 Bit Messwerte im RAM mit 16 Bit Konstanten 
vergleichen. Dabei fällt auf, dass der Zugriff mit low / high(Name) bei 
den Konstanten funktioniert, aber bei Variablen im RAM Müll liefert.
Beispiel:

;Konstante
.equ    NTCblau     = 0x0123  ; kalt, <60 Grad

;Variable im RAM
.DSEG                           ; Umschalten auf das SRAM Datensegment
NTCMittel:    .BYTE  2
;...
; Das funktioniert
ldi  r22, low (NTCblau)
ldi  r23, high(NTCblau)

;Das liefert Müll
lds  r22, low (NTCMittel)
lds  r23, high(NTCMittel)

;Der Workaround
lds  r22, NTCMittel
lds  r23, NTCMittel+1

Kann man das low/high Konstrukt nicht für RAM-Zugriff nutzen?
Warum meckert dann der Assembler nicht?

von Dr. Sommer (Gast)


Lesenswert?

Hast du denn überhaupt erst was an die Stelle im RAM geschrieben?! 
Einfach nur etwas Laden liefert irgendwelche zufälligen Werte, die beim 
Reset da drin stehen.

von Axel S. (a-za-z0-9)


Lesenswert?

Holler schrieb:
> Kann man das low/high Konstrukt nicht für RAM-Zugriff nutzen?

Nein. Es ergibt an dieser Stelle auch überhaupt keinen Sinn. NTCblau ist 
eine Konstante, die kann der Assembler zur Übersetzungszeit in low- und 
high-Teil zerlegen. NTCMittel hingegen ist eine Adresse. Eine 16-Bit 
Variable belegt im Speicher aber zwei aufeinanderfolgende 
Speicherplätze. Vulgo: die Startadresse und Startadresse+1

> Warum meckert dann der Assembler nicht?

Weil es syntaktisch korrekt ist.

Wenn du mit derartigen Trivialitäten wie dem Zugriff auf Variablen mit 
mehr als einem Byte überfordert bist, dann verwende nicht Assembler, 
sondern eine Hochsprache. Z.B. C. Oder meinetwegen auch BASIC (BASCOM) 
oder LunaAVR. Die verbergen diese Details vor dem Anwender.

von Dr. Sommer (Gast)


Lesenswert?

Äh, moment, falsch gelesen.

Holler schrieb:
> ;Das liefert Müll
> lds  r22, low (NTCMittel)
> lds  r23, high(NTCMittel)
Das kann nicht funktionieren... Das lädt r22 von der Adresse 
low(NTCMittel) - also einer völlig anderen als gewünscht, und r23 von 
high(NTCMittel), also von einer noch ganz anderen Adresse.

Holler schrieb:
> lds  r22, NTCMittel
> lds  r23, NTCMittel+1
Das ist richtig - r22 kommt von der Adresse NTCMittel, und r23 von der 
nächsten.

von Sascha W. (sascha-w)


Lesenswert?

Holler schrieb:
> Hallo zusammen,
> alle Jubeljahre beschäftige ich mich mit Mini-Controller-Projekten, so
> dass ich nicht wirklich tief in der Materie stecke.
>
> Momentan habe ich einen kleinen Temperatur- und Spannungswächter auf dem
> Tisch, soll mit einem ATTiny45 realisiert werden (habe ich gerade in der
> Bastelkiste, ist schon überdimmensioniert).
>
> Zum Punkt: ich möchte 16 Bit Messwerte im RAM mit 16 Bit Konstanten
> vergleichen. Dabei fällt auf, dass der Zugriff mit low / high(Name) bei
> den Konstanten funktioniert, aber bei Variablen im RAM Müll liefert.
> Beispiel:
>
> ;Konstante
> .equ    NTCblau     = 0x0123  ; kalt, <60 Grad
>
> ;Variable im RAM
> .DSEG                           ; Umschalten auf das SRAM Datensegment
> NTCMittel:    .BYTE  2
> ;...
> ; Das funktioniert
> ldi  r22, low (NTCblau)
> ldi  r23, high(NTCblau)
>
> ;Das liefert Müll
> lds  r22, low (NTCMittel)
> lds  r23, high(NTCMittel)
>
> ;Der Workaround
> lds  r22, NTCMittel
> lds  r23, NTCMittel+1
>
> Kann man das low/high Konstrukt nicht für RAM-Zugriff nutzen?
Nein,
lds erwartet eine 16Bit-Speicheradresse des SRAM,
Low liefert dir die unteren 8-Bit der Adresse, High die oberen 8-Bit
1
lds r22,NTCMittel
2
lds r23,NTCMittel+1
ist die richtige Wahl

ich habe mir da entsprechende Makros angelegt
1
.macro ldsw
2
lds @0H,@1
3
lds @0L,@1+1
4
.endmacro
5
6
im Code:
7
lsw X,NTCMittel

Ob du im Ram erst das H und dann das L Byte oder umgekehrt speicherst 
bleibt dir überlassen.

Sascha

von Fred (Gast)


Lesenswert?

Ich würde NTCMittel ja mal als .Word Variable definieren, dann klappts 
vielleich auch mit dem Low/High Zugriff...

von Dr. Sommer (Gast)


Lesenswert?

Fred schrieb:
> Ich würde NTCMittel ja mal als .Word Variable definieren, dann klappts
> vielleich auch mit dem Low/High Zugriff...

Völlig egal, Assembler ist nicht typisiert... Für manche Leute der 
Hauptgrund, das zu verwenden!

von Holler (Gast)


Lesenswert?

Danke für die superschnellen Antworten!

@Dr. Sommer (Gast): ja da stand etwas sinnvolles im RAM. Der Zugriff 
über das low/high Kontrukt lieferte aber weder den Inhalt noch die 
Adresse sondern irgendwas beliebiges.

@Axel Schwenke: Überfordert fühle ich mich nicht, Assembler ist schon 
das einfachst mögliche Werkzeug. Habe die Lösung ja schon in meinem 
Eingangspost skizziert. Dachte halt, dass der Assembler das selbst 
auflösen kann wenn er schon nicht meckert. Das Kontextwissen hat er ja.
Man könnte sich den Maschinencode ansehen was der Assembler daraus 
macht.

von Dr. Sommer (Gast)


Lesenswert?

Holler schrieb:
> Dachte halt, dass der Assembler das selbst
> auflösen kann wenn er schon nicht meckert. Das Kontextwissen hat er ja.

Naja, was genau soll der Assembler da sehen? Er sieht zwei völlig 
unterschiedliche Adressen, aber das kann ja Absicht sein. Woher soll er 
wissen dass du die Adressen falsch berechnest, und dass r22 und r23 
zusammen gehören?

Disassemblierten Code anschauen kann helfen...

von Holler (Gast)


Lesenswert?

War viel zu langsam mit meiner Antwort: vielen Dank für die Posts, habe 
verstanden was das low/high Konstrukt bewirkt.

von Fred (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Disassemblierten Code anschauen kann helfen...

Was soll der Quatsch? Das Assemblat hast Du vor Dir- da gibts nix zu 
"Disassemblieren"...

von Dr. Sommer (Gast)


Lesenswert?

Fred schrieb:
> Was soll der Quatsch? Das Assemblat hast Du vor Dir- da gibts nix zu
> "Disassemblieren"...
Doch, in der Disassembly sieht man die vom Assembler/Linker berechneten 
Adressen in "Reinform". Da würde man erkennen, dass das genutzte 
low()/high() -Konstrukt nicht das beabsichtigte produziert.

von Peter D. (peda)


Lesenswert?

low und high sind im Prinzip nur Macros. Sie machen folgendes:
1
#define low(x) (x & 0xFF)
2
#define high(x) low(x >> 8)

Damit ist auch klar, warum sie nicht im RAM verwendbar sind.

von Fred (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Fred schrieb:
> Was soll der Quatsch? Das Assemblat hast Du vor Dir- da gibts nix zu
> "Disassemblieren"...
>
> Doch, in der Disassembly sieht man die vom Assembler/Linker berechneten
> Adressen in "Reinform". Da würde man erkennen, dass das genutzte
> low()/high() -Konstrukt nicht das beabsichtigte produziert.

Ok, da hast Du Recht.
Wenn die Variable z.B. auf 400/401H steht würde via lds zum einen (low) 
der Inhalt von 00H, zum anderen (high) von 04H gelesen. Was sich auf 
diesen Adressen lesbar befindet steht noch einmal auf einem anderen 
Blatt.

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
Noch kein Account? Hier anmelden.