Skip to main content
Visitor II
December 3, 2025
Solved

Cortex M0 Vector Table Reallocation Problem

  • December 3, 2025
  • 10 replies
  • 707 views

In my embedded software project, I need to write a bootloader. I wrote an application code for the bootloader and testing, and everything is fine so far, but the delay function in the application code is not working. I think the reason for this is the Vector Table. I wrote the vector table to the RAM address, but it didn't work at all. It jumps to the application code, turns on the LED, but does not toggle. I would really appreciate your help. (STM32f030c8t6 board)

#define APP_START_ADDRESS 0x08006000 // User application start address
#define APP_START_ADDR 0x08006000
#define SRAM_BASE_u 0x20000000
#define VECT_TABLE_SIZE 0xC0 // 48 vectors * 4 bytes

void JumpToApplication(void)
{
 // 1. Dsiable all interrupts
 __disable_irq();

 // 2. Deinit HAL and RCC (optional if bootloader did init)
 HAL_DeInit();
 HAL_RCC_DeInit();

 // 3. Copy vector table
 memcpy((void*)SRAM_BASE_u, (void*)APP_START_ADDR, VECT_TABLE_SIZE);

 // 4. Remap SRAM to 0x00000000
 SYSCFG->CFGR1 &= ~SYSCFG_CFGR1_MEM_MODE; //Clear MEM_MODE bits
 SYSCFG->CFGR1 |= SYSCFG_CFGR1_MEM_MODE_1; // SRAM -> 0x00000000

 // 5. Load MSP and Reset Handler from RAM
 uint32_t app_sp = *(volatile uint32_t*)SRAM_BASE_u;
 uint32_t app_reset = *(volatile uint32_t*)(SRAM_BASE_u + 4);

 // 6. Set MSP and jump
 __set_MSP(app_sp);
 pFunction app_entry = (pFunction)app_reset;
 app_entry();

 while(1); // Should never return
}

Edited to apply source code formatting - please see How to insert source code for future reference.

    This topic has been closed for replies.
    Best answer by gbm

    In the bootloader, you should start the app this way:

    disable_unpend_all_ints();
    vectable_setup(app_addr);
    SYSCFG->CFGR1 = SYSCFG_CFGR1_MEM_RAM;	// map RAM at 0
    app_start(app_addr);

    Note that your app must also contain the ram_vectable definition in a source file and treat it properly in the linker script, exactly like the bootloader.

    Next time you attach some code, please remove all the unnecessary stuff, like big comments and commented-out sections. Leave only the relevant parts.

    Check the .map files of the bootloader and the app to make sure that locations of ram_vectable and the rest of data are correct.

    Update: as I am currently working on my bootloader stuff, I made some more additions to the header file. with the current version, to start the application on STM32F0 it is enough to write just one line:

    app_invoke(app_addr);

    This is equivalent to the last 3 lines of code above (does not include interrupt deactivation).

    10 replies

    Super User
    December 3, 2025

    > the delay function in the application code is not working

    The code presented looks okay to me. Maybe the delay function is bad?

    Debugging the code and stepping through should show the issue.

    Visitor II
    December 3, 2025

    It cannot return from this while loop. I am thiking that because of vector table at the begining of flash memory. Because when I loaded the code to the begining of flash, it workes as should be. Delay funtion can't get the tick value.
    Ekran görüntüsü 2025-12-03 143504.pngEkran görüntüsü 2025-12-03 143544.png

    Super User
    December 3, 2025

    Are you jumping from within an interrupt?

    Visitor II
    December 3, 2025

    No, I disabled all peripherals after I posted this post. However, it didn't work.

    Super User
    December 3, 2025

    You also need interrupts enabled if you want SysTick to work. See generic working jump code here:

    How to jump to system bootloader from application ... - STMicroelectronics Community

    Visitor II
    December 3, 2025

    Sorry my bad, I didn't pay close attention. I'll try that. Thank you :grinning_face_with_sweat:

    Graduate
    December 3, 2025

    Show the relevant parts of code and the linker script file. Enable interrupts before jumping to the app. Set the optimization level to at least -O1. Make sure you don't call the app from an ISR.

    Visitor II
    December 3, 2025

    Bootloader linker script:

    /*
    ******************************************************************************
    **
    ** @file : LinkerScript.ld
    **
    ** @author : Auto-generated by STM32CubeIDE
    **
    ** @brief : Linker script for STM32F030C8Tx Device from STM32F0 series
    ** 64KBytes FLASH
    ** 8KBytes RAM
    **
    ** Set heap size, stack size and stack location according
    ** to application requirements.
    **
    ** Set memory bank area and size if external memory is used
    **
    ** Target : STMicroelectronics STM32
    **
    ** Distribution: The file is distributed as is, without any warranty
    ** of any kind.
    **
    ******************************************************************************
    ** @attention
    **
    ** Copyright (c) 2025 STMicroelectronics.
    ** All rights reserved.
    **
    ** This software is licensed under terms that can be found in the LICENSE file
    ** in the root directory of this software component.
    ** If no LICENSE file comes with this software, it is provided AS-IS.
    **
    ******************************************************************************
    */
    
    /* Entry Point */
    ENTRY(Reset_Handler)
    
    /* Highest address of the user mode stack */
    _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
    
    _Min_Heap_Size = 0x200; /* required amount of heap */
    _Min_Stack_Size = 0x400; /* required amount of stack */
    
    /* Memories definition */
    MEMORY
    {
     RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
     FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 20K
    }
    
    /* Sections */
    SECTIONS
    {
     /* The startup code into "FLASH" Rom type memory */
     .isr_vector :
     {
     . = ALIGN(4);
     KEEP(*(.isr_vector)) /* Startup code */
     . = ALIGN(4);
     } >FLASH
    
     /* The program code and other data into "FLASH" Rom type memory */
     .text :
     {
     . = ALIGN(4);
     *(.text) /* .text sections (code) */
     *(.text*) /* .text* sections (code) */
     *(.glue_7) /* glue arm to thumb code */
     *(.glue_7t) /* glue thumb to arm code */
     *(.eh_frame)
    
     KEEP (*(.init))
     KEEP (*(.fini))
    
     . = ALIGN(4);
     _etext = .; /* define a global symbols at end of code */
     } >FLASH
    
     /* Constant data into "FLASH" Rom type memory */
     .rodata :
     {
     . = ALIGN(4);
     *(.rodata) /* .rodata sections (constants, strings, etc.) */
     *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
     . = ALIGN(4);
     } >FLASH
    
     .ARM.extab (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
     {
     . = ALIGN(4);
     *(.ARM.extab* .gnu.linkonce.armextab.*)
     . = ALIGN(4);
     } >FLASH
    
     .ARM (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
     {
     . = ALIGN(4);
     __exidx_start = .;
     *(.ARM.exidx*)
     __exidx_end = .;
     . = ALIGN(4);
     } >FLASH
    
     .preinit_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
     {
     . = ALIGN(4);
     PROVIDE_HIDDEN (__preinit_array_start = .);
     KEEP (*(.preinit_array*))
     PROVIDE_HIDDEN (__preinit_array_end = .);
     . = ALIGN(4);
     } >FLASH
    
     .init_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
     {
     . = ALIGN(4);
     PROVIDE_HIDDEN (__init_array_start = .);
     KEEP (*(SORT(.init_array.*)))
     KEEP (*(.init_array*))
     PROVIDE_HIDDEN (__init_array_end = .);
     . = ALIGN(4);
     } >FLASH
    
     .fini_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
     {
     . = ALIGN(4);
     PROVIDE_HIDDEN (__fini_array_start = .);
     KEEP (*(SORT(.fini_array.*)))
     KEEP (*(.fini_array*))
     PROVIDE_HIDDEN (__fini_array_end = .);
     . = ALIGN(4);
     } >FLASH
    
     /* Used by the startup to initialize data */
     _sidata = LOADADDR(.data);
    
     /* Initialized data sections into "RAM" Ram type memory */
     .data :
     {
     . = ALIGN(4);
     _sdata = .; /* create a global symbol at data start */
     *(.data) /* .data sections */
     *(.data*) /* .data* sections */
     *(.RamFunc) /* .RamFunc sections */
     *(.RamFunc*) /* .RamFunc* sections */
    
     . = ALIGN(4);
     _edata = .; /* define a global symbol at data end */
    
     } >RAM AT> FLASH
    
     /* Uninitialized data section into "RAM" Ram type memory */
     . = ALIGN(4);
     .bss :
     {
     /* This is used by the startup in order to initialize the .bss section */
     _sbss = .; /* define a global symbol at bss start */
     __bss_start__ = _sbss;
     *(.bss)
     *(.bss*)
     *(COMMON)
    
     . = ALIGN(4);
     _ebss = .; /* define a global symbol at bss end */
     __bss_end__ = _ebss;
     } >RAM
    
     /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
     ._user_heap_stack :
     {
     . = ALIGN(8);
     PROVIDE ( end = . );
     PROVIDE ( _end = . );
     . = . + _Min_Heap_Size;
     . = . + _Min_Stack_Size;
     . = ALIGN(8);
     } >RAM
    
     /* Remove information from the compiler libraries */
     /DISCARD/ :
     {
     libc.a ( * )
     libm.a ( * )
     libgcc.a ( * )
     }
    
     .ARM.attributes 0 : { *(.ARM.attributes) }
    }

     

    Bootloader 'main.c' file:

    /* USER CODE BEGIN Header */
    /**
     ******************************************************************************
     * @file : main.c
     * @brief : Main program body
     ******************************************************************************
     * @attention
     *
     * Copyright (c) 2025 STMicroelectronics.
     * All rights reserved.
     *
     * This software is licensed under terms that can be found in the LICENSE file
     * in the root directory of this software component.
     * If no LICENSE file comes with this software, it is provided AS-IS.
     *
     ******************************************************************************
     */
    /* USER CODE END Header */
    /* Includes ------------------------------------------------------------------*/
    #include "main.h"
    
    /* Private includes ----------------------------------------------------------*/
    /* USER CODE BEGIN Includes */
    #include "stdio.h"
    #include "string.h"
    #include "stdarg.h"
    
    /* USER CODE END Includes */
    
    /* Private typedef -----------------------------------------------------------*/
    /* USER CODE BEGIN PTD */
    
    /* USER CODE END PTD */
    
    /* Private define ------------------------------------------------------------*/
    /* USER CODE BEGIN PD */
    
    /* USER CODE END PD */
    
    /* Private macro -------------------------------------------------------------*/
    /* USER CODE BEGIN PM */
    
    /* USER CODE END PM */
    
    /* Private variables ---------------------------------------------------------*/
    UART_HandleTypeDef huart1;
    
    /* USER CODE BEGIN PV */
    uint8_t i =0;
    #define FLASH_SECTOR5_BASE_ADDR 	0x08006000U	// User application start address
    #define APP_START_ADDR 				FLASH_SECTOR5_BASE_ADDR
    #define SRAM_BASE_u 			0x20000000
    #define VECT_TABLE_SIZE 			0xC0 		// 48 vectors * 4 bytes
    
    
    /* USER CODE END PV */
    
    /* Private function prototypes -----------------------------------------------*/
    void SystemClock_Config(void);
    static void MX_GPIO_Init(void);
    static void MX_USART1_UART_Init(void);
    /* USER CODE BEGIN PFP */
    void usart_printf(char *format,...);
    
    /* USER CODE END PFP */
    
    /* Private user code ---------------------------------------------------------*/
    /* USER CODE BEGIN 0 */
    
    /* USER CODE END 0 */
    
    /**
     * @brief The application entry point.
     * @retval int
     */
    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 */
    
     /* USER CODE END SysInit */
    
     /* Initialize all configured peripherals */
     MX_GPIO_Init();
     MX_USART1_UART_Init();
     /* USER CODE BEGIN 2 */
    
     uint32_t app_msp = *((uint32_t*)APP_START_ADDR);
     uint32_t app_reset = *((uint32_t*)(APP_START_ADDR + 4));
    
     /* USER CODE END 2 */
    
     /* Infinite loop */
     /* USER CODE BEGIN WHILE */
     while (1)
     {
     /* USER CODE END WHILE */
    
     /* USER CODE BEGIN 3 */
    	 usart_printf("User Application...ON\r\n");
    	 HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    	 usart_printf("MSP=0x%08X RESET=0x%08X\n", app_msp, app_reset);
    	 HAL_Delay(1000);
     }
     /* USER CODE END 3 */
    }
    
    /**
     * @brief System Clock Configuration
     * @retval None
     */
    void SystemClock_Config(void)
    {
     RCC_OscInitTypeDef RCC_OscInitStruct = {0};
     RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
     RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    
     /** Initializes the RCC Oscillators according to the specified parameters
     * in the RCC_OscInitTypeDef structure.
     */
     RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
     RCC_OscInitStruct.HSIState = RCC_HSI_ON;
     RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
     RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
     RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
     RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12;
     RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
     if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
     {
     Error_Handler();
     }
    
     /** Initializes the CPU, AHB and APB buses clocks
     */
     RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
     |RCC_CLOCKTYPE_PCLK1;
     RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
     RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
     RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    
     if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
     {
     Error_Handler();
     }
     PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
     PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
     if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
     {
     Error_Handler();
     }
    }
    
    /**
     * @brief USART1 Initialization Function
     * @PAram None
     * @retval None
     */
    static void MX_USART1_UART_Init(void)
    {
    
     /* USER CODE BEGIN USART1_Init 0 */
    
     /* USER CODE END USART1_Init 0 */
    
     /* USER CODE BEGIN USART1_Init 1 */
    
     /* USER CODE END USART1_Init 1 */
     huart1.Instance = USART1;
     huart1.Init.BaudRate = 115200;
     huart1.Init.WordLength = UART_WORDLENGTH_8B;
     huart1.Init.StopBits = UART_STOPBITS_1;
     huart1.Init.Parity = UART_PARITY_NONE;
     huart1.Init.Mode = UART_MODE_TX_RX;
     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
     huart1.Init.OverSampling = UART_OVERSAMPLING_16;
     huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
     huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
     if (HAL_UART_Init(&huart1) != HAL_OK)
     {
     Error_Handler();
     }
     /* USER CODE BEGIN USART1_Init 2 */
    
     /* USER CODE END USART1_Init 2 */
    
    }
    
    /**
     * @brief GPIO Initialization Function
     * @PAram None
     * @retval None
     */
    static void MX_GPIO_Init(void)
    {
     GPIO_InitTypeDef GPIO_InitStruct = {0};
     /* USER CODE BEGIN MX_GPIO_Init_1 */
    
     /* USER CODE END MX_GPIO_Init_1 */
    
     /* GPIO Ports Clock Enable */
     __HAL_RCC_GPIOC_CLK_ENABLE();
     __HAL_RCC_GPIOF_CLK_ENABLE();
     __HAL_RCC_GPIOA_CLK_ENABLE();
    
     /*Configure GPIO pin Output Level */
     HAL_GPIO_WritePin(USER_LED_GPIO_Port, USER_LED_Pin, GPIO_PIN_SET);
    
     /*Configure GPIO pin : USER_LED_Pin */
     GPIO_InitStruct.Pin = USER_LED_Pin;
     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     HAL_GPIO_Init(USER_LED_GPIO_Port, &GPIO_InitStruct);
    
     /* USER CODE BEGIN MX_GPIO_Init_2 */
    
     /* USER CODE END MX_GPIO_Init_2 */
    }
    
    /* USER CODE BEGIN 4 */
    void usart_printf(char *format,...)
    {
    	char str[80] = {0};														// Created array variable in type of "char"
    	va_list	args;															// Creates an object of the type of va_list
    	va_start(args, format);													// Begins to reading arguments which is given to this functions
    	vsprintf(str, format, args);											// Writes the arguments from args to str array in the format of "format"
    	HAL_UART_Transmit(&huart1, (uint8_t*)str, strlen(str), HAL_MAX_DELAY);	// Tranmits data
    	va_end(args);															// Making end of reading of arguments
    
    	/*
    	 * Usage of this function:
    	 *
    	 * usart_printf("Hello World = %d", int_value);
    	 */
    }
    /* USER CODE END 4 */
    
    /**
     * @brief This function is executed in case of error occurrence.
     * @retval None
     */
    void Error_Handler(void)
    {
     /* USER CODE BEGIN Error_Handler_Debug */
     /* User can add his own implementation to report the HAL error return state */
     __disable_irq();
     while (1)
     {
     }
     /* USER CODE END Error_Handler_Debug */
    }
    
    #ifdef USE_FULL_ASSERT
    /**
     * @brief Reports the name of the source file and the source line number
     * where the assert_param error has occurred.
     * @PAram file: pointer to the source file name
     * @PAram line: assert_param error line source number
     * @retval None
     */
    void assert_failed(uint8_t *file, uint32_t line)
    {
     /* USER CODE BEGIN 6 */
     /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
     /* USER CODE END 6 */
    }
    #endif /* USE_FULL_ASSERT */

     

    Super User
    December 4, 2025

    You still don't show where JumpToApplication is called. Since it's not in main(), I assume it is within an interrupt, which is not a recipe for success, as explained above.

    Visitor II
    December 4, 2025

    Sorry, those files are for application code. I am confused a bit, sorry again.

    Here is the bootloader main.c file:

    /* USER CODE BEGIN Header */
    /**
     ******************************************************************************
     * @file : main.c
     * @brief : Main program body
     ******************************************************************************
     * @attention
     *
     * Copyright (c) 2025 STMicroelectronics.
     * All rights reserved.
     *
     * This software is licensed under terms that can be found in the LICENSE file
     * in the root directory of this software component.
     * If no LICENSE file comes with this software, it is provided AS-IS.
     *
     ******************************************************************************
     */
    /* USER CODE END Header */
    /* Includes ------------------------------------------------------------------*/
    #include "main.h"
    
    /* Private includes ----------------------------------------------------------*/
    /* USER CODE BEGIN Includes */
    #include "stdio.h"
    #include "string.h"
    #include "stdarg.h"
    #include "cm_boot.h"
    
    /* USER CODE END Includes */
    
    /* Private typedef -----------------------------------------------------------*/
    /* USER CODE BEGIN PTD */
    
    /* USER CODE END PTD */
    
    /* Private define ------------------------------------------------------------*/
    /* USER CODE BEGIN PD */
    #define FLASH_SECTOR5_BASE_ADDR 	0x08006000U	// User application start address
    #define APP_START_ADDR 				FLASH_SECTOR5_BASE_ADDR
    #define SRAM_BASE_u 			0x20000000
    #define VECT_TABLE_SIZE 			0xC0 		// 48 vectors * 4 bytes
    
    /* USER CODE END PD */
    
    /* Private macro -------------------------------------------------------------*/
    /* USER CODE BEGIN PM */
    
    /* USER CODE END PM */
    
    /* Private variables ---------------------------------------------------------*/
    CRC_HandleTypeDef hcrc;
    
    UART_HandleTypeDef huart1;
    
    /* USER CODE BEGIN PV */
    uint8_t variable = 0;
    typedef void (*pFunction)(void);		// Function pointer that doesn't have return parameter and doesn't taking argument
    int count = 1;
    typedef void (*pFunction)(void);
    
    /* USER CODE END PV */
    
    /* Private function prototypes -----------------------------------------------*/
    void SystemClock_Config(void);
    static void MX_GPIO_Init(void);
    static void MX_USART1_UART_Init(void);
    static void MX_CRC_Init(void);
    /* USER CODE BEGIN PFP */
    void usart_printf(char *format,...);
    void JumpToApplication(void);
    
    /* USER CODE END PFP */
    
    /* Private user code ---------------------------------------------------------*/
    /* USER CODE BEGIN 0 */
    
    /* USER CODE END 0 */
    
    /**
     * @brief The application entry point.
     * @retval int
     */
    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 */
    
     /* USER CODE END SysInit */
    
     /* Initialize all configured peripherals */
     MX_GPIO_Init();
     MX_USART1_UART_Init();
     MX_CRC_Init();
     /* USER CODE BEGIN 2 */
    
     /* USER CODE END 2 */
    
     /* Infinite loop */
     /* USER CODE BEGIN WHILE */
     while (1)
     {
     /* USER CODE END WHILE */
    
     /* USER CODE BEGIN 3 */
    	 usart_printf("This message from bootoader! %d\r\n", count);
    	 count++;
    	 HAL_Delay(1000);
    	 if(count >= 4)
    		 {
    
    		 	 JumpToApplication();
    		 }
     }
     /* USER CODE END 3 */
    }
    
    /**
     * @brief System Clock Configuration
     * @retval None
     */
    void SystemClock_Config(void)
    {
     RCC_OscInitTypeDef RCC_OscInitStruct = {0};
     RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
     RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    
     /** Initializes the RCC Oscillators according to the specified parameters
     * in the RCC_OscInitTypeDef structure.
     */
     RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
     RCC_OscInitStruct.HSIState = RCC_HSI_ON;
     RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
     RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
     RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
     RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12;
     RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
     if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
     {
     Error_Handler();
     }
    
     /** Initializes the CPU, AHB and APB buses clocks
     */
     RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
     |RCC_CLOCKTYPE_PCLK1;
     RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
     RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
     RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    
     if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
     {
     Error_Handler();
     }
     PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
     PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
     if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
     {
     Error_Handler();
     }
    }
    
    /**
     * @brief CRC Initialization Function
     * @PAram None
     * @retval None
     */
    static void MX_CRC_Init(void)
    {
    
     /* USER CODE BEGIN CRC_Init 0 */
    
     /* USER CODE END CRC_Init 0 */
    
     /* USER CODE BEGIN CRC_Init 1 */
    
     /* USER CODE END CRC_Init 1 */
     hcrc.Instance = CRC;
     hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE;
     hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE;
     hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE;
     hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
     if (HAL_CRC_Init(&hcrc) != HAL_OK)
     {
     Error_Handler();
     }
     /* USER CODE BEGIN CRC_Init 2 */
    
     /* USER CODE END CRC_Init 2 */
    
    }
    
    /**
     * @brief USART1 Initialization Function
     * @PAram None
     * @retval None
     */
    static void MX_USART1_UART_Init(void)
    {
    
     /* USER CODE BEGIN USART1_Init 0 */
    
     /* USER CODE END USART1_Init 0 */
    
     /* USER CODE BEGIN USART1_Init 1 */
    
     /* USER CODE END USART1_Init 1 */
     huart1.Instance = USART1;
     huart1.Init.BaudRate = 115200;
     huart1.Init.WordLength = UART_WORDLENGTH_8B;
     huart1.Init.StopBits = UART_STOPBITS_1;
     huart1.Init.Parity = UART_PARITY_NONE;
     huart1.Init.Mode = UART_MODE_TX_RX;
     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
     huart1.Init.OverSampling = UART_OVERSAMPLING_16;
     huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
     huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
     if (HAL_UART_Init(&huart1) != HAL_OK)
     {
     Error_Handler();
     }
     /* USER CODE BEGIN USART1_Init 2 */
    
     /* USER CODE END USART1_Init 2 */
    
    }
    
    /**
     * @brief GPIO Initialization Function
     * @PAram None
     * @retval None
     */
    static void MX_GPIO_Init(void)
    {
     /* USER CODE BEGIN MX_GPIO_Init_1 */
    
     /* USER CODE END MX_GPIO_Init_1 */
    
     /* GPIO Ports Clock Enable */
     __HAL_RCC_GPIOA_CLK_ENABLE();
    
     /* USER CODE BEGIN MX_GPIO_Init_2 */
    
     /* USER CODE END MX_GPIO_Init_2 */
    }
    
    /* USER CODE BEGIN 4 */
    
    void usart_printf(char *format,...)
    {
    	char str[80] = {0};														// Created array variable in type of "char"
    	va_list	args;															// Creates an object of the type of va_list
    	va_start(args, format);													// Begins to reading arguments which is given to this functions
    	vsprintf(str, format, args);											// Writes the arguments from args to str array in the format of "format"
    	HAL_UART_Transmit(&huart1, (uint8_t*)str, strlen(str), HAL_MAX_DELAY);	// Tranmits data
    	va_end(args);															// Making end of reading of arguments
    
    	/*
    	 * Usage of this function:
    	 *
    	 * usart_printf("Hello World = %d", int_value);
    	 */
    }
    
    void JumpToApplication(void)
    {
    
     uint32_t i=0;
     void (*SysMemBootJump)(void);
    
    /*
    	volatile uint32_t BootAddr[33];
    
    	BootAddr[C0] = 0x1FFF0000;
    	BootAddr[F030x8] = 0x1FFFEC00;
    	BootAddr[F030xx] = 0x1FFFD800;
    	BootAddr[F03xx] = 0x1FFFEC00;
    	BootAddr[F05] = 0x1FFFEC00;
    	BootAddr[F07] = 0x1FFFC800;
    	BootAddr[F09] = 0x1FFFD800;
    	BootAddr[F10xx] = 0x1FFFF000;
    	BootAddr[F105] = 0x1FFFB000;
    	BootAddr[F107] = 0x1FFFB000;
    	BootAddr[F10XL] = 0x1FFFE000;
    	BootAddr[F2] = 0x1FFF0000;
    	BootAddr[F3] = 0x1FFFD800;
    	BootAddr[F4] = 0x1FFF0000;
    	BootAddr[F7] = 0x1FF00000;
    	BootAddr[G0] = 0x1FFF0000;
    	BootAddr[G4] = 0x1FFF0000;
    	BootAddr[H503] = 0x0BF87000;
    	BootAddr[H563] = 0x0BF97000;
    	BootAddr[H573] = 0x0BF97000;
    	BootAddr[H7x] = 0x1FF09800;
    	BootAddr[H7A] = 0x1FF0A800;
    	BootAddr[H7B] = 0x1FF0A000;
    	BootAddr[L0] = 0x1FF00000;
    	BootAddr[L1] = 0x1FF00000;
    	BootAddr[L4] = 0x1FFF0000;
    	BootAddr[L5] = 0x0BF90000;
    	BootAddr[WBA] = 0x0BF88000;
    	BootAddr[WBX] = 0x1FFF0000;
    	BootAddr[WL] = 0x1FFF0000;
    	BootAddr[U5] = 0x0BF90000;
    */
    
    	/* Disable all interrupts */
    	__disable_irq();
    
    	/* Disable Systick timer */
    	SysTick->CTRL = 0;
    
    	/* Set the clock to the default state */
    	HAL_RCC_DeInit();
    
    	/* Clear Interrupt Enable Register & Interrupt Pending Register */
    	for (i=0;i<5;i++)
    	{
    		NVIC->ICER[i]=0xFFFFFFFF;
    		NVIC->ICPR[i]=0xFFFFFFFF;
    	}
    
    	/* Re-enable all interrupts */
    	__enable_irq();
    
    	/* Set up the jump to boot loader address + 4 */
    	SysMemBootJump = (void (*)(void)) (*((uint32_t *) ((APP_START_ADDR + 4))));
    
    	/* Set the main stack pointer to the boot loader stack */
    	__set_MSP(*(uint32_t *)APP_START_ADDR);
    
    	/* Call the function to jump to boot loader location */
    	SysMemBootJump();
    
    
    
    /* uint32_t app_msp = *((uint32_t *)APP_START_ADDR);
     uint32_t app_reset = *((uint32_t *)(APP_START_ADDR + 4));
     void (*reset_handler)(void) = (void (*)(void))app_reset;
    
    	usart_printf("BL_DBG_MSG: Bootloader jump to user app\r\n");
    
    	// 1. Configure the MSP by reading the value from the base address of Sector 5
    	usart_printf("BL_DBG_MSG: MSP value: %#x\r\n", app_msp);
    
    	// This function comes from CMSIS
    	__set_MSP(app_msp);
    
    
    	 * 2. Now fetch the reset handler address of the user application
    	 * from the location (FLASH_SECTOR5_BASE_ADDR + 4)
    
    	app_reset_handler = (void*)app_reset;
    
    	usart_printf("BL_DBG_MSG: App reset handler addr: %#x\r\n", app_reset_handler);
    
     // 3. Reset HAL peripherals
    	__disable_irq();
    	SysTick->CTRL = 0;
    
    	// 4. Set the clock to the default state
    	HAL_RCC_DeInit();
    
    	// 5. Clear Interrupt Enable Register & Interrupt Pending Register
    	for (i=0;i<5;i++)
    	{
    		NVIC->ICER[i]=0xFFFFFFFF;
    		NVIC->ICPR[i]=0xFFFFFFFF;
    	}
    
    	// 4. Set vector table address
    	vectable_setup(APP_START_ADDR);
    
    	// 5. Jump to reset handler of the application
    	reset_handler();*/
    }
    
    /* USER CODE END 4 */
    
    /**
     * @brief This function is executed in case of error occurrence.
     * @retval None
     */
    void Error_Handler(void)
    {
     /* USER CODE BEGIN Error_Handler_Debug */
     /* User can add his own implementation to report the HAL error return state */
     __disable_irq();
     while (1)
     {
     }
     /* USER CODE END Error_Handler_Debug */
    }
    
    #ifdef USE_FULL_ASSERT
    /**
     * @brief Reports the name of the source file and the source line number
     * where the assert_param error has occurred.
     * @PAram file: pointer to the source file name
     * @PAram line: assert_param error line source number
     * @retval None
     */
    void assert_failed(uint8_t *file, uint32_t line)
    {
     /* USER CODE BEGIN 6 */
     /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
     /* USER CODE END 6 */
    }
    #endif /* USE_FULL_ASSERT */
    Graduate
    December 4, 2025

    As I wrote above, you need to create .ram_isr_vector section in the linker script before .data section.

    I have updated the cm_boot.h file on the github with more verbose descriptions of what needs to be done in the bootloader and the application. Just follow them.

     

    After you do that, check the .map file - ram vectors will be placed at 0x20000000 and data in the .data section will start at 0x200000c0. That's the correct memory map (same for the bootloader and the app).

    You should invoke the app from the main function, NOT from any ISR or it's callback. Declare a volatile bool flag, set it in the ISR and test in in main() to decide whether you should call the app.

    Graduate II
    December 4, 2025

    Yes but for app not bootloader linker ! And section is waste energy simply move RAM start.

    Visitor II
    December 4, 2025

    The files which I shared first above are from application not botloader. Sorry, I confused a bit :)

    Visitor II
    December 4, 2025

    The messages below which have been writed to terminal by bootloader and application code. It means bootloader is jumping to application code, but after writing MSP and RESET address it should to be delayed and writing again and again. But it's not happening. I shared this that maybe can help you.

    This message from bootoader! 1
    This message from bootoader! 2
    This message from bootoader! 3
    BL_DBG_MSG: Bootloader jump to user app
    BL_DBG_MSG: MSP value: 0x20002000
    BL_DBG_MSG: App reset handler addr: 0x8006675
    User Application...ON
    MSP=0x20002000 RESET=0x08006675

     

    gbmAnswer
    Graduate
    December 4, 2025

    In the bootloader, you should start the app this way:

    disable_unpend_all_ints();
    vectable_setup(app_addr);
    SYSCFG->CFGR1 = SYSCFG_CFGR1_MEM_RAM;	// map RAM at 0
    app_start(app_addr);

    Note that your app must also contain the ram_vectable definition in a source file and treat it properly in the linker script, exactly like the bootloader.

    Next time you attach some code, please remove all the unnecessary stuff, like big comments and commented-out sections. Leave only the relevant parts.

    Check the .map files of the bootloader and the app to make sure that locations of ram_vectable and the rest of data are correct.

    Update: as I am currently working on my bootloader stuff, I made some more additions to the header file. with the current version, to start the application on STM32F0 it is enough to write just one line:

    app_invoke(app_addr);

    This is equivalent to the last 3 lines of code above (does not include interrupt deactivation).

    Visitor II
    December 6, 2025

    It's working, thank you so much bro :)