Hallo, folgendes Problem bringt mich zur Verzweiflung: Mit folgendem Code schreibe ich Werte in den Flash-Speicher. Der Funktion wird die Flash-Page und ein Pointer auf die zu schreibenden Daten übergeben. Aber aus irgendwelchen Gründen wird das erste Wort in der Flash-Page immer mit 0 beschrieben, die restlichen Wert sind korrekt. Ich habe schon alles Mögliche probiert, aber der erste Wert bleibt 0. Ich verwende einen Atmega8, so langsam glaube ich an einen Bug. static void write_page(uint16_t page,uint16_t *data) { volatile uint16_t wert,n; volatile uint16_t seite; cli(); seite=page; seite=seite*(PAGESIZE/2); // für Atmega8 um 5 bit nach links schieben // page buffer laden for(n=0;n<(PAGESIZE);n+=2) // Atmega8 Page Buffer Worte: 32 { wert=*data++; asm volatile("\n\t" "nop \n\t" "movw r30, %[wortadresse] \n\t" // z Register mit Adresse laden "movw r0, %[flashwert] \n\t" // z Register mit Adresse laden : // output Argument Liste ( keine ) :[wortadresse] "w" (n),[flashwert] "w" (wert) // input Argument Liste ( w fuer word ) ); SPMCR = (1<<SPMEN); // write pagebuffer flag asm volatile ( "spm" ); while ((SPMCR & (1<<SPMEN)) == 1); //warten bis fertig } asm volatile ( "clr _zero_reg_ " );
Genau dafür gibt es fertige, erprobte und debuggte Routinen (auch ,,nur'' in inline asm letztlich) in der avr-libc in <avr/boot.h>.
Hallo Jörg, besten Dank für die schnelle Antwort. Ich hatte keine Ahnung, dass in der avr-libc schon fertige Routinen vorhanden sind. Da hätte ich mir doch glatt 2 Tage Arbeit sparen können. Trotzdem hätte mich der Fehler in meiner Routine interessiert. Ich habe den Inline-Assembler zum ersten Mal verwendet. Das Interessante ist, dass wenn man die Routine im AVR-Studio-Simulator debugged alle Register richtig geladen werden und das Programm damit wohl auch korrekt funktionieren sollte. Wenn man die Zeile wert=*data++; durdh wert=0x1234; ersetzt, wird der Flashspeicher im echten Prozessor korrekt beschrieben. Untersucht man den Code mit dem Simulator und macht einen Speicherdump, ist auch das Array richtig initialisiert. Aber es ist und bleibt dabei, das erste Wort im echten Flash ist 0, falls man das Array verwendet. In der avr-libc ist am Amfang der Routine eine Abfrage ob EEPROM Zyklen abgeschlossen sind. Diese Abfrage habe ich in meinem Code nicht drin, da ich das EEPROM nicht beschreibe. Sollte es eventuell doch aus anderen Gründen notwendig sein?
ajax wrote: > Trotzdem hätte mich der Fehler in meiner Routine interessiert. Du müsstest vielleicht als erstes damit anfangen, den tatsächlich für alles generierten Assemblercode mal anzusehen. Was mir auf jeden Fall auffällt: zuerst kommt ein Stück inline asm, dann aber, wenn es wirklich zeitkritisch wird (SPM muss ja innerhalb eines Zeitfensters nach SPMEN ausgeführt werden), schiebst du noch extra C-Code rein. > Aber es ist und bleibt dabei, das erste Wort im echten Flash ist 0, > falls man das Array verwendet. Du könntest den Prozessor durch einen ATmega88 upgraden und dann mit debugWire auf der echten CPU live nachsehen. > In der avr-libc ist am Amfang der Routine eine Abfrage ob EEPROM Zyklen > abgeschlossen sind. Diese Abfrage habe ich in meinem Code nicht drin, da > ich das EEPROM nicht beschreibe. Sollte es eventuell doch aus anderen > Gründen notwendig sein? Nicht, dass ich wüsste, aber ich habe das auch noch nicht praktisch gemacht.
>Was mir auf jeden Fall auffällt: zuerst kommt ein Stück inline >asm, dann aber, wenn es wirklich zeitkritisch wird (SPM muss ja >innerhalb eines Zeitfensters nach SPMEN ausgeführt werden), >schiebst du noch extra C-Code rein. In der Hinsicht war es mir auch etwas unwohl, aber andererseits: Was soll der Compiler gross zwischen Register setzen und dem SPM-Befehle machen?: 125: SPMCR = (1<<SPMEN); // write pagebuffer flag +00000EAA: BF47 OUT 0x37,R20 Out to I/O location 126: asm volatile ( "spm" ); +00000EAB: 95E8 SPM Store program memory (Wie man sieht, passt's) Aber irgendwie habe ich heute keinen guten Programmiertag. Auf die schnelle habe ich mal die Routine void boot_program_page (uint32_t page, uint8_t *buf) aus der avr-libc eingebunden. Und was erhalte ich: avr-gcc.exe -mmcu=atmega8 -Wl,--section-start=.text=0x1c00 chBootloader.o -o chBootloader.elf chBootloader.o: In function `boot_program_page': ../chBootloader.c:87: undefined reference to `eeprom_busy_wait' ../chBootloader.c:89: undefined reference to `boot_page_erase' ../chBootloader.c:90: undefined reference to `boot_spm_busy_wait' ../chBootloader.c:99: undefined reference to `boot_page_fill' ../chBootloader.c:102: undefined reference to `boot_page_write' ../chBootloader.c:103: undefined reference to `boot_spm_busy_wait' ../chBootloader.c:108: undefined reference to `boot_rww_enable' make: *** [chBootloader.elf] Error 1 Build failed with 7 errors and 0 warnings... Trotz "#include <avr/pgmspace.h>" Bin ich jetzt völlig daneben?
Halt, Komando zurück, war mein Fehler, boot.h vergessen. Es ist schon spät, ich glaub, ich mach morgen weiter....
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.