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
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:
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.
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 ;-)
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...
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.
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...
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.
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.
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.
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.
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.
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?
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.