STM32F051R8T6 Bootloader IAP跳转APP触发硬故障求助
问题背景
为STM32F051_Disco开发USART IAP Bootloader,跳转至用户APP时触发硬故障。已通过STM32 Programmer验证Flash烧录内容与文件一致,尝试Stack Overflow及ST社区方案后仍未解决,故障地址为0x8003000。此前使用标准外设库可正常实现功能,切换HAL库后出现问题。
Bootloader相关代码
跳转函数
void bootloader_start_app(void) { __disable_irq(); SysTick->CTRL = 0; SysTick->LOAD = 0; SysTick->VAL = 0; __set_PRIMASK(1); // 设置主栈指针(MSP)为Flash指定地址的值 __set_MSP(*(uint32_t*) FLASH_USER_START_ADDR); // 将复位处理函数地址赋值给函数指针 app_reset_handler = (void*) *(volatile uint32_t*) reset_handler_address; // 调用用户应用的复位处理函数启动应用 app_reset_handler(); }
也曾使用以下跳转函数:
void flash_jump_to_app(void); void flash_jump_to_app(void) { if (((*(__IO uint32_t*)FLASH_USER_START_ADDR) & 0x2FFE0000 ) == 0x20000000) { // 跳转至用户应用 JumpAddress = *(__IO uint32_t*) (FLASH_USER_START_ADDR + 4); Jump_To_Application = (pFunction) JumpAddress; // 初始化用户应用的栈指针 __set_MSP(*(__IO uint32_t*) FLASH_USER_START_ADDR); // 跳转至应用 Jump_To_Application(); } }
Flash地址定义
//#define FLASH_PAGE_SIZE ((uint32_t)0x00000400) #define FLASH_USER_START_ADDR ((uint32_t)0x08003000) #define FLASH_USER_END_ADDR ((uint32_t)0x0800FC00) #define USER_FLASH_LAST_PAGE_ADDRESS 0x0800FC00
链接脚本配置
MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 15K }
已将Bootloader的Reset_Handler重命名为Boot_Reset_Handler,并同步修改Startup.s文件。
用户APP相关代码
向量表重映射配置
#define APPLICATION_ADDRESS (uint32_t)0x08003000 #define VECTOR_TABLE_BYTES 48 /* STM32F0 OTA必备配置 */ // 向量表配置 #if (defined(__CC_ARM)) __IO uint32_t VectorTable[48] __attribute__((at(0x20000000))); //0x20000000 #elif (defined(__ICCARM__)) #pragma location = 0x20000000 __no_init __IO uint32_t VectorTable[48]; #elif defined(__GNUC__) __IO uint32_t VectorTable[48] __attribute__((section(".RAMVectorTable"))); #endif
主函数初始化代码
/* 复位所有外设,初始化Flash接口和SysTick */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* 配置系统时钟 */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ for (uint32_t i = 0; i < VECTOR_TABLE_BYTES; i++) { VectorTable[i] = *(__IO uint32_t*) (APPLICATION_ADDRESS + (i << 2)); } __HAL_RCC_SYSCFG_CLK_ENABLE(); __HAL_SYSCFG_REMAPMEMORY_SRAM(); /* USER CODE END SysInit */
链接脚本配置
MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K-1024 FLASH (rx) : ORIGIN = 0x8003000, LENGTH = 64K-15k }
已在链接脚本末尾添加段配置:
.RAMVectorTable : {*(.RAMVectorTable)} >VTRAM AT> FLASH /*Added for STM32-IAP*/
排查建议
清理Bootloader外设状态:跳转前需复位所有Bootloader使用过的外设(如USART、GPIO)并禁用其中断,HAL库会保留外设寄存器状态,残留配置可能导致APP启动时触发异常。例如:
HAL_UART_DeInit(&huart1); __HAL_RCC_USART1_FORCE_RESET(); __HAL_RCC_USART1_RELEASE_RESET();修正APP向量表映射时机:当前APP在
SystemClock_Config后才重映射向量表,但HAL_Init会调用SystemInit,而默认SystemInit会将SCB->VTOR设置为Flash起始地址(0x08000000),导致复位后向量表指向Bootloader区域。需在HAL_Init前完成向量表复制与重映射,或修改SystemInit函数中的VTOR配置。确保RAM区域无重叠:APP链接脚本中需明确划分向量表占用的RAM区域,避免与其他变量重叠。例如修改MEMORY定义:
MEMORY { VTRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192 /* 48个向量×4字节 */ RAM (xrw) : ORIGIN = 0x200000C0, LENGTH = 8K-1024-192 FLASH (rx) : ORIGIN = 0x08003000, LENGTH = 64K-15K }同时确保
.RAMVectorTable段指向VTRAM。验证MSP有效性:检查APP起始地址0x08003000的第一个字(MSP值)是否在STM32F051的RAM范围内(0x20000000~0x20001FFF),若MSP值超出范围会直接触发硬故障。
分析硬故障寄存器:通过调试读取
SCB->HFSR、SCB->CFSR寄存器值,定位故障类型(如预取错误、数据访问错误),缩小排查范围。修改APP复位处理流程:在Startup.s的
Reset_Handler中,先设置向量表偏移(或SRAM重映射),再调用SystemInit和HAL_Init,确保向量表在初始化前已正确配置。
内容的提问来源于stack exchange,提问作者Bhavesh Moradiya

