STM32程序升级设计总结
1Stm32启动流程
通过设置BooT1/和BOOT0引脚的电平可以使程序重不同的存储器上启动。
- 从主存储器上启动
主存储器的起始地址为0x0800 0000,默认情况下程序都是从主存储上启动的且默认是特权模式下。
(特权模式下可以访问片上所有资源)。
M3内核上电或者复位后会取出MSP(主栈指针),然后取出PC(程序计数器,程序当前运行的位置),通过PC可以改变程序执行流程。从主存储器上启动也就是Flash启动时,会通过内存映射到flash上。
2bootloader程序设计需求
如果要实现不通过下载器进行程序更新,就需要设计一个bootloader程序,来更新我们的应用程序。 bootloader程序
- 能通过串口,网口等通信端口接收app程序。
- 能够将app程序保存起来并校验正确性。
- 能够跳转到app程序去执行(设置主堆栈SP)。
app程序
- 能够跳转到bootloader程序中执行。
3bootloader程序和App程序flash分配
一般情况下bootloader程序内存占用较小可以分配较少的空间,app程序一般较大可以多分配一些空间,预留一部分空间存放一些配置参数。
-
第一步通过编程IDE设置程序rom的起始位置和大小。
-
将bootloader程序通过下载器下载到板子上。
-
在bootloader程序中设置好app程序的起始位置。
-
检测跳转条件是否满足。
-
跳转到app程序执行。(需要app程序初始化函数中更新向量表)
4 具体实现程序主要代码
4.1 bootloader程序
功能:bootloader程序初始化串口等待升级指令,上位机发送升级指令跳转到app执行(通过IDE先将APP下载到flash指定位置上)。
主要代码main函数while(1)循环
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(1000);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_2);
if(RxTemp[0] == 1) //串口接收缓存
{
printf("boot app..........\r\n");
memset(RxTemp, 0, U1_RX_BUF_SIZE);
cnt = 0;
//这里可以加判断代码防止跑飞
IAP_ExecuteApp(0x08007800); //app在flash中存放的起始地址
}
}
跳转函数
typedef int (*iapfun)(void); //函数指针
/*
* @name IAP_ExecuteApp
* @brief 跳转到应用程序段
* @param ulAddr_App: 应用程序段起始地址
* @retval None
*/
void IAP_ExecuteApp(uint32_t ulAddr_App)
{
iapfun pJump2App;
pJump2App = (iapfun) *(__IO uint32_t *)(ulAddr_App + 4) //用户代码区第二个字为程序开始地址(复位地址)
__set_MSP(ulAddr_App) //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
pJump2App (); //跳转到APP
}
4.2 APP程序
主要设置的点
- 向量表偏移
HAL库修改的地方
在system_stm32f1xx.c文件内
通过启动.s文件SystemInit跳转过去可以看到复位后调用了下面函数
void SystemInit (void)
{
#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
#ifdef DATA_IN_ExtSRAM
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM */
#endif
/* Configure the Vector Table location -------------------------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#endif /* USER_VECT_TAB_ADDRESS */
}
通过CubeMX生成默认是没有定义USER_VECT_TAB_ADDRESS这个宏我们定义这个宏并修改VECT_TAB_OFFSET的值,这个值根据分配flash而定。
修改app在flash中存放的起始位置,编译即可。
5总结与后续拓展
- 了解到Stm32如何启动的
- 了解到Stm32如何分配空间并实现程序跳转
- 后续可以为bootloader添加网络接收和串口接收以及其他接收功能,完成一个可以使用多种升级方式的bootloader程序。
- 个人觉得学编程最主要的是了解其原理,代码只是实现的工具,编程思想才是学习的要点。