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_ " );
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?