Hallo Zusammen, ich versuche aktuell bei einem STM32G031 über den internen Bootloader von ST eine Firmware hochzuladen. Das Problem ist, dass wenn ich in meiner Applikation zum Bootloader springe erhalte ich auf meine Anfrage (0x7F) keine Antwort. Bevor ich euch meinen Code zeige und wir an der falschen stelle suchen, ist meine Frage: In der AN2606 steht, dass der interne Bootloader USART1 & USART2 verwenden kann, werden dann auch beide Schnittstellen initialisiert und warten auf die Anfrage der Software? Wenn nicht kann man das einstellen? Ich kommuniziere über die Schnittstelle USART1 und sende den Befehl 0x7F damit sollte der STM die Baudrate automatisch einstellen und eine Antwort senden. Wenn ich das mit dem Logic Analyzer anschaue (Bild im Anhang), dann sehe ich meinen Befehl erhalte vom STM aber keine Antwort.
Moot S. schrieb: > werden dann auch beide Schnittstellen > initialisiert und warten auf die Anfrage der Software? Ja werden sie. Damit das funktioniert, muss du an der nicht genutzen Schnittstelle für einen sauberen Ruhepegel sorgen, z.B. mit Pull-Up Widerständen, falls sich das nicht schon von selbst durch die Schaltung ergibt.
Steve van de Grens schrieb: > Damit das funktioniert, muss du an der nicht genutzen > Schnittstelle für einen sauberen Ruhepegel sorgen, z.B. mit Pull-Up > Widerständen, falls sich das nicht schon von selbst durch die Schaltung > ergibt. Die USART2 Schnittstelle ist am ST-Link V3 als Debug-Schnittstelle angeschlossen (ohne Pull-up). Ich werde mal versuchen diese einzubauen und melde mich dann wieder!
Moot S. schrieb: > Das Problem ist, dass wenn ich in > meiner Applikation zum Bootloader springe erhalte ich auf meine Anfrage > (0x7F) keine Antwort. Du lässt also den STM32 in Deine Applikation starten, entscheidest dort daß Du zum Bootloader willst und springst dann explizit dort hin? Das geht definitiv, man muss dabei aber sehr vorsichtig sein in welchem Zustand man den Controller an den Bootloader übergibt. Ich mache das bei einem STM32F072 erfolgreich so, aber es hat mich ein paar Anläufe gekostet bis ich die Initialisierung richtig hinbekommen hab. Ich würde daher erst mal probieren den Controller von sich aus direkt in den Bootloader starten zu lassen und zu sehen ob dann die Kommunikation funktioniert. Dann kannst Du das Problem besser eingrenzen. Ich glaube beim STM32G031 muss man erst spezielle Config-Flags setzen damit er ein BOOT-Pin auswertet, bei den F0 war das extern BOOT-Pin immer aktiv.
Gerd E. schrieb: > Du lässt also den STM32 in Deine Applikation starten, entscheidest dort > daß Du zum Bootloader willst und springst dann explizit dort hin? Genau ich Starte in meine Applikation. In der Applikation wartet der Kontroller auf einen Befehl den ich über die USART-Schnittstelle sende (Der Befehl ist z.B. "Firmware Update"). Empfange ich diesen Befehl Schalte ich alle Peripherien des Kontrollers aus und Springe in den Bootloader. Gerd E. schrieb: > Ich glaube > beim STM32G031 muss man erst spezielle Config-Flags setzen damit er ein > BOOT-Pin auswertet, bei den F0 war das extern BOOT-Pin immer aktiv. Wenn ich das richtig verstanden habe ist der Boot0 Pin beim G0 auf dem gleichen Pin wie der SWCLK Pin. Ich habe an diesem Pin mit einer Lötbrücke und einem Pull-down Widerstand schon mal vorgesehen, dass man den Pin manuell runterziehen könnte (Siehe Anhang). Wenn ich aus der Applikation in den Bootloader springe ist dann der Zustand des Boot0 Pins nicht egal? Ich dachte das ist nur relevant beim Aufstarten?
Moot S. schrieb: > Wenn ich aus der Applikation in den Bootloader springe ist dann der > Zustand des Boot0 Pins nicht egal? Ich dachte das ist nur relevant beim > Aufstarten? Ich würde erwarten, dass der Pin per Software im Bootloader augewertet wird. Im Zweifelsfall also nicht. Was mir noch bei diversen Beispielen wie man aus einer Applikation in den Bootloader spring (zb: https://stm32f4-discovery.net/2017/04/tutorial-jump-system-memory-software-stm32/ ) aufgefallen ist: Sie funktionieren nicht mit der Optimierung Os! Warum? Weil der Compiler dann zwischen __set_msp und Bootloader Anspringen den Stack nochmal bearbeitet (Ja das darf er) und dass dann schief geht. System Takt richtig eingestellt? Meine Routine für einen STM32L452 sieht wie folgt aus:
1 | void McuStartOtherProgram(void * startAddress, bool ledSignalling) { |
2 | volatile uint32_t * pStackTop = (uint32_t *)(startAddress); |
3 | volatile uint32_t * pProgramStart = (uint32_t *)(startAddress + 0x4); |
4 | if (ledSignalling) { |
5 | Led2Green(); |
6 | }
|
7 | __HAL_FLASH_INSTRUCTION_CACHE_DISABLE(); |
8 | __HAL_FLASH_DATA_CACHE_DISABLE(); |
9 | __HAL_FLASH_PREFETCH_BUFFER_DISABLE(); |
10 | McuClockToMsi(4000000, RCC_HCLK_DIV1); |
11 | HAL_RCC_DeInit(); |
12 | SysTick->CTRL = 0; |
13 | SysTick->LOAD = 0; |
14 | SysTick->VAL = 0; |
15 | __disable_irq(); |
16 | __DSB(); |
17 | __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); |
18 | __DSB(); |
19 | __ISB(); |
20 | __HAL_RCC_SPI1_FORCE_RESET(); |
21 | __HAL_RCC_SPI2_FORCE_RESET(); |
22 | __HAL_RCC_SPI3_FORCE_RESET(); |
23 | __HAL_RCC_USART1_FORCE_RESET(); |
24 | __HAL_RCC_USART2_FORCE_RESET(); |
25 | __HAL_RCC_USART3_FORCE_RESET(); |
26 | __HAL_RCC_USB_FORCE_RESET(); |
27 | __HAL_RCC_SPI1_RELEASE_RESET(); |
28 | __HAL_RCC_SPI2_RELEASE_RESET(); |
29 | __HAL_RCC_SPI3_RELEASE_RESET(); |
30 | __HAL_RCC_USART1_RELEASE_RESET(); |
31 | __HAL_RCC_USART2_RELEASE_RESET(); |
32 | __HAL_RCC_USART3_RELEASE_RESET(); |
33 | __HAL_RCC_USB_RELEASE_RESET(); |
34 | //Is there a generic maximum interrupt number defined somewhere?
|
35 | for (uint32_t i = 0; i <= I2C4_ER_IRQn; i++) { |
36 | NVIC_DisableIRQ(i); |
37 | NVIC_ClearPendingIRQ(i); |
38 | }
|
39 | __enable_irq(); //actually, the system seems to start with enabled interrupts |
40 | if (ledSignalling) { |
41 | Led1Off(); |
42 | }
|
43 | /* Writing the stack change as C code is a bad idea, because the compiler
|
44 | can insert stack changeing code before the function call. And in fact, it
|
45 | does with some optimization. So
|
46 | __set_MSP(*pStackTop);
|
47 | ptrFunction_t * pDfu = (ptrFunction_t *)(*pProgramStart);
|
48 | pDfu();
|
49 | would work with -Og optimization, but not with -Os optimization.
|
50 | Instead we use two commands of assembly, where the compiler can't add code
|
51 | inbetween.
|
52 | */
|
53 | asm("msr msp, %[newStack]\n bx %[newProg]" |
54 | : : [newStack]"r"(*pStackTop), [newProg]"r"(*pProgramStart)); |
55 | }
|
Malte _. schrieb: > Sie funktionieren nicht mit der Optimierung Os! Warum? > Weil der Compiler dann zwischen __set_msp und Bootloader Anspringen den > Stack nochmal bearbeitet (Ja das darf er) und dass dann schief geht. Optimierung habe ich auf -O0 eingestellt. Liegt somit nicht am Kompiler. Malte _. schrieb: > System Takt richtig eingestellt? Wo finde ich den wie ich den einstellen muss? Ich habe in meiner applikation nur die RCC ausgeschalten bzw. deinitialisiert. Da ich mit der LL-Library arbeite sieht meine Funktion wie folgt aus:
1 | #define STM32G031_SYSTEM_MEM_ADDR ( 0x1FFF0000 )
|
2 | |
3 | typedef void (*pFunction)(void); |
4 | |
5 | //..................................................................
|
6 | /**
|
7 | * @brief Firmware Update
|
8 | * @note Update myself :)
|
9 | * @param none
|
10 | * @retval none
|
11 | */
|
12 | void fw_update( void ) |
13 | {
|
14 | // Local variables
|
15 | uint32_t JumpAddress; |
16 | |
17 | pFunction Jump_To_Application; |
18 | |
19 | // ---------- Start Firmware Update ----------
|
20 | // Deinit peripherals
|
21 | usart_deinit(USART1); |
22 | usart_deinit(USART2); |
23 | spi_deinit( SPI1 ); |
24 | LL_CRC_DeInit(CRC); |
25 | |
26 | // Fully reset RCC to power-up state
|
27 | LL_RCC_DeInit(); |
28 | |
29 | // Disable interrupt requests from periperals
|
30 | NVIC_DisableIRQ(SysTick_IRQn); |
31 | NVIC_DisableIRQ(USART1_IRQn); |
32 | NVIC_DisableIRQ(USART2_IRQn); |
33 | NVIC_DisableIRQ(SPI1_IRQn); |
34 | |
35 | // Zero out SysTick
|
36 | SysTick->CTRL = 0; |
37 | SysTick->LOAD = 0; |
38 | SysTick->VAL = 0; |
39 | |
40 | // Disable global interrupts
|
41 | __disable_irq(); |
42 | |
43 | // Remap memory to system flash
|
44 | SYSCFG->CFGR1 = SYSCFG_CFGR1_MEM_MODE_0; |
45 | |
46 | jumpAddress = *(__IO uint32_t *) (STM32G031_SYSTEM_MEM_ADDR + 4); |
47 | JumpToApplication = (pFunction) jumpAddress; |
48 | |
49 | // Prepare MCU to jump
|
50 | __set_MSP(*(__IO uint32_t*) STM32G031_SYSTEM_MEM_ADDR); |
51 | |
52 | //Jump to application
|
53 | JumpToApplication(); |
54 | |
55 | //Never reach this
|
56 | __builtin_unreachable( ); |
57 | }
|
Hi Ich mach das auch. Das einfachste ist du setzt dir einen Marker der den Reset übersteht (z.B. an einer reservierten Adresse im RAM oder in einem RTC Register). Dann löst du einen Reset aus (z.B. per Watchdog) und schaust direkt nach dem Start (vor jeder Initialisierung) nach ob der Reset vom Watchdog kommt und ob dein Marker entsprechend gesetzt ist und springst dann den internen Bootloader an. Dann kannst du nichts vergessen was für den Bootloader rückgängig gemacht werden muss. Wenn du generierten Code verwendest musst du halt aufpassen das da nicht vorher schon was läuft wie z.B. ein clock init. Matthias
Μαtthias W. schrieb: > direkt nach dem Start (vor jeder Initialisierung) Ich hab zum Testen den Sprung direkt nach dem Aufstarten gemacht, aber ich erhalte keine Antwort vom Bootloader. Was ich auch noch gemacht habe, ist den Jumper zwischen dem Boot0 Widerstand den dem SWCLK zu schliessen, das hat aber auch keinen einfluss auf die Antwort.
Welche Baudrate verwendest du denn? Beim L431 hatte ich die Erfahrung gemacht das mehr als 19200 nicht stabil funktioniert hat. Siehe auch meine Supportanfrage https://community.st.com/s/question/0D53W00000bdFpMSAU/serial-bootloader-baudrate-mismatch Auf den Supportcase denn ich zusätzlich eröffnet hatte kam leider nichts brauchbares zurück.
Bei deinem Code fallen mir zwei Dinge auf:
1 | NVIC_DisableIRQ(SysTick_IRQn); |
Entfernen, da: https://community.arm.com/support-forums/f/armds-forum/2367/nvic_xxx-function-is-not-doing-the-inteded-job Deaktivieren tust du den danach ja schon mit Systick->CTRL = 0. Ich bin da auch drauf reingefallen.
1 | __disable_irq(); |
Ich musste die IRQs aktivieren, bevor ich zum Bootloader gesprungen bin, damit es klappt. Zu den Takt: Das müsste irgendwo im Datenblatt stehen, mit welchem Standardtakt der hochstartet. Bei meinem halt der MSI, ich vermute bei allen ohne MSI ist es der HSI ohne PLL.
Μαtthias W. schrieb: > Welche Baudrate verwendest du denn? Ich verwende 115200 Baud, sollte ja Grundsätzlich kein Problem sein, nach AN2602 geht auch noch schneller. Malte _. schrieb: > Ich musste die IRQs aktivieren, bevor ich zum Bootloader gesprungen > bin, damit es klappt. Ja kann ich auch mal versuchen, aber warum ist das so? Man sollte sie ja eigentlich ausschalten damit man fokussiert and den richtigen Punkt springen kann?
Vergesst die ganze De/Re-Initialisierung, setzt einen Merker, macht eine Reset und schaut beim Start auf den Merker. Einen Reset koennt Ihr auch direkt ausloesen NVIC_SystemReset(), es braucht nicht den Watchdog oder aehnliches.
:
Bearbeitet durch User
NVIC_SystemReset() ist nicht bei jeder CortexM Implementierung gleichwertig mit einem Watchdog Reset. Z.T. wird Peripherie durch den nvic reset nicht zurückgesetzt. Deswegen hab ich mir den Weg über den Watchdog angewöhnt. Kann aber nicht mehr sagen ob da die stm32 auch dazu gehören. Moot S. schrieb: > Ich verwende 115200 Baud, sollte ja Grundsätzlich kein Problem sein, > nach AN2602 geht auch noch schneller. Ich kann aus Erfahrung mit ein paar tausend l431 sagen daß es nicht so ist :-). Der scheint die Baudrate nicht exakt genug auszumessen. Evtl. ist das auch Chargenabhängig da die Prototypen das Verhalten nicht zeigten. Ein f091 auf dem gleichen Board ist auch nicht betroffen. Mann musste das ROM Mal durch den disassambler jagen. Allein die Zeit mir fehlt. AN5067 ist auch ganz spannend da der interne bootloader mit dem HSI/MSI läuft. Matthias
:
Bearbeitet durch User
Uwe B. schrieb: > setzt einen Merker, macht eine > Reset und schaut beim Start auf den Merker. Einen Reset koennt Ihr auch > direkt ausloesen NVIC_SystemReset(), es braucht nicht den Watchdog oder > aehnliches. Wie schon geschrieben, habe ich das auch schon versucht: Moot S. schrieb: > Ich hab zum Testen den Sprung direkt nach dem Aufstarten gemacht, aber > ich erhalte keine Antwort vom Bootloader. funktioniert nicht. Μαtthias W. schrieb: > AN5067 ist auch ganz spannend da der interne bootloader mit dem > HSI/MSI läuft. Ja sieht spannend aus, aber meine Applikation funktioniert ja auch mit der HSI Clock und 115200 Baud, warum sollte dann der Bootloader nicht funktionieren? Könnte es sein, dass die Sprungadresse falsch ist, ich verwende für den G031 0x1FFF0000?
Kommst du denn per Bootpin in den Bootloader? Pattern 11 (AN2606) erfüllt? Adresse sollte stimmen. Matthias
Du müsstest doch herausfinden Moot S. schrieb: > Ja kann ich auch mal versuchen, aber warum ist das so? Man sollte sie ja > eigentlich ausschalten damit man fokussiert and den richtigen Punkt > springen kann? Das Warum muss dir ST beantworten :) Was du noch überprüfen kannst ist, ob du ihn überhaupt richtig anspringst. Ich hab die Erfahrung gemacht, dass der manche der SPI Schnittstellen auf Slave schaltet und dann den MISO Pin auf High zieht. (Recht lästig wenn man das in der Schaltung nicht beachtet). Aber hier solltest du das messen können.
Ältere Versionen des Bootloaders hatten ein kleines Problem, AN2606 schreibt:
1 | Known limitations: |
2 | Issue is seen for all packages (except SO8, no PA3 pin), |
3 | if PA3 stays to low level, system is stuck in the USART2 |
4 | detection sequence and no other interface is detected. |
Μαtthias W. schrieb: > Welche Baudrate verwendest du denn? Beim L431 hatte ich die Erfahrung > gemacht das mehr als 19200 nicht stabil funktioniert hat. Moot S. schrieb: > Ich verwende 115200 Baud, sollte ja Grundsätzlich kein Problem sein, > nach AN2602 geht auch noch schneller. Μαtthias W. schrieb: > Der scheint die Baudrate nicht exakt genug auszumessen. Der G031 läuft mit 24MHz und benutzt den SYSTICK für die Autobaud-Mimik. Bei höheren Baudraten und/oder niedrigerem Takt wird die Auflösung der Messung immer schlechter. Du solltest es auf jeden Fall mit 9600 probieren.
Mαtthias W. schrieb: > NVIC_SystemReset() ist nicht bei jeder CortexM Implementierung > gleichwertig mit einem Watchdog Reset. Dann ist die Implemetierung krank. Es gibt teilweise auch einen Core Reset mittels des SCS_DEMCR_VC_CORERESET Bits. Aber NVIC_SystemReset() macht laut Definition einen vollstaendigen Reset und bei STM32 ist es auch so.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.