Forum: Mikrocontroller und Digitale Elektronik STM32 M3 C8T6 - DFU über USB


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Hanna (Gast)


Lesenswert?

Hallo lieber Forumgemeinde,

nachdem ich bei meinem letzten Projekt (PC Kommunikation zum STM32 M3 
mittels USB) viele tolle Antworten erhalten habe, versuche ich es 
nochmals auf diesem Weg in der Hoffnung, dass jemand die Zeit findet mir 
zu helfen.

Ich habe die hier verbreitete Routine von "W.S." genommen, um eine USB 
Virtual Com Port Kommunikation zu meinem PC ("Visual Studio") 
herzustellen.
Ich konnte ich die HAL Library von STM Cube nicht verwenden, da mein, 
für meine Verhältnisse doch recht komplexes Programm schon annähernd 
fertig und ohne HAL-Libraries geschrieben war.
Hier bot die USB.c und USB.h von W.S. (hier im Forum viel diskutiert) 
eine wirklich tolle Alternative.

Jetzt stehe ich vor dem Problem, dass für eben dieses fertige Programm 
DFU funktionieren soll. Ich könnte über das Touch Panel gezielt in den 
Firmware Modus wechseln, also in die entsprechenden Routinen springen 
und dann im DFU Modus die HEX File über den PC übertragen (entsprechende 
PC Software ist vorhanden)

Hat irgend jemand diesbezüglich einen Hinweis oder Software für mich die 
diese Option ohne HAL ermöglicht?

Für jeden Tip bin ich dankbar...

von 23mts (Gast)


Lesenswert?

https://github.com/rogerclarkmelbourne/STM32duino-bootloader
wenn es denn unbedingt ein stm32 ohne DFU-im-ROM seien soll..

von Hanna (Gast)


Lesenswert?

Hallo 23mts,

danke, aber was mache ich jetzt mit den 100 Dateien?
Die überschneiden sich ja auch z.T mit meinen clock Einstellungen tec.

Am liebsten wäre mir lediglich eine DFU.c und EINE dfu.h mit einer 
Funktion namens "EnterDFUMode"...

von Stefan F. (Gast)


Lesenswert?

Ich würde ein neues Projekt mit der HAL erstellen und dann deine ganzen 
Files dazu kopieren. Schau mal wie einfach ein hello-World mit der HAL 
aussieht:

http://stefanfrings.de/stm32/index.html#vcphal

von Hanna (Gast)


Lesenswert?

no Chance,


ich habe canbus, USB, SPI1,SPI2 am laufen incl. diverser schneller 
Zähler, PWM und Timer.

Das alles jetzt nochmal zur HAL zu übertragen halte ich für schlichtweg 
unmöglich, da ALLE SETTINGS neu gemacht werden müssen. Eine Katastrophe. 
Das hatte ich bei der Implementierung von USB schonmal mit mäßigem 
Erfolg probiert...

von Christopher J. (christopher_j23)


Lesenswert?

Die DFU-Funktionalität packt man am besten in einen eigenen Bootloader, 
d.h. ein eigenes Programm und damit oft ein eigenes Binary, was vor 
deiner eigentlichen Applikation im Flash liegt und als erstes ausgeführt 
wird. Dieser Bootloader kann dann entweder per DFU eine neue Applikation 
ins Flash laden oder wenn das nicht gewünscht ist (meist nach einem 
Timeout) einfach die normale Applikation laden, die hinter deinem 
Bootloader liegt. DFU-Bootloader für den F1 gibt es relativ viele. Neben 
dem bereits erwähnten STM32duino/Maple Bootloader z.B. 
https://github.com/PX4/Bootloader oder 
https://github.com/paparazzi/luftboot .
Der Bootloader muss natürlich zu deiner Hardware passen, d.h. du musst 
HSE-Frequenz und USB-Reenumerationsmethode anpassen. Ggf. dann noch 
Status-LED oder was auch immer. Dann deine eigentliche Applikation an 
die neue Adresse linken und den Offset der Vektortabelle setzen (VTOR).

von Hanna (Gast)


Lesenswert?

Halli Hallo Christopher,


viiielen Dank für die ausführliche Beschriebung.

Aber leider habe ich nur ca 10% deiner Ausführungen verstanden. Ich 
arbeite seit ca 2 Jahren mit dem STM und bin froh die "normalen 
Funktionen" wie SPI, CAN, UART etc ans laufen gebracht zu haben. 
(Arbeite mit EmBitz als Programmierumgebung und Programmiere über SWD. 
Wie das flashen eines eigenen Bootloaders funktioniert weiß ich leider 
nicht. Auch nicht das Einfügen der bin Datei.
Könntest du das, auch wenn es sehr ätzend für dich sein mag, ein 
bisschen für blonde erklären?

von Blaue Pille (Gast)


Angehängte Dateien:

Lesenswert?

Der hier z.B. ist für das 2€ BluePill board..

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hanna schrieb:
> Ich konnte ich die HAL Library von STM Cube nicht verwenden, da mein,
> für meine Verhältnisse doch recht komplexes Programm schon annähernd
> fertig und ohne HAL-Libraries geschrieben war.
Wenn du das alles ohne HAL hinbekommen hast, sollte es doch auch kein 
Problem sein, das DFU auch noch ohne HAL umzusetzen? Du könntest dir 
einen eigenen Request für den Control Endpoint bauen, bei dessen Empfang 
sich das Gerät trennt und wieder als DFU-Gerät anmeldet. Alternativ 
schaltest du zwischen verschiedenen Configurations um. Wenn USB an sich 
schon läuft, ist doch der Empfang von Daten und das Schreiben in den 
Flash machbar. Siehe z.B. auch hier USB-Tutorial mit STM32 zur 
Programmierung des USB ohne HAL.

von Stefan F. (Gast)


Lesenswert?

Ich glaube, jetzt hast du ihn erschreckt.

Niklas, deine Library mag eine gute Lösung sein. Doch wenn der TO sein 
eigenes Projekt nicht in ein HAL Rahmengerüst hinein bekommen kann, dann 
kommt er mit deiner Implementierung vermutlich auch nicht zurecht.

von Stefan F. (Gast)


Lesenswert?

Hanna,
hast du schon einmal daran gedacht, einfach einen ST-Link Adapter 
zusammen mit deinem Gerät auszuliefern (evtl. fest eingebaut)?

Wenn du einen mit Firmware Version 2.1 nimmst, kann man Firmware 
Upgrades ganz ohne Zusatz-Software hochladen - einfach per Drag&Drop mit 
dem Dateimanager.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Stefan U. schrieb:
> Doch wenn der TO sein
> eigenes Projekt nicht in ein HAL Rahmengerüst hinein bekommen kann, dann
> kommt er mit deiner Implementierung vermutlich auch nicht zurecht.
Die Idee war mehr, dass man W.S.' Implementierung mithilfe der im 
Tutorial übersichtlicher dargestellten Informationen umbaut, weniger 
einfach meinen Code zu übernehmen. Es wird wohl kaum einen fertigen Code 
geben, der direkt perfekt zu W.S.' VCP-Implementation passt.

Wenn man es schafft alles ohne HAL zu machen hat man offenbar schon 
einiges an Verständnis. Die USB-Peripherie ist einfacher als z.B. die 
vom USART...

von Stefan F. (Gast)


Lesenswert?

> Die USB-Peripherie ist einfacher als z.B. die
> vom USART...

Das sehe ich anders. Meine erste Hello-World Meldung hatte ich schon 
nach wenigen Minuten gesendet. Man muss ja nicht gleich mit DMA 
anfangen.

von Hanna (Gast)


Lesenswert?

Hallo,

mit ST Adapter ausliefern ist zwar möglich, die SWD Anschlüsse sind 
jetzt im Gehäusedesign nicht nach außen geführt  :-(

Ich dachte das alles wäre einfacher. Ich verstehe hier wirklich zu 80% 
nur Bahnhof  :-(

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Stefan U. schrieb:
> Das sehe ich anders. Meine erste Hello-World Meldung hatte ich schon
> nach wenigen Minuten gesendet. Man muss ja nicht gleich mit DMA
> anfangen.
Ja so schnell geht es per USB nicht. Aber zähl mal die Seiten im 
Reference Manual für USART und die für USB, und wie viele 
Einstellungs-Register die jeweils haben...

Es sollte eigentlich ohne größere Probleme möglich sein, HAL-Code für 
einzelne Komponenten ins Projekt einzubinden. Das Einbinden der HAL 
zwingt einen nicht dazu, alles damit zu machen. Das Hauptproblem besteht 
in eventuellen Namenskonflikten mit der Unzahl an Makros in der HAL - 
aber die lassen sich durch Suchen&Ersetzen lösen. Ich habe schon HAL mit 
direkten Registerzugriffen gemischt, teilweise auch beim selben 
Peripherie-Modul.

von pegel (Gast)


Lesenswert?

Der Bootloader und die Application sind verschiedene Baustellen.
Man kann auch das HAL Beispiel für DFU_Standalone oder DFU einfach für 
den Lader verwenden und das eigene Prog auf die Adresse nach dem Lader 
linken.

von Christopher J. (christopher_j23)


Lesenswert?

Hanna schrieb:
> Wie das flashen eines eigenen Bootloaders funktioniert weiß ich leider
> nicht. Auch nicht das Einfügen der bin Datei.
> Könntest du das, auch wenn es sehr ätzend für dich sein mag, ein
> bisschen für blonde erklären?

Ich kann es mal versuchen.

Erstmal ist es wichtig zu wissen, wo überhaupt so ein Cortex-M anfängt 
zu arbeiten. Am Anfang des Flash-Speichers liegt die 
Interrupt-Vektortabelle, d.h. eine Tabelle von Funktionszeigern, welche 
auf die Funktionen zeigen, die ausgeführt werden sollen, wenn ein 
entsprechender Interrupt ausgelöst wurde. Der allererste Eintrag in 
dieser Tabelle ist jedoch genau genommen kein Funktionszeiger, sondern 
der initiale Stackpointer. Der zweite Eintrag ist dann jedoch schon 
gleich der Reset-Handler und dieser wird dann auch direkt angesprungen. 
Im Reset-Handler wird unter anderem die SystemInit-Funktion aufgerufen, 
welche typischerweise die Clock-Konfiguration vornimmt, bevor am Ende 
des Reset-Handlers die eigentliche main-Funktion angesprungen wird.

Wie schon gesagt ist die DFU-Funktionalität (in Software) in Form eines 
Bootloaders (kurz BL) ein eigenes Programm. Beim von dir eingesetzten 
Controller beginnt der Flash an der Adresse 0x8000000. Mal angenommen 
der Bootloader hat (auf volle kB aufgerundet) 8192 Byte, dann ist der 
Bereich von 0x8000000 bis 0x8001FFF mit deinem BL belegt. Wenn dein 
Controller startet, dann startet er also erstmal (über den 
Reset-Handler) in die main des BL. Typischerweise lauscht der BL dann 
für eine bestimmte Zeit ob eine Verbindung mit DFU zu Stande gekommen 
ist. Ist das der Fall, dann kann der BL deine eigentliche Applikation 
(App) per USB laden und sie in den Flash schreiben und zwar hinter den 
BL, d.h. in diesem Beispiel beginnend bei 0x8002000. Ist keine 
DFU-Verbindung zu einem PC zu Stande gekommen, sorgt der Bootloader 
dafür, dass die Applikation, welche hinter dem Bootloader liegt 
ausgeführt wird, d.h. er lädt den Stackpointer wieder auf das Ende des 
RAM und springt den Reset-Vektor an (den deiner App bei 0x8002000). Nun 
folgt wieder das Prozedere vom Anfang, d.h. der (App-)Reset-Handler ruft 
die (App-)SystemInit und (App-)main auf.

Damit deine App bei 0x8002000 überhaupt funktionieren kann muss diese 
erstmal an diese Adresse gelinkt werden (statt 0x8000000). Dazu musst du 
das Linkerscript anpassen (xyz.ld). Normalerweise steht da so etwas wie
1
MEMORY
2
{
3
    flash (rx) : ORIGIN = 0x08000000, LENGTH = 64K
4
    sram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
5
}
in dem Beispiel mit dem 8kB großen BL wird daraus dann
1
MEMORY
2
{
3
    flash (rx) : ORIGIN = 0x08002000, LENGTH = 56K
4
    sram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
5
}
d.h. statt 0x8000000 ist der "origin" nun bei 0x8002000 und die größe 
des Flashs ist von diesem Punkt betrachtet nur noch 56kB (weil ja die 
ersten 8kB vom BL belegt sind).

Jetzt hast du also den BL bei 0x8000000 und deine App bei 0x8002000 
jedoch hast du jetzt auch zwei Interrupt-Vektortabellen. Ohne weiteres 
Zutun würde jetzt ein Interrupt in deiner App den Interrupt-Handler des 
BL aufrufen, weil dessen Tabelle nunmal am Beginn des Flash liegt. Um 
das zu ändern gibt es bei den Cortex-M3 ein "Vector Table Offset 
Register". In dieses Register schreibt man dann den Wert, an welchem die 
"neue" Vektortabelle liegt, d.h. in diesem Fall 0x8002000, d.h.
1
SCB->VTOR = 0x8002000;
Das packst du in die SystemInit deiner App oder zumindest an den Anfang 
deiner (App-)main aber jedenfalls bevor irgendein Interrupt feuern kann. 
Falls du die SPL nutzt, dann gibt es in der SystemInit schon ein #define 
VECT_TAB_OFFSET, welches du nur anpassen musst (auf 0x2000 statt 0x0).

Wie man mit dem ST-Link Utility (mit dem Embitz daherkommt) eine Binary 
an eine bestimmte Adresse flashen kann weiß ich nicht, weil ich das 
Programm noch nie genutzt habe aber das ist ganz sicher möglich. Den 
Bootloader flashst du ja auch ganz normal wie jedes andere Programm auch 
an den Anfang des Flashes. Lediglich deine Applikation landet an anderer 
Stelle.

von Hmm (Gast)


Lesenswert?

Die STM32, die ich kenne, können USB-DFU ganz ohne eine einzige 
Codezeile.
Man muss nur BOOT0 auf HIGH ziehen, zack, los gehts. Man muss natürlich 
die Beschaltung haben, die im Datenblatt steht.
Der interne Bootloader macht das.

Beispielweise bei den Typen STM32F072 und STM32F303ZE ist das so. Hast 
du mal geprüft, ob deine das nicht eh auch kann?

Dann kannst du die die ganze Aktion nämlich schenken. Vor allem benötigt 
der interne Bootloader genau 0,0 Flash.

von Stefan F. (Gast)


Lesenswert?

> Man muss nur BOOT0 auf HIGH ziehen, zack, los gehts

Das trifft nur auf die größeren Modelle zu.

von Peter (Gast)


Lesenswert?

Wollte noch diesen Bootloader in die Runde werfen:
https://github.com/devanlai/dapboot
Habe keine Erfahrung damit, aber diese WebUSB-Geschichte klingt ganz 
interessant.

von Hmm (Gast)


Lesenswert?

Stefan U. schrieb:
>> Man muss nur BOOT0 auf HIGH ziehen, zack, los gehts
>
> Das trifft nur auf die größeren Modelle zu.

Mir riecht das zuviel nach Bauernregel. Und Bauernregeln haben in der 
Elektronik nichts zu suchen.

Der STM32F072 ist ein F0, d.h. von der Billigserie. Als "größeres 
Modell" würde ich den nicht sehen. Bei uns hat der ATMEGAs ersetzt. Der 
STM32F072 kann das. So ganz stimmen kann deine Aussage also nicht.

@Hanna:
Bitte nenne doch mal das konkrete Device. Dann kann man nachsehen und 
Klarheit schaffen.

von Stefan F. (Gast)


Lesenswert?

> Mir riecht das zuviel nach Bauernregel.

Du hast Recht, ich denke immer nur an die STM32F1 Serie weil ich mit 
allen anderen STM32 Serien noch nie zu tun hatte.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hmm schrieb:
> Mir riecht das zuviel nach Bauernregel. Und Bauernregeln haben in der
> Elektronik nichts zu suchen.
Der Thread-Titel klingt nach einem verunglückten Versuch, STM32F103C8T6 
zu schreiben. Der ist auch sehr verbreitet bei China-Billig-Boards. Im 
Titel des Datasheet steht "Medium Density". Im Reference Manual steht 
auf S. 60:

* In low-, medium- and high-density devices the bootoader is activated 
through the USART1 interface.
* In XL-density devices the boot loader is activated through the 
following interfaces: USART1 or USART2 (remapped).
* In connectivity line devices the boot loader can be activated through 
one of the following interfaces: USART1, USART2 (remapped), CAN2 
(remapped) or USB OTG FS in Device mode (DFU: device firmware upgrade).

Also nur USART1.

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Schau Dir den Bootloader der Blackmagic Debug Probe an 
https://github.com/blacksphere/blackmagic

von W.S. (Gast)


Lesenswert?

Hanna schrieb:
> Hat irgend jemand diesbezüglich einen Hinweis oder Software für mich die
> diese Option ohne HAL ermöglicht?

Also nochmal alles ganz in Ruhe:

1. Du hast einen STM32Fxxx (den genauen Typ hast du nicht genannt).

2. Also sieh in den Appnotes von ST zu den Bootladern (Nummern hab ich 
nicht auswendig gelernt) nach, welcher Chip welchen Bootlader 
tatsächlich enthält.

3. Wenn dein Chip einen Bootlader enthält, der mit dem USB umgehen kann, 
dann kümmere dich darum, wie dein Kunde diesen gezielt gestartet bekommt 
- und zwar auch dann, wenn beim Firmware-Update etwas schief gelaufen 
ist und die alte Firmware perdü ist.

4. Wenn dein Chip einen Bootlader enthält, der USB eben NICHT kann, 
dann gehst du anders vor:

5a) du schreibst ein Programm für den PC, das per irgendeiner sinnvollen 
Übertragung (heutzutage zumeist USB-->Seriell) mit dem Botlader umgehen 
kann. Und dieses Programm zusammenmit einem billigen Adapter USB-Seriell 
gibst du deinem Kunden.

5b) du schreibst dir einen eigenen Bootlader, der etwa so, wie 
Christopher es weiter oben bereits umrissen hat, am Anfang deines 
Flashes steht und in der Lage ist, den Rest deiner Firmware zu löschen 
und mit neuem Zeug zu beschreiben. Dessen Speicherplatz geht natürlich 
von dem Umfang des Flashes ab, so daß deine FW halt ein bissel kleiner 
sein muß - und obendrein mußt du dir Gedanken machen über die benötigten 
Interrupts, denn es wäre extrem töricht, beim FW-Update den gesamten 
Flash neu zu schreiben. Es könnte nämlich was schief gehen und dann ist 
dein Gerät erstmal gebrickt. Klaro?

Es gibt noch was zu beachten:
6. Entweder kann dein Bootlader nicht nur VCP, sondern auch 
Massenspeicher, dann hat es dein Kunde leichter, weil er bloß per 
Dateimanager oder so die FW auf diesen externen Massenspeicher kopieren 
muß. Oder dein Bootlader kann eben nur VCP, dann mußt du wieder ein 
Programm für den PC schreiben, was mit dem BL geeignet kommuniziert.

7. Gehe mal in dich und frage dich, ob es denn UNBEDINGT ein STM32 sein 
soll. Grund: Bei NXP gibt es einige µC, die einen solchen Bootlader 
drinhaben, der mit USB klarkommt und sich als Massenspeicher ausgeben 
kann. Damit hast du das Updateproblem für deinen Kunden sehr 
vereinfacht. Nen passenden USB-VCP-Treiber für den Normalbetrieb für 
z.B. die LPC13.. und LPC17.. hab ich grad vor kurzem hier irgendwo 
gepostet.

W.S.

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.