Last Update: Information subject to change.
This is another Application Note relevent to using STM32CubeMX and True Studio. All the older Decaf IOC boards with the 72MHz Cortex-M3 (STM32F103 variants) used a DFU loader stored in the bottom of Flash memory (0x0800 0000). The board USB firmware was loaded at 0x0800 3000. All boards have a jumper that, if removed, causes the board to boot into DFU mode: utilities provided the means for users to load updates directly via the USB port. It also means that we don’t have a JTAG or ST-Link connector.
Loading the board firmware at 0x0800 3000 requires the Interrupt Vector Table to be moved upwards by 0x3000. In the older CMSIS firmware, this was done using …
#define InterruptVectorAddress 0x3000 #define ApplicationAddress 0x08003000 and first in main.c NVIC_SetVectorTable(NVIC_VectTab_FLASH, InterruptVectorAddress);
In the MX code base, the above does not exist, and the process to achieve the relocation is different. It’s important to set the new vector table address after calling HAL_Init(), because it calls the generated HAL_MspInit(), see below.
In the generated project file system_stm32f1xx.c we find around line #107 and line #220…
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
Since the file system_stm32f1xx.c is generated by the project, we can change the value of VECT_TAB_OFFSET in firmware code as needed. Note here that we DON’T change the value of VECT_TAB_OFFSET.
In main.c we have a call to HAL_Init(); Function source comments state …
@brief This function is used to initialize the HAL Library; it must be the first instruction to be executed in the main program (before to call any other HAL function), it performs the following: Configure the Flash prefetch. Configures the SysTick to generate an interrupt each 1 millisecond, which is clocked by the HSI (at this stage, the clock is not yet configured and thus the system is running from the internal HSI at 16 MHz). Set NVIC Group Priority to 4. Calls the HAL_MspInit() callback function defined in user file "stm32f1xx_hal_msp.c" to do the global low level hardware initialization
Note the call to …
void HAL_MspInit(void) { __HAL_RCC_AFIO_CLK_ENABLE(); __HAL_RCC_PWR_CLK_ENABLE(); __HAL_AFIO_REMAP_SWJ_DISABLE(); }
What we wanted to do was use the earlier DFU Core code loaded at 0x0800 0000 and create the new firmware (with the Interrupt Vector relocation) that would load at 0x0800 3000. The TS project creates a .hex file that defaults to a base address 0x0800 0000: the ST-Link utility does not allow for the load address to be specified. The .hex file build has to do it via the linker script.
See the generated linker script STM32F103C8_FLASH.ld (name is our project mcu type). At approximately line #70, update
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K to FLASH (rx) : ORIGIN = 0x08003000, LENGTH = 64K-0x3000 This specifies the new load address. For the IOC-M-2, this is 0x0800 3000
So … in main.c we now need
#define InterruptVectorAddress 0x3000 void NVIC_Relocate(void) { SCB->VTOR = (FLASH_BASE | InterruptVectorAddress); } int main (void { HAL_Init(); NVIC_Relocate(); ... }
Alternatively, we could use ... void HAL_MspInit(void) { __HAL_RCC_AFIO_CLK_ENABLE(); __HAL_RCC_PWR_CLK_ENABLE(); __HAL_AFIO_REMAP_SWJ_DISABLE(); SCB->VTOR = (FLASH_BASE | InterruptVectorAddress); }
Comments, clarifications and questions are welcome, see Contact.
Since you are here … do please have a look around our site. These products may be of interest.
Decaf IOC-M-2 Decaf IOC-2xe Decaf IOC-235 Decaf IOC-280Z-4 Decaf IOC-350 Decaf IOC-370
[xyz-ihs snippet=”PageCopyrightStatement”]
Copyright © 2025 PiXCL Automation Tech Notes, Canada. All Rights Reserved.