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
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ß
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
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
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.
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
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.
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.
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.
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.
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?
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.
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...
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;
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
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.
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?
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.
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. ;-)
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.
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.