Forum: Mikrocontroller und Digitale Elektronik Problem EEPROM nutzung


von Justus Jonas (Gast)


Angehängte Dateien:

Lesenswert?

Moin Zusammen,
ich hab ein Problem, was ich nicht ganz nachvollziehen kann.

Ich habe eine struct wo verschiedene Einstellungen für einen 
Schrittmotor abgelegt sind. Diese sollen auch im EEPROM abgelegt werden.
1
stepperSetting stepperSetXYZ[2] = { 0 };
2
stepperSetting eestepperSetXYZ[2] EEMEM = { 0 };

Der einzige Zugriff auf eestepperSetXYZ[2] erfolgt mit:
1
void readSetandInitStepper(){
2
  cli();
3
  eeprom_read_block(&stepperSetXYZ, &eestepperSetXYZ, sizeof(stepperSetXYZ));
4
  sei();
5
}
6
7
void writeStepperSettingstoEEPROM(){
8
  cli();
9
  eeprom_update_block(&stepperSetXYZ, &eestepperSetXYZ, sizeof(stepperSetXYZ));
10
  sei();
11
}

Nun ist mein Problem, dass die Daten nicht geschrieben/gelesen werden. 
Beim debuggen ist mir aufgefallen, dass beim Anhalten vom uC und dem 
schreiben eines Wertes (egal ob data oder eeprom), der Wert sich sofort 
auch in den anderen Speicher überträgt. (Siehe beigefügtes Bild, es 
wurde nur eine 55 per Hand gesetzt.) Das ganze ist nicht so schön, wo 
kann diese Verknüpfung herkommen?

Gruß Justus

von 123 (Gast)


Lesenswert?

Justus Jonas schrieb:
> uC

Welcher Typ?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Justus Jonas schrieb:
> Diese sollen auch im EEPROM abgelegt werden.
In welchem EEPROM? Was machen die Funktionen eeprom_read_block() und 
eeprom_update_block()?

von Anselm (Gast)


Lesenswert?

Justus Jonas schrieb:
> void readSetandInitStepper(){
>   cli();
>   eeprom_read_block(&stepperSetXYZ, &eestepperSetXYZ,
> sizeof(stepperSetXYZ));
>   sei();
> }
> void writeStepperSettingstoEEPROM(){
>   cli();
>   eeprom_update_block(&stepperSetXYZ, &eestepperSetXYZ,
> sizeof(stepperSetXYZ));
>   sei();
> }

eehm, du sagts eeprom read aber gibts als parameter die Speicheraddresse 
der normalen Variable, und nicht der "eestepperSetXYZ"
Ist das so beabsichtigt?

von W.S. (Gast)


Lesenswert?

Justus Jonas schrieb:
> Ich habe eine struct wo verschiedene Einstellungen für einen
> Schrittmotor abgelegt sind. Diese sollen auch im EEPROM abgelegt werden.

Schön für dich, daß du eine struct hast.
Aber wo ist der Treiber, der den EEPROM betreibt? Und was für ein EEPROM 
ist das? ein interner in deinem Controller? oder ein externer über SPI 
oder I2C?

In beiden Fällen solltest du erstmal nachlesen, wie der EEPROM zu 
behandeln ist. Und dem EEPROM ist es im Grunde auch egal, ob du eine 
struct hast oder nicht, der funktioniert zumeist stur auf Byte-Basis. 
Also Adresse angeben, beim Schreiben Byte angeben, dann Schreibfunktion 
auslösen. All dieser Kleinkram ist das, was der Treiber erledigen muß.

Bei µC, die einen Teil des Programm-Flashs als EEPROM-Ersatz benutzen, 
geht das zwar anders, braucht aber auch nen Treiber, der die benötigten 
Lösch- und Schreibarbeiten durchführt.

W.S.

von EAF (Gast)


Lesenswert?

W.S. schrieb:
> **Viele Worte um nichts!**

Offensichtlich ist dreht es sich hier um AVR.
Genutzt wird die beim AVR-Gcc mitgelieferte eeprom.h
(aber das kannst du ja nicht erkennen, vermutlich falsche Brille auf)


Hier ist schon mal ein fetter Bock gefunden:
Anselm schrieb:
> du sagts eeprom read aber gibts als parameter die Speicheraddresse
> der normalen Variable

Und ja, der Programmtext ist bis zur Untestbarkeit verstümmelt.
Schade eigentlich.....

von Justus Jonas (Gast)


Lesenswert?

Moin,
es handelt sich um einen Atmega2560 und die eeprom.h

Ich übergebe Speicheradresse im eeprom und die Speicheradresse im ram. 
Die Anordnung ist bei read und update/Write getauscht. Also read(&src, 
&dest, size)
update(&dest, &src, size).

Ich wundere mich einfach sehr, dass sich im angehaltenen Zustand des uC 
der Inhalt vom eeprom ändert, wenn ich den RAM beeinflusse.

Gruß

von Justus Jonas (Gast)


Lesenswert?

Moin,
es ist ein Atmega2560.

Die EEPROM funktionen stammen aus der avr/eeprom.h
https://www.nongnu.org/avr-libc/user-manual/group__avr__eeprom.html

Gruß
Jonas

von Stefan F. (Gast)


Lesenswert?

Justus Jonas schrieb:
> Ich übergebe Speicheradresse im eeprom und die Speicheradresse im ram.

Ich finde seltsam, dass beide Variablen im Debugger auf der gleichen 
Adresse 0x02cb liegen. Das kann doch nicht richtig sein. Die Adressen 
vom EEPROM beginnen nämlich bei 0x0000.

Kontrolliere mal, ob EEMEM überhaupt richtig gesetzt ist.

Zum Beispiel so:
1
#define XSTR(x) STR(x)
2
#define STR(x) #x
3
#pragma message "EEMEM is: " XSTR(EEMEM)

Du solltest dann beim Compilieren eine entsprechende Ausgabe erhalten.

von EAF (Gast)


Lesenswert?

Justus Jonas schrieb:
> Die Anordnung ist bei read und update/Write getauscht.
Da hast du war!
(sieht zumindest in der Doku so aus)

Übrigens:
Ich habe die beiden Funktionen mal versucht zu testen.
Das zerrüttet offensichtlich den Speicher.
Fehlfunktionen, als ob Speicher versehentlich überschreiben wird.

Arduino kennt die äquivalenten Methoden EEPROM.put() und get().
Die funktionieren dagegen prächtig.

Gut, kann mein Bug sein.
Aber zum Ausgleich sehe ich in nicht.

Wie auch immer: Meine Tests waren unbefriedigend.

Und ein unverstümmeltes (original) Testprogramm dürfen wir/ich weiterhin 
nicht erhalten

von Stefan F. (Gast)


Lesenswert?

EAF schrieb:
>> Die Anordnung ist bei read und update/Write getauscht.
> Da hast du war! (sieht zumindest in der Doku so aus)

Sehe ich anders.

Justus Jonas schrieb:
> eeprom_read_block(&stepperSetXYZ, &eestepperSetXYZ,
> eeprom_update_block(&stepperSetXYZ, &eestepperSetXYZ,

https://www.nongnu.org/avr-libc/user-manual/group__avr__eeprom.html 
sagt:
> eeprom_read_block (void *__dst, const void *__src, size_t __n)
> eeprom_update_block (const void *__src, void *__dst, size_t __n)

Das passt doch!

EAF schrieb:
> Ich habe die beiden Funktionen mal versucht zu testen.
> Das zerrüttet offensichtlich den Speicher.
> Fehlfunktionen, als ob Speicher versehentlich überschreiben wird.

Ich habe die Funktionen schon oft benutzt, sie haben immer funktioniert. 
Es wäre auch mehr als seltsam, wenn so ein Bug in weit über 10 Jahren 
nicht behoben worden wäre.

von Uwe (Gast)


Lesenswert?

Hi,
>Ich finde seltsam, dass beide Variablen im Debugger auf der gleichen
>Adresse 0x02cb liegen. Das kann doch nicht richtig sein. Die Adressen
>vom EEPROM beginnen nämlich bei 0x0000.
die Adresse ist zwar etwas ungewöhnlich, mache ich aber auch manchmal
wenn ich Ram zum EEProm spiegle. Dann aber meistens ab $60 oder $100 je 
nach dem wo Ram beginnt. Die Adresse ist dann einfach die selbe.

viel Erfolg, Uwe

von EAF (Gast)


Lesenswert?

Stefan F. schrieb:
> Sehe ich anders.

Stefan F. schrieb:
> Das passt doch!

Du widersprichst dich selber.
src und dest sind in der Signatur vertauscht.

Aber alles gut, das wird schon wieder...

von Stefan F. (Gast)


Lesenswert?

Uwe schrieb:
> die Adresse ist zwar etwas ungewöhnlich, mache ich aber auch manchmal
> wenn ich Ram zum EEProm spiegle.

Da war das Absicht. Hier hat er das aber nicht so programmiert, sondern 
lässt die Adresse von der Toolchain vorgeben. Und die beginnt bei 
0x0000.

Test:
1
#include <avr/eeprom.h>
2
3
int imRam;
4
5
int EEMEM imEEPROM1;
6
int EEMEM imEEPROM2;
7
int EEMEM imEEPROM3;
8
9
int main() {
10
    imRam = 0x0011;
11
    eeprom_update_block((void*) &imRam, &imEEPROM1, 2);
12
    imRam = 0x0022;
13
    eeprom_update_block((void*) &imRam, &imEEPROM2, 2);
14
    imRam = 0x0033;
15
    eeprom_update_block((void*) &imRam, &imEEPROM3, 2);
16
}
1
avr-gcc -mmcu=atmega328p -O1 test.c
2
avr-objdump -h -S a.out

Erzeugt diesen Output:
1
00000090 <main>:
2
3
; imRam = 0x0011
4
5
  90:  81 e1         ldi  r24, 0x11    ; Integer 0x0011
6
  92:  90 e0         ldi  r25, 0x00
7
8
  94:  90 93 01 01   sts  0x0101, r25  ; Variable speichern
9
  98:  80 93 00 01   sts  0x0100, r24 
10
  
11
; eeprom_update_block((void*) &imRam, &imEEPROM1, 2)
12
13
  9c:  42 e0         ldi  r20, 0x02  ; die Länge, 0x0002 Bytes
14
  9e:  50 e0         ldi  r21, 0x00
15
16
  a0:  64 e0         ldi  r22, 0x04  ; die Adresse im EEPROM 0x0004
17
  a2:  70 e0         ldi  r23, 0x00
18
19
  a4:  80 e0         ldi  r24, 0x00  ; Adresse der Variable im RAM 0x0100
20
  a6:  91 e0         ldi  r25, 0x01
21
22
  a8:  0e 94 75 00   call  0xea      ; eeprom_update_block() aufrufen
23
;---------------------------------------------------------
24
25
; imRam = 0x0022;
26
27
  ac:  82 e2         ldi  r24, 0x22    ; Integer 0x0022
28
  ae:  90 e0         ldi  r25, 0x00
29
30
  b0:  90 93 01 01   sts  0x0101, r25  ; Variable speichern
31
  b4:  80 93 00 01   sts  0x0100, r24 
32
33
; eeprom_update_block((void*) &imRam, &imEEPROM2, 2)
34
35
  b8:  42 e0         ldi  r20, 0x02  ; die Länge, 0x0002 Bytes
36
  ba:  50 e0         ldi  r21, 0x00  
37
38
  bc:  62 e0         ldi  r22, 0x02  ; die Adresse im EEPROM 0x0002
39
  be:  70 e0         ldi  r23, 0x00
40
41
  c0:  80 e0         ldi  r24, 0x00  ; Adresse der Variable im RAM 0x0100
42
  c2:  91 e0         ldi  r25, 0x01
43
44
  c4:  0e 94 75 00   call  0xea      ; eeprom_update_block() aufrufen
45
;---------------------------------------------------------
46
47
; imRam = 0x0033;
48
49
  c8:  83 e3         ldi  r24, 0x33    ; Integer 0x0033
50
  ca:  90 e0         ldi  r25, 0x00  
51
52
  cc:  90 93 01 01   sts  0x0101, r25  ; Variable speichern
53
  d0:  80 93 00 01   sts  0x0100, r24  
54
55
; eeprom_update_block((void*) &imRam, &imEEPROM3, 2)
56
57
  d4:  42 e0         ldi  r20, 0x02  ; die Länge, 0x0002 Bytes
58
  d6:  50 e0         ldi  r21, 0x00  
59
60
  d8:  60 e0         ldi  r22, 0x00  ; die Adresse im EEPROM 0x0000
61
  da:  70 e0         ldi  r23, 0x00 
62
63
  dc:  80 e0         ldi  r24, 0x00  ; Adresse der Variable im RAM 0x0100
64
  de:  91 e0         ldi  r25, 0x01 
65
66
  e0:  0e 94 75 00   call  0xea      ; eeprom_update_block() aufrufen

Ich habe da ein paar Kommentare eingefügt.

Interessanterweise hat er die drei Variablen im EEPROM in rückwärts 
Reihenfolge angelegt. Aber was ich hier eigentlich zeigen wollte sieht 
man sehr gut: Dass er den Anfang des EEPROM belegt hat, nicht irgendwo 
die Mitte an Adresse 0x02cb wie beim TO.

von Justus Jonas (Gast)


Angehängte Dateien:

Lesenswert?

Moin,

Stefan F. schrieb:
> Ich finde seltsam, dass beide Variablen im Debugger auf der gleichen
> Adresse 0x02cb liegen. Das kann doch nicht richtig sein. Die Adressen
> vom EEPROM beginnen nämlich bei 0x0000.

Siehe Bilder

Ich habe jetzt mal vor dem write und dahinter angehalten.

Vor dem Write ist die EEPROM Adresse 0x0000 und danach wird sie neu 
gesetzt, in meinem Kopf ist gerade nur die Frage: "Was geschieht denn 
hier?"

Habt ihr noch eine Idee?

von Stefan F. (Gast)


Lesenswert?

Justus Jonas schrieb:
> Siehe Bilder

Ich kappiere nicht, wieso sich die Adressen der Speicherplätze während 
des Programmablaufes ändern. Achte auf die Adressen hinter dem @ 
Zeichen. Das bedeutet doch "Adresse", oder nicht?

Kann es sein, dass der Debugger einen Bug hat?

von Justus Jonas (Gast)


Lesenswert?

Moin,
nein es funktioniert ja auch nicht, daher debugge ich überhaupt.
Ich habe noch ein Array aus ints welches ich auf die gleiche Art 
wegspeichere mit update und read block. Da funktioniert alles super.

Vllt kommt die Funktion mit der struct nicht klar...


Gruß Hannes

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Ach ich habs! Du musst die & Zeichen weg nehmen. Das sind Arrays, und 
Namen von Arrays sind bereits Zeiger auf den Beginn der Daten!

Was du der eeprom_update_block() Funktion hier effektiv übergibst sind 
Zeiger auf Zeiger auf Daten. Dafür sind die Funktionen nicht ausgelegt. 
Sie braucht Zeiger auf Daten (also deren Adressen).

von Justus Jonas (Gast)


Lesenswert?

Auch ohne die & besteht das Problem weiterhin leider.

Kann der Inhalt der struct ein Problem sein?
Ich habe 2 float variablen in der struct.


Gruß Jonas

von Justus Jonas (Gast)


Lesenswert?

Moin,
ich verstehe es immer weniger.

Bild Nr. 3:
eestepperSetXYZ wird 3 mal im Projekt genutzt. Einmal beim deklarieren 
und zweimal beim update/read.

Bild Nr. 4: Beim initialisieren von Werten sollte nichts passieren
Bild Nr. 5: Zack in *eestepperSetXYZ[0].maxCurrentx100mA wird eine 173 
reingeschrieben???

Warum wird plötzlich was in den EEPROM Speicher Bereich geschrieben? 
Verstehe die Welt nicht mehr.

Gruß Hannes

von Justus Jonas (Gast)


Angehängte Dateien:

Lesenswert?

Bilder vergessen

von Stefan F. (Gast)


Lesenswert?

Justus Jonas schrieb:
> Warum wird plötzlich was in den EEPROM Speicher Bereich geschrieben?

Weil du die & Zeichen entfernt hast und damit der eeprom Funktion nun 
korrekte Adressen auf die Speicherbereiche übergibst.

Die Sternchen in den anderen Screenshot sind genau so falsch wie vorher 
die & Zeichen.

Schalte alle Warnungen des Compilers ein (Option-Wall), der compiliert 
deinen Code dann bestimmt nicht ohne entsprechende Hinweise. Eigentlich 
hätte auch der Editor deiner IDE Warnmeldungen anzeigen müssen. Was ist 
denn das für eine dumme IDE?

Liest dich ein, wie man in C auf Arrays zugreift und wie man sie an 
Funktionen übergibt, und wie man Zeiger verwendet.

https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/011_c_arrays_001.htm
https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/012_c_zeiger_001.htm

von Justus Jonas (Gast)


Lesenswert?

Ich glaube ich bin dem Problem nah.

Meine struct besteht hauptsächlich aus Pointern welche auf Daten in 
einem Input Buffer zeigen.
1
typedef struct{
2
  uint8_t *maxCurrentx100mA;
3
  uint8_t *stillstandCurrentx100mA;
4
  uint8_t *stillstandCurrentTime; 
5
  
6
  uint16_t *maxRPM;
7
  uint16_t *minRPM;
8
  uint16_t *breakRPM;
9
  
10
  uint8_t *endstopDIGroupForward; //Endstops
11
  uint8_t *endstopDIPinForward;
12
  uint8_t *endstopDIGroupReverse;
13
  uint8_t *endstopDIPinReverse;
14
  
15
  uint8_t *referenceDIGroup; //referencestop and speed
16
  uint8_t *referenceDIPin;
17
  uint16_t *refSpeedFast;
18
  uint16_t *refSpeedSlow;
19
  
20
  uint8_t *breakDIGroup; //conveyormode 
21
  uint8_t *breakDIPin;
22
  uint8_t *stopDIGroup;
23
  uint8_t *stopDIPin;
24
  uint16_t *breakSpeed;
25
  
26
  uint8_t *currentSenseResistor;
27
  
28
  uint8_t *a;
29
  float b;
30
  
31
  uint16_t *stepsPerRound;
32
  uint8_t *microstepsPerRound;
33
  
34
} stepperSetting;

Das scheint schon mal nicht so gut zu funktionieren. Aber die 
Seiteneffekte kann ich mir trotzdem überhaupt nicht herleiten.

von Stefan F. (Gast)


Lesenswert?

Justus Jonas schrieb:
> Das scheint schon mal nicht so gut zu funktionieren.

Natürlich nicht, wohin zeigen die Pointer denn? Wo ist der Code, der für 
die Daten Speicherplatz reserviert und die Pointer darauf zeigen lässt?

> Aber die Seiteneffekte kann ich mir trotzdem überhaupt nicht herleiten.

Wenn du über nicht initialisierte Pointer auf irgendwelchen 
undefinierten  Speicher zugreifst, kann alles passieren. Über das mal 
lieber gründlich auf einem PC. Meistens werden solche Programme mit 
einem Speicherzugriffsfehler (Segmentation fault) abgebrochen. 
Mikrocontroller haben diese Kontrolle jedoch nicht. Die machen dann 
einfach etwas unerwartetes.

von Stefan F. (Gast)


Lesenswert?

In Screenshot 4.png und 5.png stimmen die Kommentare nicht mit den 
Werten überein. Irreführende Kommentare sind schlimmer als gar keine!

Dein if/else hat so keinen Sinn weil in beiden Fällen das gleiche 
passiert.

von EAF (Gast)


Lesenswert?

Justus Jonas schrieb:
> Meine struct besteht hauptsächlich aus Pointern

Es ist meist eine dumme Idee, Pointer im EEPROM zu speichern.
Denn die könne bei/nach jedem Kompilieren woanders hin zeigen.

OKOK, ich bin jetzt raus.

von Justus Jonas (Gast)


Lesenswert?

Stefan F. schrieb:
> In Screenshot 4.png und 5.png stimmen die Kommentare nicht mit den
> Werten überein. Irreführende Kommentare sind schlimmer als gar keine!
>
> Dein if/else hat so keinen Sinn weil in beiden Fällen das gleiche
> passiert.

Ich habe aktuell 0,4 Ohm und einen 5,5A Motor an dem Con Stepper, das 
ist aber nicht die Serienbestückung. Das passt schon.

Stefan F. schrieb:
> Justus Jonas schrieb:
>> Das scheint schon mal nicht so gut zu funktionieren.
>
> Natürlich nicht, wohin zeigen die Pointer denn? Wo ist der Code, der für
> die Daten Speicherplatz reserviert und die Pointer darauf zeigen lässt?
>
>> Aber die Seiteneffekte kann ich mir trotzdem überhaupt nicht herleiten.
>
> Wenn du über nicht initialisierte Pointer auf irgendwelchen
> undefinierten  Speicher zugreifst, kann alles passieren. Über das mal
> lieber gründlich auf einem PC. Meistens werden solche Programme mit
> einem Speicherzugriffsfehler (Segmentation fault) abgebrochen.
> Mikrocontroller haben diese Kontrolle jedoch nicht. Die machen dann
> einfach etwas unerwartetes.

Die Pointer sind alle auf einen Buffer gemappt und das funktioniert 
auch. Die Werte werden alle initialisiert. Es funktioniert nur die 
Speicherung im EEPROM nicht und dadurch auch das einlesen dieser Werte. 
Wirklich!


Mir ist noch aufgefallen, dass die Adresse von stepperSetXYZ 0x02fb 
lautet, die Daten aber alle davor liegen. Aber das erste Struct Element 
liegt bei 0x0281 also vor der Adresse. Irgendwie unschön oder?

von Stefan F. (Gast)


Lesenswert?

Justus Jonas schrieb:
> Die Pointer sind alle auf einen Buffer gemappt und das funktioniert
> auch. Die Werte werden alle initialisiert. Es funktioniert nur die
> Speicherung im EEPROM nicht und dadurch auch das einlesen dieser Werte.
> Wirklich!

Logisch. Du Speicherst Zeiger ins EEPROM, die auf Daten im RAM zeigen. 
Was passiert wohl mit den Daten im RAM, wenn man neu startet?

Dieser wilde Misch-Masch aus Zeigern tut nicht einmal ansatzweise das, 
was es vermutlich tun soll. Und was es tun soll ist auch nicht klar 
erkennbar, so falsch sind die Fragmente des gezeigten Quelltextes.

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.