Skip to main content
Explorer II
December 8, 2025
Question

custom bootloader on STM32F446

  • December 8, 2025
  • 2 replies
  • 132 views

Hi everybody,

I'm trying to make a bootloader in my STM32F446. The aim if this one is the possibility to update the firmware but with keeping the previous one in case of issue. So, I'll have two slots for firmware.

For now, I have the following sectors in my flash :

BOOTLOADER : 0x0800 0000 -> 0x0800BFFF (it only uses sector 0 & 1 for code, so I use last word of sector 2 (0x0800 BFFE & 0x0800 BFFF) to write a "magic word" which gives me the information, if we're currently running on SLOT 1 or 2).

SLOT 1 : 0x0800 C000 -> 0x0800 3FFF

SLOT 2 : 0x0804 0000 -> 0x0807 FFFF

My FW is running on slot 1. It receives the order to update, so it restarts, checks on which slot the new FM must be copied, writes into the flash, and starts again on new slot (and this is done at each update, so FM is running on SLOT1/2 alternatively).

Everything works well, except the last step, it always run on slot 1 (even if all the code has been written in the slot 2).

In the two first 32 bytes (0x0800 0000), I have the stack pointer and the program counter. One thing, I have noticed is that the PC is always the same (0x08010AC1), but it must be changed if the FW runs on slot2, but I cannot change this one when I made the *.hex* (and I don't want) because I'll never know in advance where the FW is running.

I think I misunderstand something, if you can help me on this point.

Thank you in advance,

 

 

    This topic has been closed for replies.

    2 replies

    Technical Moderator
    December 9, 2025

    Hello @fab04 

    When the bootloader needs to start the firmware from slot 2, it should perform the following steps:

    1. Reads the vector table from the base address of slot 2 (0x08040000).
    2. Sets the Main Stack Pointer (MSP) to the value found at the start of slot 2, ensuring the application has the correct stack configuration.
    3. Jumps to the reset handler (the second word in the vector table) in slot 2, effectively starting the application as if it had booted from its original address.
    fab04Author
    Explorer II
    December 9, 2025

    Hello Saket_Om,

    Thank you for your answer.

    What I've done is the following :

    void
    jump_to_app(uint32_t addr_app) {
    	uint32_t sp = *(__IO uint32_t*)addr_app;			/*<! Main Stack Pointer */
    	uint32_t pc = *(__IO uint32_t*)(addr_app + 4);		/*<! Program Counter */
    
    	// Vérifier que SP et PC sont plausibles
    	if ((sp < SRAM_BASE) || (sp > (SRAM_BASE + SRAM_SIZE)) ||
    		(pc < FLASH_BASE) || (pc > (FLASH_BASE + FLASH_SIZE))) {
    		// Erreur : slot invalide
    		while(1); // Bloquer ou signaler erreur
    	}
    
    	__disable_irq();
    
    	SCB->CPACR |= (0xF << 20); // CP10 & CP11 full access
    	//__DSB();
    	//__ISB();
    
    	FPU->FPCCR &= ~(FPU_FPCCR_ASPEN_Msk | FPU_FPCCR_LSPEN_Msk);
    	//__DSB();
    	//__ISB();
    
     /* désactiver UART + DMA */
     //HAL_UART_DMAStop(&huart1);
     HAL_DMA_DeInit(&hdma_usart1_rx);
     HAL_UART_DeInit(&huart1);
     HAL_RCC_DeInit();
     HAL_DeInit();
    
     SysTick->CTRL = 0;
     SysTick->LOAD = 0;
     SysTick->VAL = 0;
    
     /* Remap du vecteur d'interruptions */
     SCB->VTOR = addr_app;
    
     for (int i = 0; i < 8; i++) {
    	 NVIC->ICER[i] = 0xFFFFFFFF; // 240 IRQ max
    	 NVIC->ICPR[i] = 0xFFFFFFFF; // clear pending flags
     }
    
     /* Charger le MSP de l'application */
     __set_MSP(sp);
    
     __enable_irq();
    
     __DSB();
     __ISB();
    
     pFunction app_main = (pFunction)(pc | 1U);
     app_main();
    
     while(1) { __NOP(); } // ne devrait jamais revenir
    }

    When I put my first version of firmware , I've the following data :

    0x0800 C000 : 2002 0000 (address of MSP)

    0x0800 C004 : 08024AC1 (Program Counter)

    When I put my new version of FM (I just change a colour of LED), I've the following data :

    0x0800 C000 : 2002 0000

    0x0800 C004 : 08024AC1

    In the two cases, I've the same data at these addresses, so I think it's normal that it jumps only on slot 1. I think the PC address must be changed, but I think it must be done dynamically, because when I compile my firmware, I don't know in which slot it will put.

     

    Graduate
    December 9, 2025

    Read the content of this file, esp. the comments:

    https://github.com/gbm-ii/STM32_Inc/blob/main/cm_boot.h

    Your code will probably fail with -O0. Use -O1 or above.