Hallo,
ich arbeite mich gerade in das Thema Bootloader - bei ST "in Application
programming" ein. In meinem Fall will ich ein STM32F103 via CAN flashen.
Der Bootloader sollte möglichst nur aus der Anwendung aufgerufen werden
können. Ich hab hier im Forum ein wenig gestöbert und bin hautsächlich
auf die Prozedur gestoßen: Bootloader am Anfang vom Flash, wenn keine
Anfrage, dann nach x ms in Anwendung springen.
Idee wäre den Bootloader irgendwo ans Ende zu schreiben, nur wenn was
schief geht muss man wieder mit einem Programmer anrücken oder?
Mir geht es hier nicht um Verschlüsselung, ich will mir nur den Weg zu
den µC sparen.
Vielen Dank schon im Vorraus.
MfG Peter
Hi!
Ich hab das (allerdings beim STM32F4) so gemacht:
- Die Anwendung liegt bei 0x08000000, der Bootloader bei 0x08020000, so
kann man mit normalem Programmierer immer auch die Anwendung
überschreiben, ohne den Bootloader mit zu überschreiben; den Bootloader
programmiere ich an diese Adresse mit dem ST-Link Utility
- Wichtig hier ist, sich die Sektoraufteilung des Flash anzusehen, am
einfachsten beim Beschreiben ist es, ganze Sektoren zu löschen. Daher am
besten den Bootloader bei einem neuen Sektor starten lassen!
- Das Bootloader-Programm braucht einige Besonderheiten: Im Linker-File
muss der ROM Origin auf 0x08020000 gesetzt werden. Zudem muss die
Vektor-Tabelle ein Offset von 0x20000 bekommen (verwendet in der
system_stm32fxxx.c Datei):
1
#define VECT_TAB_OFFSET 0x00000
- In der eigentlichen Anwendung gibt es einen Aufruf, welcher den Proz.
zurücksetzt und dann in den Bootloader springt, etwa so:
1
uint8_tbootloader_init(void){
2
3
//magic RAM constant
4
*((uint32_t*)0x2000FFF0)=0xDEADBEEF;
5
NVIC_SystemReset();
6
7
return1;
8
9
}
- Vor Aufruf des Reset-Vektors wird eine Speicheradresse 0x2000FFF0 mit
einem besonderen Wert (magic constant) beschrieben.
- Im Startskript der Anwendung ist dann die eigentliche Verzweigung in
den Bootloader:
1
Reset_Handler:
2
//check for magic constant in RAM for bootloader operation
3
ldr r0, =0x2000FFF0
4
ldr r1, =0xDEADBEEF
5
ldr r2, [r0, #0]
6
str r0, [r0, #0] //invalidate constant to prevent jumping twice
7
cmp r2, r1
8
beq BootLoader
9
//...
10
//normal start script follows here
11
//...
12
BootLoader:
13
ldr r0, =0x08020000
14
ldr sp, [r0, #0]
15
ldr r0, [r0, #4]
16
bx r0
Empfehlenswert für das Beschreiben des Flash ist auch das Flash-Beispiel
aus der STM32 Standard Peripheral Lib.
Viel Erfolg!
wosnet schrieb:> Ich hab das (allerdings beim STM32F4) so gemacht:> - Die Anwendung liegt bei 0x08000000, der Bootloader bei 0x08020000, so> kann man mit normalem Programmierer immer auch die Anwendung> überschreiben, ohne den Bootloader mit zu überschreiben;
Das kannst Du auch wenn der Bootloader vorne und die Anwendung hinten
liegt. Auch dann kann man problemlos die Anwendung flashen und debuggen
ohne dabei den Bootloader zu berühren.
verwende EM-Blocks mit dem ST-Link. Da kann ich leider nirgends eine
(andere) Basisadresse einstellen für den Debugger, d.h. debuggen und
programmieren auf einer anderen Adresse als 0x08000000 bekomme ich nicht
hin. Kannst bitte kurz beschrieben wo da was zu konfigurieren ist?
Vielen Dank!
Peter schrieb:> Idee wäre den Bootloader irgendwo ans Ende zu schreiben, nur wenn was> schief geht muss man wieder mit einem Programmer anrücken oder?
Die Frage ist nur, wie möchtest Du zum Bootloader verzweigen, wenn etwas
schief gegangen ist? Du lässt den Bootloader von deiner Firmware
starten. Jetzt ist etwas schief gegangen und die Firmware läuft nicht
mehr richtig. Dann wirst Du auch den Bootloader nicht mehr aktiviert
bekommen.
wosnet schrieb:> Kannst bitte kurz beschrieben wo da was zu konfigurieren ist?
Mein Bootloader liegt vorne (bei Kinetis ist das 0x0) und startet nach
dem Reset. Wenn er 200ms lang erfolglos auf Kommunikation von meinem
Update-Tool gewartet hat dann biegt er die Vektortabelle um auf 0x800
(er ist kleiner als 2k) und macht einen simulierten Reset um in die
Anwendung zu springen indem er SP und PC von 0x800 und 0x804 lädt
(letzteres ist ein Sprung).
Wenn ich die (für 0x800 gelinkte) Anwendung mit gdb hochlade und debugge
dann springt er natürlich zuerst mal in den Bootloader (der muss
natürlich schon da sein) aber nach 200ms springt er dann in die zu
debuggende Anwendung und wenn ich dort irgendeinen Breakpoint setze dann
trifft er den auch und ich kann ganz normal debuggen.
> Da kann ich leider nirgends eine (andere)> Basisadresse einstellen für den Debugger
Das steht doch alles im .elf file drin.
Es war keine irgendwie geartete Konfiguration dazu nötig denn wozu auch?
Der gdb weiß aus dem .elf file automatisch ganz genau daß diese
Anwendung bei 0x800 anfängt, wohin er sie laden muss und an welche
Adressen welche Symbole gelinkt wurden, deshalb lädt er sie auch genau
dort hin und deshalb kann ich dort auch Breakpoints setzen, warum sollte
das nicht gehen?
Der gdb lädt es brav nach 0x800, genau so wie es im elf drin steht, dann
macht er einen Reset (bei 0x0), dann dreht der Controller eine
Ehrenrunde in meinem Bootloader und nach 200ms läuft er auf irgendeinen
Breakpoint in meiner Anwendung.
Das es geht, wenn die Anwendung bei 0x08000000 liegt und startet
verstehe ich. Angenommen ich möchte aber nur den Bootloader bei
0x08020000 debuggen, ohne dass bei 0x08000000 eine Anwendung liegt. Im
ELF steht dann ja auch diese Adresse als Startadresse drin,
funktionieren tuts bei mir trotzdem nur in den Fällen, in denen das
Programm bei 0x08000000 beginnt.
wosnet schrieb:> Das es geht, wenn die Anwendung bei 0x08000000 liegt und startet> verstehe ich. Angenommen ich möchte aber nur den Bootloader bei> 0x08020000 debuggen, ohne dass bei 0x08000000 eine Anwendung liegt.
Natürlich muss dann bei 0x0800000 irgendwas liegen das ihn nach einem
Reset in wohlgeordneter Weise nach 0x08020000 befördert wo man es dann
debuggen kann, und wenns auch nur ein untätiger Stub ist der nur den
Sprung macht.
Bei mir ist das der Bootloader. Ich flashe zuerst den Bootloader. Danach
kann ich sicher sein daß nach jedem Einschalten oder jedem Reset (zum
Beispiel beim Reset durch den Start im Debugger) irgendwann (nach 0.2s)
nach hinten gesprungen wird (wo dann der Debugger schon wartet wenn ich
das debuggen will was ich hinten hingeladen habe).
Peter schrieb:> Der Bootloader sollte möglichst nur aus der Anwendung aufgerufen werden> können.
Ich mach das in meinen IO-Link devices so, ich kann jederzeit per Befehl
in den Bootloader springen.
Ganz vorne im Flash liegt mein Bootloader, ein Stück weiter hinten liegt
beginnend an einer Seitengrenze die eigentliche Anwendung. Beim
Einschalten oder bei jedem Reset startet immer erst der Bootloader und
kurz danach lässt dieser in die Anwendung springen. Die Anwendung
kommuniziert dann für den Rest ihres Lebens per IO-Link-Protokoll mit
dem Master, so wie sich das für ein anständiges IO-Link Device gehört.
Jedoch gibt es im Protokoll ein Master-Kommando mit dem der Master (in
dem Fall mein PC-Update-Tool) dem Device per IO-Link sagen kann: "Mache
jetzt sofort einen Reset [und implizit: und springe somit logischerweise
wieder in den Bootloader]".
Wenn ich das Kommando empfange dann schalte ich alle Interrupts ab,
biege die Vektortabelle wieder zurück auf 0x00000000 (könnt ich mir
wahrscheinlich sogar sparen) und mache dann einen NVIC_SystemReset().
Danach hat mein PC-Tool etwa 200ms Zeit dem Bootloader Hallo zu sagen.
Wenn das unterbleibt springt er automatisch wieder in die Anwendung und
die Anwendung startet neu.