技术原理
MCU启动后,从8000000H开始运行代码,此处是boot loader程序。
应用程序编译到8010000H位置,boot loader启动后,跳转到8010000H运行。
在进行OTA的时候,需要将IDE生成的hex文件转换为bin文件,使用工具转换即可:
fromelf.exe --bin .\app.axf --output .\app.bin
bootloader中的跳转
从应用程序开头读取栈顶,程序入口地址。
#define APP_BASE 0x8010000
void (*app)(void) ;
// 获取应用程序栈顶和入口地址
stack_addr = *(__IO uint32_t *) APP_BASE;
application_addr = *(__IO uint32_t *)( APP_BASE +4);
// 设置MP,运行app
app =(void(*)(void))application_addr;
__set_MSP( *(__IO uint32_t *) APP_BASE);
app();
app测试程序
app的测试程序,由STM32CubeMx生成,主要初始化打开led指示灯,循环间隔500ms发送串口数据。
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 */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(500);
while((USART1->ISR & 0X40) == 0);
USART1->TDR = 0x55;
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
设置编译地址到8010000H,size变为1000H
遇到的问题
现象:
boot loader运行后,可以跳转到应用程序,可以打开led,串口没有发送数据。
查找原因:
用flash烧录工具,将app烧录到8010000H地址,在boot loader项目中在线调试,app启动后,可以看到Disassembly窗口中出现了app的汇编代码,单步调试发现CPU只在附近这几句跑:
用工具将app生成asm文件:
fromelf.exe --text -c -o .\app.asm .\app.axf
查找汇编文件中对于地址的代码
可以发现CPU一直停留在HAL_Delay方法中。
验证HAL_Delay的问题,将应用代码改为:
while (1)
{
while((USART1->ISR & 0X40) == 0);
USART1->TDR = 0x55;
}
app启动后,串口可以收到数据。
总结:
跳转到APP后,Systick没有正常工作。
解决方案:
查看app的初始化代码,SysTick部分是CubeMx生成的,编译到8000000H地址可以正常运行,所以代码没问题;而SysTick没有变化,可能是中断未执行
void SysTick_Handler(void)
{
HAL_IncTick();
}
检查中断向量表是否有问题,在system_stm32xxx.c文件中,有如下代码
#define VECT_TAB_BASE_ADDRESS FLASH_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
...
void SystemInit(void)
{
/* Configure the Vector Table location -------------------------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation */
#endif /* USER_VECT_TAB_ADDRESS */
}
中断向量默认在8000000H位置,当中断向量发生变化后,应该在初始化的时候修改中断向量地址,所以将上述代码修改为
#define VECT_TAB_BASE_ADDRESS FLASH_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x00010000U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
...
void SystemInit(void)
{
/* Configure the Vector Table location -------------------------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation */
#endif /* USER_VECT_TAB_ADDRESS */
}
在IDE中,添加宏
再次启动,boot loader可以正常拉起app程序。