Forum: Mikrocontroller und Digitale Elektronik STM32 Bootloader nur aus der Anwendung


von Peter (Gast)


Lesenswert?

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

von wosnet (Gast)


Lesenswert?

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_t bootloader_init(void) {
2
3
  //magic RAM constant
4
  *((uint32_t *)0x2000FFF0) = 0xDEADBEEF;
5
  NVIC_SystemReset();
6
7
  return 1;
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!

von Bernd K. (prof7bit)


Lesenswert?

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.

von wosnet (Gast)


Lesenswert?

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!

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

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.

von Bernd K. (prof7bit)


Lesenswert?

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.

: Bearbeitet durch User
von wosnet (Gast)


Lesenswert?

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.

von Bernd K. (prof7bit)


Lesenswert?

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).

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

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.

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