Forum: Mikrocontroller und Digitale Elektronik Probleme mit .db oder .dw in SRAM ?


von Oliver F. (rocky)


Lesenswert?

Ich versuche seit stunden eine möglichkeit zu finden meinen Speicher
optimal auszunutzen und würde gerne in mein SRAM einige Bytes ablegen,
das sind keine Variablen sondern Konstante die ich aber mit einem
Pointer ansprechen muss. Das EEPROM ist bereits anderwertig belegt.

Nun zu meinem eigentlich Problem, ich wollte gerne per AVR-Studio 4 den
SRAM direkt beschreiben. Dafür gibt es ja angeblich solche tollen
Befehle .db und .dw.
Da ich ein Tiny26 nutze, habe ich natürlich auch nur ein SRAM mit 8
Bit! somit fällt .dw für mich sowieso weg.
Nun habe ich schon überall nach einer erklärung gesucht wie ich nun
meine Liste einfügen. Ich stelle euch mal vor was ich beisher gemacht
habe.

...
.dseg
.org $0060 (habe bereits gemerkt das ich org weglassen kann)
.db 9,25,37,40
.cseg
loop:
ldi YL,sram_start

ld R16,Y
out porta, R16
rjmp loop

Ich habe auch schon versucht direkt das SRAM auszulesen mit lds aber
egal welche teile ich auslese ich bekomme total flasche werte raus und
auch wenn ich die werte im db ändere dann ändern sich die werte nicht,
immer noch totaler müll.
Als Hinweis, ich programmiere nur in Assembler, und wie oben erwähnt
habe ich ein Tiny26 und der SRAM beginnt ab 0x60 ($0060). Und der SRAM
hat 128 Byte größe.
Ich hoffe ihr könnt mir helfen.

von Εrnst B. (ernst)


Lesenswert?

Der SRAM Speicher hat nach dem Reset undefinierte Werte, und kann auch
nicht per ISP o.ä. "Vorprogrammiert" werden.

(Der Ram-Inhalt ist auch nicht im HEX-File)

Du müsstest also deine Konstanten im Flash ablegen, und beim
Programmstart in das SRAM umkopieren, oder gleich dort lassen.

(So macht das auch der C-Compiler, wenn man Variablen vorbelegt)

/Ernst

von Oliver F. (rocky)


Lesenswert?

Genau das habe ich vermutet ... aber gehofft das es nicht so ist :(

Also müsste ich für meinen Pointer doch wieder auf den EEPROM
umsteigen.

Wenn ich die Daten aus dem Flash ins SRAM kopiere brauche ich
mindestens 2 Befehle ...

ldi R16,irgendeinWert
sts 0x60,R16

gibts da vllt eine kürzere Variante, also das ich den Wert direkt in
den SRAM schreiben kann beim Start des Programms, dann wäre es vllt
doch noch eine überlegung ...

von Εrnst B. (ernst)


Lesenswert?

Einfach einen Bereich mit Konstanten im Flash ablegen, und beim Start in
einer Schleife ins SRam kopieren?

Braucht nur beim Start ein bischen Zeit, und danach ist der Zugriff
aufs SRAM schnell...

/Ernst

von Jadeclaw D. (jadeclaw)


Lesenswert?

Müssen denn diese Konstanten während des Programmlaufs geändert werden?
Wenn nicht, dann lässt du das Schreiben ins SRAM für die Konstanten
ganz weg und liest direkt mit dem LPM-Befehl aus dem Flash.
Bis auf den AT90S1200 haben den alle drin.
  ldi ZL, Low(Daten*2)  ;StartAdresse setzen.
  ldi ZH, High(Daten*2)
  lpm R16, Z      ;Wert in R16 laden.
Und wenn du eine Tabelle abgrasen willst, pack den:
  lpm R16, Z+      ;Wert in R16 laden.
in eine Schleife.
Das + bedeutet, dass das Z-Register automatisch erhöht wird.

Gruss
Jadeclaw.

von Oliver F. (rocky)


Lesenswert?

Darüber bin ich gerade am grübbeln, aber irgendwie habe ich wohl ein
Brett vorm kopf, denn mir fällt dafür keine schleife ein. Da ich nicht
alle Register belegen kann weiß ich nicht wie ich die daten per
schleife jedesmal in ein (oberes)register ziehen kann.

.equ erste_info = 0x05
.equ zweite_info = 0x38
.equ dritte_info = 0x44
... ca 50 daten

loop:
ldi R16,erste_info
sts y+,R16

und hier fällt mir nicht ein, wie ich ihm sagen soll was den das
nächste ist was er in R16 laden soll.

rjmp loop

Ich muss zugeben, ich habe nicht gedacht das es doch noch so
umständlich wird ...

Eine 2. Frage noch nebenbei zu db und dw ...
Ich weiß das die Befehle mit eseg funktionieren um das EEPROM zu
beschreiben. Aber ich habe es auch schon mitten im asm code gesehen,
und angeblich soll es da auch funktionieren ?! Also es stand mitten
drin aber ich weiß nicht was der befehl dann zur folge haben soll, da
es ja kein Befehl direkt ist sondern nur zum assemblieren.

http://www.avr-asm-tutorial.net/avr_de/quellen/Lcd4IncC.asm

Habe das da gelesen ... habe das programm mir nicht weiter angeschaut,
nur das .db war mir aufgefallen.

von Sebastian (Gast)


Lesenswert?

.db sagt dem Assambler einfach dass hier ein Datenbyte kommt, er die
Daten also nicht in Code übersetzten soll.
.dw macht das gleiche mit einem Datenwort.

Aber genaueres sagt dir die Hilfe deines Assamblers.

von Hannes L. (hannes)


Lesenswert?

.db und .dw funktioniert auch im .cseg, also im Flash. In Verbindung mit
Labels kannst du mit LPM über den Z-Pointer jederzeit darauf zugreifen.

Aber das wurde weiter oben schon erklärt...

...

von Εrnst B. (ernst)


Lesenswert?

Das sind Konstanten, die im Flash abgelegt werden.
Werden also wie normale opcodes mit ins Flash kopiert, man muss nur
aufpassen das der AVR nie versucht die auszuführen.
können dann mit der LPM Anweisung (drei Taktzyklen) gelesen werden.

/Ernst

von Oliver F. (rocky)


Lesenswert?

Wow, es hat gerade klick gemacht ;) Danke für die schnellen Antworten
... habe das mit dem LPM zwar mal gelesen aber noch nie bisher getestet
... werde mich morgen damit mal auseinandersetzen, dümmer machen kann es
einen bestimmt nicht :)

@Jadeclaw
Du hast da YH und YL gewählt, ist das überhaupt nötig beim Tiny 26 ?
und was ist den (daten*2), also muss ich für daten die position angeben
im flash? Wenn ja wie finde ich die den raus, oder vorher einfach org
$0000 setzen ?

Wie ihr merkt, fehlt mir da noch ein wenig das Feingefühl und die
Praxis, die ich gerade auffrischen möchte :)

Nochmals Danke für die ganzen Infos, auch auf die (aus eurer Ansicht)
dusseligen Fragen ... :)

von Jadeclaw D. (jadeclaw)


Lesenswert?

Der AVR kennt keine 16Bit-Ladebefehle, deshalb muss man ZH und ZL
separat laden.
Das mit den 'Daten*2' hat einen einfachen Grund:
Adressen beziehen sich für den Assembler immer auf 16bit-Worte,
die Adressindexierung über X/Y/Z-Register beziehen sich aber auf
8Bit-Bytes, deshalb das 'Daten*2'.
'Daten' ist das Label, *2 verdoppelt den Wert, damit man den
richtigen Adresswert für den Byte-Zugriff hat.
Und man braucht dafür keinen Extra-.org setzen, wenn der Assembler auf
ein Label mit daran folgenden .db oder .dw-Anweisungen findet,
setzt er automatisch den richtigen Adresswert ein.
So bringt man Daten in den Flash:
Text: .db "Dies ist ein Test", 0x0D, 0x0A, "Zweite Zeile", 0x00

Abruf:
  ldi ZL, Low(Text*2)  ;StartAdresse setzen.
  ldi ZH, High(Text*2)
  lpm R16, Z      ;Wert in R16 laden.

Der Assembler ersetzt nun 'Text' durch die beim Assemblieren
errechnete tatsächliche Adresse.
Lässt du das Stück Code laufen,
landet der erste Buchstabe ('D') in R16.

Übrigens, LPM geht nur mit dem Z-Register.
Gruss
Jadeclaw.

von Hannes L. (hannes)


Lesenswert?

> und was ist den (daten*2), also muss ich für daten die position
> angeben
> im flash? Wenn ja wie finde ich die den raus, oder vorher einfach
> org
> $0000 setzen ?

'daten' ist das Label, das vor dem '.db' zu stehen hat.

Dieses Label ist für uns Menschen ein (leicht merkbares) Wort, für den
Compiler aber nur eine Zahl, in diesem Fall die
(doppelbyte-orientierte) Adresse im Flash.
Da LPM aber die Adresse byte-orientiert braucht, muss sie beim Setzen
des Z-Pointers verdoppelt werden.

...

von Thomas O. (Gast)


Lesenswert?

so habe ich das letzens gemacht. Erst habe ich den nötigen Platz
reserviert, und dann die Sachen ins SRAM geschrieben. Und danach erst
zum eigentlichen Programmanfang. Interessieren würde mich ob man auch
halbe Bytes reservieren kann da ich in diesem Beispiel jeweils nur 4
Bits ablege.

.DSEG  ;Reserve jeweils 1 Byte eim SRAM
Voll1:  .byte  1
Voll2:  .byte  1
Voll3:  .byte  1
Voll4:  .byte  1

ldi temp, 0b10100000  ;Speichere Schrittfolge im SRAM um Register zu
sparen
sts Voll1, temp
ldi temp, 0b10010000
sts Voll2, temp
ldi temp, 0b01010000
sts Voll3, temp
ldi temp, 0b01100000
sts Voll4, temp
ldi temp, 0b10100000

lds temp, Voll1        ; hier wird dann die Speicherstelle Voll1
ausgelesen bzw. nach temp geladen
out porta, temp

von Oliver F. (rocky)


Lesenswert?

Nun habe ich das wie folgt aufgebaut:

char:
.db 0x43,0x4F,0x52,0x53

ldi R30,low(char*2)
ldi R31,high(char*2)

lpm R16,z+
lpm R17,z

Ich wollte das nur mal testen, aber nun schreibt der assembler mir:

lpm R16,z+; unsupported insruction on ATtiny26 :(

Hat einer eine Idee wie ich es ggf umgehen kann oder ob das beim tiny26
wirklich net möglich ist :(

von Oliver F. (rocky)


Lesenswert?

Ok, die Frage hat sich ein wenig vereinfacht ich habe herausbekommen das
man ja einfach folgendes tun kann um an den 2. wert zu gelangen.

char:
.db 0x43,0x4F,0x52,0x53

ldi R30,char*2

;ldi R31,high(char*2) (den teil habe ich raus genommen da es den nicht
gibt, besser gesagt ich kann ihn nicht direkt auslesen

lpm R16,z
inc R30 oder ldi R30,(char*2)+1
lpm R17,z


Schade das z+ net geht, aber so gehts auch in einer schleife wird der
eine inc befehle nicht soviel resourcen ausmachen ...

von Kriki (Gast)


Lesenswert?

Prinzipiell funktionierts ganz einfach:

Irgendwo definierst du wo das ganze hin soll im SRAM

.equ SRAMStartposition = 0x60 (wenns das das .org  gewesen sein
sollte)

dann hast du dein Programm ...

bla bla bla

LDI r31,high(Tabelle<<1)
LDI r30,low(Tabelle<<1)
LDI r29,high(TabelleEnde<<1)
LDI r28,low(TabelleEnde<<1)

LDI r27,high(SRAMStartposition)
LDI r26,low(SRAMStartposition)


loop:
      LPM r16,Z   ;Kopiert vom Programmspeicher
      inc r30     ;Erhöht Z
      cpi r30,0x00
      brne loop2
      inc r31
loop2:
      STS X+,r16   ;Speichert r16 im SRAM
      cp r28,r30   ;Vergleicht ob schon am Ende
      brne loop
      cp r29,r31
      brne loop
weiter im Code ..
bla bla bla

Programm fertig.

dann kannst du folgendes machen

Tabelle:

.db 0x00,0x01,0x02 ... (sollte gerade Anzahl haben)
.db 0x10,0x11 ....

TabelleEnde:
Fertig

von Kriki (Gast)


Lesenswert?

Upsa .. Fehler mit eingebaut

STS X+,r16   ;Speichert r16 im SRAM FALSCH
ST X+,r16   ;Speichert r16 im SRAM RICHTIG

von Hannes L. (hannes)


Lesenswert?

> Hat einer eine Idee wie ich es ggf umgehen kann oder ob das beim
> tiny26 wirklich net möglich ist :(

Die Classics und die alten Tinys unterstützen LPM nur in seiner Urform,
kopieren das adressierte Byte also nach R0.

Ich helfe mir auf den Tinys meist damit, dass ich je ein unteres
Register für 0 und 1 reserviere und dann den Zugriff so organisiere:

 lpm                        ;nächste Tondauer aus Liste nach R0 holen
 mov dauer,r0               ;und in Tondauerzähler kopieren
 add zl,eins                ;Pointer erhöhen
 adc zh,null                ;evtl: Übertrag auch

Das Beispiel stammt aus einem Melodiegenerator mit Tiny15.

...

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.