Forum: Compiler & IDEs Probleme rund um den EEPROM und Header-files


von Peter K. (Gast)


Lesenswert?

Hallo zusammen,

ich habe folgendes Problem:
Ich bin Anfänger.
Nein, also es geht darum dass ich einen CAN-Bus aufbauen möchte. Daher 
sollen alle Konfigurationen des Controllers bequem im EEPROM landen und 
dort auch eine feste Position haben. D.h. Ich möchte den EEPROM wie 
folgt "einteilen":
1
eeprom-adresse |  Inhalt
2
---------------+------------
3
0x000          | 0x00 (soll angeblich besser leer bleiben)
4
0x001          | <CAN-Controller Register-Adresse 1>
5
0x002          | <Wert, der in CAN-Register1 geschriebn werden soll>
6
0x003          | <CAN-Controller Register-Adresse 2>
7
0x004          | <Wert, der in CAN-Register2 geschriebn werden soll>
8
...
9
0x01E          | <CAN-Controller Register-Adresse 15>
10
0x01F          | <Wert, der in CAN-Register15 geschriebn werden soll>
11
...

Im Programm soll dann einfach eine Schleife laufen, die jeweils 2 Werte 
ausliest und diese mit nem Scheibbefehl an den CAN-Controller sendet.
(am SPI-Bus wäre das dann: Schreibbefehl, Register-Adresse, 
Register-Wert.)
Die paar Zeilen, die den EEPROM auslesen sollen und deren Inhalt per SPI 
verschicken sollen, sind aber nicht das Problem, vielmehr der EEPROM 
macht mir Ärger.

Nun habe ich mich im AVR-Tutorial belesen und auch sonst viel gegoogelt, 
doch ganz will ich nicht schlau werden, da es wohl keine schöne Lösung 
für sowas gibt.

Meine Fragen lauten nun also:
Wie generiere ich eine .eep-Datei, die ich anschliesend mit dem 
AVR-Studio auf meinen ATMEGA laden kann?
Muss ich da umständlich im AVR-Studio die im Tutorial beschriebenen 
Tricks und Umwege gehen, oder kann ich die auch irgendwie extern 
erzeugen?
Wenn ich die tatsächlich im AVR-Studio "generieren" muss ( mit einem 
Array, das den gesamten EEPROM füllt ), wo wird dann dieses Array 
definiert? Im Header (z.B. eep.h) wärs fehl am Platz, klar. Im 
Source-File (eep.c) würde ich es hinschieben. Ist das richtig?

Wär nett wenn mir diesbazüglich jemand helfen könnte.
MfG
Peter

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

1) Du definierst eine Struktur, die dein Datenobjekt darstellt.

2) Du erzeugst davon so viele Instanzen wie du brauchst und in den
   Speicherbereichen wo sie gebraucht werden. ZB eine im RAM und eine
   im EEPROM mit EEMEM aus <avr/eeprom.h>

3) Je nach sichbarkeit stehen im Header extern-Decls oder das Zeug ist
   static in den Modules die's brauchen. Im Header brauchst du das
   EEMEM nicht mit angeben, so daß du nicht die eeprom.h in alle
   Quellen mitincluden musst.

4) Zugriff mit den Funktionen eeprom_* (für EEPROM), pgm_* (Flash), oder
   C-üblich (RAM)

5) Du lässt die eeprmo-Datei erzeugen, zB IHex-Format:
1
avr-objcopy -j .eeprom --change-section-lma .eeprom=1 -O ihex alles.elf alles.eeprom.hex

von Peter K. (Gast)


Lesenswert?

Danke. Aber deine Antwort zeigt mir, dass ich mich undeutlch ausgedrückt 
habe. Gut vieles ist trotzdem sehr informativ, vorallem das mit dem 
extern und static muss ich mnir nochmal anschauen, aber:

Ich möchte auf mehreren Nodes am CAN-Bus die Configuration verändern 
können, indem ich ganz einfach den EEPROM überschreibe. D.h. Ich brauche 
einen weg, auf dem ich von der oben beschriebenen Liste die Daten an die 
richtigen Stellen im EEPROM bekomme.

 Strukturen sind für meinen Geschmack da schon oversized und blähen 
besstenfalls den Code auf, der so wie ich das gerade abschätze eher 
knapp auf meinen Mega48 passen wird.

Zu Schitt 5. da habe ich ja dann wieder die "Zufällige" Anordnung der 
Daten im EEPROM!? Genau das will ich vermeiden.

von g457 (Gast)


Lesenswert?

Mit dem Hexeditor Deines Vertrauens eine Datei mit dem gewünschten 
Inhalt anlegen (ein Speicherabbild des Eeproms sozusagen), per objcopy 
mit Eingabeformat 'binary' in ein Ausgabeformat wandeln, das Dein 
Brenner versteht (z.B. ihex), glücklich sein ;-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter K. schrieb:

> Zu Schitt 5. da habe ich ja dann wieder die "Zufällige" Anordnung der
> Daten im EEPROM!? Genau das will ich vermeiden.

Was soll das demm heissen? DU definierst eine Variable foo und wenn du 
darauf zugreifen willst machst da was über das Symbol foo d.h. über den 
Name der Variablen. Was ist daran zufällig? Variablenzugriff ist doch 
kein Russisch Roulette...
1
// Ein CAN-Node
2
typedef struct
3
{
4
    uint8_t addr;
5
    uint8_t value;
6
} can_node_t;
7
8
// Das EEPROM
9
typedef struct
10
{
11
    can_node_t can_nodes[15];
12
} eeprom_t;
13
14
extern can_node_t eeprom_read_can_node (unsigend int);
15
16
...
17
18
#include <avr/eeprom.h>
19
20
eeprom_t eeprom EEMEM = 
21
{
22
    { 0xab, 0x12 }, // Node 0
23
    { 0x23, 0x3f }, // Node 1
24
    ...
25
    { 0xbb, 0x42 }  // Node 15
26
};
27
28
can_node_t eeprom_read_can_node (unsigend int index)
29
{
30
    can_node_t node;
31
32
    node.addr  = eeprom_read_byte (& eeprom.can_nodes[index].addr);
33
    node.value = eeprom_read_byte (& eeprom.can_nodes[index].value);
34
35
    return node;
36
}
37
38
// oder
39
40
can_node_t eeprom_read_can_node (unsigend int index)
41
{
42
    static can_node_t node;
43
44
    eeprom_read_block (&node, &eeprom.can_nodes[index], sizeof (can_node_t));
45
46
    return node;
47
}
48
49
// oder (oben anderer Protptyp!)
50
51
void can_node_t eeprom_read_can_node (can_node_t * pnode, unsigend int index)
52
{
53
    eeprom_read_block (pnode, &eeprom.can_nodes[index], sizeof (can_node_t));
54
}

Schreiben geht analog. Zeug nur noch so einbauen, daß es in dein Projekt 
passt (Header, C-Files, etc)

von Karl H. (kbuchegg)


Lesenswert?

Peter K. schrieb:

> Ich möchte auf mehreren Nodes am CAN-Bus die Configuration verändern
> können, indem ich ganz einfach den EEPROM überschreibe. D.h. Ich brauche
> einen weg, auf dem ich von der oben beschriebenen Liste die Daten an die
> richtigen Stellen im EEPROM bekomme.

Es steht dir immer noch der WEg offen, vollkommen eigenständig und 
losgelöst vom Compiler, die Adressverwaltung im EEPROM selber zu machen.

Der Funktion eeprom_read_byte, und auch den anderen wie sie alle 
heissen, ist es ja völlig Wurscht, wo die Adresse her kommt. Sie wollen 
eine Adresse im EEPROM haben, von der sie lesen. Wie diese zustande 
kommt, interessiert die Funktionen nicht.
1
#define EEPROM_ADR_REG_1     0x01
2
#define EEPROM_VAL_REG_1     0x02
3
#define EEPROM_ADR_REG_2     0x03
4
...
5
6
   erg_adr = eeprom_read_byte( EEPROM_ADR_REG_1 );



Du kannst dir natürlich auch Strukturen zurechtlegen und die mit im 
Grunde demselben Mechanismus auf eine Adresse festpinnen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Warum sollte man sein Programm so verunstalten? Bei RAM-Adressen hätte 
man viel zu tun, wenn die alls händisch zu vergeben wären. Dito Flash. 
Wozu hat man denn ne Hochsprache...

von Karl H. (kbuchegg)


Lesenswert?

Johann L. schrieb:
> Warum sollte man sein Programm so verunstalten?

Weil man bestimmte Dinge möglichst billig im EEPROM an bestimmten 
Adressen festpinnen möchte.

> Bei RAM-Adressen hätte
> man viel zu tun, wenn die alls händisch zu vergeben wären.

Von RAM war ja auch keine Rede.


Aber ich hab jetzt nochmal das Eröffnungsposting gelesen. Der Teil macht 
ihm anscheinend eh keine Probleme. Er will ein EEP File generieren. Das 
wird allerdings so nicht gehen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl heinz Buchegger schrieb:
> Johann L. schrieb:
>> Warum sollte man sein Programm so verunstalten?
>
> Weil man bestimmte Dinge möglichst billig im EEPROM an bestimmten
> Adressen festpinnen möchte.

Dann lässt man die Instanz den eeprom-Dingens einfach aus der Quelle und 
gibt dem Linker via --defsym eeprom=<ADDRESS> die Adresse vor.

Das ist allemal einfacher als händlisch zig Adressen reinzuwurschteld 
und erfordert überhaut keine Änderungen im Programm (ausser anlegen des 
einen Objekts).

BTW -- wenn nur ein Objekt im EEPROM existiert ist auch dessen Adresse 
immer bekannt: Die Startadresse der Section. Auch die kann man angeben 
wenn man denn möchte. S.o.

von Karl H. (kbuchegg)


Lesenswert?

Johann L. schrieb:
> Karl heinz Buchegger schrieb:
>> Johann L. schrieb:
>>> Warum sollte man sein Programm so verunstalten?
>>
>> Weil man bestimmte Dinge möglichst billig im EEPROM an bestimmten
>> Adressen festpinnen möchte.
>
> Dann lässt man die Instanz den eeprom-Dingens einfach aus der Quelle und
> gibt dem Linker via --defsym eeprom=<ADDRESS> die Adresse vor.
>
> Das ist allemal einfacher als händlisch zig Adressen reinzuwurschteld
> und erfordert überhaut keine Änderungen im Programm (ausser anlegen des
> einen Objekts).


Für dich: bin überzeugt, das das für dich einfach ist.

Für mich ... ist es einfacher, die <10 EEPROM Sachen mit einem #define 
festzupinnen :-)

Du hast natürlich recht. Section an eine Adresse legen ist der technisch 
richtige Weg.

von Peter K. (Gast)


Lesenswert?

Johann L. schrieb:
> Karl heinz Buchegger schrieb:
>> Johann L. schrieb:
>>> Warum sollte man sein Programm so verunstalten?
>>
>> Weil man bestimmte Dinge möglichst billig im EEPROM an bestimmten
>> Adressen festpinnen möchte.
>
> Dann lässt man die Instanz den eeprom-Dingens einfach aus der Quelle und
> gibt dem Linker via --defsym eeprom=<ADDRESS> die Adresse vor.

Klingt hoch interessant, allerdings sagt es mir genau nichts, da ich
1. noch nie dem Linker per "kommandozeile" Befehle erteilt habe,
2. mir auch unter "--defsym eeprom=<ADDRESS>" nicht vorstelln kann was 
dann an ADDRESS landet.





Karl heinz Buchegger schrieb:
> Der Funktion eeprom_read_byte, und auch den anderen wie sie alle
> heissen, ist es ja völlig Wurscht, wo die Adresse her kommt. Sie wollen
> eine Adresse im EEPROM haben, von der sie lesen. Wie diese zustande
> kommt, interessiert die Funktionen nicht.
> #define EEPROM_ADR_REG_1     0x01
> #define EEPROM_VAL_REG_1     0x02
> #define EEPROM_ADR_REG_2     0x03
> ...
>
>    erg_adr = eeprom_read_byte( EEPROM_ADR_REG_1 );

Das ist der weg, den ich jetzt auch eingeschalgen hätte, nur wie fülle 
ich den EEPROM? muss ich da erst ein Programm scheiben, das den EEPROM 
Füllt, und anschließend mein eigentliches Programm aufspielen?!







Johann L. schrieb:
> Du lässt die eeprmo-Datei erzeugen, zB IHex-Format:
> avr-objcopy -j .eeprom --change-section-lma .eeprom=1 -O ihex alles.elf 
alles.eeprom.hex

Da werde ich noch drüber googeln müssen... heute nicht mehr.

von Karl H. (kbuchegg)


Lesenswert?

Peter K. schrieb:

> Das ist der weg, den ich jetzt auch eingeschalgen hätte, nur wie fülle
> ich den EEPROM? muss ich da erst ein Programm scheiben, das den EEPROM
> Füllt, und anschließend mein eigentliches Programm aufspielen?!

Ja.

Ich machs meistens so, dass ich nur 1 Programm habe, indem dann beim 
Start von main auch das EEPROM mit seiner Erstbelegung an Werten 
versorgt wird.

Der Codeteil wird dann mit einem Flag/Schalter oder einem #ifdef 
abgeschaltet.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Woze muss da Code ausgeblendet werden?

Man kann doch schlich einen Initializer schreiben, der kostet kein Code.

Wenn man beim Brennen nicht immer wieder den EEPROM schreiben will, 
schreibt man den EEPROM eben nicht (und setzt sinnigerweise EESAVE). 
Odewr steh ich total aufm Schlauch was ihr da treiben wollt?

von Karl H. (kbuchegg)


Lesenswert?

Johann L. schrieb:
> Woze muss da Code ausgeblendet werden?
>
> Man kann doch schlich einen Initializer schreiben, der kostet kein Code.
>
> Wenn man beim Brennen nicht immer wieder den EEPROM schreiben will,
> schreibt man den EEPROM eben nicht (und setzt sinnigerweise EESAVE).
> Odewr steh ich total aufm Schlauch was ihr da treiben wollt?

Genau darum gehts.
Mir ist es nämlich zu umständlich, jedesmal die EESAVE Fuse zu 
verändern. Zumal ich das aus dem AVR-Studio heraus nicht kann, sondern 
ein externes Programm nehmen muss. Zudem arbeite ich meist mit 
Bootloader.

Für meine Arbeitsweise ist es einfacher, einfach ein #define 
auszukommentieren und damit den Code stillzulegen, der im EEPROM eine 
erste Wertebelegung macht.

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.