Forum: Mikrocontroller und Digitale Elektronik EEPROM per ISP mit Werten füllen


You were forwarded to this site from EmbDev.net. Back to EmbDev.net
von Chris (Gast)


Lesenswert?

Hi,

Ich habe jetzt schon alles durchwühlt finde aber nichts.

Ich arbeite nicht oft mit EEPROM Routinen, insofern bin ich hier noch 
etwas unerfahren, daher bitte um Nachsicht ;)

Ich habe einen AtMega16 mit einem Hauptprogramm gefüttert und suche 
jetzt nach einer Möglichkeit per ISP das interne EEPROM mit Werten 
(Zahlen <100) zu füttern, die einmalig zum Programmstart vom 
Hauptprogramm ausgelesen werden.

Sinn ist, das ein User relativ einfach Werte per ISP und EEPROM 
veränderen können muss, ohne jedoch mit dem Hauptprogramm überhaupt in 
Berührung zu kommen.

Der User soll also im Idealfall ein seperates Projekt haben, wo er Werte 
verändert, das Projekt compiliert und die .eep Datei auf den AVR 
überträgt.

Ich habe schon versucht per

uint8_t light_index_1_s = eeprom_read_byte(&light_index_1_s);

die Variable auszulesen.

Um ein .eep Datei zu erzeugen habe ich ein seperates Projekt erstellt 
und einfach eine Globale Variable

uint8_t light_index_1_s EEMEM = 5;

erzeugt. Die daraus compilierte .eep Datei habe ich dann hoffnungsvoll 
per ISP übertragen, natürlich ohne Erfolg. Im Hauptprogramm war nichts 
auslesbar.


Mir würde es schon reichen wenn mir jemand erklären würde, wie mein Plan 
generell umsetzbar ist. Also wie genau ich manuell eine .eep Datei mit 
Werten erzeuge, die ein davon unabhängiges Hauptprogramm dann auslesen 
kann.

Dank im Voraus

von Christian S. (roehrenvorheizer)


Lesenswert?

Chris schrieb:
> Also wie genau ich manuell eine .eep Datei mit
> Werten erzeuge,

Hallo,

es gibt schon lange ien Tutorial, z.B.:
https://www.mikrocontroller.net/articles/AVR-Tutorial:_Speicher

Mittels Winavrasm kann man in ASM ein Datensement definieren, das nach 
dem Assemblieren eine eep-Datei erzeugt, die man mittels Ponyprog oder 
avrdude in den Mega16 kopieren kann. Es dürfte noch etliche andere Tools 
dafür geben.

siehe auch:
http://avr-asm-tutorial.net/avr_de/beginner/adressieren/adressieren_eeprom.html

In C ist das wieder eine eigene Welt, den Link habe ich gerade nicht 
parat.

mfg

: Bearbeitet durch User
von STK500-Besitzer (Gast)


Lesenswert?

Chris schrieb:
> Mir würde es schon reichen wenn mir jemand erklären würde, wie mein Plan
> generell umsetzbar ist. Also wie genau ich manuell eine .eep Datei mit
> Werten erzeuge, die ein davon unabhängiges Hauptprogramm dann auslesen
> kann.

Wird das EEPROM beim Programmieren des Chips (Flash) geschützt?

von S. Landolt (Gast)


Angehängte Dateien:

Lesenswert?

> Wird das EEPROM beim Programmieren des Chips (Flash) geschützt?

Ergänzend: Fuse High Byte, Bit 3 'EESAVE'.

von W.S. (Gast)


Lesenswert?

Chris schrieb:
> Ich habe einen AtMega16 mit einem Hauptprogramm gefüttert und suche
> jetzt nach einer Möglichkeit per ISP das interne EEPROM mit Werten
> (Zahlen <100) zu füttern,...

Normalerweise benutzt man ein EEPROM zu dem Zwecke, daß man von der 
Firmware aus sich darin Werte merken kann, die auch bei ausgeschaltetem 
Gerät erhalten bleiben. Folglich muß sowieso irgend ein Lese- und 
Schreib-Treiber für das EEPROM in der Firmware drin sein. Dazu kommt, 
daß das Lesen und Schreiben des EEPROM's langsamer ist als der Zugriff 
auf eine Variable im RAM. Also macht man es oftmals so, daß man ein 
Datenfeld (bei C ein Struct) sich definiert, dazu im RAM eine Variable 
anlegt und diese beim Einschalten mit den Werten aus dem EEPROM befüllt. 
Man kann es daher auch so machen, daß man im Code ein konstantes 
Datenfeld mit Defaultwerten anordnet und dieses in die Variable im RAM 
kopiert, wenn irgendein Kriterium (z.B. ein Boolean 'daten_gelten') bei 
den Daten im EEPROM anzeigt, daß die Daten nicht gelten. So eben bei der 
frisch zusammengelöteten LP.

Deshalb ist es ein ziemlich unnützes Vorhaben, irgend eine spezielle 
Möglichkeit zum Befüllen des EEPROM's per ISP sich ausdenken zu wollen. 
Laß das die Firmware selber erledigen. Allenfalls ein Kommando dazu über 
irgend eine Kommunikations-Schnittstelle wie z.B. UART.

W.S.

von STK500-Besitzer (Gast)


Lesenswert?

W.S. schrieb:
> Normalerweise benutzt man ein EEPROM zu dem Zwecke, daß man von der
> Firmware aus sich darin Werte merken kann, die auch bei ausgeschaltetem
> Gerät erhalten bleiben. Folglich muß sowieso irgend ein Lese- und
> Schreib-Treiber für das EEPROM in der Firmware drin sein. Dazu kommt,
> daß das Lesen und Schreiben des EEPROM's langsamer ist als der Zugriff
> auf eine Variable im RAM. Also macht man es oftmals so, daß man ein
> Datenfeld (bei C ein Struct) sich definiert, dazu im RAM eine Variable
> anlegt und diese beim Einschalten mit den Werten aus dem EEPROM befüllt.
> Man kann es daher auch so machen, daß man im Code ein konstantes
> Datenfeld mit Defaultwerten anordnet und dieses in die Variable im RAM
> kopiert, wenn irgendein Kriterium (z.B. ein Boolean 'daten_gelten') bei
> den Daten im EEPROM anzeigt, daß die Daten nicht gelten. So eben bei der
> frisch zusammengelöteten LP.
>
> Deshalb ist es ein ziemlich unnützes Vorhaben, irgend eine spezielle
> Möglichkeit zum Befüllen des EEPROM's per ISP sich ausdenken zu wollen.
> Laß das die Firmware selber erledigen. Allenfalls ein Kommando dazu über
> irgend eine Kommunikations-Schnittstelle wie z.B. UART.

Tinnef!
Man kann dort bspw. fortlaufende Seriennummern o.dergl hinterlegen.
Wenn man die EEP-Datei extern erzeugt, kann man sie auf dem gewünschten 
Weg für jede (hausinterne Standrd-)Platine übertragen.
Danach kann man dann (bei geschütztem EEPROM) eine beliebige Firmare in 
Abhängigkeit des Zielgerätes darauf installieren.
Schon komisch, dass wir das so bei AVR-basierenden Geräten handhaben.
Oder halt umgekehrt (erst die Firmware und dann denn EEPROM-Inhalt u.a. 
mit Kalibrierdaten).

von EAF (Gast)


Lesenswert?

W.S. schrieb:
> Deshalb ist es ein ziemlich unnützes Vorhaben, irgend eine spezielle
> Möglichkeit zum Befüllen des EEPROM's per ISP sich ausdenken zu wollen.
> Laß das die Firmware selber erledigen. Allenfalls ein Kommando dazu über
> irgend eine Kommunikations-Schnittstelle wie z.B. UART.

Zumindest das belegen mit default Werten macht Sinn.

Chris schrieb:
> uint8_t light_index_1_s EEMEM = 5;

Mache ich durchaus auch so.
Und das erzeugen und übertragen der *.eep ist problemlos.
Ich weiß also nicht, welche Sorgen du damit hast.

Chris schrieb:
> uint8_t light_index_1_s = eeprom_read_byte(&light_index_1_s);
Hier sollten sich die Namen unterscheiden! (denke ich mal)
uint8_t temp = eeprom_read_byte(&light_index_1_s);

von Gerald B. (gerald_b)


Lesenswert?

Chris schrieb:
> Der User soll also im Idealfall ein seperates Projekt haben, wo er Werte
> verändert, das Projekt compiliert und die .eep Datei auf den AVR
> überträgt.

eXtreme Burner AVR könnte was für dich sein. Ist im Stile eines 
Hex-Editors und hat 3 Reiter. Jeweils Einen für FLASH, EEPROM und Fuses.
Mittels USBasp kannst du über ISP dann das eep File in den Controller 
schieben.

Ich nutze eXtrme Burner, wenn ich mehrere µC als Kleinserie mit dem 
selben Hex-File befüllen will ;-)

von Chris (Gast)


Lesenswert?

Also aktuell habe ich versucht mit einem seperatem Projekt und
zum Beispiel:

uint8_t light_index_1_s EEMEM = 5;

einen Wert zu erzeugen, der dann nach compilieren in einer .eep Datei 
steckt.

Soweit so gut. Das ganze habe ich dann im Atmel Studio direkt in den 
EEPROM übertragen. Kein Problem

Mir ist nicht klar wie ich im Hauptprogramm den Wert gezielt aus dem 
EEPROM lese, zumal EEMEM ja meines Wissens nach einfach einen freien 
Platz im EEPROM sucht und den Wert dort ablegt, es gibt ja quasi keine 
Adresse.

Gefühlt müsste das Ganze eine einfache Sache sein aber aktuell fehlt mir 
komplett die Idee.

Zusammenfassend aber nochmal.

Programm A (Hauptprogramm) - wird einmal in den AVR geschoben und fertig 
- der User kommt mit dem Programm nicht in Berührung, sieht also 
nichtmal seinen Quelltext.

Programm B (EEPROM Werte) - ein kleines Extra Programm was nur darauf 
abzielt einzelne Werte zu ändern und dann nach compilieren durch den 
User per .eep ins EEPROM zu schieben.
Wenn man so will eine Liste Variablen die geändert werden können.

Das war es eigentlich ... eigentlich

von EAF (Gast)


Lesenswert?

Chris schrieb:
> Mir ist nicht klar wie ich im Hauptprogramm den Wert gezielt aus dem
> EEPROM lese, zumal EEMEM ja meines Wissens nach einfach einen freien
> Platz im EEPROM sucht und den Wert dort ablegt, es gibt ja quasi keine
> Adresse.

Doch natürlich gibt es eine Adresse!
Eben die Adresse, welcher der Linker dafür vorsieht.


Wenn du darauf wert legst, dass du die Adresse kennst/bestimmst. 
solltest du mit Strukturen und offsetof() arbeiten.
https://en.wikipedia.org/wiki/Offsetof

von Chris (Gast)


Lesenswert?

Ich brauch auch nicht zwingend eine Adresse.

Vielmehr habe ich keine Ahnung wie das Hauptprogramm wieder an den Wert 
kommen soll, der per .eep Datei übertragen wurde

Zb.

uint8_t light_index_1_s EEMEM = 5; per .eep ins EEPROM geschrieben

und im Hauptprogramm versucht mit

uint8_t temp = eeprom_read_byte(&light_index_1_s);

auszulesen führt nicht zum Erfolg .

von EAF (Gast)


Lesenswert?

Chris schrieb:
> führt nicht zum Erfolg .

Sollte aber!

Ist zwar Arduino C++, sollte sich aber im Punkte Eeprom nicht 
unterscheiden
1
#include <avr/eeprom.h>
2
byte test EEMEM = 5;
3
4
5
void setup() 
6
{
7
  Serial.begin(9600);
8
  Serial.println(unsigned(&test));
9
  Serial.println(eeprom_read_byte(&test));
10
}
11
12
void loop() 
13
{
14
15
}

Folgende *.eep wird erzeugt:
1
:0100000005FA
2
:00000001FF

Die Ausgabe ist:
1
0
2
5
Wie es auch zu erwarten ist.

von Chris (Gast)


Lesenswert?

Ok nein das das in einem Programm zusammen klappt ist klar.
Der Compiler weiß ja wo er "test" im EEPROM abgelegt hat und wo er dann 
beim lesen suchen muss.

Ich habe dagegen das Hauptprogramm was nur zb. den folgenen Teil 
enthält.

void setup()
1
{
2
3
  Serial.begin(9600);
4
5
  Serial.println(unsigned(&test));
6
7
  Serial.println(eeprom_read_byte(&test));
8
9
}

Dann habe ich ein seperates Programm was der User mit Werten füllt also 
zb.
byte test EEMEM = 5;

Dieses .eep wird dann ins EEPROM geschickt.

Ich gehe aktuell davon aus das das Problem darin liegt das (da beides 
unabhängige Programme sind) beim Lesen einfach keine Zuordnung besteht.
Das Programm weiß also nicht wo es "test" im EEPROM finden soll.

Am Ende gibt der Compiler ja dem wert "test" auch einfach eine 
adressierung die zum entsprechendem Speicherplatz im EEPROM führt.

von EAF (Gast)


Lesenswert?

Chris schrieb:
> Ok nein das das in einem Programm zusammen klappt ist klar.
Das war mit bisher nicht klar, dass das bei dir funktioniert.
Dann Kommt Teil 2 eines meiner vorherigen Posts zur Geltung!

Chris schrieb:
> Ich brauch auch nicht zwingend eine Adresse.
Die brauchst du nicht nur, sondern sie muss auch fest angenagelt werden!



Die Struktur muss in beiden Programmen angelegt werden um die Adressen 
anzunageln.
(die Strukturdefinition sieht in C etwas anders aus)
1
#include <avr/eeprom.h>
2
3
4
struct DatenImEEPROM
5
{
6
  byte a;
7
  byte b;
8
};
9
10
DatenImEEPROM imEeprom  __attribute__((section(".eeprom"),used)) EEMEM{7,5}; // diese Zeile braucht es nur um die .eep zu erzeugen
11
12
void setup() 
13
{
14
  Serial.begin(9600);
15
  Serial.println(unsigned(offsetof(DatenImEEPROM,b)));
16
  Serial.println(eeprom_read_byte(offsetof(DatenImEEPROM,b)));
17
}
18
19
void loop() 
20
{
21
22
}

von Chris (Gast)


Lesenswert?

Perfekt, genau danach habe ich gesucht.

Funktioniert jetzt wie gewollt.

Tausend Dank !

von EAF (Gast)


Lesenswert?

Das ist ja schön...
(dann ist ja, ein Arduino Jünger, doch auch mal zu was Nütze)

von Chris (Gast)


Lesenswert?

Doch noch eine Nachfrage.

Wenn ich im Hauptprogramm soweit alles deklariere
1
 struct Cue1  
2
 {
3
char cue_1_sekunde;
4
char cue_1_minute;
5
 };
6
 
7
8
#ifdef __AVR__
9
Cue1 imCue1 EEMEM __attribute__((section(".eeprom"),used)) ;
10
#endif

und dann versuche die werte aus dem EEPROM zu bekommen mit
1
cue_1_s = eeprom_read_byte (offsetof(Cue1,cue_1_sekunde));
2
cue_1_m = eeprom_read_byte (offsetof(Cue1,cue_1_minute));

bekomme ich für cue_1_m
"invalid conversion from 'unsigned int' to 'const uint8_t* {aka const 
unsigned char*}' "

Die Datenabfrage für cue_1_s dagegen klappt tadellos.

Gehe mal davon aus das offsetof hier das Problem ist.
Der offset müsste für cue_1_m ja quasi cue_1_sekunde+cue_1_minute sein 
?!


Eine Idee hierzu ?

von EAF (Gast)


Lesenswert?

Untestbar!

von EAF (Gast)


Angehängte Dateien:

Lesenswert?

Nochmal, die Fehlermeldung ist bis zur Unkenntlichkeit verstümmelt.
Der Code ist so verkürzt, dass die Fehlerquelle nicht zu sehen ist.

Ich bin voll auf Arduino, also nutze ich die Sprache C++!
Welche Sprache nutzt du?

Chris schrieb:
> Cue1 imCue1 EEMEM __attribute__((section(".eeprom"),used)) ;
Die Zeile ist sicherlich überflüssig, wenn keine Vorbesetzungen für die 
*.eep Datei gemacht werden.

Annahme 1:
Wenn die Adressen korrekt ermittelt werden, sind auch die Zugriffe auf 
das EEPROM korrekt durchführbar.

Annahme 2:
Du verwendest C.

Also hier eine C Datei, mit Funktionen, welche die Adressen in der 
Struktur ermitteln.

Die Ausgabe der Adressen erfolgt dann in einem Arduino C++ Programm.

Testen:
In der Arduino IDE ein Tab mit der *.c Datei anlegen, Inhalte 
übertragen.

Selbstredend:
Die Adressen werden fehlerfrei ausgegeben.

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.