Go to bootloader in STM32 using application using Boot 0 and Boot 1 Pins in boot mode from custom flash

I have a requirement for updating the firmware. I plan to use the USB DFU class. But the command for updating the firmware will come from the PC application in my case. so I need to switch to the bootloader, which is in System memory. As I initially run the application, so it loads from User flash. I have Boot0 and Boot 1 pins configured for User flash. Since the DFU loader is located in System flash, now for these settings Boot0 and Boot1 you need to change the settings. Is there a way like Boot 0, and the Boot 1 settings remain the same as user flash, and in the application we go to system memory?

+5
source share
4 answers

Boot0 / 1 bottles are only selected at processor startup to check whether to load user code from memory or load the bootloader. The state of these contacts does not affect the bootloader after that.

I ran into a similar query and found two ways to boot the bootloader on demand.

First, you can "JUMP" from custom code to the loader. For example, you can go to the bootloader when you click a button.

But ... this is much more complicated than a simple JUMP instruction: some registers and devices must be reconfigured correctly to work with the bootloader, you must make sure that IRQ will not start during JUMP, ... In fact, you must reconfigure the processor, as if it was only started after reset. You can find information about this technique: in this video from ST .

I managed to do such things in the STM32F1xx project. However, in a more complex project based on STM32F4, this will become really difficult ... I would have to stop all devices (timers, communication interface, ADC, DAC, ...), to ensure that IRQ will not start, reconfigure all hours , ...

Instead, I decided to implement this second solution: when I want to go to the bootloader, I write a byte in one of the backup registers, and then issue a soft-reset. Then, when the processor restarts, at the very beginning of the program it will read this register. This register contains a value indicating that it should be rebooted in bootloader mode. Then the transition to the bootloader is much easier, as presented in the youtube video .

+16
source

To switch to a new image is not so difficult. I did it successfully as part of a self test.

  • You need to pass the address where your second image (the loader in this case) is in the flash memory for the linker when you link the second image. Instead, you can use code with an independent position, but it has other problems.
  • You should obviously run the second image program, starting at the same address as you provided the linker.
  • Define the transition function: void (* const jumpFunction)(void) = (void (*)(void))(APPLICATION_ADDRESS + 4ul + 1ul); An offset of four means going through the stack pointer, an offset of one for the Thumbmode.
  • Specify a new starting stack pointer: __set_MSP((uint32_t)*APPLICATION_ADDRESS) , the first four bytes from the second image will contain the new stack pointer.
  • Go by calling the function: jumpFunction();
  • In the second program, the default initialization will try to set the offset of the vector table (VTOR) SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; . You must change this to SCB->VTOR = APPLICATION_ADDRESS | VECT_TAB_OFFSET; SCB->VTOR = APPLICATION_ADDRESS | VECT_TAB_OFFSET;

I have a POST program in FLASH_BASE that uses the associated SRAM for its stack, and then runs memory checks on the main SRAM, authenticates the main program, and then moves on to the main program.

I can still debug the main program, as if nothing had changed.

NB! I just recently did it myself. There are a few things I need to check. One of the problems is what will happen to the reset software. If you call from the second program, then, in my opinion, it will be executed in the reset routine of the second program, and not the first.

+3
source

MicroPython has a pyb.bootloader () function that is used to enter DFU mode.

C code that implements this can be found in the source repository .

I made extensive use of the STM32F4 version (#else block ) and the F7 variant several times (although it was at that time).

I would put the body of the function here, since the above links may become obsolete if this file changes:

 // Activate the bootloader without BOOT* pins. STATIC NORETURN mp_obj_t machine_bootloader(void) { pyb_usb_dev_deinit(); storage_flush(); HAL_RCC_DeInit(); HAL_DeInit(); #if defined(MCU_SERIES_F7) // arm-none-eabi-gcc 4.9.0 does not correctly inline this // MSP function, so we write it out explicitly here. //__set_MSP(*((uint32_t*) 0x1FF00000)); __ASM volatile ("movw r3, #0x0000\nmovt r3, #0x1FF0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp"); ((void (*)(void)) *((uint32_t*) 0x1FF00004))(); #else __HAL_REMAPMEMORY_SYSTEMFLASH(); // arm-none-eabi-gcc 4.9.0 does not correctly inline this // MSP function, so we write it out explicitly here. //__set_MSP(*((uint32_t*) 0x00000000)); __ASM volatile ("movs r3, #0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp"); ((void (*)(void)) *((uint32_t*) 0x00000004))(); #endif while (1); } 

The pyb_usb_dev_deinit () function disables USB, and storage_flush writes data to the cached file system. HAL functions come from HAL STM32Cube files.

If you are using a newer version of dfu-util (IIRC 0.8 or later), you can specify the -s :leave command line -s :leave so that your recently flashed program runs at the end of the blink. Combining with the above, I go through the flash / test cycles without touching the board, and use only BOOT0 / RESET when the firmware works hard.

There is also python DFU flasher called pydfu.py: https://github.com/micropython/micropython/blob/master/tools/pydfu.py , which is slightly faster than dfu-util.

+3
source

You can simulate the bootloader state. Connect the capacitor and parallel resistor from the BOOT pin to ground. Connect another loose pin to the BOOT pin. The capacitor can be charged with an external pin and discharged by a resistor. I do not remember the exact values ​​that you can calculate / experiment (the time constant of the RC circuit is important).

Charge this capacitor by setting the external contact to 1, execute the reset software on NVIC_SystemReset . After reset, it will launch the bootloader. A resistor connected to the capacitor will discharge. After updating the firmware, you can reset the device and it will work in your application.

We use this in some applications, and it works well. The disadvantage of this solution is that you need an external circuit, but it is very easy to implement and universal for all STM32 devices.

+2
source

Source: https://habr.com/ru/post/1206730/


All Articles