Forum: Mikrocontroller und Digitale Elektronik GD32F303: Bootloader der Originalfirmware für Open Source Projekt nutzen


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 Hochsitz C. (hochsitzcola)


Lesenswert?

Ich bin gerade dabei, eine Firmware für E-Bike Controller der Fa. Bafang 
zu schreiben. Über SWD geflasht funktioniert das bereits, es ist aber 
für Otto-Normal-User eine riesige Hürde, den Controller 
auseinanderzuschrauben, ggf. Vergussmasse wegzupulen um dann einen SWD 
Programmer anzuschließen. Bafang macht Firmwareupdates über CAN. Tool 
und Firmwarefiles findet man einfach im Internet.
Jetzt möchte ich es ermöglichen, die offene Firmware über diesen Weg zu 
flashen. Da die Prozessoren nicht lesegeschützt sind, kann man sie 
leicht auslesen. Die offiziellen Update-Files werden 1:1 in den 
Flash-Speicher geschrieben, da ist also zum Glück nichts verschlüsselt. 
Das Programm startet offensichtlich an Adresse 0x08004000, auch wenn 
noch 32 Bytes davor geschrieben werden, die aber wohl nur zum Abgleich 
der Hardwareversion dienen.
Ich habe mir jetzt gedacht, ich schreibe meine Firmware einfach an diese 
Startadresse und der Bootloader springt die dann schon an, leider 
rebootet der Prozessor so ständig. Im Bootloader blinkt eine LED auf dem 
Board nervös, daher kann man das schön sehen. :-(

hier gibt es den Flash-Dump des Controllers, ein Bafang-Update-File und 
natürlich mein Projekt:
https://github.com/stancecoke/BAFANG_HUB_GD32F303RCT6/commit/77195818d6f7622e33b4172cb34941b24be92ce8

Ich habe es mit einem anderen Bootloader probiert, da hat es 
funktioniert, das Verschieben der Startadresse und der Interrupt-Vektor 
Offset scheinen korrekt implementiert zu sein. Auch wenn es 
interessanterweise relevant ist, an welcher Stelle im Code der 
Interrupt-Vektor Offset gesetzt wird. Direkt als erstes nach dem int 
main(void){ geht es nicht, gleich am Anfang der SystemInit() Funktion 
geht es....

Hat jemand eine Idee, warum der Prozessor immer rebootet? Ist das eher 
ein Bug in meinem Programm, das ständig einen Reset auslöst, oder checkt 
der Bootloader irgendwie, ob eine bekannte Firmware vorliegt und wenn 
der Check fehlschlägt, wird rebootet?

Gruß
hochsitzcola
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hochsitz C. schrieb:
> Hat jemand eine Idee, warum der Prozessor immer rebootet?

Im Debugger geprüft ob dein Code (Reset_Handler) überhaupt gestartet 
wird? Erwartet der Bootloader eine Checksum (CRC)?
von Alexander (alecxs)


Lesenswert?

Genau, habe das schon irgendwo mal gelesen... hier (NationZ)

Beitrag "Re: ALLPOWERS S2000 PRO Reparaturhilfe"
von Hochsitz C. (hochsitzcola)


Lesenswert?

Niklas G. schrieb:
> Im Debugger geprüft ob dein Code (Reset_Handler) überhaupt gestartet
> wird?

Ja, der Reset Handler wird angesprungen.
https://github.com/stancecoke/BAFANG_HUB_GD32F303RCT6/blob/77195818d6f7622e33b4172cb34941b24be92ce8/gcc_startup/startup_gd32f30x_hd.S#L23

also wird es wohl nicht am Bootloader liegen, sondern an meinem Code 
liegen?
: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hochsitz C. schrieb:
> also wird es wohl nicht am Bootloader liegen, sondern an meinem Code
> liegen?

Klingt so. Ist doch super, debugge es step-by-step und du siehst wo es 
rausfliegt. Ggf. direkt am Anfang vom Reset_Handler die Interrupts 
abschalten (cpsid i), eventuell macht der Bootloader das nicht und 
irgendeine aktivierte Peripherie löst einen Interrupt aus der ins 
Nirvana geht. Auch immer das VTOR im Auge behalten.

Vielleicht ist auch Takt, Flash Wait States, ... Komisch konfiguriert 
vom Bootloader was dein Programm nicht mag.
von Hochsitz C. (hochsitzcola)


Lesenswert?

Ich werde wohl erst mal mit einem einfachen Blink-Beispiel anfangen, um 
zu schauen, ob das prinzipiell läuft, oder doch irgendwie der Bootloader 
reinspuckt.
von Hochsitz C. (hochsitzcola)


Lesenswert?

Das war leider nicht erfolgreich. Ich habe ein ganz einfaches Programm 
geflasht, daß einfach nichts tut, nur eine Endlosschleife ohne weitere 
Aktivität, auch dann rebootet der Prozessor ständig. Scheint also doch 
irgendeine Abfrage vom Bootloader zu sein. Wie kann man so etwas auf die 
Spur kommen?

Ich bekomme auch den ständigen Neustart mit dem Debugger gar nicht 
angehalten...
: Bearbeitet durch User
von Benedikt H. (hunz)


Lesenswert?

In den RCU_RSTSCK Flags prüfen, ob ein Watchdog den Reset ausgelöst hat. 
Wenn da ein Watchdog aktiviert ist muss der ge-serviced werden.
von Hochsitz C. (hochsitzcola)


Lesenswert?

Hm, der Watchdog scheint es nicht zu sein. Der Zähler WWDGT_CTL steht 
immer auf 127, was der Default-Wert zu sein scheint.

RCU_RSTSCK hat den Wert 2, also nur das Signal, daß der Takt stabil 
ist....

https://download.gigadevice.com/User_Manual/GD32F30x_User_Manual_Rev3.4.pdf
von Thomas W. (goaty)


Lesenswert?

Hardware Watchdog auf der Platine vielleicht ?
von Hochsitz C. (hochsitzcola)


Lesenswert?

Der müsste ja auch anspringen, wenn ich meine Firmware von 0x08000000 
starte, da läuft sie aber problemlos.

Ich habe auch das WWDGT_HOLD Flag im DBG_CTL0 Register gesetzt, der 
Prozessor bootet trotzdem ständig neu auf wenn der Debugger auf Pause 
steht :-(
von Benedikt H. (hunz)


Lesenswert?

Hochsitz C. schrieb:
> RCU_RSTSCK hat den Wert 2, also nur das Signal, daß der Takt stabil
> ist....

Das lässt sich imo aber nur so erklären, dass der Bootloader die Flags 
löscht. Zumindest PORRSTF sollte sonst ja gesetzt sein.
Zusätzlicher Hardware-watchdog ist bei einem E-Bike-Controller schon 
auch denkbar.
Ansonsten mal Breakpoints an den Anfang von allen Exception Handlern 
streuen und den Bootloader entry point. Mit letzterem kann man dann auch 
die ungelöschten Reset Flags in RCU_RSTSCK abgreifen.
von Hochsitz C. (hochsitzcola)


Lesenswert?

Benedikt H. schrieb:
> und den Bootloader entry point.

Da muss ich erst mal schauen, wie man das mit Open GDB macht, ich 
debugge aus dem Eclipse-basierten GDEmbeddedBuilder
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hochsitz C. schrieb:
> GDB

break *0x08....

Adresse des Reset Handler des Bootloaders angeben.
von Hochsitz C. (hochsitzcola)


Lesenswert?

Niklas G. schrieb:
> Adresse des Reset Handler des Bootloaders angeben

Wie bekomme ich die heraus?!
: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hochsitz C. schrieb:
> Wie bekomme ich die heraus?!

Steht im Interrupt-Vektor an Stelle 1, d.h. in Bytes 4-7 des binary 
Image. Little Endian natürlich.
von Hochsitz C. (hochsitzcola)


Lesenswert?

Danke, das wäre 0x080001B1, dann probiere ich das mal...
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hochsitz C. schrieb:
> 0x080001B1

Probier ggf. 0x080001B0, hab nicht im Kopf ob es mit 0x080001B1 geht 
beim GDB. Die tatsächliche Adresse ist natürlich immer gerade, das 
unterste Bit wird bei Sprungzielen (wie hier im Interrupt-Vektor) auf 1 
gesetzt und anzuzeigen dass dort Thumb-Code liegt. Beim Cortex-M eine 
gerade Adresse anzugspringen ist übrigens auch ein Grund für einen 
Crash, weil die CPU den "ARM" Code nicht unterstützt.
: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Angehängte Dateien:

Lesenswert?

Ich krieg den Breakpoint hin, aber kann in diesem Zustand den RCU_RSTSCK 
nicht lesen, in den Expressions wird der Wert nur angezeigt, wenn der 
Breakpoint im eigenen Code liegt. Das geht doch alles deutlich über das 
hinaus, was ich bisher mit Mikrocontrollern gemacht hab :-)
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hochsitz C. schrieb:
> aber kann in diesem Zustand den RCU_RSTSCK nicht lesen

Auf der GDB Konsole:
x/1xw 0x123...

Adresse des gewünschten Registers angeben.
von Thomas W. (goaty)


Lesenswert?

In der Eclipse gibt's da die Debug Console oder evtl geht's über 
Variables/Expressions
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thomas W. schrieb:
> In der Eclipse gibt's da die Debug Console oder evtl geht's über
> Variables/Expressions

Die diversen IDEs zicken da manchmal und wollen sowas nicht ausgeben, 
warum auch immer. Wenn man direkt die GDB-Befehle eingeben kann umgeht 
man das
von Hochsitz C. (hochsitzcola)


Angehängte Dateien:

Lesenswert?

für RCU_RSTSCK wird volatile uint32_t 
*)(uint32_t)((((uint32_t)0x40018000U) + 0x00009000U) + 0x24U))angezeigt, 
sollte also 0x40021024 sein.

aber das klappt irgendwie nicht...

Das ganze Debuggen aus der Kommandozeile starten würde vielleicht besser 
gehen?
: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hochsitz C. schrieb:
> aber das klappt irgendwie nicht...

Adresse ist falsch eingegeben (0x04... Statt 0x40...).

Die CPU ist nicht angehalten? Klingt als wäre es bereits 
abgestürzt/neugestartet? Passiert das so auch wenn du nur dein Programm 
"normal" geflasht hast, und genau so direkt im Reset_Habdler angehalten?

Ist die Spannungsversorgung stabil? Debuggen und auch Flashen braucht 
viel Strom, wenn die Spannung einbricht startet der Controller neu und 
der Debugger fliegt raus.

Alternativ mal nen besseren Debugadapter verwenden (J-Link oder so).
: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Lesenswert?

Der Debugger hält den Prozessor nicht an, die LED flackert immer weiter

Ich hab den Befehl im falschen Fenster eingegeben. Im Fenster "Debugger 
Console" funkioniert es, aber keine neue Erkenntnis.

x/1xw 0x40021024

0x40021024:  0x00000002

Das Debuggen meines Codes direkt ohne den Bootloader an Adresse 
0x08000000 gestartet funktioniert einwandfrei.
: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hochsitz C. schrieb:
> Der Debugger hält den Prozessor nicht an, die LED flackert immer weiter

Da wird der Bootloader wohl das Debug Interface abschalten. Du könntest 
ganz am Anfang deiner software das Interface wieder einschalten und die 
BKPT Instruktion nutzen um das Programm garantiert anzuhalten.
von Hochsitz C. (hochsitzcola)


Lesenswert?

Niklas G. schrieb:
> Da wird der Bootloader wohl das Debug Interface abschalten.

Hm, aber der Debugger kommt ja dazwischen um die Firmware zu flashen und 
die Session zu starten.

auch mit einem __asm__("BKPT #01"); ganz am Anfang meines Codes rebootet 
der Prozessor fröhlich weiter

xPSR: 0x61000000 pc: 0x080066ba msp: 0x20001354
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x080066ba msp: 0x20001354
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x080066ba msp: 0x20001354
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x080066ba msp: 0x20001354
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x080066ba msp: 0x20001354
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x080066ba msp: 0x20001354
target halted due to breakpoint, current mode: Thread

Wie würde man denn das Debug interface wieder einschalten? Ich habe da 
keinen Befehl zu gefunden :-(
: Bearbeitet durch User
von Dieter S. (ds1)


Lesenswert?

Lade doch mal den kompletten Flash-Dump mit dem "Blink" Testprogramm 
hier hoch (also alles inklusive dem Bootloader).
: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)



Lesenswert?

Bitte schön! Die erst Datei ist nur der Bootloader ...

ich habe auch noch die original Firmware drangehangen, die nicht 
rebootet, wenn man sie an die Startadresse 0x08004000 flasht.
: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hochsitz C. schrieb:
> Hm, aber der Debugger kommt ja dazwischen um die Firmware zu flashen und
> die Session zu starten.

Hochsitz C. schrieb:
> xPSR: 0x61000000 pc: 0x080066ba msp: 0x20001354
> target halted due to breakpoint, current mode: Thread
> xPSR:

Aber 0x080066ba ist doch gar nicht die Reset Handler Adresse vom 
Bootloader? Da wird nicht richtig unterbrochen. Der Stack Pointer sieht 
auch komisch aus.

Du könntest versuchen im Original Bootloader Image die erste Instruktion 
durch BKPT zu ersetzen und dann im Bootloader manuell zu "emulieren". 
Dann durchsteppen und schauen wo es neu startet.
von Dieter S. (ds1)


Lesenswert?

In einem ARM Simulator würde das Blink Programm aufgerufen, allerdings 
werden dabei eventuelle Beeinflussungen durch die Peripherie (IO) 
ignoriert.

Im Bootloader findet man eine Funktion zum Berechnen einer 16-Bit CRC 
über den Bereich ab 0x8004000. Allerdings bin ich mir nicht sicher ob 
das eventuell nur beim Laden der Firmware über den CAN-Bus benutzt wird 
und dann nach dem Schreiben des Updates nicht mehr aufgerufen wird.

Die 32 Byte vor 0x8004000 entsprechen den 32 Byte Header in der Firmware 
Update Datei, dort steht wohl auch die 16-Bit CRC (ab Offset 0x10 im 
Header), allerdings sind die Werte in der Firmware Update Datei und dann 
im Flash unterschiedlich. Auch hier ist noch nicht ganz klar warum das 
so ist.

Gibt es denn ein offizielles Tool mit dem das Firmware Update 
durchgeführt wird? Dann könnte man versuchen das "Blink" Programm in 
eine Update Datei umzuwandeln und über das Update Tool zu schreiben. Die 
CRC Berechnung für die Firmware Update Datei kann man nachvollziehen und 
eine passende CRC in den Header schreiben.

Nachtrag: Was auch noch wichtig ist: Der Bootloader startet den FWDGT 
("Free watchdog timer") den muss man dann auch bedienen.
: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Lesenswert?

Das Tool mit dem man die Firmware updaten kann, gibt es als Open Source
https://endless-sphere.com/sphere/threads/bafang-canable-pro-master-discussion.128228/

Ich hatte die zwei Bytes 16 Bytes vor dem 0x8004000 von Hand gelöscht, 
das Original Programm läuft auch ohne. Wahrscheinlich wird da nur 
während des Firmwareupdates eine Checksumme geprüft.

Wie wird denn der FWDGT bedient? Ich hatte mir nur das einzige Beispiel 
aus der GS Library angeschaut, das war nicht verdächtig... Der Zähler 
vom WWDGT_CTL steht immer auf 127

Kommt das hier her?
https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/watchdog/wdt_fwdgt_gd32.c

Das würde ja heißen, dass da ein RTOS läuft?
: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hochsitz C. schrieb:
> Das würde ja heißen, dass da ein RTOS läuft?

Möglich, wäre für den Bootloader aber recht ungewöhnlich.
von Dieter S. (ds1)


Lesenswert?

Warum braucht es ein RTOS um periodisch einen Watchdog zu triggern? Der 
Booloader läuft im Prinzip in einem Loop und ruft dann immer wieder die 
Funktion zum Triggern des Watchdog auf. Probiere das halt auch mal in 
dem "Blink" Programm (0xAAAA nach FWDGT_CTL schreiben).
von Benedikt H. (hunz)


Lesenswert?

Hochsitz C. schrieb:
> Wie wird denn der FWDGT bedient? Ich hatte mir nur das einzige Beispiel
> aus der GS Library angeschaut, das war nicht verdächtig... Der Zähler
> vom WWDGT_CTL steht immer auf 127

Schau ins & lese doch erstmal das User Manual und/oder nutze eine 
Internetsuche um ein Beispiel zu finden.
Im User Manual unter 14.1.4. steht z.B.:
1
CMD[15:0] Write only. Several different fuctions(sic!) are realized by writing these bits with different Values:
2
...
3
0xAAAA: Reload the counter
Da steht also genau was du tun musst. Lies doch erstmal die vorhandene 
Doku und probiere aus ob das klappt.

> Kommt das hier her?
> 
https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/watchdog/wdt_fwdgt_gd32.c

Warum sollte das da her kommen? Generische non-window Watchdogs sind 
überhaupt nichts exotisches und ausserhalb von Arduino-Gebastel werden 
die auch genutzt wenn man halbwegs irgendwelche Safety-Anforderungen 
hat. Da braucht man kein Zephyr um einen Watchdog zu nutzen.

Noch ein Nachtrag:
> Ich bin gerade dabei, eine Firmware für E-Bike Controller der Fa. Bafang zu
> schreiben.
Vom Thread lesen hab ich ehrlich gesagt das Gefühl, dass du da etwas 
"out of your depth" bist, zumindest aber eine nicht so flache Lernkurve 
vor dir hast 😅
: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Lesenswert?

Kleiner Teilerfolg, ich habe mir den falschen Watchdog angeschaut.
Ich hatte nur den wwdgt auf dem Schirm, genutzt wird anscheinend der 
fwdgt. Wenn ich ganz zu Anfang meines Codes den Watchdog auf deutlich 
längere Zeiten setze, kommt der Reboot deutlich später
1
fwdgt_config(65000, FWDGT_PSC_DIV256);
aber das normale Programm, in dem ich den fwdgt in der Haupschleife und 
in den Interrupts mit fwdgt_counter_reload(); zurücksetze, läuft 
trotzdem nicht.... :-(

Update: ich habe festgestellt, daß sich der Prozessor im ADCinit 
aufhängt.
Konkret in der Funktion
1
void delay_1ms(uint32_t count)
2
{
3
    delay = count;
4
5
    while(0U != delay){
6
    }
7
}
Wenn ich das while auskommentiere, läuft die Hauptschleife, es kommt 
kein Reset mehr, aber es kommen keine Interrupts.
Aber immerhin ein Fortschritt....
: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Lesenswert?

so, Problem gelöst. Anscheinend deaktiviert der Bootloader die 
Interrupts. Mit
1
    nvic_vector_table_set(NVIC_VECTTAB_FLASH, 0x4000);
2
    __enable_irq();

gleich am Anfang der main() läuft es jetzt. Vielen Dank für die 
hilfreichen Tipps!

Bleibt noch herauszufinden, wie die Checksumme für das Flashen berechnet 
wird, damit über das Bafang Canable Tool keine Fehlermeldung kommt. Das 
Flashen funktioniert zwar, schließt aber mit einer Fehlermeldung ab.
: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hochsitz C. schrieb:
> Bleibt noch herauszufinden, wie die Checksumme für das Flashen berechnet
> wird,

Wahrscheinlich nutzt der Bootloader die CRC-Peripherie des Controllers. 
Die implementiert CRC32 mit Ethernet Polynom. Leider ist nicht 
dokumentiert in welcher Reihenfolge die Bits verarbeitet werden, und ob 
Eingabe/Ausgabe invertiert ist. Das kannst du aber ziemlich simpel 
ausprobieren, da du ja ein Image mit korrekter CRC vorliegen hast.

Versuch mal:
- In C die crc32_z Funktion der zlib
- In Python binascii.crc32

Probier alle Kombinieren aus:
- Initialwert 0 oder 0xFFFFFFFF
- Endergebnis invertiert oder nicht
- Die Bits eines jeden 4-Byte-Words umgedreht

Such im Bootloader Image mal nach 0x40023000 (Bytes tauschen für Little 
Endian), das ist die Adresse der CRC-Peripherie. Da drum herum könnte 
man den Algorithmus "ablesen".
: Bearbeitet durch User
von Dieter S. (ds1)


Lesenswert?

Ich habe hier bereits beschrieben dass der Bootloader die 16-Bit CRC 
berechnet. In der Firmware Update Datei "MMG522C4814F802010.1-CR 
X10N.510.FC 2.0 20240131.bin" (von Github 
https://github.com/stancecoke/BAFANG_HUB_GD32F303RCT6) ist die CRC 
0xD20A (Datei Offset 0x10). Mit z.B. "reveng" kann man das so berechnen:

1
reveng -w 16 -p 1021 -i 0000 -c -f firmware.bin

"firmware.bin" ist dabei die eigentliche Firmware ohne den 32-Byte 
Header.
: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Lesenswert?

Prima, Danke! Dann probiere ich mal aus, ob das Firmware Update so ohne 
Fehlermeldung klappt.
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Dieter S. schrieb:
> Ich habe hier bereits beschrieben dass der Bootloader die 16-Bit CRC
> berechnet.

Huh, kurios, verschenktes Potential - weniger effizient und weniger 
sicher als die Hardware CRC32 zu nutzen.
von Hochsitz C. (hochsitzcola)


Angehängte Dateien:

Lesenswert?

Dieter S. schrieb:
> "reveng" kann man das so berechnen

Hat funktioniert! Ich bin begeistert! Danke für die Unterstützung!
von Hochsitz C. (hochsitzcola)


Angehängte Dateien:

Lesenswert?

Dieter S. schrieb:
> Mit z.B. "reveng" kann man das so berechnen:

So, nachdem die Erstellung der Binärdateien jetzt für zwei verschiedene 
Bootloader problemlos geklappt hat, bin ich jetzt mit einem dritten 
Bootloader (vom Bafang M820) konfrontiert, der in den Bytes 14 und 15 
offensichtlich eine zweite Checksumme erwartet. Die CRC16 an Bytes 16 
und 17 wird berechenet wie oben schon herausgefunden. Kann jemand die 
Bytes 14 und 15 in dieser Datei zuordnen?

https://github.com/EBiCS/BAFANG_GD32F303RCT6/raw/refs/heads/M560/documentation/Suche%20zweite%20Checksum.bin
: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Lesenswert?

von Soul E. (soul_eye)


Lesenswert?

Hochsitz C. schrieb:
> Hat sich geklärt, das ist die Anzahl der Bytes minus 2^16

Wahrscheinlich eher modulo 2^16, also die letzten vier 
Hexadezimal-Stellen.
von Hochsitz C. (hochsitzcola)


Lesenswert?

Soul E. schrieb:
> Wahrscheinlich eher modulo 2^16

Guter Hinweis, werde ich ausprobieren. Ich hatte schon befürchtet, mein 
Binary File künstlich mit 0xFFs auffüllen zu müssen, da mein 
compilierter Code gar nicht so groß ist!
von Hochsitz C. (hochsitzcola)


Lesenswert?

So, nächstes Problem mit einem Bafang Bootloader. Ich habe jetzt einen 
Mittelmotor M820 auf der Werkbank. Der M820 ist ein kleiner schlanker 
Motor. Er hat den gleichen Prozessor, einen anderen Bootloader.
Das Problem: Der Bootloader schaltet offensichtlich die Selbsthaltung 
der Spannungsversorgung wieder ab, so das diese im Code als erstes 
wieder eingeschaltet werden muß, damit der Controller nach dem Verlassen 
des Bootloaders und dem Anspringen des eigentlichen Codes (bei diesem 
Bootloader ab Adresse 0x08005000) weiterläuft. Ich habe mit trial and 
error alle verdächtigen Pins ein- und ausgeschaltet, aber keinen Erfolg 
gehabt. Ich habe mir auch alle Port-Stati angeschaut, bin damit aber 
auch nicht weiter gekommen. :-(
Gibt es eine Strategie, wie man hier systematisch Vorgehen kann?
Der Flash Dump vom Bootloader ist bei GitHub zu finden:

https://github.com/EBiCS/BAFANG_GD32F303RCT6/blob/M820/documentation/M820_nur_Bootloader.bin
: Bearbeitet durch User
von Alexander (alecxs)


Lesenswert?

Hochsitz C. schrieb:
> Gibt es eine Strategie, wie man hier systematisch Vorgehen kann?

Von der Seite der Spannungsversorgung rantasten. Ist da evtl. ein 
Hardware Watchdog im Spiel der ein PWM erwartet?

Ich werfe mal einen TLE4271 in den Raum nur damit Du Dir darunter was 
vorstellen kannst (nutze ich in einem meiner Projekte)

Beitrag "watch dog input von Spannungsregler TLE4271 im debug modus"
: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Lesenswert?

Alexander schrieb:
> Ist da evtl. ein Hardware Watchdog im Spiel der ein PWM erwartet?

Der DC/DC ist ein EG1192L, der erzeugt die 12V Zwischenspannung, die 5V 
und 3.3V machen einfache Längsregler.

https://jlcpcb.com/partdetail/EGMicro-EG1192L/C2987436

Ich werde mal versuchen, den Enable Pin vom DC/DC auf der Platine 
nachzuverfolgen
: Bearbeitet durch User
von Dieter S. (ds1)


Lesenswert?

Der Bootloader von

https://github.com/EBiCS/BAFANG_GD32F303RCT6/blob/M820/documentation/M820_nur_Bootloader.bin

benutzt auf den ersten Blick nur PB4, PB5 und PB12. Zusätzlich wird PA11 
und PA12 konfiguriert, vermutlich für den CAN-Bus.

Ich habe aber nur auf die Schnelle geschaut, daher ohne Garantie.
von Hochsitz C. (hochsitzcola)


Lesenswert?

Dieter S. schrieb:
> benutzt auf den ersten Blick nur PB4, PB5 und PB12.

Das hört Sicht erst mal logisch an. PB5 schaltet die volle Akkuspannung 
auf das Display, PB12 ist die Onboard LED.
PB4 schaltet auch bei den anderen Bootloadern bzw. der anderen Hardware 
die Versorgung ab, aber ich habe auch dort nicht herausgefunden, wie die 
Selbsthaltung eingeschaltet wird.
: Bearbeitet durch User
von Dieter S. (ds1)


Lesenswert?

PB4 wird beim Starten des Bootloaders auf 1 gesetzt, wenn der Bootloader 
aktiv war (z.B. Firmware Update) und dann nach 0x08005000 springt wird 
unter bestimmten Umständen (die Details habe ich mir noch nicht 
angeschaut) PB4 auf 0 gesetzt.

Ruft der Booloader direkt 0x08005000 auf ohne weiter Aktion dann wird 
PB4 nicht auf 0 gesetzt.

Wie schon weiter oben, ohne Garantie.
von Hochsitz C. (hochsitzcola)


Angehängte Dateien:

Lesenswert?

Dieter S. schrieb:
> PB4 wird beim Starten des Bootloaders auf 1 gesetzt

Ich habe mal in die GPIO Register geschaut, wenn der Bootloader läuft. 
Der Prozessor bleibt im Bootloader, wenn ich meine Firmware mit GDB mit 
0x5000 offset starte.
In diesem Zustand kann ich die Spannungsversorgung mit PB4 ein und 
ausschalten, wenn ich das Bit setzte/lösche. Wenn ich aber meinen Code 
direkt an die 0x080000000 schreibe und die Register exakt gleich setze, 
kommt und bleibt die Versorgungsspannung trotzdem nicht. Es scheint noch 
irgendeine andere Bedingung zu geben, damit die Versorgung anbleibt. :-(
von Dieter S. (ds1)


Lesenswert?

Die GPIO-Reihenfolge beim Starten des Bootloaders ist: PB4 auf 1, dann 
PB5 auf 0 und am Ende PB12 auf 1. Das Ganze wird unmittelbar nach dem 
Reset vom Bootloader ausgeführt.

Und, wie schon geschrieben, man kann nach dem Firmware Update den 
Bootloader wohl auch verlassen ohne dass PB4 auf 0 gesetzt wird.
: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Lesenswert?

Dieter S. schrieb:
> Die GPIO-Reihenfolge beim Starten des Bootloaders ist: PB4 auf 1, dann
> PB5 auf 0 und am Ende PB12 auf 1.

Ich habe es so implementiert, direkt nach der Initialisierung des 
Taktes.
1
    rcu_periph_clock_enable(RCU_GPIOB);
2
    gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_12);
3
    gpio_bit_set(GPIOB,GPIO_PIN_4); //set Pin4 (set by Bootloader on BL38)
4
    gpio_bit_reset(GPIOB,GPIO_PIN_5); // Display Off
5
    gpio_bit_set(GPIOB,GPIO_PIN_12); //LED off


funktioniert aber leider nicht :-(

Es muß wohl noch irgendwas anders gesetzt werden oder irgendwelche 
delays eingehalten?!
: Bearbeitet durch User
von Dieter S. (ds1)


Lesenswert?

Der Code für die GPIO Initialisierung des Bootloader steht ab 0x8000B8C. 
Die Funktion kann man direkt aufrufen (erwartet keine Parameter), 
vielleicht mal das direkte Aufrufen ausprobieren.

Und wie schon geschrieben, direkt nach dem Reset, noch bevor irgend 
etwas anderes gemacht wird.
von Hochsitz C. (hochsitzcola)


Lesenswert?

Dieter S. schrieb:
> Die Funktion kann man direkt aufrufen (erwartet keine Parameter),

Das geht ehrlich gesagt über mein Halbwissen. Von Decompilieren oder 
Deassemblieren habe ich keine Ahnung. :-(
von Dieter S. (ds1)


Lesenswert?

Sollte in C eigentlich so funktionieren (auch wenn es kein schöner Code 
ist):

1
void (*GPIO_init_bootloader)(void) = (void (*)(void))(0x8000B8C + 1);
2
GPIO_init_bootloader();

Ich denke aber dass das Problem eher daran liegt die GPIO 
Initialisierung nicht sofort nach dem Reset zu machen.
von Hochsitz C. (hochsitzcola)


Lesenswert?

Dieter S. schrieb:
> Ich denke aber dass das Problem eher daran liegt die GPIO
> Initialisierung nicht sofort nach dem Reset zu machen

Wie zwingt man denn den Compiler, die GPIO Initialisierung direkt nach 
dem Reset zu machen? Ich habe es schon direkt als ersten Befehl nach dem
1
int main(void)
2
{

probiert...
von Hochsitz C. (hochsitzcola)


Angehängte Dateien:

Lesenswert?

Alexander schrieb:
> Ist da evtl. ein
> Hardware Watchdog im Spiel der ein PWM erwartet?

Hochsitz C. schrieb:
> Ich werde mal versuchen, den Enable Pin vom DC/DC auf der Platine
> nachzuverfolgen

So, erstaunliche Erkenntnisse, aber leider keine Lösung. Mit dem 
originalen Bootloader hat PB4 kontinuierlich 3.3V, also high gesetzt.
PB8 schickt alle 250ms einen 5ms langen High Puls.

Wenn ich das in meiner Firmware nachbaue, zieht aber offensichtlich 
irgendwas die Signale von PB4 und PB8 auf ca. 0,3V runter, so daß die 
Selbsthaltung nicht funktioniert :-(

In dem rückwärts entwickelten Schaltplan fehlt also offensichtlich noch 
irgendwas essentielles ...
von Alexander (alecxs)


Lesenswert?

Hochsitz C. schrieb:
> Wenn ich das in meiner Firmware nachbaue, zieht aber offensichtlich
> irgendwas die Signale von PB4 und PB8 auf ca. 0,3V runter,

Funktioniert denn Dein Quellcode, GPIOB Clock enabled, als Output 
konfiguriert, andere Anfängerfehler?
von Hochsitz C. (hochsitzcola)


Lesenswert?

Alexander schrieb:
> Funktioniert denn Dein Quellcode, GPIOB Clock enabled, als Output
> konfiguriert, andere Anfängerfehler?

Ja, das ist alles korrekt. Den letzten Stand mit PB4 und PB8 habe ich 
noch nicht commited, aber die Intitialisierung ist OK.
Die ganze Sensorik mit Einlesen und Ausgeben von Signalen funktioniert 
auch einwandfrei.

https://github.com/EBiCS/BAFANG_GD32F303RCT6/blob/3656278eaa890d3de8aa06337c73ab4e6a93c21c/src/main.c#L578

Ich habe derzeit keine Idee, ob da analoge Hardware über irgendeine 
Zeitkonsante per Widerstand + Kondensator in die Suppe spuckt, oder doch 
noch ein Pin des Prozessors anders gesetzt werden muss :-(

ich verstehe auch ehrlich gesagt die Schaltung an PB8 nicht. Über die 
Diode kann PB8 den Enable Eingang vom DC/DC gar nicht schalten. Aber die 
Pulse würden ja dafür sprechen, irgend einen Kondensator nachzuladen...
: Bearbeitet durch User
von Dieter S. (ds1)


Lesenswert?

Falls es immer noch um diesen Bootloader geht:

https://github.com/EBiCS/BAFANG_GD32F303RCT6/blob/M820/documentation/M820_nur_Bootloader.bin

Ich sehe nicht wo dort PB8 verwendet werden soll.

Hast Du eventuell auch einen kompletten Dump, also Bootloader und die 
eigentliche Firmware? Vielleicht sieht man in der eigentlichen Firmware 
für was PB8 benutzt wird.
: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)



Lesenswert?

Dieter S. schrieb:
> Hast Du eventuell auch einen kompletten Dump

Habe ich bei GitHub hochgeladen:
https://github.com/EBiCS/BAFANG_GD32F303RCT6/blob/M820/documentation/M820.bin
: Bearbeitet durch User
von Dieter S. (ds1)


Lesenswert?

Die eigentliche Firmware macht etwas mit PB8, das könnten eventuell 
Impulse sein, die da erzeugt werden. Der Bootloader macht das aber 
relativ sicher nicht.

Bist Du sicher dass nur der Bootloader läuft und nicht die eigentliche 
Firmware wenn die Impulse an PB8 zu sehen sind?
: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Lesenswert?

Dieter S. schrieb:
> Bist Du sicher dass nur der Bootloader läuft und nicht die eigentliche
> Firmware wenn die Impulse an PB8 zu sehen sind?

Nein, die Pulse kommen erst, wenn man den on/off Button wieder los 
lässt. Kann sein, daß da der Bootloader schon abgearbeitet ist und man 
schon im Hauptprogramm unterwegs ist.
Ich könnte das noch mal prüfen, indem ich eine Debugsession mit meiner 
Firmware an Offset 0x5000 starte, bei dem Versuch bleibt der Code im 
Bootloader hängen, aber die Spannungsversorgung bleibt an.
von Dieter S. (ds1)


Lesenswert?

Laut den GPIO Registern von hier

Beitrag "Re: GD32F303: Bootloader der Originalfirmware für Open Source Projekt nutzen"

ist PB8 im Bootloader auf Input gesetzt.
von Alexander (alecxs)


Lesenswert?

D.h. die Pulse kommen von außen?
von Hochsitz C. (hochsitzcola)


Lesenswert?

Bei den anderen Bafang Controllern ist PB8 der Eingang für das z-Signal 
vom Encoder. Ob der Encoder Pulse sendet, wenn er kein Magnetfeld sieht, 
muss ich nachlesen...
von Alexander (alecxs)


Lesenswert?

Hm dann war das wohl ne Sackgasse.
von Hochsitz C. (hochsitzcola)


Lesenswert?

Will ich so noch nicht sagen, PB8 ist auf jeden Fall in der Schaltung 
zur Selbsthaltung beteiligt...

Aber eins ist mir noch eingefallen, beim Timer3 init, konfiguriere ich 
PB8 wieder als Input, das habe ich jetzt aus kommentiert, jetzt kommen 
die Pulse auch mit 3,3V, die Selbsthaltung geht aber immer noch nicht 
:-(
: Bearbeitet durch User
von Dieter S. (ds1)


Lesenswert?

Ich habe mir Deinen Code nicht angeschaut aber PB4 ist per Default 
NJTRST für JTAG und wird erst per Remap zum GPIO Pin. Der Bootloader 
macht das Remap.

Eventuell geht da ja was beim eigenen Code schief.
: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Lesenswert?

Dieter S. schrieb:
> PB4 ist per Default NJTRST für JTAG

Ah, so genau habe ich nicht ins Datenblatt geschaut. Das hört sich 
hochverdächtig an. Werde ich am Sonntag probieren!
von Hochsitz C. (hochsitzcola)


Lesenswert?

Dieter S. schrieb:
> und wird erst per Remap zum GPIO Pin

Das war tatsächlich des Rätsels Lösung! Vielen Dank!!!

Diese zwei Zeilen haben das Problem gelöst :-)
1
    rcu_periph_clock_enable(RCU_AF);
2
    gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE);
https://github.com/EBiCS/BAFANG_GD32F303RCT6/commit/1988c8839bfff3dc797a6d9ff7104f079b04ded8
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.