Forum: Mikrocontroller und Digitale Elektronik STM32F1 Bootloader


von Michaela (Gast)


Lesenswert?

Hallo zusammen,

vielleicht stelle ich mich momentan ja nur sau doof an, aber irgendwie 
komme ich nicht weiter. Ich suche einen Weg, wie ich einen STM32F1 über 
eine eigene Schnittstelle (in meinem Fall RS485) programmieren kann. 
Offenbar mache ich allerdings irgendetwas falsch, da ich nicht einen 
einzigen Ansatz im Web finden kann, bei dem jemand versucht hätte, diese 
Mikrocontroller über etwas Anderes als über JTAG/SWD zu programmieren... 
Kann den das sein?

Gibt es denn wirklich keinen selbst geschriebenen Bootloader für den 
STM32?
Ich hätte da nur zu gerne etwas abgekupfert, da ich noch nie einen 
Bootloader geschrieben habe. JTAG/SWD möchte ich allerdings umgehen, da 
ich meine Mikrocontroller später bevorzugt tief im System vergaben und 
verschraubt programmieren möchte ohne wieder das Gehäuse öffnen zu 
müssen. Und einen weiteren Stecker am Gehäuse möchte ich noch viel 
weniger.

Vielen Dank
Gruß Michaela

von Fabian K. (Firma: meleon engineering) (fabian_keller)


Lesenswert?

Schau mal im Ref. Manual auf Seite 60/61 unter Boot configuration 
(Embedded Bootloader) vielleicht hilft dir das weiter.

http://www.st.com/web/en/resource/technical/document/reference_manual/CD00171190.pdf

Gruß

von Sven (Gast)


Lesenswert?

Hallo Michaela,

der STM hat standardmäßig einen Bootloader auf Usart1. Dieser kann über 
das Flash Downloader Tool von STM geflashed werden. Wenn du daran einen 
RS485 Treiber klemmst und USB zu RS485 an den Rechner klemmst, kannst du 
direkt flashen. Um in den bootloader modus zulangen musst du nur ein Pin 
(siehe Datenblatt) auf high ziehen.


Gruß

von Arne (Gast)


Lesenswert?

Moin,

> Gibt es denn wirklich keinen selbst geschriebenen Bootloader für den
> STM32?
Doch... hier! Wird sogar in weisser Ware von uns genutzt.
Bootloader ist erstmal ein Programm wie jedes andere auch! Das einzig 
Interessante ist der Sprung in die Applikationssoftware (also die SW, 
die der Kundee nutzt. Vom Bootloader soll er vermutlich nichts 
mitbekommen.)

Welche Fragen hast Du genau?

ciao, Arne

von Martin K. (martinko)


Lesenswert?

Hi,

Viel gesucht haben kannst Du nicht.
Der SMT32 hat einein eigenen Bootloader mit verschiedenen 
Kommunikationswegeg onboard und bei ST gibt es verschiedene Application 
Notes und Beispiel Code wi so etwas über Ethernet, SPI, ... aussehen 
kann.

Gruß Martin

von Steffen R. (steffen_rose)


Lesenswert?

Ein Bootloader beim STM32 ist vergleichsweise einfach. Du brauchst dich 
nicht damit herumzuschlagen, dass die Flashroutinen wie üblich im RAM 
laufen u.ä.
Wenn Du magst, kannst Du direkt aus dem Flash heraus auf das Flash 
schreiben. Es sollte nur einen andere Erase Page sein als der Bootloader 
belegt. Du musst ja vorab den Flash löschen.

von Michaela (Gast)


Lesenswert?

Hallo zusammen,

also wenn ich dann jetzt alles was ihr schreibt und ich im Internet so 
finde zusammen bringe komme ich also zu folgendem Ergebnis:
Wenn ich einen Bootloader für den STM schrieben möchte, dann ist das 
letztlich nichts anderes als ein normales Programm, bevorzugt am Anfang 
des Speichers, das beim Start des STM anläuft, prüft ob eine 
Programmierbedingung gegeben ist und wenn nicht, dann startet es das 
Benutzerprogramm, welches so compiliert werden muss, dass es ab 
Speicheradresse 0x8003000 läuft, vor dem Start des Programms muss 
natürlich noch die NVIC-Tabelle auf selbige Adresse umgebogen werden.

Mit den BOOT-Pins hat das ganze allerdings nichts zu tun. Mir wird zwar 
nicht ganz klar, wofür die dann da sind, aber vielleicht komme ich 
irgendwann noch auf den Hund.
Nur schade, dass es offenbar keinen fertigen Code im Internet gibt, 
hätte da ganz gerne einmal rein geschaut und dessen Idee versucht zu 
verstehen.

Danke euch trotzdem
Gruß Michaela

von (prx) A. K. (prx)


Lesenswert?

Michaela schrieb:
> Mit den BOOT-Pins hat das ganze allerdings nichts zu tun. Mir wird zwar
> nicht ganz klar, wofür die dann da sind, aber vielleicht komme ich
> irgendwann noch auf den Hund.

Nochmal ganz langsam zum mitschreiben: Die STM32 enthalten ab Werk schon 
einen fix und fertigen Bootloader, je nach Typ mindestens über UART. Der 
ist da schon drin. Immer. Und m.W. nicht löschbar.

Die BOOT Pins sind dazu da, diesem Bootloader eine Chance zu geben.

> Nur schade, dass es offenbar keinen fertigen Code im Internet gibt,

Das könnte daran liegen, dass niemand Lust drauf hat, das Rad neu zu 
erfinden.

: Bearbeitet durch User
von Werner (Gast)


Lesenswert?

A. K. schrieb:
> Das könnte daran liegen, dass niemand Lust drauf hat, das Rad neu zu
> erfinden.

Es gibt in der Welt auch noch andere Wege als UART/RS485. Über CAN 
programmiere ich ein externes EEProm und der Bootloader überträgt die 
Firmware dann ins Flash. Da CAN so laaaaangsam ist, musste ich es leider 
so machen.

von Davis (Gast)


Lesenswert?

A. K. schrieb:

> Das könnte daran liegen, dass niemand Lust drauf hat, das Rad neu zu
> erfinden.

Wenn man das Update/die Software verschlüsseln möchte, dann bleibt einem 
nichts anderes übrig.

von (prx) A. K. (prx)


Lesenswert?

Habt ihr beide eure Software veröffentlicht?

von Davis (Gast)


Lesenswert?

A. K. schrieb:

> Habt ihr beide eure Software veröffentlicht?

Natürlich nicht.

von Steffen R. (steffen_rose)


Lesenswert?

Michaela schrieb:
> dann startet es das
> Benutzerprogramm, welches so compiliert werden muss, dass es ab
> Speicheradresse 0x8003000 läuft, vor dem Start des Programms muss
> natürlich noch die NVIC-Tabelle auf selbige Adresse umgebogen werden.

Die konkrete Adresse kommt auf deinen Bootloader drauf an.
Wie der Sprung in die Applikation auszusehen hat findest Du in den 
Applikation Notes. Soweit ich mich erinnere ist es kein reiner jump.

> Mit den BOOT-Pins hat das ganze allerdings nichts zu tun.
> Mir wird zwar nicht ganz klar, wofür die dann da sind,

Mit den Boot-Pins kommst Du in den CPU internen Bootloader. Der liegt 
außerhalb des normalen Flashes und bleibt erhalten, auch wenn du einen 
eigenen Bootloader schreibst.

: Bearbeitet durch User
von ..,- (Gast)


Lesenswert?

Man kann den internen/eingebetteten Bootloader auch aus der eigenen 
Applikation anspringen ... ohne an den Pins zu ziehen.

von Michaela (Gast)


Lesenswert?

OK hier kommt noch eine sehr konkrete Frage. Ich komme mit dem Text im 
Manual nicht klar:

RM0008, 3.4  Boot configuration, p.60/61:
1
The BOOT pins are also re-sampled when exiting from Standby mode.
2
Consequently they must be kept in the required Boot mode configuration
3
in Standby mode.
Bis hier hin ist's klar, aber dann:
1
After this startup delay has elapsed, the CPU fetches the top-of-stack
2
value from address 0x0000 0000, then starts code execution from the boot
3
memory starting from 0x0000 0004.

Wenn mir das jemand übersetzen könnte? also nicht Englich->Deutsch, 
sondern... naja, Technik->Frau halt?
Was passiert da?
gefunden habe ich dazu bereits folgendes:

Albert ... schrieb:
> An Adresse 0x0000 0004 steht NUR die Adresse des Reset Handlers. Aber
> die erste Aufgabe des Controllers ist es an die dort angegebene Adresse
> zu springen. Er fängt also mit einem Sprung an diese Adresse an. Danach
> (ab Adresse 0x0000 0008) folgen andere Interrupt Handler (die ersten 15
> sind Core spezifisch, danach folgen die Herstellerspezifischen für die
> Peripherie). [...]

Nur ungeklärt bleibt, was mit Adresse 0x0800 0000 passiert? Deren Inhalt 
wird als top-of-stack verwendet? also quasi die Initialisierung des 
Stack-Pointers.
Und vielleicht ist mir nur der Begriff nicht geläufig aber 
"top-of-stack" wird das genannt, da der Stack ja "up-side-down" (im 
Vergleich zum Stapel Papier wie man es ja so schön beigebracht bekommt) 
im Speicher liegt, also sich von der höchsten Adresse abwärts aufbaut?
Ist das richtig so?

von (prx) A. K. (prx)


Lesenswert?

Michaela schrieb:
> Nur ungeklärt bleibt, was mit Adresse 0x0800 0000 passiert? Deren Inhalt
> wird als top-of-stack verwendet? also quasi die Initialisierung des
> Stack-Pointers.

Ebendies.

Bei den meisten Prozessoren findet diese Initialiserung in einem in 
Assembler geschriebenen Startup-Code statt. Weil man manches nicht in C 
machen kann, und dazu gehört die Initialisierung des Stackpointers.

Eine Besonderheit der Cortex-M Prozessoren ist, dass bei Exceptions aber 
auch hier darauf geachtet wurde, dass alles in normalem C ohne besondere 
Attributierungen geschrieben werden kann. Daher erfolgt die 
Initialisierung des Stackpointers auf diese Art.

: Bearbeitet durch User
von Michaela (Gast)


Lesenswert?

A. K. schrieb:
> Eine Besonderheit der Cortex-M Prozessoren ist, dass bei Exceptions aber
> auch hier darauf geachtet wurde, dass alles in normalem C ohne besondere
> Attributierungen geschrieben werden kann. Daher erfolgt die
> Initialisierung des Stackpointers auf diese Art.

Ok, wie sieht das denn dann aus? Hast du ein Beispiel dafür?
Das kann ich mir gerade gar nicht vorstellen, wie man mit normalem 
C-Code dem Compiler mitteilen soll, dass an Adresse 0x0800 0000 ein 
bestimmter Wert stehen soll...

von (prx) A. K. (prx)


Lesenswert?

Michaela schrieb:
> Das kann ich mir gerade gar nicht vorstellen, wie man mit normalem
> C-Code dem Compiler mitteilen soll, dass an Adresse 0x0800 0000 ein
> bestimmter Wert stehen soll...

Erstens ist das kein Problem, zweitens bezog ich mich nicht auf den Code 
des Bootloaders, sondern auf den Code der Anwendung.

*(unsigned *)0x08000000 = 0x12345678;

von Arne (Gast)


Lesenswert?

Michaela schrieb:
> Ok, wie sieht das denn dann aus? Hast du ein Beispiel dafür?
> Das kann ich mir gerade gar nicht vorstellen, wie man mit normalem
> C-Code dem Compiler mitteilen soll, dass an Adresse 0x0800 0000 ein
> bestimmter Wert stehen soll...

A.K. hat zwar Deine Frage korrekt beantwortet, aber sie hilft in Deinem 
Fall wohl nicht weiter ;)

Im Endeffekt willst Du die Vektortabelle ab 0x08000000 beginnen lassen. 
Dazu gibt es z.B. beim GCC folgenden Code
1
  
2
__attribute__ ((section("vectors")))
3
void (* const __vector_table[]) (void) = {
4
5
STACK_TBD,    /* SP <<<<<< use linker skript definition here  */
6
start_cold,   /* PC  */
7
...           /* vector #2 */
8
              /* etc */
9
};
Wir benutzen den IAR, daher kann ich zu GCC nix sagen, aber das Anlegen 
der Section "vectors" muss dann im Linkerscript geschehen - das alles 
ist Compiler/Linker-abhängig. Und im Linkerscript passiert auch die 
Zuweisung, dass "vectors" ab 0x08000000 beginnt.
Wie in einer normalen (nicht-Bootloader) Applikation auch. Einfach 
copy&paste!
Mach Dir bewusst, welche Aufgaben Compiler bzw. Linker übernehmen, dann 
wird es vielleicht deutlicher.
Deine Anwendungssoftware schreibst Du mit einer Vektortabelle, die sich 
formal von obiger nicht unterscheidet (natürlich stehen andere 
Startadressen zuz den ISRs drin). Im Linkerscript zur Anwendungssoftware 
legst Du "vectors" dann an 0x08003000 und die "text" und "data" sections 
dahinter. Finito!
Ich weiss nicht, welchen Compiler/Linker Du nutzt, aber schau Dir mal 
das Linkerskript eines Beispieles irgendeiner Beispielapplikation dazu 
an.

Den internen Bootloader konnte ich z.B. nicht nehmen, da ich noch 
externes SPI Flash/EEPROM über ihn füllen muss. Sowas geht mit dem 
internen nicht.

Nochmal: der einzig interessante Aspekt m.E. ist der Sprung vom 
Bootloader in die Applikation in C. Wenn Du soweit bist, such ich meinen 
Code raus.

ciao, Arne

von Arne (Gast)


Lesenswert?

Michaela schrieb:
> Nur ungeklärt bleibt, was mit Adresse 0x0800 0000 passiert? Deren Inhalt
> wird als top-of-stack verwendet? also quasi die Initialisierung des
> Stack-Pointers.
Der Prozessor kopiert die 32bit ab 0x08000000 in seinen Stackpointer, 
dann die 32bit ab 0x08000004 in den PC (Programcounter) und schon kann 
er loslaufen. Ab 0x08000004 steht auch nicht die Adresse von main(), 
sondern des StartUpCodes, den der Linker hinzupackt. Dieser Code nullt 
das BSS aus und kopiert das Data-Segment vom Flash ins RAM. Musst Du 
Dich i.d.R. nicht drum kümmern, wenn Du ein funktionierendes 
Linkerskript nimmst.

> Und vielleicht ist mir nur der Begriff nicht geläufig aber
> "top-of-stack" wird das genannt, da der Stack ja "up-side-down" (im
> Vergleich zum Stapel Papier wie man es ja so schön beigebracht bekommt)
> im Speicher liegt, also sich von der höchsten Adresse abwärts aufbaut?
> Ist das richtig so?
Ja.

von Arne (Gast)


Lesenswert?

Michaela schrieb:
> Wenn mir das jemand übersetzen könnte? also nicht Englich->Deutsch,
> sondern... naja, Technik->Frau halt?
> Was passiert da?

Der interne Bootloader steht im ROM, nicht im Flash, kann durch Dich 
nicht überschrieben werden! Er wird durch eine bestimmte Kombination von 
Spannungspegeln an den Bootpins in während der Resetphase aktiviert. 
Auch dieser interne Bootloader braucht natürlich einen SP (ab 
0x00000000) und PC (ab 0x00000004). Auch er hat eine Vektortabelle, die 
formal wie alle anderen Vektortabellen für den M3 aufgebaut ist. Wenn Du 
Deinen eigenen Bootloader schreiben willst, musst Du nur darauf achten, 
dass die BOOT-Pins in der Resetphase nicht die Werte annehmen, dass der 
M3 in seinen internen Bootloader springt.

Letztendlich ist die Frage: was willst Du mit einem Bootloader machen?
Internes Flash löschen/schreiben? Andere Devices (I2C, SPI,...) über den 
Bootloader schreiben/lesen oder nur einen Bootloader schreiben, um was 
zu lernen?

von Steffen R. (steffen_rose)


Lesenswert?

Arne schrieb:
> Der Prozessor kopiert die 32bit ab 0x08000000 in seinen Stackpointer,
> dann die 32bit ab 0x08000004 in den PC (Programcounter) und schon kann
> er loslaufen.

Zu beachten ist, dass du dies natürlich "per Hand" nachbilden mußt, wenn 
Du aus deinem selbstgeschriebenen Bootloader in die Applikation 
springst. Die Applikation möchte ja ihre gewohnten Einstellungen 
vorfinden.

Anmerkung:
Desweiteren sollte deine Applikation die gesamte benötigte Hardware 
komplett initialisieren. Zumindest an einigen Stellen findet die 
Applikation nicht die Reset-Zustände nach Handbuch.

von Arne (Gast)


Lesenswert?

Steffen Rose schrieb:
> Zu beachten ist, dass du dies natürlich "per Hand" nachbilden mußt

Was meinst Du im Detail damit?
Ich habe z.B. zwei IAR Projekte (Bootloader & Applikation). Bootloader 
ab 0x08000000 und Appl. ab 0x08006000. Jedes Projekt hat sein 
Linkerskript und gut ist. Und das funktioniert sogar in der Endanwendung 
damit. ;-)

von Steffen R. (steffen_rose)


Lesenswert?

Man merkt eher keinen Unterschied, wenn alles aus einer Hand kommt. Du 
wirst für den Bootloader und die Applikation auch den gleichen Compiler 
nutzen. Insofern stellt der Bootloader für sich genau das gleiche ein 
wie die Applikation erwartet.

Wenn Du nur einen jump vom Bootloader in die Applikation aus einer 
Unterfunktion heraus machst, steht der Stackpointer nicht am Anfang des 
Stacks, wie ihn der Bootloader definiert hat.

Nicht weiter schlimm. Sind ja nur ein paar Byte.

Schlimm wird es erst, wenn die Applikation den Stack an anderer Stelle 
haben will als der Bootloader.

von Arne (Gast)


Lesenswert?

Steffen Rose schrieb:
> Wenn Du nur einen jump vom Bootloader in die Applikation aus einer
> Unterfunktion heraus machst, steht der Stackpointer nicht am Anfang des
> Stacks, wie ihn der Bootloader definiert hat.

Das ist richtig, korrigiere ich aber mit einem __MSR_MSP(..).
Der Rest geht dann in C.

von newbies (Gast)


Lesenswert?

Gibt es einen Tutorial wo gezeigt wird wie man einen ganz einfachen 
Bootloader für STM32F1 oder F0 schreibt. ?

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.