Ich habe hier einen E-Bike-Controller, den ich gern über UART flashen
würde. Wäre prinzipiell kein Problem, leider hat der Hersteller den
Boot0 Pin nicht auf einen Header gelegt und die Platine komplett
vergossen. Also möchte ich einen eigenen Bootloader auf die Startadresse
legen und mein eigentliches Programm an eine höhere Adresse. Dazu gibt
es einige Beispielprojekte, ich habe dieses auf den STM32F031C6
portiert:
https://github.com/ferenc-nemeth/stm32-bootloader#references
Das Blöde ist, der Bootloader frisst alleine schon knapp 8kB und der C6
hat nur 32, so daß die Luft für das eigentliche Programm knapp wird.
Kennt jemand einen geeigneten Bootloader, der weniger Speicher frisst?
Gruß
hochsitzcola
Da ist doch schon ein UART Bootloader eingebaut, man muss ihn "nur"
starten. Dein Bootloader müsste nur entscheiden, was gestartet werden
soll, Hauptprogramm oder integrierter Bootloader. Das darf maximal 42
Byte kosten.
Wenn der NRST Pin raus geführt ist, kann dein Bootloader das RCC_CSR
abfragen. Wenn PIN_RSTF nicht gesetzt ist, wird das Hauptprogramm
gestartet, sonst der UART Bootloader. Ohne Reset-Pin muss man irgendwas
anderes abfragen, aber das Prinzip bleibt gleich.
Obwohl so ein Programm nur ein paar Zeilen hat, findet man vor allem
viele misslungene Versuche. Die BootLoaderUniversalAnsprungFunktion()
hat auch einige Anläufe gebraucht, aber sie hat am Ende funktioniert:
Beitrag "Re: STM32L031K6 Sprung in Bootloader aus Applikation funktioniert nicht"
Da der integrierte Bootloader nicht verwendbar war (UART-Pins
anderweitig besetzt) musste ich einen eigenen schreiben, incl.
CRC-Berechnung, Software-UART, der nach dem Reset max. 10ms auf ein
bestimmtes Muster wartet und sonst in die Applikation springt. Das ging
mit etwas Mühe beim G030 in 2kByte, man muss halt das ganze HAL-Zeugs
weglassen ...
Bauform B. schrieb:
> Die BootLoaderUniversalAnsprungFunktion()
> hat auch einige Anläufe gebraucht
Prima, auf die Idee, per Software den nativen Bootloader anzuspringen,
bin ich gar nicht gekommen, das werde ich ausprobieren!
Gruß
hochsitzcola
Hm, der STM32F031c6 ist ein ARM Cortex M0 Prozessor, der anscheinend das
Remapping nicht beherrscht:
[q]Physical remap
Once the boot mode is selected, the application software can modify the
memory accessible
in the code area. This modification is performed by programming the
MEM_MODE bits in
the SYSCFG configuration register 1 (SYSCFG_CFGR1). Unlike Cortex® M3
and M4, the
M0 CPU does not support the vector table relocation. For application
code which is located
in a different address than 0x0800 0000, some additional code must be
added in order to be
able to serve the application interrupts. A solution is to relocate by
software the vector table
to the internal SRAM:
• Copy the vector table from the flash (mapped at the base of the
application load
address) to the base address of the SRAM at 0x2000 0000.
• Remap SRAM at address 0x0000 0000, using SYSCFG configuration register
1.
• Then once an interrupt occurs, the Cortex®-M0 processor fetches the
interrupt handler
start address from the relocated vector table in SRAM, then it jumps to
execute the
interrupt handler located in the flash. [/q]
Prinzipiell steht da ja, was man machen muß, für mich sind das
allerdings bisher böhmische Dörfer, da werde ich mich wohl tiefer
reinknien müssen.
https://community.st.com/t5/stm32-mcus-embedded-software/interrupt-vector-table-relocation-on-cortex-m0/td-p/483434
Gruß
hochsitzcola
Hochsitz C. schrieb:
> Dazu gibt es einige Beispielprojekte, ich habe dieses auf
> den STM32F031C6 portiert:
> https://github.com/ferenc-nemeth/stm32-bootloader#references
Wie weit bist du denn mit der Portierung? Im Original wird doch auch das
VTOR benutzt? Die Kopie im RAM ist für die Hardware oder auf
Assembler-Ebene kein Problem, aber wie sieht das Linker Script dafür
aus???
Welchen Compiler bzw. welche IDE benutzt du für das Hauptprogramm?
Ich glaube, es wird einfacher, wenn es nur ein Programm gibt. Dann liegt
die Vectortable ganz normal im Flash auf 0. Das normale Hauptprogramm
entscheidet dann, ob es selbst starten soll oder ob es zum eingebauten
UART-Bootloader springt.
Diese Entscheidung könnte theoretisch ein Menüpunkt in der normalen
Benutzeroberfläche sein. Aber ich würde auf jeden Fall den NRST-Pin o.ä.
abfragen. Wenn der Code dafür erstmal funktioniert, sollte der
Mechanismus doch genauso unkaputtbar sein wie ein getrennter Bootloader.
Es sind ja nur wenige Zeilen im crt0 aka reset_handler aka
startup_xxx.s.
Ich habe jetzt viel gelesen, leider funktioniert es nicht :-(
Es stolpern wohl regelmäßig Verwender der STM32F0-Prozessoren über
dieses Problem:
Zum Beispiel hier:
https://community.st.com/t5/stm32-mcus-products/stm32f072-boot-to-random-address-without-vtor/td-p/579357
Ich habe versucht die vector Tabelle an die Adresse 0x20000000 zu
schreiben: 1 | __IO uint32_t VectorTable[48] __attribute__((section(".RAMVectorTable")));
| 2 | ...
| 3 |
| 4 | void __attribute__ ((noreturn))BootLoaderUniversalAnsprungFunktion(void) // ™pegel
| 5 | {
| 6 |
| 7 |
| 8 |
| 9 | for(i = 0; i < 48; i++)
| 10 | {
| 11 | VectorTable[i] = *(__IO uint32_t*)(0x08000000 + (i<<2));
| 12 | }
| 13 | RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; //Takt aktivieren
| 14 | SYSCFG->CFGR1 &= ~SYSCFG_CFGR1_MEM_MODE_1; //Bit löschen
| 15 | SYSCFG->CFGR1 |= SYSCFG_CFGR1_MEM_MODE_0; //System Memory auf Adresse 0 remappen
| 16 | // //SysTick zurücksetzen, wird im Bootloader benötigt
| 17 | SysTick->CTRL = 0;
| 18 | SysTick->LOAD = 0;
| 19 | SysTick->VAL = 0;
| 20 |
| 21 |
| 22 | __asm__ volatile (
| 23 | " movs r0, #0\n" // Auf 0x0 befindet sich jetzt system memory
| 24 | " ldr r1, [r0, #4]\n" // Startadresse des Bootloaders
| 25 | " ldr r0, [r0, #0]\n" // sein initial Stackpointer
| 26 | " msr msp, r0\n" //
| 27 | " mov pc, r1\n" // dies ist ein jump aka branch
| 28 | );
| 29 |
| 30 | while(1);
| 31 | }
|
Geht leider nicht :-(
Ich arbeite mit der Cube IDE. Ich konnte nicht mal herausfinden wo
.RAMVectorTable definiert ist, aber er kennt es anscheinend..
Irgendwelche Ideen?
Gruß
hochsitzcola
Hochsitz C. schrieb: 1 | SYSCFG->CFGR1 &= ~SYSCFG_CFGR1_MEM_MODE_1; //Bit löschen
| 2 | SYSCFG->CFGR1 |= SYSCFG_CFGR1_MEM_MODE_0; //System Memory auf Adresse 0 remappen
|
Das ist die Einstellung für System Memory, also für den internen
Bootloader, Wenn du den starten willst, musst du nichts kopieren. Es
geht auch garnicht, weil ab 0 Flash ist (eben System Memory). Für den
Bootloader braucht man auch kein VTOR.
Für RAM ab 0 müssten beide CFGR Bits gesetzt sein. Aber dazu passt die
Flash-Adresse der Kopie nicht. 0x08000000 wäre ja dein Bootloader.
Was hast du jetzt genau vor?
> Ich arbeite mit der Cube IDE. Ich konnte nicht mal herausfinden wo
> .RAMVectorTable definiert ist, aber er kennt es anscheinend..
Nachdem der Name nur für die section gebraucht wird, muss er den nicht
kennen. Der Linker legt einfach eine section mit dem Namen an.
Bauform B. schrieb:
> Das normale Hauptprogramm
> entscheidet dann, ob es selbst starten soll oder ob es zum eingebauten
> UART-Bootloader springt.
Bauform B. schrieb:
> Was hast du jetzt genau vor?
Ich möchte einfach nur auf Befehl in den nativen Bootloader springen,
damit ich mit dem STM32CubeProgrammer über UART die Firmware updaten
kann.
Der Befehl kann zum Beispiel ein gezogener Bremhebel (GPIO Pin wird auf
0 gezogen) beim Einschalten sein.
Kann ich dann nicht einfach an die Bootloaderadresse 0x1FFFEC00
springen?!
https://www.st.com/resource/en/application_note/an2606-stm32-microcontroller-system-memory-boot-mode-stmicroelectronics.pdf
Gruß
hochsitzcola
Hochsitz C. schrieb:
> Ich möchte einfach nur auf Befehl in den nativen Bootloader springen,
Aus dem normalen Hauptprogramm heraus? Das auf 0x08000000 beginnt?
Dann befindet sich die Vectortable ja automatisch auf der richtigen
Adresse und es funktioniert ohne VTOR und du musst nichts kopieren.
> Kann ich dann nicht einfach an die Bootloaderadresse 0x1FFFEC00
> springen?!
Du musst nicht einmal die genaue Adresse kennen, die steht ja im Flash
(System Memory) und das wird mit dem SYSCFG.CFGR nach 0 umgeschaltet.
Danach steht die Adresse für den Sprung auf 0x00000004. Das kleine
Assemblerprogramm liest die und springt zum Bootloader.
Bauform B. schrieb:
> Das kleine
> Assemblerprogramm liest die und springt zum Bootloader.
Hm, funktioniert aber nicht. Wenn ich das 1 | SysTick->CTRL = 0;
| 2 | SysTick->LOAD = 0;
| 3 | SysTick->VAL = 0;
|
weglasse, bootet der Prozessor sofort neu in das normale Programm.
Mit den drei Zeilen stoppt zwar die "normale" UART Kommunikation, aber
CubeProgrammer kann sich trotzdem nicht mit dem Prozessor verbinden:
> 06:44:29 : Serial Port COM6 is successfully opened.
> 06:44:29 : Port configuration: parity = even, baudrate = 115200, data-bit= 8,
stop-bit = 1.0, flow-control = off
> 06:44:31 : Timeout error occured while waiting for acknowledgement.
> 06:44:31 : Error: Activating device: KO. Please, verify the boot mode
configuration and check the serial port configuration. Reset your device then try
again...
Gruß
hochsitzcola
Schön langsam brauchen wir jemand, der sich mit Cube auskennt...
Hochsitz C. schrieb:
> bootet der Prozessor sofort neu in das normale Programm.
Immerhin, es könnte schlimmer sein, vielleicht fehlt nur eine kleine
Kleinigkeit. Aber auch dafür wäre es seht hilfreich, wenn wir hier dein
aktuelles Programm anschauen könnten.
Besonders interessant ist natürlich deine Datei mit dem Assemblertext,
und main, und die startup Datei. In dem github-Projekt heißt die
startup/startup_stm32f100xb.s; weiß jemand, wo Cube den entsprechenden
Quelltext versteckt?
Wenn du die nicht findest: die ELF-Datei, die du zum Flashen benutzt
hast, wäre ein guter Ersatz.
Hi,
ich habe das ganze für einen STM32F072 umgesetzt, dazu hier ein paar
Code-Schnipsel, ich hoffe sie helfen weiter.
Für die Vektortabelle muss man im Linkerskript (z.B. STM32F072C8TX.ld im
CUBE-Projektverzeichnis) eine zusätzliche Section am Anfang des RAM
anlegen.
Die muss die erste RAM-Section sein, also vor der .data-Section:
Das muss sowohl im (Boot)Loader als auch in der eigentlichen Applikation
gemacht werden, damit die Vektortabelle dort jeweils an der richtigen
Stelle liegt.
1 | /* zus?tzliche Section f?r Vektortabelle im RAM: */
| 2 |
| 3 | .isr_vector_ram (NOLOAD):
| 4 | {
| 5 | . = ALIGN(4);
| 6 | KEEP(*(.isr_vector_ram)) /* Startup code */
| 7 | . = ALIGN(4);
| 8 | } >RAM
|
Die Vektortabelle dann folgendermaßen im RAM definieren (main.c): 1 | #define VECTOR_TABLE_SRAM
| 2 | #define VECTOR_TABLE_LENGTH 48 // Länge der Interrupt-Vektortabelle, siehe Startup-Code.
| 3 | #define ST_BOOTLOADER_STARTADRESSE 0x1FFFC800 // siehe Datenblatt
| 4 | #define BOOTLOADER_FLASH_SIZE_KB 12 // für Bootloader reservierter Speicher. Muss ein Vielfaches der Pagegröße sein!
| 5 |
| 6 | #define VECTOR_TABLE_ARRAY_SIZE (VECTOR_TABLE_LENGTH+1) // hinter Vektortabelle noch 1 Platz mehr für Variable für Bootloader-Request
| 7 |
| 8 | // Muss mit Angaben im Linkerskript der Applikation übereinstimmen. Linkerskript des Bootloaders idealerweise auch anpassen, damit es keine Überlappung geben kann.
| 9 | #define APPLIKATION_STARTADRESSE (0x08000000 + BOOTLOADER_FLASH_SIZE_KB * 1024) // Platz für Bootloader freihalten
| 10 |
| 11 | #ifdef VECTOR_TABLE_SRAM
| 12 | // Die Interrupt-Vektortabelle im RAM. Dort müssen nachher die Vektoren der Applikation hinkopiert werden
| 13 | volatile uint32_t VectorTable[VECTOR_TABLE_ARRAY_SIZE] __attribute__((section(".isr_vector_ram"))) = {0}; //
| 14 | #endif
|
Ich habe hinter der Vektortabelle noch einen zusätzlichen Eintrag
freigelassen, damit kann das Hauptprogramm dort eine Magic Number
reinschreiben und anschließend einen RESET auslösen. Der Bootloader kann
dann auf diese Nummer prüfen und ggf. den ST-Bootloader starten. So kann
der Bootloader indirekt aus dem Hauptprogramm gestartet werden
1 | static uint32_t check_backup_reg_bootloader()
| 2 | {
| 3 | uint32_t ret = 0;
| 4 | uint32_t bkup_reg;
| 5 |
| 6 | // reservierte RAM-Variable laden
| 7 | bkup_reg = VectorTable[VECTOR_TABLE_ARRAY_SIZE-1];
| 8 |
| 9 | if (bkup_reg == MAGIC_NUMBER_START_ST_BOOTLOADER) // ST-Bootloader starten, vorher aber Nummber löschen, sonst Endlosschleife.
| 10 | {
| 11 | ret = 1;
| 12 | }
| 13 | else if (bkup_reg == MAGIC_NUMBER_START_CUSTOM_BOOTLOADER) // custom Bootloader bleibt aktiv, Timeout deaktivieren
| 14 | {
| 15 | ret = 2;
| 16 | }
| 17 | else if (bkup_reg == MAGIC_NUMBER_START_APP)
| 18 | {
| 19 | ret = 3;
| 20 | }
| 21 |
| 22 | VectorTable[VECTOR_TABLE_ARRAY_SIZE-1] = 0; // Nummer löschen
| 23 | __DSB(); // memory barrier, damit Schreibzugriff garantiert zu Ende ist
| 24 |
| 25 | return ret;
| 26 | }
|
Das Anspringen von ST-Bootloader oder Hauptprogramm geht folgendermaßen:
1 | int main(void)
| 2 | {
| 3 | uint32_t check;
| 4 | check = check_backup_reg_bootloader(); // Backupregister prüfen, ggf. Bootloader starten
| 5 | if (check == 1)
| 6 | {
| 7 | // ST-Bootloader
| 8 | start_app_or_bootloader(0);
| 9 | }
| 10 | else if (check == 2)
| 11 | {
| 12 | // Applikation
| 13 | start_app_or_bootloader(1);
| 14 | }
| 15 |
| 16 | while(1)
| 17 | {
| 18 | }
| 19 | }
| 20 |
| 21 | // 0 = Bootloader, 1 = Applikation
| 22 | static void start_app_or_bootloader(uint32_t mode)
| 23 | {
| 24 | void (*JumpAddress)(void);
| 25 |
| 26 | // Startadresse der Applikation bzw des Bootloaders: dort beginnt die Vektortabelle
| 27 | volatile uint32_t addr;
| 28 | if (mode == 0)
| 29 | {
| 30 | addr = ST_BOOTLOADER_STARTADRESSE; // Adresse des SystemFLASH Bootloaders
| 31 | }
| 32 | else
| 33 | {
| 34 | addr = APPLIKATION_STARTADRESSE;
| 35 | }
| 36 |
| 37 | if (mode == 0) // Bootloader --> System Memory auf 0 remappen
| 38 | {
| 39 | __DSB(); // memory access barrier
| 40 | __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); // remap system memory to address 0:
| 41 | __DSB();
| 42 | }
| 43 | else // Applikation: Vektortabelle der Applikation dorthin kopieren und dann SRAM auf 0 remappen
| 44 | {
| 45 | #ifdef VECTOR_TABLE_SRAM
| 46 | // Vektortabelle ins RAM kopieren
| 47 | uint32_t* app_ptr = (uint32_t*)((uint32_t)APPLIKATION_STARTADRESSE);
| 48 | for (uint32_t i=0; i<VECTOR_TABLE_LENGTH; i++)
| 49 | {
| 50 | VectorTable[i] = app_ptr[i];
| 51 | }
| 52 | __DSB(); // memory access barrier
| 53 | __HAL_SYSCFG_REMAPMEMORY_SRAM(); // remap SRAM to address 0:
| 54 | __DSB();
| 55 | #else
| 56 | // TODO: VTOR setzen für Prozessoren die es haben
| 57 | #error "VTOR noch nicht implementiert!"
| 58 | #endif
| 59 | }
| 60 |
| 61 | // Sprungadresse ist zweiter Eintrag der Vektortabelle (erster Eintrag ist Stackpointer)
| 62 | // Use address with 4 bytes offset which specifies jump location where program starts
| 63 | JumpAddress = (void (*)(void)) (*((uint32_t *)(addr + 4)));
| 64 |
| 65 | /**
| 66 | * Set main stack pointer.
| 67 | * This step must be done last otherwise local variables in this function
| 68 | * don't have proper value since stack pointer is located on different position
| 69 | *
| 70 | * Set direct address location which specifies stack pointer in SRAM location
| 71 | */
| 72 | __set_MSP(*(uint32_t *)addr);
| 73 | __DSB();
| 74 |
| 75 | /**
| 76 | * Call our function to jump to set location
| 77 | * This will start system memory execution
| 78 | */
| 79 | JumpAddress();
| 80 |
| 81 | // sollte hier nie ankommen
| 82 | while(1) HAL_NVIC_SystemReset();
| 83 | }
|
Bauform B. schrieb:
> Aber auch dafür wäre es seht hilfreich, wenn wir hier dein aktuelles
> Programm anschauen könnten.
Das Projekt findest du hier:
https://github.com/stancecoke/Lishui9FET
Allerdings habe ich die nicht funktionierende Funktion noch nicht
commited. Kann ich heute Abend mal machen und auch die elf Datei mit
hochladen.
@emigraen: das muss ich erst mal sacken lassen 😁 Ich bin gestern über
ähnliche Tipps gestolpert, aber mir fehlt da offensichtlich eine Menge
Hintergrundwissen. Ich will ja gar keinen custom Bootloader verwenden,
wenn es auch mit dem nativen geht...
Gruß
hochsitzcola
Hochsitz C. schrieb:
> Ich will ja gar keinen custom Bootloader verwenden,
> wenn es auch mit dem nativen geht...
Musst du auch nicht, dann vereinfacht es die Sache deutlich.
Dann brauchst du die Vektortabelle im RAM garnicht, sondern musst
einfach direkt aus deinem Hauptprogramm meine Beispielfunktion aufrufen:
1 | start_app_or_bootloader(0);
|
Die entsprechenden Code-Teile zum Umkopieren der Tabelle kannst du dort
dann rauslöschen und das Linkerskript muss dann auch nicht angepasst
werden.
Der Vorteil an einem kleinen Custom-Bootloader wäre, dass er prüfen
könnte ob überhaupt eine Applikation geflasht ist und dann im Notfall
immer den ST-Bootloader anspringt. (Er braucht gar keine eigene
Flash-Funktion haben, sondern springt nur weiter entweder zur
Applikation oder zum ST-Bootloader.)
Chris R. schrieb:
> Die entsprechenden Code-Teile zum Umkopieren der Tabelle kannst du dort
> dann rauslöschen und das Linkerskript muss dann auch nicht angepasst
> werden
Das habe ich jetzt auch gemacht, natürlich die Bootloaderadresse
angepasst, aber das geht auch nicht :-(
Wenn ich im Debugmode die Routine anspringe kommt diese Meldung:
>Break at address "0x2050604" with no debug information available, or outside of
program code.
Ich habe mit den verschiedensten Kombinationen der vorgeschlagenen
Lösungen rum gespielt, darum nicht über die vielen auskommentierten
Zeilen wundern.
https://github.com/stancecoke/Lishui9FET/commit/541ecbb84eb2d1370c0b425124a7ff16c917790c
Die elf-Datei liegt auch im Repo:
https://github.com/stancecoke/Lishui9FET/blob/main/Documentation/Lishui9FET.elf
Gruß
hochsitzcola
Bauform B. schrieb:
> Ich glaube, es wird einfacher, wenn es nur ein Programm gibt. Dann liegt
> die Vectortable ganz normal im Flash auf 0. Das normale Hauptprogramm
> entscheidet dann, ob es selbst starten soll oder ob es zum eingebauten
> UART-Bootloader springt.
Das ist genau das Gegenteil von einem guten Bootloader. Von so einem
sollte das zu ladende "Hauptprogramm" überhaupt nichts wissen müssen
(allerhöchstens, dass es etwas weniger Flash zur Verfügung hat als es
"normal" für das Target ist, damit beim Linken eine entsprechende
Fehlermeldung geworfen werden kann).
Und wenn es nötig ist, das aus dem "Hauptprogramm" den Bootloader zu
starten, dann sollte es reichen, den µC einfach von dort aus zu zu
resetten. Wenn die Architektur keine Softwarelösung dafür hergibt (eher
die Ausnahme), dann halt notfalls über einen GPIO an RESET (mit
entsprechender Hilfsschaltung dazwischen, sprich: Monoflop).
Hochsitz C. schrieb:
> Das habe ich jetzt auch gemacht, natürlich die Bootloaderadresse
> angepasst, aber das geht auch nicht :-(
Es fehlt (in deinem auskommentierten Code) mindestens das Remapping des
System Memory auf Adresse 0 wie in meinem Code oben geschrieben: 1 | __DSB(); // memory access barrier
| 2 | __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); // remap system memory to address 0:
| 3 | __DSB();
|
Ohne das funktioniert es nicht.
Es kann auch potenziell problematisch sein (sollte mit dem Fehler wsl.
nichts zu tun haben), wenn Teile der HW initialisiert sind wenn man zum
ST-Bootloader springt. Man weiß nicht, wie genau er initialisiert, also
sollte vorher alles zurückgesetzt sein. Am einfachsten lässt sich das
sicherstellen, wenn man vor dem Init von Hardware zum Bootloader
springt.
Ich mache das so, dass ich eben die Magic Number nach der Vektortabelle
ganz am Anfang der main() prüfe und ggf. springe, noch bevor Takt usw.
initialisiert wird. Dann kann man nichts vergessen zu de-initialisieren.
Versuch mal testweise, ganz am Anfang der main() zu springen, um solche
Probleme auszuschließen.
Hochsitz C. schrieb:
> Break at address "0x2050604" with no debug information available, or
> outside of
> program code.
0x2050604 ist wohl tatsächlich ungültiger Speicherbereich, siehe Memory
Map im Datenblatt. Also springst du irgendwo falsch hin.
Mit Assembler kann ich leider nicht weiterhelfen, aber im C-Code kannst
du ja die Sprungadresse (Variable JumpAddress) im Debugger anschauen,
bevor der Sprung ausgeführt wird. Dass nach dem Sprung das Debuggen
nicht mehr geht, sollte normal sein, da dann ja der ST-Bootloader
ausgeführt wird.
https://www.st.com/resource/en/reference_manual/rm0091-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
Nachtrag: Denkbar wäre auch, dass noch Interrupts aktiviert sind, wenn
du nicht alles sauber deinitialisierst. Wenn in der Vektortabelle des
ST-Bootloaders dann kein gültiger Handler eingetragen ist, springt er
evtl. in ungültigen Bereich. Also noch ein Argument, möglichst früh im
Programm dorthin zu springen. (Oder einmal den Umweg über RESET zu
gehen.)
Chris R. schrieb:
> du ja die Sprungadresse (Variable JumpAddress) im Debugger anschauen
Die Adresse passt und das remap system memory to address 0 hatte ich
auch gemacht. Interrupts deaktivieren auch. Direkt am Anfang der main()
auch nicht. Ich glaub ich brauch erst mal ne Pause :-)
Vielleicht probiere ich dann erst mal den BOOT0 PIN auf GND zu legen, ob
der STCube Programmer dann die Verbindung hinbekommt...
Gruß
hochsitzcola
An den Boot0 Pin ist nicht ranzukommen :-(
Gibt es eigentlich einen Timeout, wie lange der Bootloader auf den
Programmer wartet? Und was hat es mit dem Magic Number auf sich, von dem
immer die Rede ist?!
Gruß
hochsitzcola
Vielleicht bringt mich das auf die richtige Spur?!
https://community.st.com/t5/stm32-mcus/how-to-jump-to-system-bootloader-from-application-code-on-stm32/ta-p/49424
Lässt mich dieser empty-check ggf. stolpern:
>except for the STM32F0 and some STM32L0 that have an empty check mechanism in
place.
Im reference manual steht:
>Empty check
On STM32F04x and STM32F09x devices only, internal empty check flag is
implemented to
allow easy programming of virgin devices by the boot loader
Damit sollte der STM32F031C6 diesen empty check nicht haben?!
Edit:
ich habe das o.g. How-To so eingebaut, siehe letztes commit, wenn ich
jetzt im Debug-Mode den Prozessor anhalte, tummelt er sich irgendwo im
Adressbereich 0x1fffed72, 0x1fffed68, 0x1fffed7c, sollte also eigentlich
passen. Aber warum reagiert er nicht auf den Verbindungsversuch vom Cube
Programmer?!
Hochsitz C. schrieb:
> Vielleicht bringt mich das auf die richtige Spur?!
Da geht's doch darum, wie man den Bootloader aus dem laufenden
Hauptprogramm heraus aufruft. Das meiste davon ist überflüssig, wenn das
Hauptprogramm garnicht läuft. Also wenn du diese Abfrage noch vor main()
einbaust:
Hochsitz C. schrieb:
> Der Befehl kann zum Beispiel ein gezogener Bremhebel (GPIO Pin wird auf
> 0 gezogen) beim Einschalten sein.
Hochsitz C. schrieb:
> Gibt es eigentlich einen Timeout, wie lange der Bootloader auf den
> Programmer wartet?
Der eingebaute wartet beliebig lange, bis zum nächsten Reset.
> Und was hat es mit dem Magic Number auf sich, von dem
> immer die Rede ist?!
Der entscheidende Punkt: beim Start des Bootloaders müssen die
Hardware-Register so aussehen, wie nach einem Reset. Dafür gibt es drei
Möglichkeiten:
a) man startet den Bootloader so früh wie möglich, bevor irgendwelche
Hardware initialisiert wird
b) man setzt alle einzeln zurück
c) das Hauptprogramm erzeugt selbst einen Hardware-Reset per AIRCR.
Nachdem das Programm wieder startet, muss es erkennen, ob das ein
normaler Reset war oder der selbst erzeugte. Dafür kann man eine Magic
Number ins RAM oder in ein Backup-Register schreiben. Wenn da die
magische Bitkombination steht, wird zum Bootloader gesprungen, sonst zum
Hauptprogramm. Man kann stattdessen auch das RCC.CSR Register auswerten.
Das ist genau dafür da, um verschiedene Reset-Auslöser zu unterscheiden.
Bauform B. schrieb:
> Also wenn du diese Abfrage noch vor main()
> einbaust:
habe ich ja auch probiert, vor jeder Hardwareinitialisierung zu
springen:
https://github.com/stancecoke/Lishui9FET/blob/92edff1ca3bb2cc05348b4964c219251c542f4e0/Core/Src/main.c#L163
der Prozessor tummelt sich ja anscheinend auch im richtigen
Adressbereich. Nur er mag sich nicht mit dem Cube Programmer verbinden
:-(
Gruß
hochsitzcola
Hm, habe noch mal viel gelesen und probiert, hat immer noch nicht
geklappt. Ich werde das Ganze als nächste an einem Bluepill-Board
ausprobieren um zu schauen, ob es ggf. an einer Eigenart des STM32F031
liegt...
Gruß
hochsitzcola
Aaaahhh, ich bin so ein Depp! Die Hardware, die ich nutze, hat UART1 auf
PB6/PB7 remapped. Dann kann das natürlich nicht gehen mit dem nativen
Bootloader. :-)
Gruß
hochsitzcola
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|