Forum: Compiler & IDEs AVR GCC inline assembler problem


von ajax (Gast)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Genau dafür gibt es fertige, erprobte und debuggte Routinen (auch
,,nur'' in inline asm letztlich) in der avr-libc in <avr/boot.h>.

von ajax (Gast)


Lesenswert?

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?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von ajax (Gast)


Lesenswert?

>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?

von ajax (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.