Benutzerdefinierter Bootloader, der die Steuerung an den Anwendungscode in STM32 übergibt

Ich versuche zu verstehen, dass, wenn für die STM32F405-MCU ein benutzerdefinierter Bootloader auf der MCU verwendet wird, jedes der beiden Projekte für den benutzerdefinierten Bootloader und den Anwendungscode über eigene „startup.s“-Dateien verfügt.

Was ich verstehe ist, dass beide der beiden Binärdateien, dh der Bootloader und der Anwendungscode, beide an verschiedenen Stellen im Flash liegen.

Wenn nun der benutzerdefinierte Bootloader beendet wird und die Steuerung zurückgibt, sollte die Steuerung an den Startcode des Anwendungscodes übergeben werden. Aber ich weiß nicht, wie es wirklich passiert. Befinden sich die beiden Binärprogramme an zusammenhängenden Orten, sodass nach Abschluss des Bootloaders die nächste Anweisung die des Startcodes ist?

Oder befinden sie sich an verschiedenen Orten und irgendwie wird die Startadresse des Starts des Anwendungscodes als Sprungadresse am Ende der Bootloader-Binärdatei gespeichert?

Macht es einen Unterschied in der Art und Weise, wie es tatsächlich implementiert wird, wenn ich den Keil- oder GCC-Compiler verwende?

Obwohl Sie Antworten erhalten haben, die zum größten Teil richtig sind, werden viele wichtige Details beschönigt. Hier gibt es mehrere Fragen, die praktische Schwierigkeiten abdecken, auf die Sie wahrscheinlich stoßen werden, wenn Sie die Kontrolle von einem Programm an ein anderes übergeben, insbesondere im Hinblick auf die Chipkonfiguration ... In vielen Fällen ist es am besten, ein Flag zu setzen, die CPU zurückzusetzen und dann das Flag in der Startup-Assembly erkennen und zum Ziel verzweigen, bevor die Initialisierungsfunktionen des Bootloaders ausgeführt werden können, und den Chip erneut in einen anderen Zustand versetzen, als das Hauptprogramm erwartet.
Warum müssen wir die CPU zurücksetzen, um die Steuerung vom Bootloader zum Hauptprogramm zu übergeben?

Antworten (2)

Das kompilierte Abbild einer STM32-Anwendung beginnt mit einer Vektortabelle, in der das erste Wort den anfänglichen Stapelzeigerwert enthält, das nächste die Adresse der ersten Anweisung.

Der Bootloader muss natürlich die Adresse kennen, unter der die Anwendung geladen wird (wie könnte er sie sonst laden?), damit er sich die ersten beiden Wörter des gerade geflashten Images ansehen kann.

Bei der Festlegung der Startadresse der Anwendung müssen Sie das Layout der Flash-Sektoren berücksichtigen. Wenn Teile des Bootloaders und der Anwendung im selben Flash-Sektor landen, kann der Bootloader die App nicht neu flashen.

Geben Sie hier die Bildbeschreibung ein

Die Designer dieser MCU hatten genau zu diesem Zweck ein paar kürzere Sektoren zu Beginn des Flashs angeordnet. Vielleicht möchten Sie 32 KB für den Bootloader reservieren und die Anwendung 0x08008000beispielsweise unter platzieren, es liegt an Ihnen (und der Komplexität des Bootloaders).

Macht es einen Unterschied in der Art und Weise, wie es tatsächlich implementiert wird, wenn ich den Keil- oder GCC-Compiler verwende?

Der einzige Unterschied bestünde in den Linker-Konfigurationsdateien, die dem Linker mitteilen, wo er die Anwendung laden soll. Der GNU-Linker entnimmt es einem Linker-Skript ( *.ld), Keil nennt es Scatter-Datei . Sie haben den gleichen Zweck, aber eine unterschiedliche Syntax. Sie sollten auch das Linker-Skript/die Scatter-Datei des Bootloaders anpassen, um die verfügbare Flash-Menge zu begrenzen.

Compiler spielt keine Rolle, einer kann für den Bootloader und ein anderer für die Anwendung verwendet werden. Zuerst schreiben Sie den Bootloader und sehen, wie groß er ist. Dann runden Sie auf die nächste Flash-Sektorgrenze auf, da Sie keinen Sektor mit Bootloader-Code löschen möchten. Lassen Sie den Bootloader zum Start des ersten freien Sektors springen. Weisen Sie dann den Linker an, Code zu generieren, damit der Anwendungscode nicht bis zum Start des Flash geladen wird (Bootloader ist vorhanden), sondern zum Start des ersten freien Sektors nach dem Bootloader.

"Lassen Sie den Bootloader zum Start des ersten freien Sektors springen." Bedeutet das, dass wir beim Schreiben des 'Bootloaders' vorher wissen sollten, wohin wir springen müssen, nachdem der Bootloader beendet wurde? Also schreiben wir diese Sprungadresse als letzte Anweisung in den Bootloader-Code? Oder müssen wir die Sprungadresse außerhalb des Bootloader-Codes irgendwo anders in die anderen Dateien schreiben?
Wenn Sie es so machen, wie ich vorgeschlagen habe, ja, dann bestimmen Sie die Startadresse der Anwendung selbst und machen den Bootloader und die Anwendung auf ihre Adressen aufmerksam. Fühlen Sie sich frei, komplexere Schemata zu implementieren, wenn Sie möchten. Ja, der Bootloader springt aus seinem Codebereich heraus, um die Adresse zu erreichen, die Sie im Bootloader-Code angeben, und das ist die Adresse, an der der Anwendungscodebereich beginnt. Wenn diese Binärdateien auf die MCU geladen werden, gibt es kein Konzept von Dateien, sondern nur Adressen, zu denen Sie springen können. Entschuldigung, wenn ich nicht verstehe, was Sie fragen.
Im Wesentlichen wird hier vorgeschlagen, nicht zu einer festen Adresse zu springen, sondern an einer festen Stelle einen Zeiger auf die entsprechende Adresse zu setzen . Da die Hardware sowieso den Chip startet, ist es sehr sinnvoll, diesen Mechanismus auszuleihen. Und wenn Sie dies tun, können Sie den Vektorblock der Anwendung einfach an den Anfang des Flashs kopieren, wo der Bootloader hingehen würde, und die Anwendung auch ohne den Bootloader ausführen - was manchmal das Debuggen vereinfacht.
@ChrisStratton genau das muss passieren. Es ist die Standardmethode, wie der STM32 bootet, es lädt Stapelzeiger und Befehlszeiger vom Beginn des Flashs. Und nach der gleichen Logik, da die Anwendung verknüpft werden muss, um an einer späteren Adresse zu beginnen, muss der Bootloader diese Adresse kennen, wo er den Stapelzeiger und den Befehlszeiger der Anwendung abrufen und dann zu dieser Adresse springen kann. Die Anwendung ist also nur eine Standardanwendung, kann aber normal verknüpft werden, um das Debuggen ohne Bootloader zu ermöglichen, oder speziell mit einer späteren Adresse verknüpft werden.