BootLoader ist für viele Menschen ein geläufiger Begriff und wird sogar häufig verwendet. Wir benötigen ihn beispielsweise, wenn wir das System online aktualisieren und das Programm im externen Speicher ausführen. In diesem Beitrag stellen wir Ihnen vor, wie Sie ein BootLoader-Programm für MCUs der STM32-Serie entwerfen.
Grundprinzip des Bootloaders
Da wir ein Bootloader-Programm für STM32 implementieren möchten, müssen wir zunächst die Grundprinzipien des Bootloader-Programms verstehen.
Wie wir wissen, muss das Bootloader-Programm die Systemsteuerung übernehmen, was die Grundfunktion des Bootloader-Programms ist. Bei den MCUs der STM32-Serie wird das Programm nach dem Systemstart von der Startadresse des internen Flash-Speichers aus ausgeführt. Anschließend wird das Anwendungsprogramm aufgerufen und gemäß der festgelegten Reihenfolge ausgeführt. Zu diesem Zeitpunkt sind der Bootloader und das Anwendungsprogramm integriert, wie in der Abbildung dargestellt:

Manchmal möchten wir jedoch nicht, dass die Anwendung direkt ausgeführt wird, beispielsweise wenn wir IAP für das System implementieren möchten, oder wenn wir nicht möchten, dass die Anwendung in unserem internen Flash-Speicher ausgeführt wird, oder wenn die Anwendung zwar im internen Flash-Speicher ausgeführt wird, wir aber möchten, dass die Anwendung von der von uns angegebenen internen Flash-Adresse aus ausgeführt wird, und so weiter. In diesen Fällen benötigen wir ein separates BootLoader-Programm. Das System startet zunächst das BootLoader-Programm und wechselt nach der Vorbereitung des Systems zur Ausführung des Anwendungsprogramms, wie in der Abbildung dargestellt:

Auf dem obigen Bild speichern wir die Anwendung tatsächlich an dem angegebenen Speicherort des internen Flash-Speichers, was natürlich dazu dient, einige unserer Anforderungen zu erfüllen, wie z. B. System-IAP. Natürlich können wir das Anwendungsprogramm auch im externen Flash-Speicher speichern, und dann springt das BootLoader-Programm zum externen Flash-Speicher, um das Anwendungsprogramm auszuführen, aber die Voraussetzung dafür ist, dass der externe Flash-Speicher das Ausführungsprogramm enthält. Der konkrete Ablauf ist wie folgt:

Natürlich ist dies nur ein Beispiel, und wir müssen lediglich die Adresse für verschiedene Speicher ändern. Welche Funktionen im BootLoader-Programm implementiert werden sollen, hängt von der Verwendung ab. Grundsätzlich können wir jede beliebige Funktion hinzufügen, z. B. Hardwareerkennung, Systemaktualisierung usw.
Bootloader-Design für STM32
Blitzplanung
Wir verwenden STM32F407IGT6 als Ziel-MCU, die über 1 MB Flash und 192 KB SRAM verfügt. Wir teilen den Flash-Speicher in zwei Teile auf: einen Boot-Programmbereich (0x0800 0000 – 0x0800 3FFF) mit einer Größe von 16 KB und einen Anwendungsprogrammbereich (0x0800 4000 – 0x080F FFFF). Die konkrete Aufteilung sieht wie folgt aus:

Wir lassen das BootLoader-Programm 16 KB Speicherplatz belegen. Es kann jedoch den gesamten Flash-Speicherplatz nutzen.
Bootloader-Struktur
Betrachten wir die Struktur des BootLoader-Programms. Der Hauptzweck unseres Entwurfs des BootLoader-Programms ist die Aktualisierung des Anwendungsprogramms. Was sind also die wichtigsten Funktionen, die im BootLoader-Programm implementiert werden müssen? Es gibt mehrere Aspekte, die berücksichtigt werden müssen. Zum einen die Grundkonfiguration, wie z. B. die Uhr usw., die wir im Hauptprogramm implementieren; zum anderen die Bedienung des Flash-Speichers, den wir beim Aktualisieren des Anwendungsprogramms auf jeden Fall überprüfen und beschreiben werden; zum dritten das Sprungsteuerungsprogramm, da wir am Ende das Anwendungsprogramm ausführen müssen und die Sprungfunktion unerlässlich ist. Natürlich kann es je nach Bedarf auch andere Anforderungen geben. Konkret wie in der folgenden Abbildung dargestellt:

In der obigen Abbildung haben wir zusätzlich zu den drei grundlegenden Implementierungen der Signatur auch die Funktion zum Abrufen von IAP-Dateien hinzugefügt. Dieser Teil der Funktion ist ebenfalls erforderlich, kann jedoch in verschiedenen Modi große Unterschiede aufweisen. Denn die Art und Weise, wie Dateien abgerufen werden, kann verschiedene Kommunikationsarten umfassen, wie z. B. Ethernet-Port, serielle Schnittstelle usw. Es kann sich auch um verschiedene Speichertypen handeln, wie z. B. SD-Karte, U-Disk usw. Daher ist diese Funktion zwar unverzichtbar, die Implementierungsmethode jedoch sehr flexibel. In der nachfolgenden Implementierung werden wir spezifische Fragen im Detail analysieren.
BootLoader-Implementierung
Nun haben wir die Aufteilung von Flash festgelegt und verstehen den grundlegenden Arbeitsablauf von BootLoader. Als Nächstes werde ich erläutern, wie ein BootLoader-Programm implementiert wird.
BootLoader-Kodierung
Wir wissen, dass der Chip beim Einschalten zunächst das BootLoader-Programm ausführt und dann zum Anwendungsprogrammbereich springt, um das Anwendungsprogramm auszuführen. Daher prüfen wir beim Schreiben des BootLoader-Programms zunächst, ob das System IAP-Anforderungen hat. Wenn eine IAP-Anforderung vorliegt, wechselt es in den IAP-Modus. Nach Abschluss springt es zum Anwendungsprogramm, um dieses auszuführen. Wenn keine IAP-Anforderung vorliegt, springt es direkt zum Anwendungsprogramm, um dieses auszuführen. Der konkrete Ablauf ist wie folgt:

Was die Verarbeitung von IAP betrifft, so gibt es je nach Situation unterschiedliche Verarbeitungsmethoden. Hier betrachten wir hauptsächlich das Sprungsteuerungsprogramm. Definieren Sie zunächst die erste Adresse der Anwendung und deklarieren Sie einen Funktionszeigertyp. Details wie folgt:
#define ApplicationAddress 0x08004000 //Application first address definition
typedef void (*pFunction)(void); //Define the jump function pointer type
Manche fragen sich vielleicht, was einen solchen Funktionszeigertyp definiert, da wir schließlich zur Funktion Reset_Handler springen und daher einen Funktionszeiger benötigen, der auf diese Funktion verweisen kann. Als Nächstes können wir das Sprungprogramm implementieren.
/*jump to application processing function*/
static void JumpToApplication(void)
{
uint32_tStackAddr; //Application stack address
uint32_tResetVector; //The address of the application interrupt vector table
pFunctionJumpToApp; //Define the jump function pointer
__set_PRIMASK(1); //Turn off global interrupt
StackAddr= *(__IO uint32_t*)ApplicationAddress; //0x08004000;
ResetVector = *(__IO uint32_t*)(ApplicationAddress + 4); //0x08004004;
if((StackAddr&0x2FFC0000)==0x20000000) //Check whether the stack top address is legal.
{
__set_MSP(StackAddr); //Initialize the application stack pointer
JumpToApp = (pFunction)ResetVector;
JumpToApp();
}
}
App-Verarbeitung
Nachdem wir die Codierung des BootLoaders realisiert haben, müssen wir die App entsprechend modifizieren, wenn wir zur App springen wollen, damit sie korrekt ausgeführt wird. Es gibt zwei wichtige Änderungen. Wenn es sich bei der Anwendung um ein Bare-Metal-Programm handelt, müssen wir den globalen Midrange aktivieren, bevor wir die Uhr konfigurieren.
/*Enable global interrupt, closed in BootLoader*/
__set_PRIMASK(0);
Gleichzeitig muss auch die Offset-Adresse der Mid-End-Vektortabelle geändert werden. Bei dem von uns verwendeten STM32F07 kann dies direkt in der Datei system_stm32f4xx.c geändert werden.
#define VECT_TAB_OFFSET 0x4000 /*!< Vector Table base offsetfield.
Anschließend müssen wir auch die erforderlichen Änderungen in der Entwicklungsumgebung vornehmen, wobei wir das von uns verwendete IAR EWARM V8.4 als Beispiel nehmen. Ändern Sie die Einstellungen der Interrupt-Vektortabelle und des Flash-Speicherbereichs in der icf-Datei. Die Details lauten wie folgt:


Nach Abschluss der oben genannten Konfiguration können wir das Anwendungsprogramm und das BootLoader-Programm herunterladen, um den korrekten Sprung zu realisieren.
Zusammenfassung
In diesem Artikel haben wir gerade ein einfaches BootLoader-Programm implementiert. Nach dem Herunterladen auf die Ziel-MCU wird der Sprung realisiert, und das Anwendungsprogramm läuft ebenfalls normal, was zeigt, dass unser Entwurf korrekt ist und auf dieser Grundlage verschiedene Funktionen hinzugefügt werden können, um die entsprechende IAP-Anwendung zu realisieren.
Es ist zu beachten, dass wir den globalen Interrupt im BootLoader-Programm deaktiviert haben. Denken Sie daran, den globalen Interrupt zu aktivieren, bevor die Anwendung die Systemuhr initialisiert, da sonst SystemTick nicht funktioniert und ein Hardwarefehler (Hardfault) auftritt. Wenn die App jedoch auf dem RTOS läuft, kann es falsch sein, den Interrupt zu aktivieren, was beachtet werden muss.




