ATTiny85 und avrdude: EEPROM auslesen nur jedes zweite Byte

OP #6585093
Lesenswert?

Hallo zusammen,

ich hab ein kleines Problem bzw. eine Frage und hab dazu hier oder im 
Datenblatt nichts gefunden... was nicht heisst, dass da kein Brett vorm 
Kopf sein kann ;-)

Ich schreibe ein Programm, das Daten im EEPROM des ATTiny85 speichern 
und bei Gelegenheit wieder auslesen soll. So weit, so primitiv. Hab den 
Beispielcode aus dem Datenblatt kopiert, leicht angepasst, ein 
Testscript geschrieben und lösche beim Aufspielen des Flash auch gleich 
das EEPROM auf 0x00 (weil 0xFF als Default im Programm zu Problemen 
führen würde).

Dann mache ich folgendes:
200x ein Byte Daten hintereinander ins EEPROM speichern
--> EEPROM sollte so aussehen: 0x00,0x01,0x02,0x03...,0xc7, dann nur 
noch Nullen
200x diese EEPROM-Daten Byte für Byte auslesen, als Code bitweise auf 
LED ausgeben, in die nächsten 200 EEPROM-Speicherplätze schreiben
--> EEPROM sollte so aussehen: 
0x00,0x01,0x02,0x03...,0xc7,0x00,0x01,0x02...

Die Bytes werden von der LED sehr nett ausgegeben, stimmen alle mit der 
Erwartung überein. Der Code scheint also genau das zu machen, was er 
soll.

ABER wenn ich jetzt das EEPROM mit avrdude auslese:
avrdude -c avr910 -p t85 -P /dev/ttyUSB0 -U eeprom:r:IR_RemoteData.hex:h

dann sieht das File IR_RemoteData.hex so aus:
0x00,0x01,0x00,0x03,0x00,0x05...,0xc7,0x00,0x00,0x02,0x00,0x04,0x00,0x06 
...

Das heisst, es wird nur jedes zweite Byte ausgelesen. Ich sehe auch hier 
am "Frameshift" von erster zu zweiter Sequenz, dass die Daten da sind 
(sonst könnte das 0x02 von der zweiten Sequenz nicht da sein, es wurde 
ja direkt von der ersten Sequenz kopiert), aber eben - jedes zweite Byte 
fehlt.

Das ist sowohl beim Format Hex (Format-Code h) als auch bei Intel Hex 
(Format-Code i) der Fall, daran liegt's nicht...

Diese Situation ist fürs Debugging blöd und ich würde die Daten auch aus 
Interesse gern auslesen... Weiss jemand, was hier schiefgeht?

Viele Grüsse und danke schonmal,
Simon
OP #6585122
Lesenswert?

Hallo zusammen,

es geht hier gar nicht um den Code. Wie gesagt: Die Daten werden korrekt 
ins EEPROM geschrieben, korrekt ausgelesen und neu geschrieben (jeweils 
mit LED überprüft). Was nicht klappt, ist das Auslesen mittels avrdude.

Ich programmiere in Assembler, habe also keine Probleme mit den 
Datentypen...

Viele Grüsse,
Simon
Gast #6585143
Lesenswert?

> es geht hier gar nicht um den Code
Nun ja, so steht es im Betreff: "... avrdude ...".

> Daten werden korrekt ins EEPROM geschrieben, korrekt ausgelesen
Avrdude kenne ich nicht, gebe aber zu bedenken, dass es noch eine andere 
Möglichkeit gibt, dass nämlich der 'Assembler-Code' sowohl beim 
Schreiben wie beim Lesen den selben Versatz hat. Also wäre das Programm 
vielleicht doch von Interesse, zumindest solange nicht ein 
Avrdude-Kenner das Fehlverhalten bestätigt.
OP #6585258
Lesenswert?

Problem gelöst - danke an S. Landolt für den entscheidenden Hinweis!

Fürs Protokoll: Ich lag mit meiner Analyse daneben, der avrdude 
funktioniert einwandfrei. Asche auf mein Haupt und ja, es wäre schneller 
gegangen, wenn ich den Code einkopiert hätte... auch wenn ich nach wie 
vor nicht weiss, was genau logisch/mathematisch falsch war. Hab eine (in 
meinen Augen funktional identische) Alternative ausprobiert und 
schwupps, klappt alles.

Vielleicht weiss das ja jemand? (Diesmal mit Code.)

Ich habe in r17 den Wert, der ins EEPROM soll, in r18 und r19 die 
low/high-Bytes der Adressen (und nein, sie sind nicht vertauscht).

Ich inkrementiere die Adresse in jedem Schritt so (Snippet aus dem alten 
Code):
1
ldi r16, 0   ; dummy zero for adding with carry
2
inc r18      ; low byte ==> das ist offenbar schon ein Fehler, weil inc kein Carry setzt (laut Datenblatt nur Z,N,V), aber da ich nur von 0-200 zähle, sollte ein nicht gesetztes Carry keinen Unterschied machen (hätte ich gedacht). Falsch ist es trotzdem. Sollte subi r18, -1 sein, denke ich.
3
adc r19, r16 ; high byte, add carry

Das führt dazu, dass jedes ZWEITE Byte an die richtige Stelle im EEPROM 
geschrieben wird und jedes ANDERE ZWEITE Byte sehr viel weiter hinten 
(oberhalb von Position 256, nicht exakt - die genaue Stelle weiss ich 
nicht mehr). r18/r19 scheinen also immer hin und her zu springen. Ich 
verstehe nicht warum.

Alternativ hab ich folgendes probiert, das einwandfrei funktioniert:
1
  ldi ZH, 0  ; low(EEPROM address)
2
  ldi ZL,  0 ; high(EEPROM address)
3
  ldi r17, 1 ; Data to be written to EEPROM
4

5
  ; Write data to first 200 bytes in EEPROM
6
  DLoop1:
7
    rcall EEPROM_write  ; Write r17 to EEPROM address H:L r19:r18
8
    adiw Z, 1           ; Increment address
9
    mov r18, ZL
10
    mov r19, ZH
11
    inc r17             ; Increment data to be written
12
    cpi r17, 200        ; Stop after 200 writes
13
    brne DLoop1
14

15
  ; Verify data in first 200 bytes of EEPROM by reading them and writing them to second 200 bytes
16
  ldi r20, 200
17
  ldi ZH, 0 ; Reset EEPROM address
18
  ldi ZL, 0
19
  DLoop2:
20
    mov r18, ZL
21
    mov r19, ZH
22
    rcall EEPROM_read   ; Read EEPROM data from H:L r19:r18 into r17
23

24
;    rcall DEBUGr17 ; Ausgabe von r17 (Data von EEPROM) als Blinken auf LED
25

26
    adiw Z, 50          ; Go to address x+200 - adiw accepts only values <60??? Found nothing about this in datasheet.
27
    adiw Z, 50          ; Go to address x+200
28
    adiw Z, 50          ; Go to address x+200
29
    adiw Z, 50          ; Go to address x+200
30
    mov r18, ZL
31
    mov r19, ZH
32
    rcall EEPROM_write  ; Store r17 here
33

34
    sbiw Z, 49          ; Increment to next address
35
    sbiw Z, 50
36
    sbiw Z, 50
37
    sbiw Z, 50
38
    dec r20             ; Count down, do this 200x

Nach dieser Erkenntnis wäre es vermutlich sinnvoll, wenn ich meinen 
EEPROM_write und EEPROM_read auf die Nutzung von ZH/ZL umschreiben 
würde, dann spar ich mir die Kopiererei...

Weiss jemand, wo das mit der Werte-Obergrenze beim adiw dokumentiert 
ist?

Viele Grüsse,
Simon
Gast #6585764
Lesenswert?

S. Landolt schrieb:

> Mir ist ohnehin nicht klar, was sich Atmel bei den Befehlen adiw und
> sbiw gedacht hat - nie schneller als subi sbci, und nur im Fall 0..63
> kürzer.

Naja, früher(tm) gab es die Instruktionen überhaupt nur für den 
Immediate-Bereich 0..63. Ist das heute anders?

Und der Vorteil der adiw, subiw war natürlich wirklich die Ersparnis von 
Flashspace. Das, was die C-ler als "Zeigerarithmetik" betiteln, läßt 
sich damit bezüglich des Platzbedarfs wirklich ganz ordentlich 
eindampfen, aber auch der Zugriff auf Datenstrukturen im Flash, denn 
leider gibt es für (e)lpm ja keine indizierte Adressierung mit Offset, 
da ist man zur exzessiven Nutzung von "Zeigerarithmetik" von Haus aus 
gezwungen.
Gast #6585792
Lesenswert?

Ihr erster Absatz ist mir völlig unverständlich.

"Datenstrukturen im Flash": wenn ich solche wirklich umfangreich nutzen 
wollte, würde ich sie innerhalb von 256-Byte-Blöcken anordnen und mit 
subi ZL arbeiten (was auch noch jeweils 1 Takt spart).

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren