cancel
Showing results for 
Search instead for 
Did you mean: 

Active BOOT0 by software on STM32L432

SBaro.11
Associate III

Hi all,

I'm creating a personnal board with an STM32L432 mcu, but I have a question about BOOT0. I'd like my futur to give the possibility at my futur clients to update the board. To do thaht I know I can use DFU mode and to enter to this mode BOOT0 should be high.

But I don't want to add a specific button beceause I don't have place and the board wouldn't be accessible so is it possible to active BOOT0 by software for example before reset the board ?

1 ACCEPTED SOLUTION

Accepted Solutions
NandanV
Associate III

If you just need to jump to bootloader consider the below snippet from this post.

inline void launchBootloader(void)
{
    typedef void (*pFunction)(void);
    pFunction JumpToApplication;
    //    uint32_t JumpAddress;
    HAL_RCC_DeInit();
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;
    /* Step: Disable all interrupts */
    __disable_irq();/* ARM Cortex-M Programming Guide to Memory Barrier Instructions.*/
    __DSB();
    __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();/* Remap is bot visible at once. Execute some 
unrelated command! */
    __DSB();
    __ISB();
    JumpToApplication = (void (*)(void))(*((uint32_t*)(SYSTEM_MEMORY
                                                       + 4)));/* Initialize user application's 
Stack Pointer */
    __set_MSP(*(__IO uint32_t*)SYSTEM_MEMORY);
    JumpToApplication();
}

View solution in original post

7 REPLIES 7
NandanV
Associate III

If you just need to jump to bootloader consider the below snippet from this post.

inline void launchBootloader(void)
{
    typedef void (*pFunction)(void);
    pFunction JumpToApplication;
    //    uint32_t JumpAddress;
    HAL_RCC_DeInit();
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;
    /* Step: Disable all interrupts */
    __disable_irq();/* ARM Cortex-M Programming Guide to Memory Barrier Instructions.*/
    __DSB();
    __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();/* Remap is bot visible at once. Execute some 
unrelated command! */
    __DSB();
    __ISB();
    JumpToApplication = (void (*)(void))(*((uint32_t*)(SYSTEM_MEMORY
                                                       + 4)));/* Initialize user application's 
Stack Pointer */
    __set_MSP(*(__IO uint32_t*)SYSTEM_MEMORY);
    JumpToApplication();
}

Wolfgang Pupp
Associate III

Generally, its possible to just enter the bootloader directly.

There are a few caveats though:

  • You should get everything (peripherals, clocks) into default state before you do this to avoid problems.
  • Active external peripherals might prevent the builtin bootloader from doing what you want: E.g., you might be wanting to use the builtin bootloader over the USB interface, but your device is going to be receiving CAN messages at all times, which can trick the bootloader into expecting the firmware update over the CAN interface instead of USB and that'll be a problem. This obviously depends completely on your usecase.

To do this, just do whatever the actual core does when the bootloader starts:

  1. Reset jour peripherals and clocks to default state (make especially sure that are NOT going to be incoming interrupts during the next steps)
  2. Map the system memory to the 0x0000 - Address range (you can probably skip this step)
  3. Then just set the stackpointer and jump, see snippet below (that's for GCC/CubeIDE):

static __attribute__((noreturn)) inline void set_stackpointer_and_branch(
		uint32_t sp, uint32_t exec_addr)
{
	__asm__ volatile ("MSR msp, %0\n"
			"BX %1\n"
			: : "r" (sp),
			"r" (exec_addr));
	__builtin_unreachable();
}
 
void bootBuiltinUpdater(void)
{
	// De-Init peripherals and clocks here
 
	// System memory begin
	uint32_t *baseaddr = (uint32_t*) 0x1FFF0000;
	set_stackpointer_and_branch(baseaddr[0], baseaddr[1]);
}

This is untested, but it should work-- I have used the very same method on a number of STM controllers.

I would still advice against this in general; providing your own Updater will afford you more freedom and is more robust especially with heavy peripheral use.

Uwe Bonnes
Principal II

Best is, have code early in startup that checks for some magic and trigger reset from your programm. That way, everything is reset.

Disabling the IRQ has consequences..

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Which consequences @Community member​ ?

The most obvious one being them not being enabled again...

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
YBCH_.1
Associate II

Hi,

I need help with this topic.

I tried to implement everything suggested here but it's not working.

I'm working with STM32L47 and I'm trying to add the option to update the FW via DFU without toggling BOOT0.

I tried to make the Stackpointer jump to the same address the BOOT0 as it's sent by the BOOT0 press (0x1FFF0000) but the only thing I get is a fast close on open of the USB port (as seen by Device manger of Windows) and then the Stackpointer is going back to address 0x08000000 and the application code is being executed.

My sequence is as follows:

  1. Run main() as usual until CB_BootLoaderCheck()
  2. CB_BootLoaderCheck() checks for a dedicated magic word in flash and decides if to jump or not.
  3. If magic word does not exist, the application code runs normally.
  4. Via CLI I'm running DFU mode command which writes the magic word in flash and execute reset NVIC_SystemReset().
  5. After the reset, the magic word does exist and CB_JumpToBootLoader() is called and supposed to send the Stackpointer to the desire address (0x1FFF0000)
int main(void)
 
{
 
 /* USER CODE BEGIN 1 */
 
 /* USER CODE END 1 */
 
 /* MCU Configuration--------------------------------------------------------*/
 
 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
 
 HAL_Init();
 
 /* USER CODE BEGIN Init */
 
 /* USER CODE END Init */
 
 /* Configure the system clock */
 
 SystemClock_Config();
 
 /* USER CODE BEGIN SysInit */
 
 CB_BootLoaderCheck();
void CB_BootLoaderCheck(void)
{
	if((*(__IO long *) (BK_SRAM_BASE + 0)) == SRAM_FLAG_SET_VAL)
	{
		(*(__IO long *) (BK_SRAM_BASE + 0)) = SRAM_FLAG_CLEAR_VAL; // Reset memory, if desired.
		CB_JumpToBootLoader();
	}
}
 
 
 
void CB_JumpToBootLoader(void)
{
	volatile uint32_t SYSTEM_MEMORY = 0x1FFF0000;
	typedef void (*pFunction)(void);
	pFunction JumpToApplication;
	//    uint32_t JumpAddress;
	HAL_RCC_DeInit();
	SysTick->CTRL = 0;
	SysTick->LOAD = 0;
	SysTick->VAL = 0;
	/* Step: Disable all interrupts */
	//__disable_irq();/* ARM Cortex-M Programming Guide to Memory Barrier Instructions.*/
	__DSB();
	__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();/* Remap is bot visible at once. Execute some
	unrelated command! */
	__DSB();
	__ISB();
	JumpToApplication = (void (*)(void))(*((uint32_t*)(SYSTEM_MEMORY
													   + 4)));/* Initialize user application's
	Stack Pointer */
	__set_MSP(*(__IO uint32_t*)SYSTEM_MEMORY);
	    JumpToApplication();
}
case DFU_MODE:
		printf("Logger__r: insert MCU into bootloader mode\r\n");
		CB_SetDFU_FlagSRAM();
		Logger_ResetMCU();
		break;

The problem is that it's not working. The Stackpointer keeps returning to the application code.

What am I doing wrong?