Forum: Mikrocontroller und Digitale Elektronik Bootloader schreiben


von Atmega (Gast)


Lesenswert?

Hallo,

ich will mal einen Bootloader schreiben. Nun will ich erstmal verstehen, 
was ich überhaupt tun muss.

Ich habe das mal versucht zusammen zu schreiben und würde mich freuen, 
wenn ihr mich korrigieren könntet, wenn etwas falsch ist.

Für den Atmega16M1 mit einer Boot size von 2048 words.

Dh. der Bootloader hat 4096 Byte platz und liegt im flash 0x1800 bis 
0x1FFF

Die eigetliche Applikation liegt im falsh von 0x0000 bis 0x17FF

Nun müsste doch die erste Page bei der Adresse 0x0000 und die nächste 
bei 0x0400 und die darauf nächste 0x0800 liegen usw. (Sprich 128*8*n mit 
n = 0,1,2...) Und jede Page 4096/32 = 128 Byte groß sein...? Dh. ich 
muss 128 Byte sammeln und kann dann eine Page beschreiben.

Meine Idee, da ich immer nur 8 Nutzdaten (Plus Ext ID) verschicken kann 
und es sein könnte, dass mal eine Nachricht verloren geht, das ganze zu 
zählen. (Oder hält das jemand für übertrieben?)

Ich würde also immer Abschnittsweise versenden. Jeder Abschnitt hat 32 
Nachrichten und somit 256 Byte (Dh. beim 16M1 und 32M1 könnten zwei 
pages  und beim 64M1 eine page beschrieben werde) Nachdem der letzte 
Abschnitt gesendet wurde, schicke ich eine weitere Nachricht um dem MCU 
zu sagen, er soll in die Applikation springen.

Bei welcher Nachricht des Abschnitts ich bin, würde ich in die CAN ID 
(Nutze 29Bit) unterbringen.


Nun ist mir das mit dem Sammeln der Date noch nicht ganz klar. Wie macht 
man das am besten? Man muss ja erstmal 128 Byte sammeln, um überhaupt 
eine Page komplett schreiben zu können. Macht man das am besten mit 
memcpy() oder gibt es auch andere, sparsammere Varianten?

Ich habe auch noch nicht ganz raus, was man mit dem Read While Write 
Speicher macht, der im Datenblatt im Bootloader Bereich genannt wird.


Und dann als letzte Frage: Wie kommt man am geschicktesten vom 
Bootloader wieder in die soeben geschriebene Applikation? Ich habe 
einige Varianten online gefunden, verstehe davon aber meist nicht all zu 
viel...
1
void boot_jump_to_application(void)
2
{
3
// Das verändern des Int Vektors ist noch klar
4
  uint8_t reg = MCUCR & ~((1 << IVCE) | (1 << IVSEL));
5
  MCUCR = reg | (1 << IVCE);
6
  MCUCR = reg;
7
8
// Könnte mir das hier jemand erklären?
9
#if FLASHEND > 0xffff
10
  __asm__ __volatile__(
11
      "push __zero_reg__" "\n\t"
12
      "push __zero_reg__" "\n\t"
13
      "push __zero_reg__" "\n\t");
14
#else
15
  __asm__ __volatile__(
16
      "push __zero_reg__" "\n\t"
17
      "push __zero_reg__" "\n\t");
18
#endif
19
}

Könnte mir das jemand erklären?

von Cube_S (Gast)


Lesenswert?

Ich habe seit kurzem genau so etwas gemacht. Die Can ID nutze ich nicht 
für Daten, sondern nur für Kommandos. Daten übertrage ich in einen 
Puffer der die Größe der Page hat. Die 8-Can Bytes nutze ich so: Das 
erste Byte ist eine Adresse (die mit 7 multipliziert wird) innerhalb der 
aktuellen Page, die restlichen 1-7 Bytes sind Nutzdaten.

Jede solche Meldung schicke ich als ACK wieder zurück. Kommt kein ACK 
schicke ich das entsprechende Paket noch einmal. Irgendwann ist der 
Page-Puffer voll und ich schicke einen Schreib-Befehl für die Page. 
Wieder quittiert durch ein ACK

Zurück ins Hauptprogramm komme ich so:
1
((void (*)())0)();

von Cube_S (Gast)


Lesenswert?

1
      "push __zero_reg__" "\n\t"
2
      "push __zero_reg__" "\n\t"
3
      "push __zero_reg__" "\n\t");
Ich würde sage hier wird die 0 als Rücksprungadresse auf den Stack 
geladen und damit endet die Prozedur bei 0.

von Martin L. (maveric00)


Lesenswert?

Hallo,

unter

https://github.com/maveric00/HomeCANtrol/tree/master/src/Bootloader

ist ein CAN-Bootloader für ATMega und ATTiny-Prozessoren zu finden 
(wiederum inspiriert vom Roboternetz-CAN-Bootloader); eventuell kannst 
Du ja Inspirationen ziehen (allerdings für MCP2515 über SPI, als mein 
Projekt angefangen hat, war der M1 noch nicht lieferbar und inzwischen 
schwenke ich auf die STM32 über)

Schöne Grüße,
Martin

von Christian S. (vivus)


Lesenswert?

Danke schonmal für eure Antworten!

Cube_S schrieb:
> Zurück ins Hauptprogramm komme ich so:
> ((void (*)())0)();

Kannst du erklären, was da genau passiert? Also abgesehen, dass es 
zurück zum Hauptprogramm gehen soll :) Würde das ganz gern verstehen... 
Wie kommt an auf dieses Konstrukt?


Ich habe ja folgendes geschrieben:

Atmega schrieb:
> Nun müsste doch die erste Page bei der Adresse 0x0000 und die nächste
> bei 0x0400 und die darauf nächste 0x0800 liegen usw. (Sprich 128*8*n mit
> n = 0,1,2...) Und jede Page 4096/32 = 128 Byte groß sein...? Dh. ich
> muss 128 Byte sammeln und kann dann eine Page beschreiben.

Ist das so korrekt?

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.