Hallo zusammen, ich habe möchte gerne im Bootloader ( http://www.mikrocontroller.net/articles/Konzept_f%C3%BCr_einen_ATtiny-Bootloader_in_C) in das eeprom schreiben und lesen. Leider klappt das aber nicht. Schreibe ich den Code ohne den linkerzusatz "-Wl,--section-start=.text=0xBC0" klappt es. Muss ich das eeprom anders addressieren oder was mache ich falsch? Prozessor : Attiny45 Vielen Dank vorab. Gruß Frank
Hallo ! Ich hab' zwar nicht so viel Ahnung, aber gehört der Bootloader nicht in's Flash und der ATiny hat keine FUSES für einen Bootbereich, also geht das überhaupt ?
Frank Z. schrieb: > ich habe möchte gerne im Bootloader ( > http://www.mikrocontroller.net/articles/Konzept_f%C3%BCr_einen_ATtiny-Bootloader_in_C) > in das eeprom schreiben und lesen. Leider klappt das aber nicht. > Schreibe ich den Code ohne den linkerzusatz > "-Wl,--section-start=.text=0xBC0" klappt es. Ich hab in diesem Projekt nicht gesehen, daß das R/W des EEPROM überhaupt implementiert ist. Was dann plötzlich funktionieren soll, ist mir daher auch rätselhaft. Frank Z. schrieb: > Muss ich das eeprom anders addressieren oder was mache ich falsch? Du mußt die EEPROM-Funktionen implementieren. EEPROM und Flash sind zwei verschiedene Paar Schuhe. knollo schrieb: > Ich hab' zwar nicht so viel Ahnung, aber gehört der Bootloader nicht > in's Flash und der ATiny hat keine FUSES für einen Bootbereich, also > geht das überhaupt ? Ja, mit ein bißchen Trickserei und Reset-/Interrupt-Vektoren verbiegen geht das.
:
Bearbeitet durch User
Frank Z. schrieb: > ich habe möchte gerne im Bootloader ( > http://www.mikrocontroller.net/articles/Konzept_f%C3%BCr_einen_ATtiny-Bootloader_in_C) > in das eeprom schreiben und lesen. Leider klappt das aber nicht. Eine sehr ausführliche Beschreibung deines Problems hast du da abgeliefert. Ich liefere dir gerne eine ebenso ausführliche Ursachenanalyse: "du machst etwas falsch". > Schreibe ich den Code ohne den linkerzusatz > "-Wl,--section-start=.text=0xBC0" klappt es. > > Muss ich das eeprom anders addressieren oder was mache ich falsch? Das Verschieben deines Codes an eine andere Adresse im Flash wird nicht die Funktion des Codes verändern. Das passiert auch in normalen Programmen laufend. Je nach Größe einzelner Programmteile werden Funktionen mal an die eine, mal an eine andere Adresse gelinkt. Trotzdem funktionieren diese Funktionen immer gleich. Du machst also ganz offensichtlich etwas falsch. Was genau, kann dir natürlich mangels Informationen keiner sagen.
Hallo zusammen, vielen Dank für Eure Antworten. Ich sehe ein, dass es tatsächlich nicht ganz so ausführlich ist. Dies möchte ich gerne hier noch einmal nachholen. Wie oben gesagt, habe ich den bootloader aus dem Artikel implementiert. Es funktioniert auch alles einbandfrei. Da ich aber eine Variable innerhalb des Bootloader ins eeprom schreiben möchte, habe ich die folgenden Funktionen benutzt:
1 | ...
|
2 | int main(void) { |
3 | ....
|
4 | uint8_t eeFooByte = 0x00; |
5 | unsigned char myByte = 0x33; |
6 | eeprom_write_byte(&eeFooByte, myByte); |
7 | ....
|
8 | }
|
ebenfalls habe ich folgendes wie im Datasheet beschrieben ausprobiert:
1 | void EEPUT(int location, unsigned char byte) { |
2 | while (EECR & (1<<EEPE)); /* Check if EEPROM is ready*/ |
3 | EEAR = location; /* Write EEPROM address register*/ |
4 | EEDR = byte; /* Write EEPROM data register*/ |
5 | EECR |= (1<<EEMPE); /* Set master write enable signal*/ |
6 | EECR |= (1<<EEPE); /* Set write strobe*/ |
7 | }
|
8 | ...
|
9 | int main(void) { |
10 | ....
|
11 | EEPUT(0x00, 0x33); |
12 | ....
|
13 | }
|
Beide Implementierungen funktionieren, wenn ich den Code nicht in einen höheren Bereich verschiebe. Dies machen ich per Linkeranweisung mit: -Wl,--section-start=.text=0xBC0 -Wl,--section-start=.bootreset=0x00 -Wl,--section-start=.data=0x800080 Wenn ich nur das nachfolgenen Elementes aus der Anweisung entferne, funktioniert der Code : -Wl,--section-start=.text=0xBC0 ( neue Linkeranweisung: -Wl,--section-start=.bootreset=0x00 -Wl,--section-start=.data=0x800080) Warum schreiben die o.a. Funktionen nach der Verschiebung des Codes nicht mehr ins eeprom. Ich debuge das ganzen mit Atmel Studio und dem Dragon im OneWireDebug Modus. Vielen dank noch mal vorab. Gruß Frank
Frank Z. schrieb: > uint8_t eeFooByte = 0x00; > unsigned char myByte = 0x33; > eeprom_write_byte(&eeFooByte, myByte); eeFooByte ist eine Variable im RAM. Die hat zwar auch eine Adresse, die auf das EEPROM passen könnte, der Adressbereich fängt aber nicht bei 0 an, sondern bei deinem Tiny bei 0x60. Mit einer RAM-Adresse sind die ersten 96 Byte des EEPROM gar nicht adressierbar und Zugriffe auf die letzten 96 Byte erfolgen im Nirwana. Du musst die Variable also im EEPROM anlegen:
1 | uint8_t eeFooByte EEMEM = 0; |
Oder du sparst dir das und verwaltest die Adressen selbst:
1 | eeprom_write_byte((unsigned char*)E2END, myByte); |
Damit schreibst du bspw. auf die letzte Speicherstelle im EEPROM. Aber du schiesst dir ins Knie, wenn du statt char ein int dahin schreibst. Also überlasse es lieber dem Compiler. Frank Z. schrieb: > Warum schreiben die o.a. Funktionen nach der Verschiebung des Codes > nicht mehr ins eeprom. Keine Ahnung. Ist auch nicht wichtig, da du es grundsätzlich falsch machst.
Frank Z. schrieb:
1 | > ... |
2 | > int main(void) { |
3 | > .... |
4 | > uint8_t eeFooByte = 0x00; |
5 | > unsigned char myByte = 0x33; |
6 | > eeprom_write_byte(&eeFooByte, myByte); |
7 | > .... |
8 | > } |
Das ist natürlich falsch, wie dein (unser?) Vorbild schon sagte. Der
erste Parameter für eeprom_write_byte() ist ein Pointer (vulgo: eine
Adresse) im EEPROM. Dazu kannst du die entsprechende Variable entweder
in die entsprechende section legen (z.B. mit dem EEMEM Makro) oder du
verwaltest die paar Adressen im EEPROM manuell und übergibst hier eine
Zahl. Die erste Variante hat den Vorteil, daß der Compiler ein HEX File
erzeugen kann mit dem du die initialen Werte im EEPROM setzen kannst.
> ebenfalls habe ich folgendes wie im Datasheet beschrieben ausprobiert:
1 | > void EEPUT(int location, unsigned char byte) { |
2 | > while (EECR & (1<<EEPE)); /* Check if EEPROM is ready*/ |
3 | > EEAR = location; /* Write EEPROM address register*/ |
4 | > EEDR = byte; /* Write EEPROM data register*/ |
5 | > EECR |= (1<<EEMPE); /* Set master write enable signal*/ |
6 | > EECR |= (1<<EEPE); /* Set write strobe*/ |
7 | > } |
8 | > ... |
9 | > int main(void) { |
10 | > .... |
11 | > EEPUT(0x00, 0x33); |
12 | > .... |
13 | > } |
Das hingegen könnte funktionieren; es schreibt deine 0x33 an die erste Adresse (0x00) des EEPROMs. Hier ist das Problem, daß du möglicherweise die Zeitanforderung von maximal 4 Takten zwischen dem Setzen von EEMPE und EEPE nicht einhältst. Deswegen ist dieser Teil besser in Inline-Assembler zu erledigen. > Ich debuge das ganzen mit Atmel Studio und dem Dragon im OneWireDebug > Modus. Unter Debugger-Kontrolle ist es noch wahrscheinlicher, daß du die Zeitanforderung nicht einhältst. Wenn du diesen Teil gefixt hast und es trotzdem nicht funktioniert, wäre es hilfreich, wenn du dein "geht nicht" noch etwas präzisierst. Was passiert genau? Steht nach dem Schreiben noch der alte Wert im EEPROM? Oder gar ein ganz anderer Wert? Mein Vorschlag wäre, das EEPROM einmal mit 0x00 und einmal mit 0xFF zu initialisieren (z.B. über ISP) und dann mit deinem Bootloader auf 0x33 zu schreiben. Danach haben wir einen etwas besseren Überblick was da passiert.
Einen ganz grossen Dank für Eure Anmerkungen. Hat mir echt geholfen. Der Fehler lag aber nicht an den eeprom Funktionen. Es lag daran, dass ich den Code zu weit nach hinten geschoben hatte. Grösse neue berechnet - und schon klappt es mit dem eeprom. Wie gesagt - vielen Dank. Hat mir echt geholfen. Gruß Frank
Axel S. schrieb: > Hier ist das Problem, daß du möglicherweise > die Zeitanforderung von maximal 4 Takten zwischen dem Setzen von EEMPE > und EEPE nicht einhältst. Deswegen ist dieser Teil besser in > Inline-Assembler zu erledigen. das könnte von moby oder chater sein ;-) ne, das schafft der Compiler mit links in 4 Takten
Frank Z. schrieb: > Der Fehler lag ... nicht an den eeprom Funktionen. Es lag daran, dass > ich den Code zu weit nach hinten geschoben hatte. Grösse neue berechnet > - und schon klappt es mit dem eeprom. Autsch. Dann hast du da noch einen Fehler in deiner Build-Umgebung. Wenn der Linker ein Executable erzeugt, das zu groß für den Ziel-µC ist, dann muß da eine Fehlermeldung aufpoppen.
Walter S. schrieb: > Axel S. schrieb: >> Hier ist das Problem, daß du möglicherweise >> die Zeitanforderung von maximal 4 Takten zwischen dem Setzen von EEMPE >> und EEPE nicht einhältst. Deswegen ist dieser Teil besser in >> Inline-Assembler zu erledigen. > > das könnte von moby oder chater sein ;-) Also, das war ja wohl weit unter der Gürtellinie, Freundchen! Ich erwarte eine schriftliche Entschuldigung bis morgen 9:00 Uhr! > ne, das schafft der Compiler mit links in 4 Takten Du kannst dich aber nicht darauf verlassen, daß das immer und mit allen Compilerschaltern so ist. So wie er dasteht, verläßt sich der Code auf ein Verhalten des Compilers, das nirgendwo zugesichert wird. Und weil C gar keine Ausdrucksmittel hat, um ein bestimmtes Zeitverhalten zu erzwingen, kann man das in reinem C gar nicht sauber implementieren. Deswegen mein Vorschlag für Inline-Assembler. Streng genommen gehört das auch in einen nicht-unterbrechbaren Block. Und jetzt darfst du genau einmal raten, wie das in avr-libc implementiert ist. In C oder in Assembler?
Axel S. schrieb: > Und jetzt darfst du genau einmal raten, wie das in avr-libc > implementiert ist. In C oder in Assembler? du darfst auch einmal raten wie es z.B. im Datenblatt des mega8 vorgeschlagen wird Theoretisch hast du ja recht, aber es gibt halt keinen üblichen C-Compiler der derart schlechten Code erzeugt Axel S. schrieb: > Streng genommen gehört das > auch in einen nicht-unterbrechbaren Block. das dagegen ist unbedingt notwendig
Walter S. schrieb: > Axel S. schrieb: >> Und jetzt darfst du genau einmal raten, wie das in avr-libc >> implementiert ist. In C oder in Assembler? > > du darfst auch einmal raten wie es z.B. im Datenblatt des mega8 > vorgeschlagen wird Das muß ich nicht raten, das weiß ich. Aber der Beispielcode im Datenblatt ist auch eher als Illustration zum nebenstehenden Prosatext zu sehen denn als Anleitung, wie man das produktionsreif implementiert. >> Streng genommen gehört das >> auch in einen nicht-unterbrechbaren Block. > > das dagegen ist unbedingt notwendig Und was sagt dir das jetzt, daß das im Datenblatt-Beispielcode auch nicht so gemacht wird? "Der da macht es aber auch falsch" ist keine akzeptable Entschuldigung.
Axel S. schrieb: > Und was sagt dir das jetzt, daß das im Datenblatt-Beispielcode auch > nicht so gemacht wird? muss man ja auch nicht machen wenn man weiß dass keine Unterbrechungen vorkommen. Aber ich bin dann hier raus, du darfst das letzte Wort haben.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.