0

I have seen that there are quite a few questions about jumping from an app to the ST system bootloader, for example this one. These use the method of setting the MSP and PC then doing the jump with a function pointer.

This seems to cause an issue with the system bootloader dual-bank management whereby the first jump fails and a second jump needs to be done.

My question is - would it be possible/better to use the user option bytes to jump to the bootloader instead?

Since the OB register is read during boot in the OBL phase, if we set both the "nBOOT1 bit" and "nBOOT_SEL bit" and clear the "nBOOT0 bit" then do a soft reset would this avoid the empty check weirdness and let us jump to the bootloader in one go?

2

(Just for context - this would be the first step of doing updates via CAN as the MCU in question has a CAN bootloader built in)

Thanks in advance!

  • Maybe someone who reads the question will knows the answer off the top of their head and tell you the answer straight away, but if not then these all sound like ideas that you could mock-up on an evaluation board quite quickly. – Tom V Aug 18 '22 at 07:54
  • @TomV You might be right. I now have a Nucleo-G0B1RE so I'll have a play and see what happens. I'm using the built in ST Link and STM32CubeIDE so somebody with more knowledge and better tools may still provide insight I can't glean myself. – ThatKeffordGuy Aug 18 '22 at 09:22
  • As a side note maybe consider using CAN FD as that might be more suitable for fast updates over bootloader. I've written my share of classic CAN bootloaders running at 1MHz and while they are safe and rugged, they tend to be slow. – Lundin Aug 19 '22 at 10:12
  • @Lundin I'm afraid the CAN bus bitrate is fixed to 500Kbps due to other devices on the bus. Also the factory CAN bootloader is set for 500Kbps (luckily for me). I would be happy with a working but slow bootloader though, compared to no bootloader at all :P – ThatKeffordGuy Aug 19 '22 at 17:12

1 Answers1

0

After some time tinkering with a dev board and with some help from Tilen Majerle I found that this is indeed possible and does work well.

I added the following in my main() while(1) loop so that when the blue button is pressed, the user option bits are modified and a reset is performed.

I found that we don't have to do the soft reset ourselves as the HAL_FLASH_OB_Launch() function triggers the reset for us, after which we should boot into system memory according to the reference manual page 67.

Also I found that the flash and option bytes must be unlocked before setting the option bytes, but not locked afterwards or the reset won't occur.

Here is the code to do it:

if(HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_RESET)
{
   // Basic de-bounce for testing
   HAL_Delay(100);
   while(HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_RESET)
   {
      __NOP();
   }

   // Read, modify & write user option bits
   // nBOOT1 = 1, nBOOT_SEL = 1, nBOOT0 = 0; will select system memory as boot area
   uint32_t optBits = FLASH->OPTR;
   optBits = (optBits | FLASH_OPTR_nBOOT1 | FLASH_OPTR_nBOOT_SEL);
   optBits &= ~(FLASH_OPTR_nBOOT0);

   // Unlock flash
   HAL_FLASH_Unlock();

   // Clear OPTLOCK
   HAL_FLASH_OB_Unlock();

   // Set up struct with desired bits
   FLASH_OBProgramInitTypeDef optionBytesSetting = {0};
   optionBytesSetting.OptionType = OPTIONBYTE_USER;
   optionBytesSetting.USERConfig = optBits;
   optionBytesSetting.USERType = OB_USER_nBOOT0;

   // Write Option Bytes
   HAL_FLASHEx_OBProgram(&optionBytesSetting);

   HAL_Delay(10);

   // Soft reset
   HAL_FLASH_OB_Launch();
   NVIC_SystemReset();    // is not reached
}

I verified that the flash OPTR register is modified correctly (it goes from 0xFFFFFEAA to 0xFBFFFEAA, essentially just the nBOOT0 bit is cleared as the other two bits were already set). The MCU does reset at HAL_FLASH_OB_Launch() as expected and pausing the program reveals that after reset it is running the system bootloader based on the PC address.

I also verified it using STM32CubeProgrammer which allows me to view the PC and option bytes, plus lets me set nBOOT0 back to 1 and boot the board to my app.

As for reverting the OB settings programmatically, you could either use the Write Memory command before jumping to the app, or you could use the Go command to jump to the app then modify the option bytes first thing in your app.