Forum: Mikrocontroller und Digitale Elektronik Eigener Bootloader stm32f103


von Stefan M. (mannitb303)


Lesenswert?

Hallo an alle,
ich habe folgendes Problem. Ich habe einen funktionierenden 
MIDI-Controller auf Basis eines AtMega2560 gebaut. Im Netz habe ich 
einen Bootloader gefunden der ein Update der Firmware über eine SD-Karte 
erlaubt (https://github.com/FleetProbe/MicroBridge-Arduino-ATMega2560). 
Das habe ich benutzt um im Menü des Controllers ein Update zu starten 
(also User gesteuert).
Nun bin ich mit meinem MIDI Controller auf einen STM32F103 umgestiegen 
und es funktioniert alles wie beim AtMega2560. Ich finde sehr viel über 
Bootloader für den STM aber ich kapiers einfach nicht.
Ich bräuchte einen Bootloader der von der Mechanik her wie der für den 
AtMega2560 ist.
1
The bootloader looks for byte in eeprom at address 0x1FF:
2
-if it is set to 0xF0 bootloader will look for a bin file on the sdcard named 
3
 firmware.bin and use it to flash the firmware then reset the byte to 0xFF so it
4
 does this only once
5
6
-otherwise no action is taken and bootloader works as a arduino bootloader except
7
 some of the debugging functions are missing
Leider finde ich nicht wirklich etwas verständliches im Netz. Ich habe 
einige Custom Bootloader gefunden, weiss aber nicht wirklich wie ich die 
so modifizieren kann das es so funktioniert wie ich das gerne hätte.
Kann mir jemand ein paar Tipps zu Custom Bootloadern geben.

Vielen Dank schon mal.

: Bearbeitet durch Moderator
von Johannes (zuberjo)


Lesenswert?

Beim STM32 ist ein eigener Bootloader nichts anderes als eine Firmware. 
Der Factory Bootloader von STM kann nicht geändert werden und startet 
immer zuerst. Die Jump Adresse für den Start der Firmware ist daher 
immer 0x0800000000. Den eigenen Bootloader kann man daher dann wie eine 
ganz normale Firmware aufspielen. Diese kann dann schauen ob eine 
valide, zweite Firmware auf einer SD Karte liegt, diese in den Flash 
kopieren, zb Address ab 0x082000000 und dann diese von dort ausführen. 
Damit das funktioniert muss die zweite Firmware mit einem Offset 
erstellt und kompiliert werden. Aber dazu gibt es jede Menge Anleitungen 
im Netz

von N. M. (mani)


Lesenswert?

Stefan M. schrieb:
> The bootloader looks for byte in eeprom at address 0x1FF:
> -if it is set to 0xF0 bootloader will look for a bin file

Den Mechanismus würde ich mir komplett sparen z.B. indem du das File 
nach dem Update löschst/umbenennst oder einen nicht initialisieren RAM 
Bereich nutzt (in vielen Bootlaodern nehmen sie ein Register in der 
RTC). Der STM hat kein EEPROM an Board und man müsste dann deshalb 
unnötig im Flash rum schreiben.

Allgemein: Bei MIDI bist du doch 100 pro über USB verbunden. Warum dann 
überhaupt der Umweg über SD? Auf GitHub findest du zig fertige USB 
Bootloader. Teilweise sogar mit Massenspeicher und UF2 File. 
Komfortabler geht's ja nicht mehr für den Kunden.

von Flunder (flunder)


Lesenswert?

Bootloader sind auch ein Stück Software. Allerdings derart dicht an der 
Hardware unterwegs, dass der Umug von einer µC - Architektur auf eine 
andere auf ein so gut wie komplettes Neuschreiben heraus läuft.

Es gibt STM32 mit einem eingebauten ROM, in dem ein Bootloader steht. Da 
wird die neue Software allerdings über ein ganz eigenes Protokoll auf 
USB oder Seriellport (RS232 3,3V)  erwartet. Immerhin, schauen die 
STM32, die ich bisher benutzt habe, am Ende des Reset auf I/O-Pins und 
beginnen die Abarbeitung der Firmware an unterschiedlichen Adressen, je 
nach Pegel. Eine davon zeigt auf den Programmstart im ROM.

Wenn Du die SD-Karte zu nichts anderes benutzt kannst Du natürlich das 
Card-Detect vom Kartenslot dafür nutzen.

Andererseits kannst Du auch immer zuerst Deinen Bootloader starten. Nach 
einer SD-Karte suchen und dann auf der SD-Karte nach einer Datei mit 
neuer Applikation. Dann nur noch Prüfsumme und Versionsnummer der 
Applikation im Flash checken und wenn die fehlerhaft oder älter als die 
auf der Karte ist updaten. Das dauert halt. Ich habe ja auch keine 
Ahnung, ob das Gerät zu spontanen Jam-Sessions benutzt werden soll oder 
ob die Röhrenendstufe sowieso noch ein wenig zum Vorheizen braucht.

Es soll nämlich auch unterbrochene oder fehlerhafte Updateversuche 
geben, die dann dazu führen, dass das Starten der Applikation das Gerät 
zuverlässig ins Land der Träume schickt. Wenn man davor nicht zum 
Aufspielen neuer Software abzweigen kann, hat man einen Briefbeschwerer 
mehr, bis jemand, der sich auskennt, per SWD oder JTAG was neues 
einspielt.

Natürlich kann man zusätzlich einen Einsprungpunkt im Bootloader 
einbauen, so dass die Applikation, wenn sie merkt, dass da ein Benutzer 
mit neuer Firmware um die Kurve kommt, diese einspielen lassen kann.

Ob es da vielleicht in diesem Universum schon was fertiges gibt, weiss 
ich nicht.

von Flunder (flunder)


Lesenswert?

N. M. schrieb:
> Allgemein: Bei MIDI bist du doch 100 pro über USB verbunden. Warum dann
MIDI ist eher ein RS232 Signal. Wobei allerdings die logischen Pegel als 
Strom codiert sind, per Optokoppler potentialfrei gemacht werden und 
eine eher exotische Baudrate haben.
Und ja : es gibt unter dem Stichwort SysEx bestimmt auch die 
Möglichkeit, Firmwareupdates über MIDI zu verschieben.

von N. M. (mani)


Lesenswert?

Flunder schrieb:
> Allerdings derart dicht an der Hardware unterwegs, dass der Umug von
> einer µC - Architektur auf eine andere auf ein so gut wie komplettes
> Neuschreiben heraus läuft.

Du sagst ja selbst, es ist ein Stück Software wie jede andere. Warum 
sollte das dann so sein? Musst du halt richtig abstrahieren und bei 
einem neuen Device die HAL austauschen.

Flunder schrieb:
> Es gibt STM32 mit einem eingebauten ROM, in dem ein Bootloader steht. Da
> wird die neue Software allerdings über ein ganz eigenes Protokoll auf
> USB oder Seriellport (RS232 3,3V)  erwartet.

Beim F103 aber nicht über USB. UART geht, bräuchte man aber einen 
externen USB/Seriell Wandler. Oder eben einen eigenen Bootloader.

Flunder schrieb:
> Das dauert halt.

Der Check geht verdammt schnell wenn man die interne CRC Engine mit dem 
DMA füttert. Das Flashen dann wenige Sekunden. Auf jeden Fall nicht so 
lange um eine Röhrenendstufe vorheizen zu können 😄

Flunder schrieb:
> Es soll nämlich auch unterbrochene oder fehlerhafte Updateversuche
> geben, die dann dazu führen, dass das Starten der Applikation das Gerät
> zuverlässig ins Land der Träume schickt.

Einfach im Bootloader die im Flash stehende Applikation checken bevor 
man sie anspringt. Wenn sie kaputt ist kann man sowieso nichts mit 
anfangen und man bleibt im Bootloader für ein Update. Dann kannst du 
jederzeit ein neues Update einspielen.

Flunder schrieb:
> MIDI ist eher ein RS232 Signal.

Heute auch noch?
Die MIDI-Controler die ich im Internet finde haben alle USB. Aber 
tatsächlich kenne ich mich da nicht sonderlich aus.

Flunder schrieb:
> gibt unter dem Stichwort SysEx bestimmt auch die Möglichkeit,
> Firmwareupdates über MIDI zu verschieben.

Der Gedanke war eher der, dass der Bootloader bei einem Update Request 
über USB z.B. einen Massenspeicher o.ä. zur Verfügung stellt über den 
ein neues Update geladen werden kann.
Die eigentliche Applikation nutz den gleichen USB für MIDI.

von Stefan M. (mannitb303)


Lesenswert?

Hallo,

danke für die vielen Antworten.

Ja, mein MIDI-Controller hat einen 5pol-Din sowie auch USB. Allerdings 
habe ich noch einen Atmega 90USB162 für die MIDI Komunikation auf meinem 
Board, da ich auf diesem die LUFA USB Midi Firmware darauf habe.

Wenn ich Johannes richtig verstanden habe dann könnte ich ja den STm 
Bootloader darauf lassen, dann einen eigenen "Bootloader" ab der 
normalen Startadresse flashen. Der eigenen pseudo Bootloader schaut dann 
einfach ob eine Update Datei auf der SD Karte ist und flashed diese ab 
Adresse xxxx. Falls keine Update Datei vorhanden ist springt mein pseudo 
Bootloader einfach an die Adresse xxxx.

Das wäre ja eigentlich ganz cool da könnte ich ja mein Display auch zur 
Anzeige, Abfrage ob man wirkich updaten möchte, etc. nutzen.

Wird das dann getrennt geflashed also eigener Bootloader und dann 
eigentliche Firmware oder sind beide Programmcodes in einer Datei mit 
Adresszuweisungen?

Vielen Dank

von Frank O. (fop)


Lesenswert?

Stefan M. schrieb:
> Wird das dann getrennt geflashed also eigener Bootloader und dann
> eigentliche Firmware oder sind beide Programmcodes in einer Datei mit
> Adresszuweisungen?

Ich würde es der Übersicht halber in 2 getrennten Projekten entwickeln. 
Beide mit unterschiedlichen Linker-Scripts, so dass der Code woanders im 
Flashspeicher landet.

Für den Fall, dass man mehrere davon aufbauen will, würde ich die .hex 
Dateien der beiden Projekte vereinen und die Mikrocontroller damit schon 
mal befüllen. So dass die Applikation nicht erst im 2. Schritt 
aufgespielt werden muss.

Bedenke auch, dass bei jedem hochfahren mit Update Datei auf gesteckter 
SD-Karte, der Bootloader wieder ansetzt, den Flash des Mikrocontrollers 
zu überschreiben. Daher wohl der Vorschlag mit dem Vergleich der 
Versionsnummern.

von Frank O. (fop)


Lesenswert?

N. M. schrieb:
> Du sagst ja selbst, es ist ein Stück Software wie jede andere. Warum
> sollte das dann so sein? Musst du halt richtig abstrahieren und bei
> einem neuen Device die HAL austauschen.

Nunja, das Verhältnis Applikation zu HAL ist bei einem Bootloader halt 
ein anderes als bei einer Adressverwaltung. Sprich der wiederverwertbare 
Teil des Bootloaders ist das, was im 1. Werner Film mit den Worten "sehr 
übersichtlich" beschrieben wurde.

von Harry L. (mysth)


Lesenswert?

Nur mal so als Anregung:

Bei Objektiven von Viltrox (mit USB-Port) läuft das so:

Wenn man die anstöpselt, melden die sich wie ein USB-Speicher-Stick. 
(egal welches Betriebssystem)
Auf diesem Speicher findet man eine Textdatei mit Informationen zur 
aktuellen Hardware- und Firmware-Version.

Man kopiert dann das neue Firmware-File (eine simple bin-Datei) auf 
diesen Speicher, und sobald der Schreibvorgang abgeschlossen ist, 
beginnt der Update Vorgang, die Textdatei wird aktualisiert, und die 
.bin-Datei wird im Anschluss gelöscht.
Natürlich wird vorher geprüft, ob das Update zur Hardware passt.

Ich hab einige Objektive dieses Herstellers, hab da schon Zig Updates 
eingespielt, und Probleme gab es nie.

: Bearbeitet durch User
von Stefan M. (mannitb303)


Lesenswert?

Frank O. schrieb:
> Ich würde es der Übersicht halber in 2 getrennten Projekten entwickeln.
> Beide mit unterschiedlichen Linker-Scripts, so dass der Code woanders im
> Flashspeicher landet.

Aktuell nutze ich Platformio, da ich es sehr übersichtlich finde. Soweit 
ich weiss kann man da auch eigene Linker-Scripts benutzen.

Frank O. schrieb:
> Für den Fall, dass man mehrere davon aufbauen will, würde ich die .hex
> Dateien der beiden Projekte vereinen und die Mikrocontroller damit schon
> mal befüllen. So dass die Applikation nicht erst im 2. Schritt
> aufgespielt werden muss.

Ziel ist es mehrere davon zu bauen und zu vermarkten.

Frank O. schrieb:
> Bedenke auch, dass bei jedem hochfahren mit Update Datei auf gesteckter
> SD-Karte, der Bootloader wieder ansetzt, den Flash des Mikrocontrollers
> zu überschreiben. Daher wohl der Vorschlag mit dem Vergleich der
> Versionsnummern.
Das könnte man ja lösen indem die Update Datei nach dem flashen auf der 
SD-Karte gelöscht wird.

Ich muss ja dan in meinen eigenen Bootloader auch die SD-Library und die 
OLEDLibrary mit einbinden um auf die SD Karte zugreifen zu können und 
den fortschritt bzw. Fehler auf dem Display anzeigen zu lassen.

Wenn z.B. meine Firmware ab Adresse 0x082000000 liegt, kopiert mein 
Bootloader die Updatedatei von der SD Karte dann einfach direkt an diese 
Adresse oder erst woanders hin und dann an die eigentliche Adresse?

von Harry L. (mysth)


Lesenswert?

Stefan M. schrieb:
> Ich muss ja dan in meinen eigenen Bootloader auch die SD-Library und die
> OLEDLibrary mit einbinden um auf die SD Karte zugreifen zu können und
> den fortschritt bzw. Fehler auf dem Display anzeigen zu lassen.

Wenn ich sowas lese, enstehen bei mir Zweifel, ob du in der Lage bist, 
einen Bootloader zu schreiben, und ob es nicht eventuell sinnvoller 
wäre, sich erstmal mit der Architektur der STM32-Familie intensiver zu 
beschäftigen.

Stefan M. schrieb:
> Wenn z.B. meine Firmware ab Adresse 0x082000000 liegt, kopiert mein
> Bootloader die Updatedatei von der SD Karte dann einfach direkt an diese
> Adresse oder erst woanders hin und dann an die eigentliche Adresse?

Das bestätigt meine obige Aussage.
Hättest du auch nur eine ungefähre Vorstellung davon, wie ein Bootloader 
funktioniert und ein STM32 aufgebaut ist, hättest du diese Frage nicht 
stellen müssen.


Mein Rat: lern erstmal die Basics.

Bootloader sind bereits mindestens Level 2.

Stefan M. schrieb:
> Ziel ist es mehrere davon zu bauen und zu vermarkten.

Vergiss es!

Du bist ein "Heimwerker" der von einem "Produkt" meilenweit entfernt 
ist.
Wenn du ganz, ganz fleißig bisst, und am Ball bleibst, können wir in nem 
Jahr vielleicht nochmal drüber reden.

: Bearbeitet durch User
von Johannes (zuberjo)


Lesenswert?

Man kann für die Versionskontrolle auch einen Header in die Binary 
Implementieren. Mache ich auch bei jeder Firmware so, zumindest bei den 
kommerziellen. Dafür eine Structure anlegen, diese mit einer dedizierten 
Adresse versehen, bei STM32 glaube ich 0x400 Offset von der 
Startadresse, da der erste Bereich für die Vector-Tables reserviert ist. 
Müsste man im Datwnblatt nachlesen um sicherzugehen. Diesen Header kann 
man jedenfalls easy abfragen, bevor man die file in den Flash schreibt.

von Flunder (flunder)


Lesenswert?

Harry L. schrieb:
> Mein Rat: lern erstmal die Basics.
>
> Bootloader sind bereits mindestens Level 2.

Jeder hat mal angefangen. Ok, die meisten klein.

von Flunder (flunder)


Lesenswert?

Stefan M. schrieb:
> Das könnte man ja lösen indem die Update Datei nach dem flashen auf der
> SD-Karte gelöscht wird.

Dann muss jemand, der mehrere updaten will, die Datei immer wieder auf 
die SD-Karte kopieren. Funktioniert aber erstmal...

von Flunder (flunder)


Lesenswert?

Stefan M. schrieb:
> Aktuell nutze ich Platformio, da ich es sehr übersichtlich finde. Soweit

Also mehr so Arduino - naja damit bleibt Dir zumindest die Klippe 
erspart, dass CubeMX nicht lauffähigen Code für SD-Karten-Zugriffe 
erzeugt.

von Flunder (flunder)


Lesenswert?

Stefan M. schrieb:
> Wenn z.B. meine Firmware ab Adresse 0x082000000 liegt, kopiert mein
> Bootloader die Updatedatei von der SD Karte dann einfach direkt an diese
> Adresse oder erst woanders hin und dann an die eigentliche Adresse?

Genau deshalb sollen Bootloader und Applikation an verschiedenen 
Adressen liegen. Du kannst die Applikation direkt platt machen, ohne 
erst hierhin und dann dorthin zu kopieren. Schlimmstenfalls hast Du nur 
ein Flash, das auch nur entweder oder beherrscht. Das bedeutet, 
während Du neu flashst, kann kein Code aus dem Flash ausgeführt werden. 
Dann muss die (kurze) Überschreibroutine ins RAM kopiert werden und von 
dort ausgeführt werden (mit gesperrten Interrupts). Aber in so Fragen 
sind Datenblatt und Referenzmanual Deine Freunde.

: Bearbeitet durch User
von Flunder (flunder)


Lesenswert?

A propos Versionen und kontrollieren : Was Du Dir angewöhnen solltest, 
ist ein Vesionsverwaltung für Deine Quellcodes zu verwenden. git ist da 
momentan ganz hipp, aber auch Subversion sollte für Dich mehr als 
ausreichend sein. Mit Tortoise(git|svn) gibt es nette Einbindungen in 
den Explorer. Visual Studio Code hat dafür auch Extensions.
Das hilft extrem bei der Frage, seit wann und warum geht das nicht mehr.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Stefan M. schrieb:
> Ja, mein MIDI-Controller hat einen 5pol-Din sowie auch USB. Allerdings
> habe ich noch einen Atmega 90USB162 für die MIDI Komunikation auf meinem
> Board, da ich auf diesem die LUFA USB Midi Firmware darauf habe.

Wenn du den ATmega weglässt, und statt des STM32F103, der ja der 
allererste Ur-STM32 ist, einen aktuelleren STM32 nutzt (z.B. STM32G4), 
hat dieser einen fest integrierten USB-Bootloader. Dann kannst du den 
wunderbar komfortabel über die STM32CubeProgrammer Software über USB 
programmieren, ohne dass du irgendwas auf der Firmware-Seite dafür tun 
müsstest. Dann kannst du das USB-MIDI Protokoll auch direkt auf diesem 
Controller implementieren und hast dann alles in einem und brauchst gar 
kein Update per SD-Karte. Das kann man sogar wenig technisch versierten 
Kunden zumuten, die brauchen halt einen PC dafür. Hardwareseitig sollte 
man aber 2 Buttons haben - für Reset und BOOT0 Pin, letzterer löst das 
Update aus.

Siehe AN2602:
https://www.st.com/resource/en/application_note/an2606-introduction-to-system-memory-boot-mode-on-stm32-mcus-stmicroelectronics.pdf

Flunder schrieb:
> Das bedeutet,
> während Du neu flashst, kann kein Code aus dem Flash ausgeführt werden.

Doch, die CPU bleibt einfach stehen während des Flash-Vorgangs, sofern 
man also während des Flashens nicht noch etwas parallel steuern muss, 
kann der Flasher-Code schon selbst im Flash stehen.

Stefan M. schrieb:
> Ich muss ja dan in meinen eigenen Bootloader auch die SD-Library und die
> OLEDLibrary mit einbinden um auf die SD Karte zugreifen zu können und
> den fortschritt bzw. Fehler auf dem Display anzeigen zu lassen.

Das würde bedeuten der Bootloader wird riesig, und dann bleibt nicht 
mehr viel Platz für die Haupt-Anwendung. Die Hauptanwendung müsste dann 
entweder den Code für die SD-Karte und das Display nochmals mitbringen 
(verschwendet viel Platz) oder den Code des Bootloaders dafür aufrufen 
(möglich aber kompliziert).

Außerdem musst du entscheiden ob der Bootloader sich selbst 
überschreiben können soll - wenn ja, bedeutet ein fehlgeschlagenes 
Update dass gar nichts mehr geht, wenn nein kann der Bootloader nie 
aktualisiert werden. Im zweiten Fall sollte der Bootloader daher so 
klein wie möglich sein, weil man es später nicht mehr optimieren kann.

Außerdem ist dann der Flash-Verbrauch des Bootloaders immer 
"aufgerundet" auf die Page-Größe des Flashs, also 1KB / 2KB je nachdem 
welcher STM32F103 es genau ist. Selbst wenn der Bootloader nur 1.5 Pages 
ist, kannst du die letzte halbe Page nicht für die Anwendung nutzen, 
denn um diese zu aktualisieren müsstest du die ganze Page löschen, 
sodass dann der Bootloader halb mitgelöscht würde.

Als Referenz: Ein "vollwertiger" STM32-Bootloader der aus einem 
seriellen NOR-Flash liest lässt sich in exakt 2048 Bytes, also eine 
2kB-Page, quetschen, aber nur unter Verzicht auf Libraries (stattdessen 
direkter Hardware-Zugriff und teilweise handoptimiertem Assembler). 
SD-Karte und LCD sind deutlich komplexer.

Frank O. schrieb:
> Ich würde es der Übersicht halber in 2 getrennten Projekten entwickeln.
> Beide mit unterschiedlichen Linker-Scripts, so dass der Code woanders im
> Flashspeicher landet.

Geht eh kaum anders. Man kann sogar auch die ELF-Datei des Bootloaders 
mit der ELF-Datei des Hauptprogramms zu einer kombinierten Datei 
vereinigen, sodass man nicht nur alles auf einmal flashen, sondern auch 
auf einmal Debuggen kann. So kann auch das Hauptprogramm auf Funktionen 
im Bootloader zugreifen (wie bei einer Library). Das ist aber recht 
umständlich umzusetzen.

N. M. schrieb:
> Der Check geht verdammt schnell wenn man die interne CRC Engine mit dem
> DMA füttert. Das Flashen dann wenige Sekunden.

Geht das wirklich per DMA? Die CRC-Engine hat ja keine DMA-Request 
Leitung - benutzt du dann den MEM2MEM-Mode? Aber auch ohne DMA geht der 
CRC-Check in deutlich unter einer Sekunde. Das kann man durchaus bei 
jedem Bootvorgang machen.

Btw, ein wichtiges Zauberwort in diesem Zusammenhang ist das "Vector 
Table Offset Register, VTOR". Dort kann man ab ARMv7M (d.h. 
Cortex-M3/4/7, aber nicht Cortex-M0) die Basisadresse des 
Interruptvektors einstellen. Das ist erforderlich, wenn die 
Hauptanwendung nicht bei 0x08000000 beginnt, sondern erst "hinter" dem 
Bootloader. Beim Umschalten von Bootloader auf Hauptanwendung muss man 
das VTOR setzen.

: Bearbeitet durch User
von Flunder (flunder)


Lesenswert?

Niklas G. schrieb:
> Außerdem musst du entscheiden ob der Bootloader sich selbst
> überschreiben können soll - wenn ja, bedeutet ein fehlgeschlagenes
> Update dass gar nichts mehr geht, wenn nein kann der Bootloader nie
> aktualisiert werden. Im zweiten Fall sollte der Bootloader daher so
> klein wie möglich sein, weil man es später nicht mehr optimieren kann.

Man kann schon Pseudo-Applikationen erstellen und verteilen, die sich 
vom Bootloader als Applikation aufspielen lassen und sobald sie 
loslaufen nix anderes machen, als den Bootloader mit einem neuen zu 
überschreiben. Danach muss man halt über den neuen Bootloader wieder 
eine echte Applikation einspielen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

PS:
Für die CRC-Prüfung muss man natürlich auch erstmal die CRC initial nach 
dem Kompilieren berechnen. Idealerweise schreibt man diese in einem 
Post-Built-Step direkt in die ELF-Datei, sodass man die Datei direkt im 
Debugger verwenden kann ohne dass der Bootloader sich beschwert. Das 
geht z.B. mit Python und der LIEF-Library. Geschickterweise konfiguriert 
man die Hardware-CRC-Einheit so, dass der Algorithmus kompatibel ist zur 
"Standard-CRC", wie sie Python, zlib und auch Java verwendet.

Flunder schrieb:
> Man kann schon Pseudo-Applikationen erstellen und verteilen, die sich
> vom Bootloader als Applikation aufspielen lassen und sobald sie
> loslaufen nix anderes machen, als den Bootloader mit einem neuen zu
> überschreiben.

Klar, aber wenn diese Anwendung mitten drin abstürzt (z.B. Einbruch der 
Versorgungsspannung), ist der Bootloader ggf. nur halb geschrieben und 
dann ist das Gerät "gebrickt". Der Bootloader könnte sich auch ohne 
diesen Umweg mit der Pseudo-Applikation direkt selbst überschreiben 
indem er sich zuvor in den RAM kopiert, aber mit dem gleichen 
"Brick"-Problem.

: Bearbeitet durch User
von Flunder (flunder)


Lesenswert?

Also ich finde der STM32CubeProgrammer ist kein für Endkunden gemachtes 
Update Tool. Nunja, das Protokoll ist irgendwo beschrieben und man 
könnte etwas eigenes Klicki-Bunti entwickeln, dass nur das macht, was 
gebraucht wird.

Da der ROM-Bootloader sämtliche Peripherie im Reset-Zustand erwartet, 
ist es gar nicht so einfach, aus der Applikation rein zu springen. Ich 
habe dann eine Verzweigung an den Anfang des Startup-Codes gesetzt und 
löse in der Applikation einen Reset aus.

Ja, das versagt, sobald ein Update schief gegangen ist, aber leider war 
das Gehäuse schneller fertig als die Software und man kam nicht mehr an 
das BOOT0 Signal.

von Flunder (flunder)


Lesenswert?

Niklas G. schrieb:

> Klar, aber wenn diese Anwendung mitten drin abstürzt (z.B. Einbruch der
> Versorgungsspannung), ist der Bootloader ggf. nur halb geschrieben und
> dann ist das Gerät "gebrickt". Der Bootloader könnte sich auch ohne
> diesen Umweg mit der Pseudo-Applikation direkt selbst überschreiben
> indem er sich zuvor in den RAM kopiert, aber mit dem gleichen
> "Brick"-Problem.

Das kann man nur mit "KISS" etwas abmildern. Der Bootloader muss so 
klein und überschaubar wie möglich sein, so dass er so gut wie nie 
upgedatet werden muss. Bootloader mit OLED-Display-Benutzerführung : 
uijuijui !!!

Spätestens wenn irgendwelche OLED-Displays abgkündigt werden und es 3 
verschiedene Bootloader je nach Hardware braucht, ist Party angesagt.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Flunder schrieb:
> Also ich finde der STM32CubeProgrammer ist kein für Endkunden gemachtes
> Update Tool.

Ja, aber für jemanden der mit MIDI umgehen kann ist es vermutlich 
zumutbar, und spart hier sehr viel Aufwand.

Flunder schrieb:
> Da der ROM-Bootloader sämtliche Peripherie im Reset-Zustand erwartet,
> ist es gar nicht so einfach, aus der Applikation rein zu springen.

Stimmt, man könnte auch in den Option-Bytes permanent nSWBOOT0=0 setzen, 
und dann für den Bootloader-Start auch nBOOT0=0 setzen und einen 
Software-Reset auslösen. Dann muss man allerdings im STM32CubeProgrammer 
nach dem Update wieder nBOOT0=1 setzen um die Anwendung wieder starten 
zu können...

Flunder schrieb:
> aber leider war
> das Gehäuse schneller fertig als die Software und man kam nicht mehr an
> das BOOT0 Signal.

Ggf. ist es auch akzeptabel wenn der Button nur bei offenem Gehäuse 
zugänglich ist.

Flunder schrieb:
> Das kann man nur mit "KISS" etwas abmildern. Der Bootloader muss so
> klein und überschaubar wie möglich sein, so dass er so gut wie nie
> upgedatet werden muss.

Wenn er klein und simpel ist, nimmt er auch wenig Platz weg, weshalb man 
ihn auch nicht später nach-optimieren muss, um Platz für die Anwendung 
zu machen; so spart man sich jedenfalls diverse Probleme. Wenn man 
tricksen muss um den Bootloader in eine Flash-Page zu quetschen ist der 
Code allerdings nicht mehr so überschaubar.

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Wenns um Kleinserie geht nimmt man einfach einen µC mit genug Flash um 
auch im Bootloader mehr zu ermöglichen. 2MB Flash gibts in 
Einzelstückzahlen schon unter 6€.

Wenns "unbrickbar" werden soll kann man auch einen mehrstufigen Ansatz 
fahren. Stufe 1 Bootloader (wird nie ausgetauscht) prüft nur die 
Integrität von einem Stufe 2 Bootloader (es gibt zwei davon) und startet 
dann diesen. Der kann das auch für die Applikation (A/B) machen oder 
wenn nur Platz für eine Applikation vorhanden dann im Bootloader stehen 
bleiben.

Es gibt da unendlich viele Konzepte wie man sowas realisieren kann. Die 
Anforderungen vorher zu klären ist immer hilfreich.

Bei einem ordentlichen Konzept sind dann auch solche Themen wie 
verschlüsselte und signierte Firmware zu klären.

Matthias

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Μαtthias W. schrieb:
> einem Stufe 2 Bootloader (es gibt zwei davon)

Wenn aber der Stufe-2-Bootloader groß ist, was ja auch der Grund dafür 
ist ihn aktualisieren können zu wollen, hat man diese Speichermenge dann 
gleich doppelt belegt...

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Niklas G. schrieb:
> Μαtthias W. schrieb:
>> einem Stufe 2 Bootloader (es gibt zwei davon)
>
> Wenn aber der Stufe-2-Bootloader groß ist, was ja auch der Grund dafür
> ist ihn aktualisieren können zu wollen, hat man diese Speichermenge dann
> gleich doppelt belegt...

Ja, das ist so. Um das etwas abzumildern könnte Stufe 2 (z.B. GZ) 
komprimiert abgelegt werden und dann ins RAM entpackt werden. Kurzer 
Test zeigt eine um 25% reduzierte Größe für ein gerade hier rumliegendes 
Cortex-M0 Binary.

Wie immer YMMV

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Μαtthias W. schrieb:
> Kurzer Test zeigt eine um 25% reduzierte Größe für ein gerade hier
> rumliegendes Cortex-M0 Binary.

Mit GCC erstellte Cortex-M Binaries enthalten eine Menge Null-Bytes, 
d.h. relativ wenig Entropie. Wäre eigentlich mal interessant zu testen 
ob man durch clevere manuelle Assembler-Optimierung Null-Bytes und 
Redundanzen so reduzieren kann, dass die Entropie steigt und der Code so 
klein wie möglich wird und dann auch kaum noch per GZ o.ä. konprimierbar 
ist. Das wird man sich aber durch reduzierte Ausführungsgeschwindigkeit 
erkaufen müssen.

von Johannes (zuberjo)


Lesenswert?

Bei einem STM32 ist oftmals auch der Flash in Dual Banks implementiert. 
Dann kann man auch den Bootloader direkt in die Firmware implementieren 
und muss nicht mit zwei Projekten arbeiten. Man kann die Version auf der 
SD Karte prüfen, wenn diese größer ist die Firmware auf die zweite Flash 
Bank schreiben und aus dem Code raus die Option Bytes setzen, um einen 
Bank Swap auszuführen. Der STM Bootloader wird dann beim nächsten 
Bootvorgang zu der zweiten Flash Bank springen. Der Vorteil ist hier, 
dass die ursprüngliche Firmware als Backup immer noch im Flash verweilt 
und auch durch setzen der Option Bytes wieder auf Flash Bank 1 
gewechselt werden kann. Der Nachteil ist, dass die Firmware maximal die 
halbe Gesamtgröße des Flashs haben darf. Was bei 2MB selten ein Problem 
sein sollte. Das funktioniert super, habe ich bei einem Projekt mit 
Firmware Updates über Ethernet am laufen

von N. M. (mani)


Lesenswert?

Niklas G. schrieb:
> Geht das wirklich per DMA?

OK, da hatte ich die neueren CRC Units im Kopf der neueren STMs. Da geht 
es definitiv.
Einziges Problem ist da nur dass man mit dem DMA maximal über 4x2^16 
Byte kommt. Man muss also je nach dem den DMA mehrmals konfigurieren. 
Aber Geschwindigkeits technisch ist das schon ziemlich gut.

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Niklas G. schrieb:
> Μαtthias W. schrieb:
>> Kurzer Test zeigt eine um 25% reduzierte Größe für ein gerade hier
>> rumliegendes Cortex-M0 Binary.
>
> Mit GCC erstellte Cortex-M Binaries enthalten eine Menge Null-Bytes,
> d.h. relativ wenig Entropie. Wäre eigentlich mal interessant zu testen

Ich denk nicht dass das am GCC liegt sondern einfach an der Verwendung 
von 0x00 in vielen Opcodes. Ganz grob haben 13% von allen Instruktionen 
in meinem Binary (16k groß) mindestens ein Nullbyte. Hier mal ein paar 
Beispiele:
1
00c9            lsls    r1, r1, #3
2
4b18            ldr     r3, [pc, #96]   
3
9b00            ldr     r3, [sp, #0]
4
e000            b.n     3452 <__divsi3+0x42>
5
b200            sxth    r0, r0
6
0031            movs    r1, r6
7
001e            movs    r6, r3
8
003c            movs    r4, r7
9
2300            movs    r3, #0
10
00d2            lsls    r2, r2, #3
11
009e            lsls    r6, r3, #2
12
d000            beq.n   11c6 
13
0056            lsls    r6, r2, #1
14
001a            movs    r2, r3
15
00bf            lsls    r7, r7, #2
16
2500            movs    r5, #0
17
d000            beq.n   2358 
18
00a2            lsls    r2, r4, #2
19
0027            movs    r7, r4
20
008b            lsls    r3, r1, #2
21
d100            bne.n   32b8 
22
0052            lsls    r2, r2, #1
23
0010            movs    r0, r2
24
0011            movs    r1, r2
25
d200            bcs.n   350e <__divsi3+0xfe>

> ob man durch clevere manuelle Assembler-Optimierung Null-Bytes und
> Redundanzen so reduzieren kann, dass die Entropie steigt und der Code so

Denke nicht das da viel zu holen ist. Vor allem wird man sich einen 
Bootloader mit den angesprochenen Features in diesen Anforderungen nicht 
geben wollen.

Matthias

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Μαtthias W. schrieb:
> Ich denk nicht dass das am GCC liegt sondern einfach an der Verwendung
> von 0x00 in vielen Opcodes.

Könnte auch am Cortex-M0 Code liegen, der Cortex-M4 Code ist da deutlich 
"dichter". Aber gerade auch die vielen Peripherie-Adressen in den 
Literal-Pools haben viele Nullen, und wiederholen sich auch ziemlich oft 
(jede Funktion die auf SPI1 zugreift enthält die SPI1-Adresse als 
Literal etc). Ähnlich bei Adressen von globalen Variablen, die erst vom 
Linker eingesetzt werden, sodass die Adresse immer als kompletter 
32bit-Wert im literal-Pool stehen muss für die Relocation.

Außerdem kann der GCC Peripheriezugriffe nicht gut optimieren; nach 
jedem Schreibzugriff entwickelt er eine gewisse Paranoia und lädt dann 
manche Register neu aus dem Literal-Pool. Das scheint eine übereifrige 
Interpretation der Strict-Aliasing-Rules zu sein.

Μαtthias W. schrieb:
> Denke nicht das da viel zu holen ist.

In Assembler kann man gerade auch die Adressen in den Literal-Pools 
zusammenfassen, also sodass mehrere Funktionen auf den selben 
Literal-Pool zugreifen. "Simple" Adressen à la 0x20000000 lassen sich 
beim Cortex-M4 auch in einer 32bit-MOV Instruktion ablegen, was aber das 
Gespann aus GCC+LD nicht kann.

Grundsätzlich könnte man das alles im Compiler umsetzen (ggf. als Teil 
vom LTO?) - machen kommerzielle Compiler das vielleicht schon?

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Niklas G. schrieb:
> Μαtthias W. schrieb:
> Außerdem kann der GCC Peripheriezugriffe nicht gut optimieren; nach
> jedem Schreibzugriff entwickelt er eine gewisse Paranoia und lädt dann
> manche Register neu aus dem Literal-Pool. Das scheint eine übereifrige
> Interpretation der Strict-Aliasing-Rules zu sein.

Das wäre m.E. ein "Problem Report" wert. (Es geht wohl nicht um Register 
sondern um Registeradressen?)

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Das wäre m.E. ein "Problem Report" wert. (Es geht wohl nicht um Register
> sondern um Registeradressen?)

Gute Frage, ich habe es bei Registeradressen beobachtet, aber würde 
vermuten dass auch andere Literals betroffen sind. Das Ganze ist 
letztlich Teil eines größeren Problems, nämlich dass C/C++ keine 
wirkliche Möglichkeit bietet um auf memory-mapped IO-Register 
zuzugreifen, und keine Möglichkeit um Pointer als "kann nicht aliasen" 
zu deklarieren ("restrict" hilft nur begrenzt und ist in C++ nur als 
GCC-Erweiterung vorhanden). Die Zugriffe per Inline-Assembly zu machen 
hilft auch nicht, weil dann die Offset-Adressierung nicht gut optimiert 
werden kann. Das Ergebnis ist, dass der Compiler nach jedem 
Schreibzugriff auf IO-Register alle Speicherstellen als "potenziell 
verändert" betrachtet.

Wenn ich mal die Muße habe stell ich ein paar Testcases zusammen und 
versuche einen Report zu erstellen...

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Niklas G. schrieb:
>> Außerdem kann der GCC Peripheriezugriffe nicht gut optimieren; nach
>> jedem Schreibzugriff entwickelt er eine gewisse Paranoia und lädt dann
>> manche Register neu aus dem Literal-Pool. Das scheint eine übereifrige
>> Interpretation der Strict-Aliasing-Rules zu sein.
>
> Das wäre m.E. ein "Problem Report" wert. (Es geht wohl nicht um Register
> sondern um Registeradressen?)

Ich würde da gerne mal ein Beispiel sehen wie das aussieht. Am Besten 
mit dem passenden C Code hier: https://godbolt.org/ Ich konnte sowas 
noch nicht beobachten.

Matthias

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Niklas G. schrieb:
> Gute Frage, ich habe es bei Registeradressen beobachtet, aber würde
> vermuten dass auch andere Literals betroffen sind. [...]
>
> Wenn ich mal die Muße habe stell ich ein paar Testcases zusammen und
> versuche einen Report zu erstellen...

Oder bevor ein neuer PR erstellt wird mal die Entwickler fragen in 
gcc-help@gcc.gnu.org.  Vielleicht gibt es ja schon nen PR dazu.

Die Internals sagen nicht viel zu MEM_ALIAS_SET und wie die für arm 
umgesetzt sind.

https://gcc.gnu.org/onlinedocs/gccint/Special-Accessors.html

Evtl. liegts auch am volatile der Registerzugriffe.  volatile bewirkt 
gerne mal nen Optimization Fence auch dann, wenn bestimmte Optimierungen 
über den Zaun hinweg eigentlich unproblematisch sind.

Evtl. wird das Alias Set sogar angezeigt, z.B. mit -save-temps -dP.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Μαtthias W. schrieb:
> Ich würde da gerne mal ein Beispiel sehen wie das aussieht.

Hier ein kleines Beispiel:

https://godbolt.org/z/d8hWqPxcz

In 3 Varianten:
- Zugriff auf Peripherieregister mittels Integer-To-Pointer cast und 
volatile, also genau wie das bei den STM32-Libraries in Massen gemacht 
wird
- Zugriff auf gewöhnliche globale Variable
- Zugriff auf "extern" Variable, Adresse per Linker-Argument definiert

Variante 1 ist um 4 bytes länger als die anderen beiden, weil der 
Compiler das Register "r3" zweimal mit der Peripherieadresse lädt, 
obwohl "r3" niemals verändert wird.

Johann L. schrieb:
> Evtl. liegts auch am volatile der Registerzugriffe.

Gut möglich, aber ohne volatile ist's schwierig! Und volatile sollte ja 
eigentlich auch nicht dafür sorgen, dass der Compiler denkt, dass sich 
CPU-Register einfach so ändern können...

Den volatile-Schreibzugriff durch Inline-Asm zu ersetzen ändert 
interessanterweise auch nichts, selbst ohne "volatile".

Es ist hier zwar nur eine Instruktion die nutzlos ist, aber über ein 
komplexes Programm mit vielen Registerzugriffen kann sich das ganz schön 
aufsummieren.

von Stefan M. (mannitb303)


Lesenswert?

Hallo Leute,

danke für die vielen Antworten. Komme gerade nicht mehr mit :). 
Vielleicht habe ich mich auch falsch ausgedrückt mit dem Bootloader. Ich 
lasse natürlich den Originalen Bootloader auf dem Chip.

Johannes schrieb:
> Beim STM32 ist ein eigener Bootloader nichts anderes als eine Firmware.
> Der Factory Bootloader von STM kann nicht geändert werden und startet
> immer zuerst. Die Jump Adresse für den Start der Firmware ist daher
> immer 0x0800000000. Den eigenen Bootloader kann man daher dann wie eine
> ganz normale Firmware aufspielen. Diese kann dann schauen ob eine
> valide, zweite Firmware auf einer SD Karte liegt, diese in den Flash
> kopieren, zb Address ab 0x082000000 und dann diese von dort ausführen.
> Damit das funktioniert muss die zweite Firmware mit einem Offset
> erstellt und kompiliert werden. Aber dazu gibt es jede Menge Anleitungen
> im Netz

Also es soll dann so aussehen: STM Bootloader starten meine Firmware1, 
die schaut ob es eine Update-Datei gibt, falls nicht startet Firmware2 
also das Hauptprogramm meiner Hardware. Gibt es eine neue Datei und alle 
Parameter stimmen( Datei vorhanden, Version neuer als die aktuelle) 
ersetzt die Datei die Firmware2 im STM. Nach erfolgreichem kopieren 
startet Firmware2.

Gibt es einen Befehl um Adressen im Speicher des STM anzuspringen (Kenne 
es nur noch vom Amiga Assembler (JSR,JMP)). Benutze aktuell halt noch 
die Arduino Umgebung auf Platformio.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Stefan M. schrieb:
> Gibt es einen Befehl um Adressen im Speicher des STM anzuspringen

In Assembler "blx", vorher Stack-Pointer initialisieren (1. Eintrag im 
ISR-Vektor) mittels "ldr" oder "mov", und SCB->VTOR auf die Adresse des 
ISR-Vektors setzen.
1
void runApp (uint32_t appAddr) {
2
  WRITE_REG(SCB->VTOR, appAddr);
3
  __asm__ volatile (
4
    "mov r4, sp\n"
5
    "ldrd r0, r1, [%[appAddr]]\n"
6
    "mov sp, r0\n"
7
    "dsb\n"
8
    "isb\n"
9
    "cpsie i\n"
10
    "blx r1\n"
11
    "mov sp, r4\n"
12
    : : [appAddr] "r" (appAddr) : "r0", "r1", "r2", "r3", "r4", "r12", "lr", "cc", "memory"
13
  );
14
}

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

Das: Beitrag "Re: Eigener Bootloader stm32f103"
würde ich an dieser Stelle exakt genauso nochmal schreiben.

von Werner P. (werner4096)


Lesenswert?

Johannes schrieb:
> Bei einem STM32 ist oftmals auch der Flash in Dual Banks implementiert.
> Dann kann man auch den Bootloader direkt in die Firmware implementieren
> und muss nicht mit zwei Projekten arbeiten. Man kann die Version auf der
> SD Karte prüfen, wenn diese größer ist die Firmware auf die zweite Flash
> Bank schreiben und aus dem Code raus die Option Bytes setzen, um einen
> Bank Swap auszuführen. Der STM Bootloader wird dann beim nächsten
> Bootvorgang zu der zweiten Flash Bank springen. Der Vorteil ist hier,
> dass die ursprüngliche Firmware als Backup immer noch im Flash verweilt
> und auch durch setzen der Option Bytes wieder auf Flash Bank 1
> gewechselt werden kann. Der Nachteil ist, dass die Firmware maximal die
> halbe Gesamtgröße des Flashs haben darf. Was bei 2MB selten ein Problem
> sein sollte. Das funktioniert super, habe ich bei einem Projekt mit
> Firmware Updates über Ethernet am laufen

Dazu eine Frage:

ich habe einen STM32L082 mit 192KB Flash.

Aktuell liegt mein Programm (ca. 62KB) auf Bank1 0x08000000 und 
funktioniert.

Jetzt flashe ich mein Programm auf Adresse: 0x08018000 (Bank 2) und 
setze danach BFB2 auf 1. Nach einem Reset wird das Programm auf Bank 2 
nicht ausgeführt.

Setze ich BFB2 auf 0 dann läuft mein Programm von Bank 1.

Habe schon gegoogelt und dabei gelesen, dass das nur funktionieren würde 
wenn der interne Bootloader aktiviert ist. Also Pin BOOT0 auf HIGH.

Stimmt das? Wenn ja, muss dann BOOT0 immer auf HIGH liegen?

Grüße, Werner

von Frank O. (fop)


Lesenswert?

Werner P. schrieb:
> Jetzt flashe ich mein Programm auf Adresse: 0x08018000 (Bank 2) und
> setze danach BFB2 auf 1. Nach einem Reset wird das Programm auf Bank 2
> nicht ausgeführt.

Dazu eine Frage : Linkst Du das Programm erneut für den Adressbereich in 
Bank 2 oder schreibst Du einfach eine .bin-Datei, die der Linker für 
Bank 1 angefertigt hat woanders hin ?

von Werner P. (werner4096)


Lesenswert?

Frank O. schrieb:
> Werner P. schrieb:
>> Jetzt flashe ich mein Programm auf Adresse: 0x08018000 (Bank 2) und
>> setze danach BFB2 auf 1. Nach einem Reset wird das Programm auf Bank 2
>> nicht ausgeführt.
>
> Dazu eine Frage : Linkst Du das Programm erneut für den Adressbereich in
> Bank 2 oder schreibst Du einfach eine .bin-Datei, die der Linker für
> Bank 1 angefertigt hat woanders hin ?

Ich compile für Bank 1 0x08000000. Das flashe ich in die Bank 1 
(0x08000000) und in die Bank 2 (0x08018000).

Habe das hier in Google gefunden:

https://community.st.com/t5/stm32-mcus-products/stm32l082-dual-nvm-banks-how-to-boot-from-bank2/td-p/65520

Now when I understand correctly this time -> the following should work 
for the stm32L082:

Exact same code for bank1 can be written in bank2.
Flash bank1 and bank2 at the addresses as mentioned earlier.
Set BFB2 flag (1)
Reset the processor
Bank2 code will be running

von Thomas Z. (usbman)


Lesenswert?

Werner P. schrieb:
> Ich compile für Bank 1 0x08000000. Das flashe ich in die Bank 1
> (0x08000000) und in die Bank 2 (0x08018000).

das ist natürlich totaler Unsinn. Ein Programm was für Bank 1 kompiliert 
ist wird niemals in Bank2 laufen.

von Frank O. (fop)


Lesenswert?

Es gibt da wohl in einigen STM32 ein Feature, dass Johannes (zuberjo) am 
02.10.2025 11:48 schonmal erwähnt hat. Da wechseln 2 Flash Banks ihre 
Adressen. Im Forum ging es um einen stm32L082, der mit einem Config-Bit 
diesen Trick vollbringt, dass für die Firmware alle Bits ab 0x08000000 
mit denen ab 0x08018000 die Plätze tauschen. Aber kann das auch der 
stm32f103 ?
Da wird anhand der Startup-Konfiguration (Pegel an Pins) einfach nur der 
Startwert des Programmcounters gesetzt. Ganz andere (primitivere) 
Technik.

von Werner P. (werner4096)


Lesenswert?

Thomas Z. schrieb:
> Werner P. schrieb:
>> Ich compile für Bank 1 0x08000000. Das flashe ich in die Bank 1
>> (0x08000000) und in die Bank 2 (0x08018000).
>
> das ist natürlich totaler Unsinn. Ein Programm was für Bank 1 kompiliert
> ist wird niemals in Bank2 laufen.

hm. hab den code auch mal für BANK2 (0x08018000) compiled. Läuft aber 
auch nicht. Irgendwie komme ich da grad nicht weiter.

Aktuell mach ich Firmware Update wie folgt:

Programm holt sich via Ethernet die Firmware und schreibt diese in BANK 
2. Danach reset und somit Start meines Bootloaders (0x08000000) welcher 
die Firmware von BANK 2 nach 0x08008000 kopiert. Dann wieder Reset und 
das wars.

Wäre halt schön gewesen wenn ich mir meinen Bootloader sparen könnte.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Werner P. schrieb:
> Läuft aber auch nicht. Irgendwie komme ich da grad nicht weiter.

Einfach mal per SWD debuggen...? Da siehst du sofort wo es stehen 
bleibt...

von Werner P. (werner4096)


Lesenswert?

so. Jetzt bin ich etwas weiter gekommen.

In main.c habe ich gleich am Anfang folgende Zeile eingefügt.
1
SCB->VTOR = 0x08000000;

Dann den Code für Bank 1 und für Bank 2 compiled und entsprechend 
geflashed.

Je nachdem wie ich Option Byte BFB2 setze startet das Programm von Bank 
1 oder Bank 2.

Somit schon mal einen Schritt weiter ;-)

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Werner P. schrieb:
> SCB->VTOR = 0x08000000;

Das ist doch der Default und sollte keinen Unterschied machen...

von Werner P. (werner4096)


Lesenswert?

Niklas G. schrieb:
> Werner P. schrieb:
>> SCB->VTOR = 0x08000000;
>
> Das ist doch der Default und sollte keinen Unterschied machen...

Dachte ich auch. Hab dann aber einen Foren Beitrag bei ST gefunden. War 
selbes Problem.

Grüße

von Werner P. (werner4096)


Lesenswert?

Hab jetzt noch mal weiter getestet.

code mit UART Ausgabe "boot from bank 1" für BANK 1 compiled.
selbigen code mit UART Ausgabe "boot from bank 2" für BANK 1 compiled.

Also gleiches programm nur mit unterschiedlichen UART Ausgaben.

Dann in BANK 1 und in BANK 2 geflasht.

Je nach Status von BFB2 läuft das Programm von BANK1 oder BANK2.

Sieht so aus als wenn:
1
SCB->VTOR = 0x08000000;
 die Lösung war.

Grüße, Werner

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Werner P. schrieb:
> Sieht so aus als wenn:
>
> SCB->VTOR = 0x08000000;
>
> die Lösung war.

Skurril, dann ist es ein seltsamer Hardware-Bug - ein Feature zu viel! 
Sicher dass du das VTOR nicht doch irgendwo vorher auf was anderes 
setzt? Hast du mal den vorigen Wert von VTOR ausgeben lassen?

: Bearbeitet durch User
von Werner P. (werner4096)


Lesenswert?

Niklas G. schrieb:
> Werner P. schrieb:
>> Sieht so aus als wenn:
>>
>> SCB->VTOR = 0x08000000;
>>
>> die Lösung war.
>
> Skurril, dann ist es ein seltsamer Hardware-Bug - ein Feature zu viel!
> Sicher dass du das VTOR nicht doch irgendwo vorher auf was anderes
> setzt? Hast du mal den vorigen Wert von VTOR ausgeben lassen?

Hier der Code in main.c
1
int main(void)
2
{
3
  /* USER CODE BEGIN 1 */
4
5
6
  /* here we check for which artifical bank in SRAM2 is the code in active Flash bank intended */
7
  uint32_t vtor = SCB->VTOR;
8
  SCB->VTOR = 0x08000000;
9
  /* USER CODE END 1 */
10
11
  /* MCU Configuration--------------------------------------------------------*/
12
13
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
14
  HAL_Init();
15
16
  /* USER CODE BEGIN Init */
17
18
  /* USER CODE END Init */
19
20
  /* Configure the system clock */
21
  SystemClock_Config();

vtor = 0x00000000, danach 0x08000000

Grüße

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Werner P. schrieb:
> vtor = 0x00000000

Interessant, vermutlich wirkt da normalerweise das Remap von 0x00 auf 
0x08000000, aber nicht wenn die Bänke getauscht sind. Steht da was im 
Errata Sheet dazu?

von Werner P. (werner4096)


Lesenswert?

Hallo,

hab mal die Errata angeschaut.

https://www.st.com/resource/en/errata_sheet/es0292-stm32l07xxxl08xxx-device-errata-stmicroelectronics.pdf

2.1.8 und 2.1.9 haben was mit dual-bank boot zu tun.

Kenne mich jetzt nicht so aus ;-)

Grüße

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Werner P. schrieb:
> 2.1.8 und 2.1.9 haben was mit dual-bank boot zu tun.

Hm, 2.1.8 ist bei aktuellen Chips repariert und 2.1.9 sollte sich nicht 
auf VTOR auswirken...

von Werner P. (werner4096)


Lesenswert?

Niklas G. schrieb:
> Werner P. schrieb:
>> 2.1.8 und 2.1.9 haben was mit dual-bank boot zu tun.
>
> Hm, 2.1.8 ist bei aktuellen Chips repariert und 2.1.9 sollte sich nicht
> auf VTOR auswirken...

ok.

Mein STM32L082: Device ID: 0x447, Revision ID: Rev V

Die habe ich vor ca. 3-4 Jahren gekauft.

2.1.9 habe ich vorsichtshalber mal im Code eingefügt ;-)

Grüße, Werner

von Stefan M. (mannitb303)


Lesenswert?

Hallo,

so ich bin auch weiter gekommen. Firmware1 habe ich in 0x08000000 
geflashed und Firmware2 habe ich in 0x0800D000 geflashed. In 
Platformio.ini habe ich in mein environment die option 
board_build.flash_offset = 0xD000 eingefügt, somit muss ich das 
linker-script nicht ändern sondern wird für die Adresse 0x0800D000 
compiliert und geflashed.
Es startet zuerst Firmware1 danach läuft Firmware2. Jetzt kommt die 
Update-Datei Abfrage, das kopieren der Datei von SD-Karte in den 
Speicher 0x0800D000.

von Johannes (zuberjo)


Lesenswert?

Bei dem Projekt, das ich damit am laufen habe, verwende ich einen 
STM32H7. Die Binary File wird ganz normal compiliert, ohne Flash Offset. 
Bei einem Bank Swap wird die zweite Bank mit 0x8000000 adressiert und 
die erste nach hinten geschoben. Das macht es ziemlich einfach und man 
muss nicht bei einem Update die Sorge haben, etwas mit den Adressen zu 
verwechseln.

Bei läuft das aber auch alles aus der Firmware raus. Neue Binary in den 
Flash schreiben (0x8100000), die Option Bytes abfragen ob Bank Swap 
aktiv ist, wenn ja deaktivieren, wenn nein aktivieren und dann einen 
Reboot initialisieren. Und so funktioniert es bei mir auch mit dem 
Programmer. Die selbe Firmware kann ein mal auf 0x8000000 und 0x8100000 
geschrieben werden. Je nach Option Bytes wird die eine oder andere 
gestartet. Ausgeben kann man dies über eine Abfrage im Code selbst über 
serielle Ausgabe. Option Bytes abfragen, wenn gesetzt, dann läuft Bank 
2, wenn nicht dann Bank 1. Funktioniert alles problemlos. Aber ob es 
irgendwelche Bugs oder Fallstricke bei anderen STM32 MCUs gibt kann ich 
natürlich nicht sagen ohne jemals damit was gemacht zu haben

von Stefan M. (mannitb303)


Lesenswert?

Hallo,

so hab es jetzt soweit am laufen. User kann über das Menü ein Update 
auslösen, Stm resetet sich Firmware1 checkt die SD-Karte und schaut ob 
eine Update Datei vorhanden ist. Falls ja kopiert er Firmware2 in den 
Flash Speicher, führt einen CRC check durch, setzt ein checkbyte zurück 
und resetet sich. Firmware1 erkennt Update durchgeführt und startet die 
aktualisierte Firmware2. Jetzt fehlt noch ein Datei Check, also ob es 
auch eine Datei für dieses System ist, Header im File und nicht 
irgendeine firmware.bin). Nur einen würde mich noch interessieren, ich 
kopiere ja die neue Firmware2 direkt von SD-Karte in den Speicher, was 
ist wenn beim kopieren schief geht? Dann stimmt natürlich der CRC Check 
nicht. In diesem Fall macht er 3 Versuche es erfolgreich zu kopieren. 
Wenn nun aber auch nach dem 3. Versuch es nicht erfolgreich kopiert ist 
dann ist ja keine lauffähige Firmware2 mehr im Flash oder sehe ich das 
falsch?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Stefan M. schrieb:
> so hab es jetzt soweit am laufen.

Cool, wie groß ist Firmware1 letztendlich? Hast du meinen Code für den 
Sprung in Firmware2 genutzt?

von Harry L. (mysth)


Lesenswert?

Ich nehme meine -voreilige- Meinung voll-umfänglich zurück!
Beitrag "Re: Eigener Bootloader stm32f103"

Gut gemacht!

von Stefan M. (mannitb303)


Lesenswert?

Niklas G. schrieb:
> Stefan M. schrieb:
>> so hab es jetzt soweit am laufen.
>
> Cool, wie groß ist Firmware1 letztendlich? Hast du meinen Code für den
> Sprung in Firmware2 genutzt?

Die ist 35Kb gross.
Ja, ich hab deinen Code benutzt, wenn ich darf.

von Stefan M. (mannitb303)


Lesenswert?

Harry L. schrieb:
> Ich nehme meine -voreilige- Meinung voll-umfänglich zurück!
> Beitrag "Re: Eigener Bootloader stm32f103"
>
> Gut gemacht!

Danke, hatte ja auch Hilfe von allen. Habe mich vielleicht auch nicht 
richtig ausgedrückt mit Bootloader.

von Stefan M. (mannitb303)


Angehängte Dateien:

Lesenswert?

Hier Mal ein Video wie es funktioniert. Update wird vom User ausgelöst.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Stefan M. schrieb:
> Die ist 35Kb gross.
> Ja, ich hab deinen Code benutzt, wenn ich darf.

Happig, hoffentlich bleibt genug für die Anwendung übrig... Ja kannst du 
nutzen, hatte mich nur gefragt ob du meine Antwort gesehen hattest

von Stefan M. (mannitb303)


Lesenswert?

Niklas G. schrieb:
> Stefan M. schrieb:
>> Die ist 35Kb gross.
>> Ja, ich hab deinen Code benutzt, wenn ich darf.
>
> Happig, hoffentlich bleibt genug für die Anwendung übrig... Ja kannst du
> nutzen, hatte mich nur gefragt ob du meine Antwort gesehen hattest
Ja, bleibt genug übrig. Der stm32f103RGT6 hat ja 1MB Flash Speicher.
Klar hab ich deine Antwort gelesen. Danke

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