Forum: Mikrocontroller und Digitale Elektronik STM32 F411 Bootoader aus Applikation starten


von Jumper (Gast)


Lesenswert?

Hallo allerseits,

ich sitzt hier gerade vor einer STM32 Black Pill, bestückt mit einem 
STM32F411CE.

Auf diesem läuft meine leere Testapplikation, die nur auf die Eingabe 
durch einen Button wartet.
Sinn und Zweck der Übung ist es, ein Firmware Update via USB durchführen 
zu können (z.B mit dem STMCubeProgrammer) ohne auf dem PCB den BOOT0 
Jumper zu ändern oder die entsprechende Tasten zu drücken.

Wenn ich jetzt den UserButton an A0 drücke (im CODE = "KEY", so sollte 
der STM32 in den Bootloader springen, ohne das ich physisch etwas an dem 
BOOT0 Pin ändere.

Tut er aber nicht. Laut ST AN2606 ist die Adresse 0x1FFF0000, zu der man 
springen soll.

Das Beispiel habe ich hier gemobst, der Kollege scheint bei ST zu 
arbeiten.
https://stm32f4-discovery.net/2017/04/tutorial-jump-system-memory-software-stm32/
1
void JumpToBootloader(void) {
2
    void (*SysMemBootJump)(void);
3
4
    /**
5
     * Step: Set system memory address.
6
     *
7
     *       For STM32F429, system memory is on 0x1FFF 0000
8
     *       For other families, check AN2606 document table 110 with descriptions of memory addresses
9
     */
10
    volatile uint32_t addr = 0x1FFF0000;
11
12
    /**
13
     * Step: Disable RCC, set it to default (after reset) settings
14
     *       Internal clock, no PLL, etc.
15
     */
16
    HAL_RCC_DeInit();
17
18
    /**
19
     * Step: Disable systick timer and reset it to default values
20
     */
21
    SysTick->CTRL = 0;
22
    SysTick->LOAD = 0;
23
    SysTick->VAL = 0;
24
25
    /**
26
     * Step: Disable all interrupts
27
     */
28
    __disable_irq();
29
30
    /**
31
     * Step: Remap system memory to address 0x0000 0000 in address space
32
     *       For each family registers may be different.
33
     *       Check reference manual for each family.
34
     *
35
     *       For STM32F4xx, MEMRMP register in SYSCFG is used (bits[1:0])
36
     *       For STM32F0xx, CFGR1 register in SYSCFG is used (bits[1:0])
37
     *       For others, check family reference manual
38
     */
39
40
    __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();    //Call HAL macro to do this for you
41
42
    /**
43
     * Step: Set jump memory location for system memory
44
     *       Use address with 4 bytes offset which specifies jump location where program starts
45
     */
46
    SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));
47
48
    /**
49
     * Step: Set main stack pointer.
50
     *       This step must be done last otherwise local variables in this function
51
     *       don't have proper value since stack pointer is located on different position
52
     *
53
     *       Set direct address location which specifies stack pointer in SRAM location
54
     */
55
    __set_MSP(*(uint32_t *)addr);
56
57
    /**
58
     * Step: Actually call our function to jump to set location
59
     *       This will start system memory execution
60
     */
61
    SysMemBootJump();
62
63
    /**
64
     * Step: Connect USB<->UART converter to dedicated USART pins and test
65
     *       and test with bootloader works with STM32 Flash Loader Demonstrator software
66
     */
67
}

Hier noch der Aufruf aus der while Schleife raus, testweise via 
UserButton A0, in der realen Applikation komtm der Sprungbefehl via USB. 
Der Sprung in die Funktion "JumpToBootloaer" klappt, nur der Bootloader 
wird nicht aktiviert.

1
  /* USER CODE BEGIN WHILE */
2
  while (1)
3
  {
4
    /* USER CODE END WHILE */
5
6
    /* USER CODE BEGIN 3 */
7
8
    HAL_Delay(500);
9
    if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == 0)
10
    {
11
      HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, RESET);
12
      JumpToBootloader();
13
    }
14
    else
15
    {
16
      HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, SET);
17
    }
18
  }
19
  /* USER CODE END 3 */

Was mache ich falsch, was übersehe ich?

Viele Grüße

von pegel (Gast)


Lesenswert?

Hi,
habe das mit BlackPill F401 getestet.
Den Code hier "geborgt":
https://community.st.com/s/question/0D50X00009XkWH5SAN/stm32f4-jump-to-mcu-bootloader

Ist wie deiner, nur vor
1
  __set_MSP(0x20001000);
steht noch
1
   __set_PRIMASK(1);      // Disable interrupts
2
   __set_PRIMASK(0x20001000);      // Set the main stack pointer to its default value

Und funktioniert.

von Jumper (Gast)


Lesenswert?

pegel schrieb:
> Und funktioniert.

Du kannst dann mit dem CubeProgrammer via USB ein Update einspielen?
Das wäre ja genau das, was ich will.

Habe den Code getestet, den du verlinkt hast, leider ohne Erflog :(.

Aber dafür habe ich das hier gefunden, es ist eine Anfrage an ST, die 
sich genau mit dem Problem beschäftigt und die Antwort ist nicht schön:

I can reproduce your issue on a DiscoveryF4 that uses STM32F407VGT that 
has same bootloader as STM32F405.
WhatI can see is that, when jumping to bootloader from application, the 
clocks are not setup properly. The RCC is not actually using the HSE. As 
USB cannot work with HSI, the behaviour we see is normal.
Unfortunately, as supporter I don't have access to the bootloader code.
I need to ask to our R&D people. I will now send them the description of 
this issue and ask for workaround.
Now, I must warn you that there is a risk that there is no possible 
solution.
I will come back to you as soon as I get some feedback,
So we will wait and see...

Da muss ich mir wohl was anderes einfallen lassen, aber danke für deine 
Unterstützung!

VG

von pegel (Gast)


Lesenswert?

Jumper schrieb:
> Du kannst dann mit dem CubeProgrammer via USB ein Update einspielen?

Ja, kann ich.
Dein F411 BlackPill hat doch auch 25MHz HSE, oder?
Sollte also auch funktionieren.

Was mir aufgefallen ist, an 0x1FFF0000 steht 0x20002560.
Ich habe MSP auf 0x20010000 gesetzt.

von pegel (Gast)


Lesenswert?

Ach ja, nach SWD flash habe ich den abgezogen und versorge das Board nur 
noch über USB.

von pegel (Gast)


Lesenswert?

05.02.2022 23:00 habe ich leider aus dem original link kopiert.
Stackende ist nicht 0x20001000 sondern 0x20010000.

von beerwema (Gast)


Lesenswert?

Ich habe noch nie mit dem Bootloader über USB gearbeitet, aber im 
Kommentarbereich schreibt Markus Gritsch, dass (entgegen der Aussage von 
ST) für den USB-Bootloader Interrupts benötigt werden. Kommentiere mal 
die Zeile __disable_irq() aus und versuche es dann noch einmal.

pegel schrieb:
> Ist wie deiner, nur vor1  __set_MSP(0x20001000);
> steht noch1   __set_PRIMASK(1);      // Disable interrupts
> 2   __set_PRIMASK(0x20001000);      // Set the main stack pointer to its
> default value
>
> Und funktioniert.

__set_PRIMASK(1) macht genau dasselbe wie __disable_irq().In beiden 
Fällen wird das PRIMASK-Bit auf 1 gesetzt. Wenn dieses Bit gesetzt ist, 
werden alle Interrupts (mit Ausnahme von NMI und HardFault) deaktiviert. 
Der Aufruf von __disable_irq() sollte deshalb ausreichen.

Die Zeile __set_PRIMASK(0x20001000) macht für mich keinen Sinn. Das 
PRIMASK-Register beinhaltet nur ein einzelnes Bit. Laut dem Kommentar 
wird durch diese Zeile der Main Stack Pointer eingestellt, hierfür wird 
jedoch __set_MSP benötigt.

Hier mal ein Link zur CMSIS-Dokumentation, wo der Effekt von PRIMASK 
beschrieben wird: 
https://www.keil.com/pack/doc/CMSIS/Core/html/group__Core__Register__gr.html#ga70b4e1a6c1c86eb913fb9d6e8400156f

von pegel (Gast)


Lesenswert?

Für F401 BlackPill zusammen gefasst.
So funktioniert es:
1
/* USER CODE BEGIN 0 */
2
void JumpToBootloader(void) {
3
4
    void (*SysMemBootJump)(void);
5
6
    volatile uint32_t addr = 0x1FFF0000;
7
8
    HAL_RCC_DeInit();
9
10
    SysTick->CTRL = 0;
11
    SysTick->LOAD = 0;
12
    SysTick->VAL = 0;
13
14
    __disable_irq();
15
16
    SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));
17
18
    __set_PRIMASK(0x20010000); // Set the main stack pointer to its default value
19
    __set_MSP(*(uint32_t *)addr);
20
    SysMemBootJump();
21
}
22
/* USER CODE END 0 */

von Jumper (Gast)


Lesenswert?

Habs grad noch mal probiert mit meiner F411er Black Pill, leider wieder 
ohne Erfolg. Ich kann mir auch nicht erklären wieso es bei dir klappt, 
da für USB ja HSE benötigt wird, die aber beim RCC_DeInit deaktivert 
wird.
Entweder hast du ne super HSI, mit der es auch so geht aber bei mir ist 
da nichts zu holen.

Aber auf jeden Fall danke für deine Hilfe!

VG

von pegel (Gast)


Lesenswert?

Funktioniert es denn wenn Du mit Boot0 Taste den BL startest?
Erkennt CubeProg dann DFU?

von Jumper (Gast)


Lesenswert?

Ja, dass klappt bestens. Da erkennt er die BlackPill im DFU Mode und ich 
kann SW Update einspielen.

VG

von pegel (Gast)


Lesenswert?

Ich habe leider auch kein anderes Board mit DFU hier.

Vielleicht kann jemand mit einem BlackPill den Code testen?

von beerwema (Gast)


Lesenswert?

Hast du es auch mal mit auskommentiertem __disable_irq() versucht? Wie 
gesagt, im Kommentarbereich hat es einer hierdurch zum Laufen bekommen.
Wäre einen Versuch wert.

von Jumper (Gast)


Lesenswert?

beerwema schrieb:
> __disable_irq()

Ja, habe ich. Leider auch ohne Erfolg :(. Ich bin echt ratlos.

VG

von pegel (Gast)


Lesenswert?

Von einem Arif Darmawan gibt es auch noch einen Code der funktioniert.

http://disq.us/p/1wtjqn1
1
void JumpToBootloader(void) {
2
void (*SysMemBootJump)(void);
3
4
__HAL_RCC_SYSCFG_CLK_ENABLE(); //make sure syscfg clocked
5
__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); //remap system memory to address 0x0000000
6
SCB->VTOR = 0; //set vector table offset to 0
7
8
SysMemBootJump = (void (*)(void))(*((uint32_t*)(4)));
9
__set_MSP(*(uint32_t*)(0));
10
11
SysMemBootJump();
12
}

Der benutzt den syscfg clock.

von Jumper (Gast)


Lesenswert?

pegel schrieb:
> Der benutzt den syscfg clock.

Klappt leider bei mir auch nicht, aber ein USB_DeInit vor dem RCC_DeInit 
bringt das gewünschte Resultat!
1
.....
2
      volatile uint32_t addr = 0x1FFF0000;
3
      /**
4
       * Step: USB DeInit
5
       */
6
7
      MX_USB_DEVICE_DeInit();
8
9
       * Step: Disable RCC, set it to default (after reset) settings
10
       *       Internal clock, no PLL, etc.
11
       */
12
      HAL_RCC_DeInit();
13
14
15
      /**
16
       * Step: Disable systick timer and reset it to default values
17
       */
18
      SysTick->CTRL = 0;
19
      SysTick->LOAD = 0;
20
      SysTick->VAL = 0;
21
.....

Ich danke euch für die Unterstützung!

Viele Grüße

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.