Hallo zusammen, ich möchte gerne einen Custom Bootloader für einen STM32F4 schreiben, der die Möglichkeit bietet, nicht nur den Flash-Bereich der Applikationssoftware, sondern auch sich selbst upzudaten. Dabei ergibt sich folgende Fragestellung: Der Bootloader liegt am Beginn des Flash bei 0x08000000. Dort befindet sich auch der Reset-Vektor mit Stackpointer und Einsprungadresse. Wenn ich nun diesen Bereich updaten will, muss ich vom "alten" Bootloader ein Backup erstellen, so dass ich bei einem Power-Loss während der Reprogrammierung auf jeden Fall einen lauffähigen Bootloader habe. Nun hab ich im Manual des Controllers aber keine Option-Bytes o.ä gefunden, um den Controller die Vektor-Tabelle an einem anderen Ort im Flash suchen zu lassen. Lediglich über die Bootpins könnte man noch den RAM auswählen etc. Was ist aber, wenn ich mein Backup des Bootloaders im Flash-Sektor 1 (bei 0x08004000) anlege? Gibts eine Möglichkeit, den Core dort nach der Vektor Tabelle suchen zu lassen? Alternativ wäre, den Einsprung immer bei Sektor 0 (0x08000000) zu haben und dort nur ein "Minimal-Programm" zu haben, das entweder an die Original-Adresse des Bootloaders springt (Sektor 1, 0x08004000) oder ins Backup bei Sektor 2, 0x08008000. Das heißt ich würde 3 Sektoren benötigen, wobei Sektor 0 über die gesamte Projektlaufzeit nie überschrieben würde und dementsprechend schlank gehalten werden soll, um möglichst keine Bugs zu enthalten. Damit würde man leider einen Sektor quasi "verschenken". Gibts eine bessere Möglichkeit? Danke und Gruß
Wie häufig updatest Du Deinen Bootloader? Meist doch eher selten bis nie, man möchte sich aber für den Fall der Fälle die Option offenhalten. Daher folgender Vorschlag: Du updatest vom Bootloader aus nur das normale Hauptprogramm. Wenn Du einmal doch den Bootloader updaten willst, dann bringst Du ein spezielles Hauptprogramm raus, was nichts macht außer den Bootloader mit einer neuen Version zu überschreiben (natürlich nicht in der Schleife, sondern nur wenn der bestehende Bootloader ein alter ist). Das spielst Du über den alten Bootloader ein und startest es. Danach kannst Du dann mit dem neuen Bootloader wieder ein richtiges Hauptprogramm einspielen.
Hallo Gerd, danke für das Feedback. Ja in der Regel wird man den Bootloader eher selten updaten. Falls dort aber doch mal was im Argen liegt, wäre es schon gut, ein Update fahren zu können. Besonders wenn ein Zugang per JTAG nicht möglich ist. Deine Idee ist an sich nicht schlecht, jedoch sehe ich folgendes Problem: Wenn das "spezielle Hauptprogramm" den Bootloader updated, muss es den entsprechenden Sektor erst löschen und dann reprogrammieren. Im Fall eines Power-Loss zwischen Löschen und Reprogrammieren, wäre die originale Bootloader Section zerstört und damit auch die Vektor-Tabelle. Ich würde also nie mehr ins Hauptprogramm springen können, um das Bootloader-Update neu anzustoßen...oder hab ich da jetzt einen Denkfehler? Danke und Gruß
Jay K. schrieb: > Im Fall eines Power-Loss zwischen Löschen und Reprogrammieren, Ja dann ists leider hinüber... wie wahrscheinlich ist denn ein Power Loss bei Deiner Anwendung? Das schon genannte minimal Programm ist die einzige mir bekannte Lösung für sowas.
>Wenn das "spezielle Hauptprogramm" den Bootloader updated, muss es den >entsprechenden Sektor erst löschen und dann reprogrammieren. >Im Fall eines Power-Loss zwischen Löschen und Reprogrammieren, wäre die >originale Bootloader Section zerstört Das Problem hast du immer wenn du ein Bootloaderupdate machen willst. Mach halt zwei Bootloader rein. Einer davon darf halt NIE ein Update bekommen.
holger schrieb: >>Wenn das "spezielle Hauptprogramm" den Bootloader updated, muss es den >>entsprechenden Sektor erst löschen und dann reprogrammieren. >>Im Fall eines Power-Loss zwischen Löschen und Reprogrammieren, wäre die >>originale Bootloader Section zerstört > > Das Problem hast du immer wenn du ein Bootloaderupdate machen willst. > Mach halt zwei Bootloader rein. Einer davon darf halt NIE ein Update > bekommen. Das meinte ich ja mit "Minimalprogramm" an 0x08000000. Naja "immer" hat man das Problem nicht. Ich kenne es von anderen Controllern, dass man z.B Option-Bytes im Flash hat, die man mit der Adresse der Vektor-Tabelle beschreiben kann. Die Sequenz wäre dann: 1. Backup Bootloader von original Bereich A an Bereich B 2. Option-Byte für Vektor-Tabelle mit Adresse B beschreiben 3. Löschen des originalen Bootloader Bereichs A 4. Schreiben des neuen Bootloaders an Bereich A 5. Option-Byte für Vektor-Tabelle mit Adresse A beschreiben 6. Backup Bereich B löschen Scheinbar sind die ARM Cores hier etwas starr und bieten solch eine Funktion nicht. Dann bleibt wohl wirklich nur der Weg mit den drei Sektoren. Gruß
Du könntest natürlich versuchen den internen Bootloader der sowieso fest im Speicher liegt zu verwenden sofern Du die passenden Schnittstellen rausgeführt hast und irgendwie den BOOT0 Pin setzen kannst...
Das geht ganz einfach: * Der Bootloader kopiert sich beim Starten in den RAM, z.B. an Adresse 0x20000000. Da der ja üblicherweise nicht allzu groß sein sollte müsste das passen. Am Anfang steht ganz normal der ISR-Vektor. * Der Bootloader setzt das VTOR (Vector Table Offset Register) auf 0x20000000, sodass der ISR-Vektor von eben da auch gelesen wird. * Der Bootloader empfängt das Hauptprogramm+neuer Bootloader über die gewünschte Schnittstelle und überschreibt den Flash. Das geht sogar asynchron, weil der Bootloader ja aus dem RAM läuft und Flash-Schreibzugriffe nicht das Programm blockieren. * Der Bootloader setzt das VTOR wieder auf 0x08000000 und führt das Hauptprogramm aus, dessen Startadresse sich nach dem Flashen ja an 0x08000004 befinden sollte. Dazu muss der Bootloader nicht einmal am Anfang des Flashes stehen, sondern kann sich irgendwo im Hauptprogramm befinden. Man kann so auch den Bootloader einfach ins Hauptprogramm integrieren, und somit beides auf einmal Flashen. Man braucht keine Option Bytes o.ä. anzupassen, die ganze Magie macht das VTOR und die Tatsache, dass der ARM Code aus dem RAM ausführen kann.
Jay K. schrieb: > Wenn das "spezielle Hauptprogramm" den Bootloader updated, muss es den > entsprechenden Sektor erst löschen und dann reprogrammieren. > Im Fall eines Power-Loss zwischen Löschen und Reprogrammieren, wäre die > originale Bootloader Section zerstört und damit auch die Vektor-Tabelle. Das stimmt natürlich. Ein Bootloader ist meist von der Größe her überschaubar, vielleicht 2 oder 4KB. Der neue Bootloader ist als Datenblock im speziellen Update-Hauptprogramm vorhanden, liegt also schon fertig auf dem µC vor und muss nicht mehr mühsam und langsam seriell oder sonstwie empfangen werden. Im Grunde müssen die Daten nur vom einen Flash-Sektor in den anderen kopiert werden. Das geht in diesem Fall wirklich fix, ne Sache von vielleicht 1-2 Sekunden äußerstes Maximum, eher < 1 Sek. Du bist also in einem Zeitbereich bei dem Du die Stromversorgung noch ohne größeren Aufwand mit normalen Elkos puffern können solltest.
Gerd E. schrieb: > Du updatest vom Bootloader aus nur das normale Hauptprogramm. Das wird alles nichts. Grund: Wenn man nicht eine hardwaremäßige Umschaltung zwischen einem Bootlader außerhalb des gewöhnlichen Flash-Bereiches hat, dann muß der Bootlader eben in den gewöhnlichen Flash-Bereich. ABER: Er muß ja als allererster beim Booten drankommen, weswegen er zumindest beim Cortex die ersten zwei Vektoren der Vektortafel benötigt. Diese lassen sich aber nicht speziell schützen, sondern werden eben immer zusammen mit dem ersten Flashblock gelöscht. Das eigentliche Nutz-Programm benötigt aber alle anderen Vektoren, weswegen selbige bei jedem Flashen neu aufgesetzt werden müssen. Obendrein braucht der Bootlader in solchem Falle die Werte die das Nutzprogramm für die ersten 2 Vektoren vorsieht, weswegen er sich selbige woanders merken muß. Man könnte einen residenten Bootlader vorsehen, der niemals erneuert wird und der könnte dann alle Vektoren mit einem Assembler-Zwischenbrenner blind weiterreichen (sowas wie ADD PC,offset). Das verzögert die Interrupts etwas. Obendrein muß natürlich das Nutzprogramm komplett ab dem zweiten Flash-Sektor gelinkt sein. Nun, dafür ist etwas Assemblerkenntnis nötig, ebenso ein passender Startupcode - bloß wer von den hier Mitlesenden kann das? W.S.
W.S. schrieb: > ABER: Er muß ja als allererster > beim Booten drankommen, Nö, wer sagt das? W.S. schrieb: > weswegen er zumindest beim Cortex die ersten > zwei Vektoren der Vektortafel benötigt Nein. W.S. schrieb: > weswegen selbige bei jedem Flashen neu aufgesetzt > werden müssen. Nö. Man kann den ISR-Vektor des Hauptprogramms sonstwohin in den Flash packen und das VTOR entsprechend setzen. W.S. schrieb: > Man könnte einen residenten Bootlader vorsehen, der niemals erneuert > wird und der könnte dann alle Vektoren mit einem > Assembler-Zwischenbrenner blind weiterreichen Unnötig dank VTOR. W.S. schrieb: > Nun, dafür ist etwas Assemblerkenntnis nötig, ebenso ein passender > Startupcode - bloß wer von den hier Mitlesenden kann das? Du brauchst auch keine P*rnos, oder? Dir geht schon einer ab wenn du deinen eigenen Startupcode siehst, dein vermutlich einziges Assembler-Programm? Und natürlich geht das auch komplett in C, da brauchts auf dem ARM keinen Assembler für.
Also ganz so düster wie W.S. sie beschreibt,ist die Situation ja nicht. Bisschen Startup-Code schreiben incl Vektortabelle und das Ganze an die richtige Stelle linken ist kein Hexenwerk. Nach dem Sprung aus dem Bootloader in die Anwendungssoftware einfach das VTOR Register umbiegen, so wie Dr. Sommer schon sagte,dann klappts auch mit den Interrupts und Exceptions ? Weitaus interessanter wirds dann den Bootloader so zu compilieren/linken,dass er auch von der Backup Location bzw aus dem RAM laufen kann. @ Dr. Sommer: Das Umbiegrn des VTOR Registers geht zwar im laufenden Betrieb, aber im Fall eines Powerfails und erneutem Hochlauf des Controllers hat dieses Register 0 als Initialwert -> Der Chip wäre gebrickt bei der von dir vorgeschlagenen Programmiersequenz Gruß
Jay K. schrieb: > Der Chip wäre > gebrickt bei der von dir vorgeschlagenen Programmiersequenz In dieser Fassung, ja... Man könnte statt das Programm zu löschen das neue Programm inkl. Bootloader hinter das erste schreiben (braucht dann natürlich genug Flash Speicher), und ganz an den Anfang packt man einen Vor-Bootloader der herausfindet welches der beiden Programme aktueller (Versionsnummer) und intakt (CRC) ist.
Genau, so war auch mein Verständnis. Den "Vor-Bootloader" schreibt man an Sektor 0,dieser wird nie mehr gelöscht und evaluiert lediglich ob der reguläre Bootloader-Bereich oder der Backup Bereich gültig sind und springt dann den eigentlichen Bootlaoder an. Dort kann man sich dann austoben mit Flash-Routinen,Signaturprüfungen und weis der Geier was. Womit wir wieder bei der Ausgangssituation wären: Es werden für dieses Konstrukt drei Flash-Sektoren benötigt. Ein Mechanismus wie Option-Bytes oder Bootheader scheint es beim Stm32 nicht zu geben
Jay K. schrieb: > Ein Mechanismus wie Option-Bytes > oder Bootheader scheint es beim Stm32 nicht zu geben Richtig, wozu auch? Dank VTOR und RAM-Ausführung ist das unnötig.
Nun man würde sich dadurch einen Flash-Sektor sparen,da man den Vor-Bootloader für das Hochlaufen und die Verzweigung nicht mehr braucht. Der Bootloader könnte dann an Hand des PC selbst evaluieren ob er gerade von der Backup-Section läuft oder nicht.
Jay K. schrieb: > Nach dem Sprung aus dem Bootloader in die Anwendungssoftware einfach das > VTOR Register umbiegen, so wie Dr. Sommer schon sagte,dann klappts auch > mit den Interrupts und Exceptions ? Also da ist etwas Vorsicht geboten: soweit ich mich erinnere, haben nur Cortex M3, M4 und aufwärts sowas. Eventuell der M0+ aber m.W. nicht der M0. Sowas geht also wirklich nur bei ausgesuchten Typen. > Weitaus interessanter wirds dann den Bootloader so zu > compilieren/linken,dass er auch von der Backup Location bzw aus dem RAM > laufen kann. Na das ist kein Hexenwerk. Ich habe sowas seit Jahren für andere Architekturen (Fujitsu und NEC) am Laufen. Man linkt seinen Bootlader auf den RAM, gibt ihn als binär aus und macht dann irgendwie (skript o.ä.) daraus eine C-Quelle mit nem const byte lader[..] = {..... Den ganzen Block muß man dann bloß noch in den RAM hieven. Aber wenn ich lese, wie vehement hier einige von Startupcodes in C schwärmen und nicht kapieren, daß der Bootlader (präziser: der Start-Teil des Bootladers) immer als allererster nach dem Reset drankommen muß, dann hab ich Zweifel, ob aus solchem Unterfangen was werden kann. W.S.
W.S. schrieb: > Also da ist etwas Vorsicht geboten: soweit ich mich erinnere, haben nur > Cortex M3, M4 und aufwärts sowas. Richtig. Manche der ST Cortex-M0 haben dafür aber einen "Patch". Der OP hat aber einen Cortex-M4. W.S. schrieb: > Na das ist kein Hexenwerk. Ich habe sowas seit Jahren für andere > Architekturen (Fujitsu und NEC) am Laufen. Man linkt seinen Bootlader > auf den RAM, gibt ihn als binär aus und macht dann irgendwie (skript > o.ä.) daraus eine C-Quelle mit nem const byte lader[..] = {..... Viel zu kompliziert... Man linkt den Bootloader so dass er RAM-Adressen verwendet, packt ihn aber in den Flash, im Endeffekt genauso wie globale Variablen. Durch das geschickte Definieren von Linker-Symbolen braucht man den Code nur noch per memcpy in den RAM zu kopieren. W.S. schrieb: > Aber wenn ich lese, wie vehement hier einige von Startupcodes in C > schwärmen Vielleicht solltest du mal über den Tellerrand schauen. Es ist auf ARMv7M überhaupt kein Problem, den Startupcode in C zu schreiben. Ist im Endeffekt ja nur ein memcpy und evtl. ein paar Zuweisungen und Funktions-Aufrufe. Du bist derjenige, der immer von seinem eigenen (Assembler-)Startupcode schwärmt! W.S. schrieb: > und nicht kapieren, daß der Bootlader (präziser: der > Start-Teil des Bootladers) immer als allererster nach dem Reset > drankommen muß, Wieso denkst du dass das so muss? Ich habe einen Bootloader für STM32F4 und CAN geschrieben, der Teil des Hauptprogramms ist, nicht am Anfang des Flashes steht, und erst dann gestartet wird wenn eine entsprechende CAN-Nachricht ankommt. Ist überhaupt kein Problem. Das "muss" nur auf dem AVR so. W.S. schrieb: > dann hab ich Zweifel, ob aus solchem Unterfangen was > werden kann. Wenn du statt Rumlästern und Selbst-Beweihräuchern hilfreiche Antworten geben würdest, stünden die Chancen besser.
Dr. Sommer schrieb: > W.S. schrieb: >> und nicht kapieren, daß der Bootlader (präziser: der >> Start-Teil des Bootladers) immer als allererster nach dem Reset >> drankommen muß, > Wieso denkst du dass das so muss? Ich habe einen Bootloader für STM32F4 > und CAN geschrieben, der Teil des Hauptprogramms ist, nicht am Anfang > des Flashes steht, und erst dann gestartet wird wenn eine entsprechende > CAN-Nachricht ankommt. Ist überhaupt kein Problem. Das "muss" nur auf > dem AVR so. Ja, in deiner Begriffswelt ist es der Vor-Bootloader, der als erstes angesprungen wird. Auf jedenfall nicht die Applikation. Die ist ja ggf. gelöscht. Und bei einem Power Loss auch der Teil im RAM. Bei mir heißt das erste Programm Bootloader und der Teil, der das Update durchführt Updater. Ich finde es etwas irreführend letzteres mit "Boot.." zu bezeichnen. Scheint aber nicht nur mir so zu gehen. Und warum benötigt ein Bootloader ein Update? Ein Teil der Gründe sollte genausogut für den Vor-Bootloader zutreffen. Und man ist wieder beim ursprünglichen Problem.
Steffen R. schrieb: > Und warum benötigt ein Bootloader ein Update? Ein Teil der Gründe sollte > genausogut für den Vor-Bootloader zutreffen. Und man ist wieder beim > ursprünglichen Problem. Naja das seh ich nicht so. Die Aufteilung in Vor-Bootloader und Bootloader (oder Updater) macht schon Sinn: Man kann den Vor-Bootloader sehr schlank halten. Im Extremfall überprüft der nur, in welchem Block ein gültiger Updater liegt und springt diesen dann an. Im Updater kann man dann sämtliche Schweinerein treiben und es ist nicht so schlimm, wenn man mal nen Bock schießt und nen kritischen Bug einbaut. Besonders zum tragen kommt das, wenn der JTAG Port deaktiviert wird und Updates generell ausschließlich über den Bootloader möglich sind
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.