Forum: Mikrocontroller und Digitale Elektronik boot_program_page Bug auf ATMega8


von Mac G. (mac_g)


Lesenswert?

Hallo,

bei meinen Versuchen den Flash eines ATMega8 über einen Bootloader zu 
beschreiben, bin ich über folgendes Phänomen gestossen:
Die Funktion "boot_program_page" wie sie in der WinAVR-Doku beschrieben 
ist, funktioniert erst richtig,
wenn zuvor die Funktion "boot_page_erase" mit einer beliebigen Page 
aufgerufen wurde.

So zum Beispiel steht nach einem Aufruf von

memset( data, 0, SPM_PAGESIZE );
boot_program_page( 0, data )

in den ersten 64 Bytes des Flashs immernoch "0xFF".

Wobei dieser Aufruf:

boot_page_erase(64);
boot_program_page( 0, data );

in den ersten 64 Bytes die korrekten Nullen reinschreibt.
Ganz kurios ist die Tatsache, dass sich die Page, die das erste Mal mit 
"boot_page_erase" bearbeitet wurde, nicht mehr beschreiben lässt, d.h.
der Aufruf:

boot_page_erase(0);
boot_program_page( 0, data );

liefert immernoch "0xff" in der Page.
Als Workaround nehmen ich momentan immer die nicht existierende Page 
"-1":

boot_page_erase(-1);
boot_program_page( 0, data );

Hatte einer von euch schonmal dasselbe Problem?

Ich benutze das AVRStudio 4 mit der WinAVR Version vom 10.01.2010 (die 
Version 10.06.2008 hab ich auch getestet).

Anbei der follständige Code (Bootloader ist 2k groß, Fuses sind auf dem 
ATMega8 entsprechen gesetzt):

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/boot.h>

void boot_program_page(uint32_t page, uint8_t* buf) {
    uint16_t i;
    uint8_t sreg;

    /* Disable interrupts.*/
    sreg = SREG;
    cli();

    eeprom_busy_wait();

    boot_page_erase(page);
    boot_spm_busy_wait();      /* Wait until the memory is erased. */

    for (i=0; i<SPM_PAGESIZE; i+=2) {
        /* Set up little-endian word. */
        uint16_t w = *buf++;
        w += (*buf++) << 8;

        boot_page_fill(page + i, w);
    }
    boot_page_write(page);     /* Store buffer in flash page.    */
    boot_spm_busy_wait();       /* Wait until the memory is written.*/

    /* Reenable RWW-section again. We need this if we want to jump back 
*/
    /* to the application after bootloading. */
    boot_rww_enable();

    /* Re-enable interrupts (if they were ever enabled). */
    SREG = sreg;
}

int main() {
  uint16_t page;

  /* Interrupt Vektoren des bootloaders verwenden */
  char sregtemp = SREG;
  cli();
  temp = GICR;
  GICR = temp | (1<<IVCE);
  GICR = temp | (1<<IVSEL);
  SREG = sregtemp;
  sei();

  /* boot_program_page funktioniert erst korrekt nach einem Aufruf von 
boot_page_erase */
  boot_page_erase(-1);

  uint8_t data[SPM_PAGESIZE];
  memset( data, 0, SPM_PAGESIZE );
  boot_program_page( 0, data );

  /* Interrupt Vektoren der Applikation verwenden */
  cli();
  temp = GICR;
  GICR = temp | (1<<IVCE);
  GICR = temp & ~(1<<IVSEL);

  return 0;
}

von Peter D. (peda)


Lesenswert?

Lesen bildet:
Wichtige Regeln - erst lesen, dann posten!

Wenn Du willst, daß sich das jemand anguckt, benutze die Formatierung 
oder poste die Source als Anhang.


Peter

von Krapao (Gast)


Lesenswert?

> Wenn Du willst, daß sich das jemand anguckt, benutze die Formatierung
> oder poste die Source als Anhang.

Bevor die fehlende Formatierung noch mehr potentielle Antworter 
abschreckt: Hier mit Formatierung :-)

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/boot.h>
4
5
void boot_program_page(uint32_t page, uint8_t* buf) {
6
    uint16_t i;
7
    uint8_t sreg;
8
9
    /* Disable interrupts.*/
10
    sreg = SREG;
11
    cli();
12
13
    eeprom_busy_wait();
14
15
    boot_page_erase(page);
16
    boot_spm_busy_wait();      /* Wait until the memory is erased. */
17
18
    for (i=0; i<SPM_PAGESIZE; i+=2) {
19
        /* Set up little-endian word. */
20
        uint16_t w = *buf++;
21
        w += (*buf++) << 8;
22
23
        boot_page_fill(page + i, w);
24
    }
25
    boot_page_write(page);     /* Store buffer in flash page.    */
26
    boot_spm_busy_wait();      /* Wait until the memory is written.*/
27
28
    /* Reenable RWW-section again. We need this if we want to jump back */
29
    /* to the application after bootloading. */
30
    boot_rww_enable();
31
32
    /* Re-enable interrupts (if they were ever enabled). */
33
    SREG = sreg;
34
}
35
36
int main() {
37
  uint16_t page;
38
39
  /* Interrupt Vektoren des bootloaders verwenden */
40
  char sregtemp = SREG;
41
  cli();
42
  temp = GICR;
43
  GICR = temp | (1<<IVCE);
44
  GICR = temp | (1<<IVSEL);
45
  SREG = sregtemp;
46
  sei();
47
48
  /* boot_program_page funktioniert erst korrekt nach einem Aufruf von boot_page_erase */
49
  boot_page_erase(-1);
50
51
  uint8_t data[SPM_PAGESIZE];
52
  memset( data, 0, SPM_PAGESIZE );
53
  boot_program_page( 0, data );
54
55
  /* Interrupt Vektoren der Applikation verwenden */
56
  cli();
57
  temp = GICR;
58
  GICR = temp | (1<<IVCE);
59
  GICR = temp & ~(1<<IVSEL);
60
61
  return 0;
62
}

von soundso (Gast)


Lesenswert?

Flash-Speicher muss immer zuerst gelöscht werden (sprich auf 0xFF 
zurückgesetzt werden) bevor etwas rein geschrieben werden kann 
(Schreiben im Flash geht nur in eine Richtung von 1 nach null)

von Mac G. (mac_g)


Lesenswert?

Ja, der Flash Speicher wird in der Funktion "boot_program_page" vor 
jedem Schreiben gelöscht.
In meinem Fall muss ich jedoch zuerst die Funktion "boot_page_erase" mit 
einer beliebigen Seite beim Starten einmal ausführen damit das Schreiben 
überhaupt funktioniert.

von Krapao (Gast)


Angehängte Dateien:

Lesenswert?

Leider kann ich das Problem nicht nachstellen bzw. bei mir funktioniert 
alles mit WinAVR-20100110 (und auch mit AVR-Toolchain-4.7.0-2012-02-19)

Die wesentlichen Dateien sind im Anhang.

Die Batchfiles sind nur zur Anschauung und bei mir für die AVR Fuses 
"2K Bootloader" (Linker Option -Ttext=0x1800) "Atmega8 bei 12 MHz 
externer Quarz" und stk200 Programmieradapter an lpt1 eingestellt.

von holger (Gast)


Lesenswert?

>in den ersten 64 Bytes des Flashs immernoch "0xFF".

Gelöschtes Flash hat in den Zellen ja auch 0xFF.
Das ist völlig in Ordnung.

>Wobei dieser Aufruf:
>
>boot_page_erase(64);
>boot_program_page( 0, data );
>
>in den ersten 64 Bytes die korrekten Nullen reinschreibt.

Dann ist das Flash nicht gelöscht sondern mit Null programmiert.

Dein Problem ist also keins.

von Mac G. (mac_g)


Lesenswert?

> Gelöschtes Flash hat in den Zellen ja auch 0xFF.
> Das ist völlig in Ordnung.

Ich hab auch nichts anderes behauptet.

> Dann ist das Flash nicht gelöscht sondern mit Null programmiert.

Da hab ich auch geschrieben, dass das korrekt ist.

Mein Problem ist der initiale Aufruf von boot_page_erase auf IRGENDEINE 
Page beim Starten des Controllers damit ich dann eine ANDERE Seite 
korrekt Löschen und beschreiben kann.

@Krapao: Danke für deine Recherche. Mit deinen HEX-Files hab ich den 
gleichen Effekt. So langsam glaube ich, dass mein Controller defekt ist. 
Ich werd das mal mit einem neuen testen.

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.