Ou Tsei
Ou Tsei

Reputation: 482

STM32 boot to system memory bootloader

I'm trying to use the STM32 system memory bootloader to program the MCU through UART1 without programmer.

I'm using STM32G030C8 on custom board and found this document explaining how to boot to the bootloader: https://www.st.com/resource/en/application_note/cd00167594-stm32-microcontroller-system-memory-boot-mode-stmicroelectronics.pdf

section 41.1 tells that:

The STM32G03xxx/G04xxx bootloader is activated by applying Pattern 11 (described in Table 2: Bootloader activation patterns). The following table shows the hardware resources used by this bootloader. Note that STM32G030x don’t have BOOT_LOCK(bit), so consider that when using pattern 11.

Table 2 tells that pattern 11 is:

enter image description here

So I tried to do this in the firmware:

            FLASH_OBProgramInitTypeDef OBInit;
            OBInit.OptionType = OPTIONBYTE_USER;
            OBInit.USERConfig = (OB_nBOOT0_RESET | OB_BOOT1_SYSTEM | OB_BOOT0_FROM_OB);
            HAL_FLASH_Unlock();
            HAL_FLASH_OB_Unlock();
            HAL_FLASHEx_OBProgram(&OBInit);
            HAL_FLASH_OB_Launch();

At first I tried to just call these functions from the application, triggered by a message to UART1. But that didn't work, nothing seems to happen.

Then I moved the above code section right to main after HAL_Init(); and SystemClock_Config();

    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 */
         FLASH_OBProgramInitTypeDef OBInit;
         OBInit.OptionType = OPTIONBYTE_USER;
         OBInit.USERConfig = (OB_nBOOT0_RESET | OB_BOOT1_SYSTEM | OB_BOOT0_FROM_OB);
         HAL_FLASH_Unlock();
         HAL_FLASH_OB_Unlock();
         HAL_FLASHEx_OBProgram(&OBInit);
         HAL_FLASH_OB_Launch();
         ...

And this did work! The MCU booted to bootloader and I was able to upload new FW with STM32CubeProgrammer.

Then I found these stackoverflow posts: Jump to Bootloader in STM32 through application i.e using Boot 0 and Boot 1 Pins in Boot mode from User flash

STM32F4 Jump to Bootloader via SoftReset and without BOOT0 and BOOT1 Pin

And figured when I want to boot to bootloader I could write a word to SRAM, issue soft reboot, and check that word in boot and run the above code. Like so:

Call this once booting to bootloader is triggered:

void boot_to_bootloader() {
    __IO uint32_t *pointer = SRAM_BASE + SRAM_OFFSET;
    *pointer = BOOTLOADER_VALUE;
    NVIC_SystemReset();
}

Then in main:

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 */
    __IO uint32_t *pointer = SRAM_BASE + SRAM_OFFSET;
    if (*pointer == BOOTLOADER_VALUE) {
            FLASH_OBProgramInitTypeDef OBInit;
            *pointer = 0x0000;
            OBInit.OptionType = OPTIONBYTE_USER;
            OBInit.USERConfig = (OB_nBOOT0_RESET | OB_BOOT1_SYSTEM | OB_BOOT0_FROM_OB);
            HAL_FLASH_Unlock();
            HAL_FLASH_OB_Unlock();
            HAL_FLASHEx_OBProgram(&OBInit);
            HAL_FLASH_OB_Launch();
    }

I verified with debugger that the mechanism works, and the bootloader booting code is run (the *pointer == BOOTLOADER_VALUE evaluated to true and all the functions are called). But nothing happens and the code just executes normally after that.

So I have two questions:

What is so different in the version with the (pointer == BOOTLOADER_VALUE) check compared to the one without any checks that the bootloader booting fails?

How do I get the device to boot to the bootloader when it is triggered in the application?

Thank you!

EDIT

So it seems that the code does something instead of just executing like normal after the ...Launch() command. But it still does not enter the bootloader correctly, at least it wont respond to the cube programmer, but it also is not running the application code, so I'm not sure what is happening. I managed to brick two of my devices already this way..

Upvotes: 1

Views: 2026

Answers (1)

Nitz
Nitz

Reputation: 11

jump to bootloader from user space

As mentioned in AN2606, general bootloader description: general bootloader description

At first, check the word you wrote to the SRAM from the beginning of void SystemInit(void) and not from int main(void)

Second thing, I would jump from user space instead of changing the boot pattern. You can do it by change the main stack pointer (MSP) located on the beginning of the system memory mentioned in AN2606, STM32G03xxx/G04xxx section

An example code for that:

typedef void resetHandler_t(void);

typedef struct isrVector_s {
    uint32_t    stackEnd;
    resetHandler_t *resetHandler;
} isrVector_t;
    
void jumpToBootloader(void)
{    
        volatile isrVector_t *bootloaderVector = (isrVector_t *)(0x1FFF0000);
        __set_MSP(bootloaderVector->stackEnd);
        bootloaderVector->resetHandler();
}

Unbrick your MCU

To unbrick the MCU you need to configure RDP register (which might be blocked by other registers, depends on your MCU). To configure the registers, you can connect the MCU with STM32CubeProgrammer on mode 'under reset', wire the MCU reset pin to 3v and connect the device. Changing read protection level to AA will unbrick the MCU.

Upvotes: 0

Related Questions