Forum: Mikrocontroller und Digitale Elektronik STM32G0 Bootloader antwortet nicht


von Moot S. (mootseeker)


Angehängte Dateien:

Lesenswert?

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.

von Monk (roehrmond)


Lesenswert?

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.

: Bearbeitet durch User
von Moot S. (mootseeker)


Lesenswert?

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!

von Gerd E. (robberknight)


Lesenswert?

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.

von Moot S. (mootseeker)


Angehängte Dateien:

Lesenswert?

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?

von Malte _. (malte) Benutzerseite


Lesenswert?

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
}

von Moot S. (mootseeker)


Lesenswert?

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
}

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

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

von Moot S. (mootseeker)


Lesenswert?

Μα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.

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

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.

von Malte _. (malte) Benutzerseite


Lesenswert?

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.

von Moot S. (mootseeker)


Lesenswert?

Μα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?

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


Lesenswert?

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
von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

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
von Moot S. (mootseeker)


Lesenswert?

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?

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Kommst du denn per Bootpin in den Bootloader? Pattern 11 (AN2606) 
erfüllt? Adresse sollte stimmen.

Matthias

von Malte _. (malte) Benutzerseite


Lesenswert?

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.

von Bauform B. (bauformb)


Lesenswert?

Ä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.

von Uwe Bonnes (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.