Custom Boot Loader [1]

In previous post, we already know about how to config BOOT pins to boot System Boot Loader, and see how it Upgrade Firmware. In this post, I will show you how to build your own custom boot loader from scratch.

1. The idea about custom boot loader

In some microcontrollers there are multiple program memories: boot ROM and user flash memory. The boot loaders are often pre-programmed in the boot ROM by the microcontroller manufacturer.

When the Power On Reset occurs:

  • the first execute boot loader code in the boot ROM
  • then VTOR is programmed to point to 0x0 address of User Flash memory by default
  • then final branching to the user application in the flash.

From here, if we want something more specific in booting phase like upgrade firmware or security, we need to build our own boot loader. This boot loader will be similar to boot loader in System Memory, but it is built by yourself and placed in Flash Memory region.

To do that thing, we need two parts in Flash Memory Area:

  • The custom boot loader to do some some tasks as upgrade image in user application (like System Memory does) or security purpose.
  • The user application placed in Flash Memory.

Finally we have the booting scenario:

Note that the VTOR value of Custom Boot Loader will point to start address of Flash, and the VTOR value of User Application will point to APPLICATION_ADDRESS where it start to flashed into memory.

Next step I will show you how to build the custom bootloader and the user application to work with it.

2. Implement custom bootloader

I choose the scenario for custom bootloader:

  • Booting after POR
  • Blink Orange LED for 3 times
  • Jump to application area if the image is valid
  • If not the Orange LED will continue blinking

First copy the GPIO_HAL project to other folder, you can also create a similar project. Now we have a blinking orange LED.

This is important part, I will show you how the boot loader jump to user application.

  • First you need define application address:
#define APPLICATION_ADDRESS 		0x08008000

The reason of choosing it because start address of Flash is 0x08000000, and the size of custom boot loader is smaller than 0x8000.

  • The supper main loop should be modified to check condition to jump to user application
  • Now to check the image is flashed in APPLICATION_ADDRESS is valid or not, we need to understand its content
    • The start address of APPLICATION_ADDRESS is start address of User Application Vector Table, so its value is the address of Main Stack Pointer (MSP)
    • The Main Stack Pointer should be placed in SRAM, so its value should be in range 0x20000000 – 0x2001FFFF, because the SRAM size of STM32F411xE is 128Kb equal 0x20000 and the start adress of SRAM in memory map is 0x20000000
    • So (MSP address) & 0x2FFE0000 should be equal 0x20000000, if not, it ran out of range 0x20000000 – 0x2001FFFF
		if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
		{
                }	
  • Now if the image in APPLICATION_ADDRESS is correct, we need to get the Reset_Handler() function address
  • Define function pointer and variable to get Reset_Handler function
/* Define function pointer to point to Reset_Handler */
typedef  void (*pFunction)(void);
pFunction Jump_To_Application;

/* Define variable to save address of Reset_Handler */
uint32_t JumpAddress;

  • Get Reset_Handler() function address from vector table and assign it to function pointer
/* The next address in vector table is the Reset_Handler function defined in vector table of application */
JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
Jump_To_Application = (pFunction) JumpAddress;
  • Now we need to initialize the MSP then run the Reset_Handler() of User Application
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
/* Run the Reset_Handler and function of application */
Jump_To_Application();
  • And the final main function for the application
int main(void)
{
    int blink_time = 0;
    /* Init to use HAL Library */
    HAL_Init();

    /* Init LED */
    LED_Init();

    while(1)
    {
        for(blink_time = 0; blink_time < 6; blink_time ++)
        {
            /* Toggle LED1_PIN */
            HAL_GPIO_TogglePin(LED_PORT, LED1_PIN);
            /* Delay 1000 ms */
            HAL_Delay(1000);
        }
       
        /* An application is flashed already in APPLICATION_ADDRESS by using Keil and IROM config */
		/* Check value at APPLICATION_ADDRESS: it is __init_sp() so its value should be in SRAM range */ 
		if (((*(__IO uint32_t*)APPLICATION_ADDRESS) &amp; 0x2FFE0000 ) == 0x20000000)
		{ 
			/* Jump to user application */
			/* The next address in vector table is the Reset_Handler function defined in vector table of application */
			JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
			Jump_To_Application = (pFunction) JumpAddress;
			/* Initialize user application's Stack Pointer */
			__set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
			/* Run the Reset_Handler and function of application */
			Jump_To_Application();
		}	
    }
    return 0;
}
  • Now build and flash the image, you will see the orange LED is blinking continuously. The reason is there is no image in the APPLICATION_ADDRESS.
  • So now we need to create an user application and flash it into APPLICATION_ADDRESS

3. Implement User Application

Now you need to create an user application and flash it into APPLICATION_ADDRESS in flash.

  • Copy GPIO_HAL project to other folder.
  • I redraw the Flash Memory Map to make you clear the size and address of user application
  • Then we need to config our application in Target
  • It helps the linker understand and then when flashing, our image will be placed from 0x8008000
  • Not finished, we need to config the VTOR in system_stm32f4xx.c file
#define VECT_TAB_OFFSET  0x8000
  • Change main function to control LED 0
while(1)
    {
        /* Toggle LED0_PIN */
        HAL_GPIO_TogglePin(LED_PORT, LED0_PIN);
        
        /* Delay 1000 ms */
        HAL_Delay(1000);
    }
  • Now build and flash it into memory, the user application is flashed into Memory.

4. Run our custom loader

Now the expect result is custom boot loader is run first, it will blink the orange LED 3 times before jump to User Application and blink the Blue LED forever.

Let flash Loader and Application to our board and take a look.

CUstom_bootloader_result

It is working perfectly as we expected.

For someone unclear about step, this is link of all project

https://github.com/phamvubinh/working_space/tree/master/STM32F411VET/CUSTOM_LOADER_1

In next post, I will do some more meaningful thing for customer loader as image upgrade from USB.

Hope you enjoy it.

Leave a Reply

Your email address will not be published. Required fields are marked *