Probleme beim Schreiben in den Flash-Speicher

Gast #1498848
Lesenswert?

Hallo,

ich bin gerade dabei einen Bootloader zu schreiben. Um erst einmal zu 
lernen man mit dem Flash-Speicher umgeht, habe ich folgende Funktion im 
Bootloader, die eine Test-Applikation (LED blinken lassen) in den 
Anwendungs-Speicher-Bereich des Flash schreiben soll:
1
void write_app()
2
{
3
  int data[] = 
4
  {
5
    0x12C0,0x19C0,0x18C0,0x17C0,0x16C0,0x15C0,0x14C0,0x13C0,
6
    0x12C0,0x11C0,0x10C0,0x0FC0,0x0EC0,0x0DC0,0x0CC0,0x0BC0,
7
    0x0AC0,0x09C0,0x08C0,0x1124,0x1FBE,0xCFE5,0xD4E0,0xDEBF,
8
    0xCDBF,0x02D0,0x1FC0,0xE4CF,0x84B3,0x8462,0x84BB,0xAA98,
9
    0xA09A,0x8A9A,0xA898,0x84B3,0x8861,0x84BB,0xAB98,0x28EC,
10
    0x30E0,0xAD9A,0x80ED,0x97E0,0xF901,0x3197,0xF1F7,0x0197,
11
    0xD9F7,0xAD98,0x80ED,0x97E0,0xF901,0x3197,0xF1F7,0x0197,
12
    0xD9F7,0xEFCF,0xF894,0xFFCF,0xFFFF,0xFFFF,0xFFFF,0xFFFF
13
  };
14

15
  cli();
16
  char i = 0;
17
  char n = 0;
18
  for (i = 0; i < 4; i++)
19
  {
20
    boot_spm_busy_wait();
21
    for (n = 0; n < 32; n+=2)
22
    {
23
      boot_page_fill(i * 32 + n, data[32 * i + n]);
24
    }
25
    boot_page_write(i);
26
  }
27
  sei();
28
}

Wenn ich allerdings den Flash auslese, nachdem der Bootloader das 
Programm geschrieben hat, erhalte ich Folgendes:
1
:100000000000400040000014001200100006000430
2
:100010000002000000054004038DC012800080042F
3
:10002000800080004000800AC000C0000008B611B7
4
:10003000E0D0AD800019B380B38090A098A861880B
5
:10004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0
6
:10005000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0
7
:10006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0
8
:10007000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90

anstelle von
1
:1000000012C019C018C017C016C015C014C013C044
2
:1000100012C011C010C00FC00EC00DC00CC00BC06C
3
:100020000AC009C008C011241FBECFE5D4E0DEBF5E
4
:10003000CDBF02D01FC0E4CF84B3846284BBAA9832
5
:10004000A09A8A9AA89884B3886184BBAB9828EC5C
6
:1000500030E0AD9A80ED97E0F9013197F1F7019723
7
:10006000D9F7AD9880ED97E0F9013197F1F7019755
8
:10007000D9F7EFCFF894FFCFFFFFFFFFFFFFFFFFA0
(So sieht es aus, wenn ich das Test-Progamm über den ISP-Programmierer 
aufspiele und anschließend den Flash-Speicher auslese)
Gast #1499460
Lesenswert?

Ok,

ich habe meinen Code entsprechend geändert:
1
void write_app()
2
{
3
  int data[] = 
4
  {
5
    0x12C0,0x19C0,0x18C0,0x17C0,0x16C0,0x15C0,0x14C0,0x13C0,
6
    0x12C0,0x11C0,0x10C0,0x0FC0,0x0EC0,0x0DC0,0x0CC0,0x0BC0,
7
    0x0AC0,0x09C0,0x08C0,0x1124,0x1FBE,0xCFE5,0xD4E0,0xDEBF,
8
    0xCDBF,0x02D0,0x1FC0,0xE4CF,0x84B3,0x8462,0x84BB,0xAA98,
9
    0xA09A,0x8A9A,0xA898,0x84B3,0x8861,0x84BB,0xAB98,0x28EC,
10
    0x30E0,0xAD9A,0x80ED,0x97E0,0xF901,0x3197,0xF1F7,0x0197,
11
    0xD9F7,0xAD98,0x80ED,0x97E0,0xF901,0x3197,0xF1F7,0x0197,
12
    0xD9F7,0xEFCF,0xF894,0xFFCF,0xFFFF,0xFFFF,0xFFFF,0xFFFF
13
  };
14

15
  cli();
16
  char i = 0;
17
  for (i = 1; i < 128; i+=2)
18
  {
19

20
    boot_page_fill(i, data[i/2]);
21
  }
22
  boot_spm_busy_wait();
23
  boot_page_write(0);
24
  boot_page_write(32);
25
  boot_page_write(64);
26
  boot_page_write(96);
27

28
  sei();
29
}

leider enthält die Hex-Datei jetzt folgenden (falschen) Inhalt:
1
:100000008000800880088004400080048000C000D8
2
:10001000C0108001C000C00700088001C00080013E
3
:10002000C0088009C000201100198501E0D09700A8
4
:10003000B7C9C0028018CFE4B3846284BB8498AA95
5
:10004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0
6
:10005000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0
7
:10006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0
8
:10007000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90
Gast #1499541
Lesenswert?

Ich bin am verzweifeln,

diese Version funktioniert auch nicht:
1
void write_app()
2
{
3
  int data[] = 
4
  {
5
    0x12C0,0x19C0,0x18C0,0x17C0,0x16C0,0x15C0,0x14C0,0x13C0,
6
    0x12C0,0x11C0,0x10C0,0x0FC0,0x0EC0,0x0DC0,0x0CC0,0x0BC0,
7
    0x0AC0,0x09C0,0x08C0,0x1124,0x1FBE,0xCFE5,0xD4E0,0xDEBF,
8
    0xCDBF,0x02D0,0x1FC0,0xE4CF,0x84B3,0x8462,0x84BB,0xAA98,
9
    0xA09A,0x8A9A,0xA898,0x84B3,0x8861,0x84BB,0xAB98,0x28EC,
10
    0x30E0,0xAD9A,0x80ED,0x97E0,0xF901,0x3197,0xF1F7,0x0197,
11
    0xD9F7,0xAD98,0x80ED,0x97E0,0xF901,0x3197,0xF1F7,0x0197,
12
    0xD9F7,0xEFCF,0xF894,0xFFCF,0xFFFF,0xFFFF,0xFFFF,0xFFFF
13
  };
14

15
  cli();
16
  char i = 0;
17
  for (i = 0; i < 128; i+=2)
18
  {
19

20
    boot_page_fill(i, data[i/2]);
21
    if (i % 32 == 0 && i > 0)
22
    {
23
      boot_page_write(i / 32);
24
    }
25
    boot_spm_busy_wait();
26
  }
27
  
28
  sei();
29
}

Ergebnis:
1
:100000008000800880088004400080048000C000D8
2
:10001000C0108001C000C00700088001C00080013E
3
:10002000C008C009C0082411BE1FE5CFE0D4BFDE60
4
:10003000BFCDD002C01FCFE4B3846284BB8498AA32
5
:10004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0
6
:10005000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0
7
:10006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0
8
:10007000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90
Gast #1499559
Lesenswert?

Ok,

jetzt habe ich nochmal auf Deinen Rat hin den Code geändert:
1
void write_app()
2
{
3
  int data[] = 
4
  {
5
    0x12C0,0x19C0,0x18C0,0x17C0,0x16C0,0x15C0,0x14C0,0x13C0,
6
    0x12C0,0x11C0,0x10C0,0x0FC0,0x0EC0,0x0DC0,0x0CC0,0x0BC0,
7
    0x0AC0,0x09C0,0x08C0,0x1124,0x1FBE,0xCFE5,0xD4E0,0xDEBF,
8
    0xCDBF,0x02D0,0x1FC0,0xE4CF,0x84B3,0x8462,0x84BB,0xAA98,
9
    0xA09A,0x8A9A,0xA898,0x84B3,0x8861,0x84BB,0xAB98,0x28EC,
10
    0x30E0,0xAD9A,0x80ED,0x97E0,0xF901,0x3197,0xF1F7,0x0197,
11
    0xD9F7,0xAD98,0x80ED,0x97E0,0xF901,0x3197,0xF1F7,0x0197,
12
    0xD9F7,0xEFCF,0xF894,0xFFCF,0xFFFF,0xFFFF,0xFFFF,0xFFFF
13
  };
14

15
  cli();
16
  char i = 0;
17
  for (i = 0; i < 128; i+=2)
18
  {
19

20
    boot_page_fill(i, data[i/2]);
21
    if (i % 64 == 0 && i > 0)
22
    {
23
      boot_page_write(i-64);
24
    }
25
    boot_spm_busy_wait();
26
  }
27
  boot_page_write(128-64);
28
  boot_spm_busy_wait();
29

30
  sei();
31
}

Ergebnis: Falscher Flash-Inhalt. :-(
1
:100000008000C019C018C017C016C015C014C01396
2
:10001000C012C011C010C00FC00EC00DC00CC00B6C
3
:10002000C00AC009C0082411BE1FE5CFE0D4BFDE5E
4
:10003000BFCDD002C01FCFE4B3846284BB8498AA32
5
:10004000FFFF9A8A98A8B3846188BB8498ABEC2898
6
:10005000E0309AADED80E09701F99731F7F1970123
7
:10006000F7D998ADED80E09701F99731F7F1970155
8
:10007000F7D9CFEF94F8CFFFFFFFFFFFFFFFFFFFA0
#1499592
Lesenswert?

jacky schrieb:

> jetzt habe ich nochmal auf Deinen Rat hin den Code geändert:

Und mittlerweile bist du bei einer etwas kruden Struktur angekommen. 
Warum hast du nicht die Struktur deiner ersten Version beibehalten?

> Ergebnis: Falscher Flash-Inhalt. :-(

Ja, die ersten beiden Bytes beider Pages sind falsch. Und ehrlich gesagt 
sehe ich so auf Anhieb nicht, warum. Vielleicht ein merkwürdiger 
Seiteneffekt des unnötigen boot_spm_busy_wait() nach jedem 
boot_page_fill()? (kann ich mir aber eigentlich nicht vorstellen)
Gast #1499600
Lesenswert?

Es ist mir etwas unangehm, ja fast peinlich, dich zu bitten, nachdem Du 
mir schon so viel Unterstützung gegeben hast, meinen Code einmal 
"sauber" aufzuschreiben. Vielleicht gibt es ja schon eine vordefinierte 
Konstante für die Page-Größe oder ähnliches.

Danke im Voraus,

der überaus dankbare Jacky
#1499649
Lesenswert?

> meinen Code einmal "sauber" aufzuschreiben

Ok, aber nur weil Wochenende ist. ;-)

1
    uint16_t page_addr;
2

3
    for (page_addr = 0; page_addr < sizeof(data)*2; page_addr += SPM_PAGESIZE) {
4

5
        boot_page_erase (page_addr);
6
        boot_spm_busy_wait ();
7

8
        for (uint8_t i = 0; i < SPM_PAGESIZE/2; i++)
9
            boot_page_fill (page_addr + (i * 2), data[i]);
10

11
        boot_page_write (page_addr);
12
        boot_spm_busy_wait ();
13
    }

So ganz "sauber" ist das aber auch nicht, denn der Code geht davon aus, 
dass data ein ganzzahliges Vielfaches der Page-Größe enthält, 
ansonsten wird die letzte Page mit Müll aufgefüllt.
Gast #1499658
Lesenswert?

Erst einmal vielen Dank für die Mühe! :-)

Leider immernoch erfolglos:
1
void write_app()
2
{
3
  int data[] = 
4
  {
5
    0x12C0,0x19C0,0x18C0,0x17C0,0x16C0,0x15C0,0x14C0,0x13C0,
6
    0x12C0,0x11C0,0x10C0,0x0FC0,0x0EC0,0x0DC0,0x0CC0,0x0BC0,
7
    0x0AC0,0x09C0,0x08C0,0x1124,0x1FBE,0xCFE5,0xD4E0,0xDEBF,
8
    0xCDBF,0x02D0,0x1FC0,0xE4CF,0x84B3,0x8462,0x84BB,0xAA98,
9
    0xA09A,0x8A9A,0xA898,0x84B3,0x8861,0x84BB,0xAB98,0x28EC,
10
    0x30E0,0xAD9A,0x80ED,0x97E0,0xF901,0x3197,0xF1F7,0x0197,
11
    0xD9F7,0xAD98,0x80ED,0x97E0,0xF901,0x3197,0xF1F7,0x0197,
12
    0xD9F7,0xEFCF,0xF894,0xFFCF,0xFFFF,0xFFFF,0xFFFF,0xFFFF
13
  };
14

15
  cli();
16

17
  uint16_t page_addr;
18

19
    for (page_addr = 0; page_addr < sizeof(data)*2; page_addr += SPM_PAGESIZE)
20
    {
21
        boot_page_erase (page_addr);
22
        boot_spm_busy_wait ();
23

24
        for (uint8_t i = 0; i < SPM_PAGESIZE/2; i++)
25
        {
26
            boot_page_fill (page_addr + (i * 2), data[i]);
27
        }
28

29
        boot_page_write (page_addr);
30
        boot_spm_busy_wait ();
31
    }
32

33
  sei();
34
}

Ergebnis im Flash:
1
:10000000C012C019C018C017C016C015C014C01344
2
:10001000C012C011C010C00FC00EC00DC00CC00B6C
3
:10002000C00AC009C0082411BE1FE5CFE0D4BFDE5E
4
:10003000BFCDD002C01FCFE4B3846284BB8498AA32
5
:10004000C012C019C018C017C016C015C014C01304
6
:10005000C012C011C010C00FC00EC00DC00CC00B2C
7
:10006000C00AC009C0082411BE1FE5CFE0D4BFDE1E
8
:10007000BFCDD002C01FCFE4B3846284BB8498AAF2
9
:10008000C012C019C018C017C016C015C014C013C4
10
:10009000C012C011C010C00FC00EC00DC00CC00BEC
11
:1000A000C00AC009C0082411BE1FE5CFE0D4BFDEDE
12
:1000B000BFCDD002C01FCFE4B3846284BB8498AAB2
13
:1000C000C012C019C018C017C016C015C014C01384
14
:1000D000C012C011C010C00FC00EC00DC00CC00BAC
15
:1000E000C00AC009C0082411BE1FE5CFE0D4BFDE9E
16
:1000F000BFCDD002C01FCFE4B3846284BB8498AA72

Daraufhin habe ich einen kleinen Fehler korrigiert, denn sizeof(data) 
gibt ja die größe des Arrays in Byte zurück und habe die äußere 
For-Schleife folgendermaßen modifiziert:

Aus
1
for (page_addr = 0; page_addr < sizeof(data)*2; page_addr += SPM_PAGESIZE)
wird
1
for (page_addr = 0; page_addr < sizeof(data)/sizeof(int)*2; page_addr += SPM_PAGESIZE)

Ergebnis im Flash:
1
:10000000C012C019C018C017C016C015C014C01344
2
:10001000C012C011C010C00FC00EC00DC00CC00B6C
3
:10002000C00AC009C0082411BE1FE5CFE0D4BFDE5E
4
:10003000BFCDD002C01FCFE4B3846284BB8498AA32
5
:10004000C012C019C018C017C016C015C014C01304
6
:10005000C012C011C010C00FC00EC00DC00CC00B2C
7
:10006000C00AC009C0082411BE1FE5CFE0D4BFDE1E
8
:10007000BFCDD002C01FCFE4B3846284BB8498AAF2

Leider immernoch falsch. :-(
#1499668
Lesenswert?

matze schrieb:

> Daraufhin habe ich einen kleinen Fehler korrigiert, denn sizeof(data)
> gibt ja die größe des Arrays in Byte zurück und habe die äußere
> For-Schleife folgendermaßen modifiziert:

Ups, sorry, als Korrektur solltest du aber einfach das *2 weglassen.

> Leider immernoch falsch. :-(

Ja.
data[i]
->
data[page_addr/2+i];
Gast #1499677
Lesenswert?

hmm... irgendwo ist noch der Wurm drin.

Jetzt erhalte ich:
1
:10000000C012C019C018C017C016C015C014C01344
2
:10001000C012C011C010C00FC00EC00DC00CC00B6C
3
:10002000C00AC009C0082411BE1FE5CFE0D4BFDE5E
4
:10003000BFCDD002C01FCFE4B3846284BB8498AA32
5
:100040009AA09A8A98A8B3846188BB8498ABEC285C
6
:10005000E0309AADED80E09701F99731F7F1970123
7
:10006000F7D998ADED80E09701F99731F7F1970155
8
:10007000F7D9CFEF94F8CFFFFFFFFFFFFFFFFFFFA0

wenn ich mein Test-Programm aber über den ISP aufspiele und dann den 
Flash auslese, dann erhalte ich:
1
:1000000012C019C018C017C016C015C014C013C044
2
:1000100012C011C010C00FC00EC00DC00CC00BC06C
3
:100020000AC009C008C011241FBECFE5D4E0DEBF5E
4
:10003000CDBF02D01FC0E4CF84B3846284BBAA9832
5
:10004000A09A8A9AA89884B3886184BBAB9828EC5C
6
:1000500030E0AD9A80ED97E0F9013197F1F7019723
7
:10006000D9F7AD9880ED97E0F9013197F1F7019755
8
:10007000D9F7EFCFF894FFCFFFFFFFFFFFFFFFFFA0

was ist das los?
Gast #1499689
Lesenswert?

Ja!

ich habe noch schnell ein paar Zeilen zum Drehen der Bytes eingefügt:
1
unsigned int word = data[page_addr/2+i];
2
unsigned int new_word = (word >> 8) | ((word << 8) & 0xFF00);
3
boot_page_fill (page_addr + (i * 2), new_word);

und jetzt funktioniert es!

Tausend Dank!!
#1499697
Lesenswert?

jacky schrieb:
> Sind da etwa alle Bytes in den Wörtern verdreht?

Natürlich, der AVR ist Little Endian.

> ich habe noch schnell ein paar Zeilen zum Drehen der Bytes eingefügt:

Wie wäre es statt dessen, data passend zu füllen? Oder das ganze auf 
Byte-Basis zu machen, statt auf Word-Basis?
Gast #1499701
Lesenswert?

Wie gesagt, das ist ja erstmal zum testweise beschreiben des AVR. Jetzt 
wird dann langsam ein "richtiger" Bootloader draus. :-)

Aber eine Frage noch: Warum funktioniert
1
void (*jump_to_app)(void) = 0x0000;
2

3
void write_app()
4
{
5
  int data[] = 
6
  {
7
    // ...
8
  };
9

10
  cli();
11

12
  for (...)
13
  {
14
      //...
15
  }
16

17
  jump_to_app();
18
  sei();
19
}
20
nicht?
21

22
Das hat zur Folge, dass der Bootloader immer wieder neustartet. Wenn ich dann allerdings das Fusebit BOOTRST lösche und den ATmega neustarte, dann startet die Anwendung ganz normal. Es scheint, als würde er an den Anfang des Bootloaders springen. Warum?
Gast #1499703
Lesenswert?

Nochmal, diesmal korrekt formatiert:
------------------------------------
Wie gesagt, das ist ja erstmal zum testweise beschreiben des AVR. Jetzt
wird dann langsam ein "richtiger" Bootloader draus. :-)

Aber eine Frage noch: Warum funktioniert
1
void (*jump_to_app)(void) = 0x0000;
2

3
void write_app()
4
{
5
  int data[] = 
6
  {
7
    // ...
8
  };
9

10
  cli();
11

12
  for (...)
13
  {
14
      //...
15
  }
16

17
  jump_to_app();
18
  sei();
19
}
nicht?

Das hat zur Folge, dass der Bootloader immer wieder neustartet. Wenn ich 
dann allerdings das Fusebit BOOTRST lösche und den ATmega neustarte, 
dann startet die Anwendung ganz normal. Es scheint, als würde er an den 
Anfang des Bootloaders springen. Warum?
#1573242
Lesenswert?

Hallo,

ich habe bei mir ebenfalls ein Problem mit dem schreiben der Seite. Ich 
möchte ein Word-Muster (0x1234) eine Seite lang an den Anfang des Flashs 
schreiben... wenn ich mir abschließend einen Hexdump vom Flash erstelle 
(per AVR-Studio), dann kann ich dieses Word-Muster allerdings nicht 
wiederfinden :-(

Mal abgesehen davon, dass bei mir wahrscheinlich auch das little-Endian 
Problem zuschlägt, hätte ich zunächst mal gern irgend etwas in meinem 
Flash stehen gesehen...

wo liegt mein Fehler?

Danke für Eure Hilfe,

Gruß Stephan
Angehängte Dateien:
Gast #1789898
Lesenswert?

Die generelle Vorgehensweise beim Umgang mit EEPROM/ Flash:

- Page löschen
- warten bis Löschvorgang fertig
- Page schreiben
- warten bis Schreibvorgang fertig
(- ggf. Sektion aktivieren - siehe AVR/ boot_rww_enable())
- lesen

MfG,
subitus

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren