Simple Bootloader Implementation Tutorial for STM32F103

Introduction to STM32F103C8T6

This experimental environment is based on the STM32F103C8T6 minimum system board, which is a low-cost learning board equipped with an ARM Cortex-M3 core. Its main features are as follows:

  • ARM 32-bit Cortex-M3 core, with a maximum frequency of 72MHz

  • 64KB or 128KB Flash

  • 20KB SRAM

  • Multiple timers, ADC (12-bit, 16 channels), USART, I²C, SPI, CAN, USB 2.0 full-speed interface

  • Rich GPIO (up to 80 pins)

This board is suitable for beginners to quickly get started and is also suitable for Bootloader-related experiments.

STM32F103 Boot Modes

The startup behavior of STM32 is determined by the level combinations of the BOOT0 and BOOT1 pins:

  1. Boot from main Flash (normal mode, BOOT0=0): After reset, user code is executed from address 0x08000000.

  2. Boot from system memory (built-in Bootloader mode, BOOT0=1, BOOT1=0): Executes the vendor-provided ROM Bootloader, which can download programs via UART, USB, etc.

  3. Boot from SRAM (debug mode, BOOT0=1, BOOT1=1): The CPU executes code from internal SRAM, commonly used for debugging or temporary experiments.

Note: If you are programming with ST-LINK, the BOOT pins generally remain at 0. If you want to download via UART, you need to set BOOT0=1.

Bootloader Implementation Approach

The Bootloader functionality we want to implement is very simple:

  1. Bootloader runs → Light up LED, print debug information;

  2. Complete initialization → Jump to application entry;

  3. Application starts running → LED blinks at 1-second intervals.

To achieve this goal, we will create two independent projects:

  • Bootloader project: Code located at Flash starting address <span>0x08000000</span> (size 16KB);

  • Application project: Code placed at <span>0x08004400</span> (size about 47KB);

Writing the Bootloader Project

1. Project Configuration

  • Enable GPIO PC13 (on-board LED) and USART1 (PA9, PA10);

  • Redirect <span>printf</span> to UART1 for convenient serial printing of debug information;

Example code (redirecting <span>printf</span>):

#ifdef __GNUC__
int __io_putchar(int ch)
#else
int fputc(int ch, FILE *f)
#endif
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
    return ch;
}

2. Bootloader Main Logic

#define MAJOR 0
#define MINOR 1
uint8_t BL_Version[2] = { MAJOR, MINOR };

static void goto_application(void) {
    printf("Jumping to Application...\n");
    // Get the application reset handler address
    uint32_t app_reset_addr = *(volatile uint32_t*)(0x08004400 + 4U);
    void (*app_reset_handler)(void) = (void*)app_reset_addr;
    // Jump to execute the application
    app_reset_handler();
}

3. Linker Script Modification

Limit the Flash area occupied by the Bootloader in <span>STM32F103C8TX_FLASH.ld</span>:

MEMORY {
  RAM   (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
  FLASH (rx)  : ORIGIN = 0x8000000,  LENGTH = 16K
}

This way, the Bootloader will be compiled to the address range 0x08000000 to 0x08003FFF.

Writing the Application Project

1. Project Configuration

  • Also enable GPIO PC13 and USART1;

  • Add <span>printf</span> redirection code;

2. Application Logic

#define MAJOR 0
#define MINOR 1
uint8_t APP_Version[2] = {MAJOR, MINOR};

printf("Application %d.%d Started!\n", APP_Version[0], APP_Version[1]);
while (1) {
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    HAL_Delay(1000); // LED blinks once per second
}

3. Linker Script Modification

The application is stored starting from <span>0x08004400</span>:

MEMORY {
  RAM   (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
  FLASH (rx)  : ORIGIN = 0x8004400,  LENGTH = 47K
}

4. Vector Table Offset Modification

In <span>system_stm32f1xx.c</span>, enable <span>USER_VECT_TAB_ADDRESS</span> and set the offset to <span>0x4400</span>:

#define USER_VECT_TAB_ADDRESS
#define VECT_TAB_OFFSET 0x00004400U

Programming and Running

  1. First, program the Bootloader to <span>0x08000000</span>;

  2. Then program the application to <span>0x08004400</span>;

  3. Open the serial debugging assistant, and you will see:

  • Bootloader running → printing version number, LED blinking rapidly;

  • Then jumping to the application → printing application version, LED blinking at 1s intervals.

Leave a Comment