Forum: Mikrocontroller und Digitale Elektronik [AVR] m8535-EEPROM wird falsch gelesen


von Eingehirner (Gast)


Lesenswert?

Ich scheine ja nicht viel Erfolg mit meinen bisherigen Fragen gehabt zu 
haben... gebe ich ZU viele Infos?

Egal, ich hab grade folgendes Problem, ich finde den Fehler einfach 
nicht (seit ca. 1 Woche auf der Suche):

Ich schreibe einen Hamster-Tacho mit grafischer Ausgabe der 
Laufgeschwindigkeit der letzten 24h (als Kurve), der Uhrzeit und der 
gesamten Kilometer pro 24h. Dafür sollen alle 20min die gezählten 
Tachokontakte am Laufrad ins EEPROM geschrieben werden (72 rotierend 
verwendete Bytes), ausserdem soll die Uhrzeit dort abgelegt werden und 
einige andere Variablen, unter anderem zwei WORDS mit der EEPROM-Adresse 
der Umdrehungszähler. Da es dabei gelegentlich Fehler beim Programmieren 
gibt, prüfe ich aktuell meine EEPROM-Routinen. Die sind auch fehlerhaft, 
vermute ich.

Das Problem ist nun: Ich schreibe das EEPROM folgendermassen ganz ans 
Ende meines Programms,
1
.ESEG ; EEPROM-Datensektion
2
Uhrzeit_Stunden:
3
.db 12
4
Uhrzeit_Minuten:
5
.db 34
6
NumIntervals:
7
.db 0
8
Umdrehungen_save: ; 72 Speicherplätze für die Kurve
9
.db 0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,  0,0
10
NumRotAddr:
11
.dw Umdrehungen_save
12
MinNumRotAddr:
13
.dw Umdrehungen_save

Wenn ich das mit avrasm2 (von Atmel) mit -e-Parameter compiliere, ergibt 
sich ein EEPROM-File, das die Daten in sinnvoller Weise enthält.

Wenn ich den µC damit beschicke (und mit dem Flashprogramm), sollen 
davon Schritt für Schritt die Werte gelesen und aufm LCD ausgegeben 
werden, klappt auch für den ersten Wert (12). Danach werden nur noch 
0xFF ausgegeben.

Lese ich das EEPROM mittels avrdude ... -Ueeprom:r:eeprom.dat:i aus, 
stehen die obigen Daten korrekt drin!

Hier der asm-Code:
1
main_loop_debug:
2
; lcd_number, lcd_x und lcd_y sind die Argumente für print_byte_LCD und
3
; print_byte_number_LCD: die Zahl wird an der Spalte lcd_x, page lcd_y 
4
; beginnend als Byte oder Dezimalzahl ausgegeben
5
        ldi lcd_number, 0
6
        ldi lcd_x, 0
7
        ldi counter,0
8
9
        ldi ZH,0 ; dient zu EEPROM-Adressierung, wie hier im Tutorial beschrieben
10
        mov ZL,counter ; geht auch mit adiw, gleicher Effekt fürs Debuggen
11
counter_loop:
12
        rcall EEPROM_read ; siehe unten, beschreibt tmp2 mit dem Wert an ZL/ZH 
13
        mov lcd_number, tmp2
14
        ldi lcd_y, 0
15
        ldi lcd_x, 6
16
        rcall print_byte_LCD ; Ausgabe des EEPROM-Wertes als Byte
17
        ldi lcd_y, 1
18
        rcall print_byte_number_LCD ; Ausgabe des EEPROM-Wertes als Zahl
19
20
        inc counter ; Counter hochzählen
21
        mov ZL, counter
22
        ldi lcd_y, 2
23
        mov lcd_number, ZL
24
        rcall print_byte_number_LCD ; Ausgabe des Adress-Counters, zur Kontrolle
25
        rcall wait1s ; damit ich was seh...
26
        rjmp counter_loop
27
28
        rjmp main_loop_debug ; wird nie erreicht
29
;----------------------------
30
EEPROM_read:
31
; lädt den EEPROM-Wert an ZH.ZL nach tmp2
32
        sbic EECR,EEWE
33
        rjmp EEPROM_read
34
        out EEARH, ZH   ; Adresse laden
35
        out EEARL, ZL
36
        sbi EECR, EERE  ; Lesevorgang aktivieren
37
        in tmp2, EEDR   ; low Byte nach tmp2 kopieren
38
        ret

von Helfer (Gast)


Lesenswert?

> Ich scheine ja nicht viel Erfolg mit meinen bisherigen Fragen gehabt zu
> haben... gebe ich ZU viele Infos?

Zu viele, so dass keiner mosern will "mehr Infos!". Und zu wenige, um 
sich in absehbarer Zeit der Sache annehmen zu können...

Einen kompletter Sourcecode, der das Problem zeigt, könnte man in den 
Simulator werfen und sich ansehen, ob es dort richtig läuft bzw. was 
schief läuft. Idealerweise käme der Code ohne externe Hardware (LCD) 
aus. Benutzt dein Restcode Interrupts und wenn ja ist das push/pop von 
Registern OK?

Wenn dein Code im Simulator den Fehler nicht zeigt, dann wären Angaben 
zur Hardware (Schaltung und Fuses - Bronwout?) notwendig.

Angaben zu Unterschieden bei der Implementierung zwischen deinem Code 
und dem Tutorialcode wären auch gut. Bei meinem Vergleich meine ich zu 
sehen: Die eigentliche EEPROM_read ist 1:1 übernommen. Ich spekuliere 
(da nicht simulierbar s.o.) auf den Verlust des Werts in ZL. Was macht 
dein Code mit diesem Stück?
1
        inc counter ; Counter hochzählen
2
        ldi lcd_y, 2
3
        mov lcd_number, counter
4
        rcall print_byte_number_LCD
5
        rcall wait1s ; damit ich was seh...
6
        mov ZL, counter
7
        rjmp counter_loop

von Helfer (Gast)


Lesenswert?

1) Add: Sicherer noch auch ZH setzen
1
        rcall wait1s ; damit ich was seh...
2
        ldi ZH, 0
3
        mov ZL, counter
4
        rjmp counter_loop

2) Die Anzeige von counter mit print_byte_number_LCD ist aber schon 
korrekt?

von Eingehirner (Gast)


Lesenswert?

OK, danke, zuviele Infos, ich hatte sowas schon vermutet...

Also: Mein Code verwendet Interrupts, genauer gesagt, den Timer1 im 
CTC-Modus mit Interrupt bei Erreichen des Maximalwerts (als 
"Uhr"-Zeitgeber) und den INT0 für die Reedkontaktsignale. Ist etwas 
schwierig zu simulieren, ABER momentan läuft nur ein Minimalbeispiel des 
Codes, den ich mal anhänge. Alle push/pop-Paare sind überprüft (und es 
treten nicht wirklich viele auf). Alle Label-Sprünge sind überprüft. Ich 
meine, das Problem auf ein meinerseits irriges Verständnis des 
EEPROM-Ansprechens reduziert zu haben.

Ich habe schon gelegentlich funktionierenden Code gesehen, bei dem ZH 
einmal gesetzt und dann nicht mehr verändert wurde, das sollte 
hoffentlich nicht das Problem sein, zumal das jetzt nur die Testversion 
ist.

denk *denk* ins Handbuch schau *fett in den eigenen Hintern tret* 
nochmal im Tutorial nachles
1
.include "m8def.inc"
2
 
3
    ldi     R16, 0xFF
4
    out     DDRB, R16               ; Port B: Ausgang
5
 
6
    ldi     ZL, LOW(daten*2)        ; Low-Byte der Adresse in Z-Pointer
7
    ldi     ZH, HIGH(daten*2)       ; High-Byte der Adresse in Z-Pointer
8
 
9
    lpm                             ; durch Z-Pointer adressiertes Byte
10
                                    ; in R0 laden
11
    out     PORTB, R0               ; an PORTB ausgeben
12
 
13
ende:   
14
    rjmp ende                       ; Endlosschleife
15
 
16
daten:
17
    .db 0b10101010
Mal ne saublöde Frage -- wieso wird hier ZL VOR ZH belegt? Im 
Datenblatt steht, dass mit dem Setzen von ZL direkt auch ZH übernommen 
wird, also kann dieses Beispiel von 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Speicher doch gar 
nicht funktionieren... oder?

von Eingehirner (Gast)


Lesenswert?

Tjaaaaa... selig sind, die nicht wissen und doch glauben? In dem Fall 
wohl nicht, das war der eklatante Fehler -- ich hatte ÜBERALL im Code ZL 
vor ZH beschrieben, getreu dem Beispiel im EEPROM-Tutorial... jetzt 
klappts. VIELEN DANK!! Es war zwar kein klarer Hinweis dabei, aber durch 
deine Antwort (Helfer) bin ich ins Nachdenken und auf die Lösung 
gekommen.... oh mann. In Zukunft wird NUR noch das Datenblatt zu sowas 
befragt :/

von Eingehirner (Gast)


Lesenswert?

Äääähm... die Geschichte mit dem low/high(LABEL*2) scheint auch nicht zu 
stimmen, es klappt bei mir nur OHNE das *2... was ist das eigentlich für 
ein Tutorial?!?

von Helfer (Gast)


Lesenswert?

> Mal ne saublöde Frage -- wieso wird hier ZL VOR ZH belegt? Im
> Datenblatt steht, dass mit dem Setzen von ZL direkt auch ZH übernommen
> wird,

Mal eine andere saublöde Frage: Wo genau im Datenblatt liest du das? Die 
zusammengefassten Register X,Y,Z sind was anderes als die speziellen 
16-Bit Hardwareadressen/-register wie z.B. EEAR. Bei letzteren ist die 
Reihenfolge für Lesen/Schreiben wichtig.

Die anderen Fragen kann ich nicht beantworten, weil aus deinen Beiträgen 
nicht klar hervor geht, was du machst. Deshalb nur ein allgemeiner Rat: 
In den x2 Beispielen musst du beachten, wo die Daten abgelegt sind: Im 
Flash-ROM (Beitrag "Re: [AVR] m8535-EEPROM wird falsch gelesen"), im 
EEPROM (Beitrag "[AVR] m8535-EEPROM wird falsch gelesen") oder im 
SRAM. Alle drei Arten verlangen ihre eigene Adressierung!

Den versprochenen Anhang finde ich nicht.

> Äääähm... die Geschichte mit dem low/high(LABEL*2) scheint auch nicht zu
> stimmen, es klappt bei mir nur OHNE das *2... was ist das eigentlich für
> ein Tutorial?!?

Wenn du ein bestimmtes Beispiel mit seinen Problemen benennen kannst, 
schaue ich mir das an. Die Zeit und Muse alle Beispiele auf potentielle 
Probleme durchzunudeln habe ich nicht.

von Eingehirner (Gast)


Lesenswert?

Hast recht, sorry, hab den Anhang einfach vergessen... ok. Blöd. Der 
liegt daheim aufm Rechner...

Im Datenblatt steht nicht direkt drin, daß man ZH vor ZL besetzen muß 
(es wird nur als Word-Register eingeführt und ich hab dieses Prinzip von 
den anderen 16-Bit-Sachen übernommen), aber nach dieser Änderung tat 
mein Code auf einmal. Ehrlich gesagt verstehe ich aber nach nochmaliger 
Lektüre aller dazugehörigen Texte hier im Tutorial immer weniger, warum 
eigentlich... kann das Behandeln des X-, Y- Z-Pointers ggf. 
compilerabhängig sein?

Das *2 hatte sich offenbar bei MIR reingemogelt, obwohl ich gar kein lpm 
verwende. Problem geklärt.

OK. Damit, trotz immer noch andauerndem Unverständnis: Probleme gelöst. 
Es tut alles. Vielen Dank!

P.S.: Wenn der Hamstertacho mal fertig ist, stell ich Schaltplan und 
Code ins Archiv, das ist vermutlich sinnvoller, als die xhundert Zeilen 
Code hier ins Forum zu packen...

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.