Forum: Mikrocontroller und Digitale Elektronik AVR231: AES Bootloader Frage zu "TYPE_PREPARE" Record


von Tycho B. (asellus)


Lesenswert?

Hallo,

in der loader.c gibt es eine Stelle, die ich nicht verstehe:
1
address = (const unsigned char __memx *)((unsigned long)bits << 16);
2
address = (const unsigned char __memx *)((unsigned long)address | ((unsigned long)*p++ << 8));
3
address = (const unsigned char __memx *)((unsigned long)address | *p++);
4
[...]
5
// Prepare for incoming data chunks by copying the page
6
// contents into the page buffer
7
case TYPE_PREPARE:
8
            {
9
              unsigned char *q = pageBuffer;
10
              const unsigned char __memx *r = address;
11
12
              do
13
              {
14
                *q++ = *r++;
15
              }
16
              while (--size);
17
              break;
18
            }

In der Appnote nennt sich das "FLASH PAGE PREPARE"

So wie ich das verstehe, wird der Flash in den RAM geladen. Wofür 
braucht man das bei einem Bootloader?

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Tycho B. schrieb:

> So wie ich das verstehe, wird der Flash in den RAM geladen.

Nein. Da wird RAM-Inhalt (ggf. auch aus externem RAM) in den page buffer 
geladen. Letzteres ist zwar sicher auch irgendwie RAM, aber nicht direkt 
im RAM-Adress-Space erreichbar. Er muss über ein spezielles Verfahren 
beschrieben werden.

Allerdings gibt es einen solchen page buffer nicht bei jedem AVR8. ES 
gibt ihn bei den "Classic"-Tinys und -Megas, aber nur bei ganz wenigen 
(oder sogar nur einer?) der neuen Baureihen. Die eine, von der mir das 
sicher bekannt ist, ist AVRxxEAyy.

Für weitere Details darfst du gerne auch selber die Datenblätter lesen. 
Das hat noch niemandem ernsthaft geschadet...

von Tycho B. (asellus)


Lesenswert?

1
union {
2
  struct {
3
    unsigned char m_rxBuffer[BUFFER_SIZE];  // Receive buffer
4
    unsigned char m_pageBuffer[PAGE_SIZE];  // Page is assembled here before
5
    // getting programmed to flash mem
6
  } part1;
7
8
  #if KEY_COUNT > 0
9
  struct {
10
    unsigned char m_tempbuf[256]; // Temp buffer for aesInit.
11
  } part2;
12
  #endif
13
} sharedbufs;
14
15
#define rxBuffer   sharedbufs.part1.m_rxBuffer
16
#define pageBuffer sharedbufs.part1.m_pageBuffer
17
#if KEY_COUNT > 0
18
#define tempbuf    sharedbufs.part2.m_tempbuf
19
#endif
20
21
switch (type)
22
          {
23
            // Erase page
24
            case TYPE_ERASE:
25
            spmErasePage(address);
26
            // Fall-through!
27
28
            // Prepare for incoming data chunks by copying the page
29
            // contents into the page buffer
30
            case TYPE_PREPARE:
31
            {
32
              unsigned char *q = pageBuffer;
33
              const unsigned char __memx *r = address;
34
35
              do
36
              {
37
                *q++ = *r++;
38
              }
39
              while (--size);
40
              break;
41
            }
42
43
            // Chunk of data is written into the page buffer
44
            case TYPE_DATA:
45
            {
46
              unsigned char *r = &pageBuffer[(unsigned long)(address) & 0xffff];
47
48
              do
49
              {
50
                *r++ = *p++;
51
              }
52
              while (--size);
53
              break;
54
            }
55
56
            // Program page buffer into flash page
57
            case TYPE_PROGRAM:
58
            {
59
              unsigned int *q = (unsigned int *)pageBuffer;
60
              const unsigned char __memx *r = address;
61
62
              do
63
              {
64
                wdt_reset();
65
                spmWriteWord(r, *q++);
66
                r += 2;
67
              }
68
              while (--size);
69
70
              spmErasePage(address);
71
              spmProgramPage(address);
72
              break;
73
            }
Nach meinem Verständnis wird mit case TYPE_DATA im normalen RAM eine 
Page aufgebaut.
Dann macht case TYPE_PROGRAM das Laden in den eigentlichen PageBuffer. 
Danach wird mit spmErasePage(address) und spmProgramPage(address) 
geschrieben.

pageBuffer ist auch keine besondere Adresse, es wird ganz normal im RAM 
allokiert.

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


Lesenswert?

Naja, steht doch da: "for incoming data chunks": wenn du nur Teile einer 
Page beschreibst über den Bootloader, willst du ja den Rest der Page auf 
dem vorherigen Zustand haben. Dafür musst du sie erstmal auslesen.

Wenn du über den Bootloader eh alles beschreibst, brauchst du das 
natürlich nicht.

: Bearbeitet durch Moderator
von Tycho B. (asellus)


Lesenswert?

Das heisst also, mit case TYPE_PREPARE liesst man den flash aus und kann 
dann mit case TYPE_DATA die ausgelesene Page im RAM modifizieren. Oder 
aber man liesst den flash gar nicht aus und benutzt case TYPE_DATA um 
die komplette Page erstmal im RAM aufzubauen. Danach wird geschrieben. 
Richtig so?

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


Lesenswert?

Ja, passt. Wenn du halt nur Teile einer Page mit TYPE_DATA sendest, dann 
wird der Rest, den du nicht gesendet hast, hinterher gelöscht. Sofern du 
eh alles schreiben wolltest, ist das natürlich egal.

von Tycho B. (asellus)


Lesenswert?

Vielen Dank!

Letzte Frage, warum macht man hier & 0xffff?
1
unsigned char *r = &pageBuffer[(unsigned long)(address) & 0xffff];

Die Page wurde mit #define PAGE_SIZE 256 allokiert, würde nicht & 0xff 
reichen?

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


Lesenswert?

Keine Ahnung.

Am sinnvollsten wäre natürlich
1
 & (PAGE_SIZE - 1)

gewesen.

Oder gleich
1
 % PAGE_SIZE

: Bearbeitet durch Moderator
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.