第五章:BootLoader与OTABootLoader刷写流程详解 —— 针对STM32的BootLoader及APP跳转与iap BootLoader指南
5.1-BootLoater前要知道
抛开BootLoater问自己从自己的C程序工程到单片机可以运行大概是怎么回事???
编译器如何处理C工程的
单片机如何保存和执行程序
相关存储器
一般启动执行流程
- 复位后,从0x0800 0000取出来复位中断地址,并且跳转到复位中断程序,
- 中断执行完,跳转到main 函数,然后一直在mian 循环
- 如果中断发送,pc指针调转中断表,然后根据中断函数执行中断,
- 然后回到main函数
5.2-BootLoater是什么
了解上面启动流程后,如果我们想给板子更新一个程序,就可以下载两个APP,一个APP检测更新,一个APP是我们的应用程序
我们总结下BootLoater程序要做的事情
5.3-写一个BootLoater程序(不含Flash操作)
这是一个BootLoater程序功能是可以跳转,回跳转到指定位置执行,相应程序。
我们还是使用第零章的代码
为了方便调试我先加入串口发送功能
添加一下重映射
/**
* @brief 重定向printf (重定向fputc),
使用时候记得勾选上魔法棒->Target->UseMicro LIB
可能需要在C文件加typedef struct __FILE FILE;
包含这个文件#include "stdio.h"
* @param
* @return
*/
int fputc(int ch,FILE *stream)
{
HAL_UART_Transmit(&huart1,( uint8_t *)&ch,1,0xFFFF);
return ch;
}
我们的IAP.c内容如下
/* Includes ------------------------------------------------------------------*/
#include "MyApp.h"
/* Private define-------------------------------------------------------------*/
/* Private variables----------------------------------------------------------*/
/* Public variables-----------------------------------------------------------*/
/* Private function prototypes------------------------------------------------*/
/*******************
* @brief 这是 C语言内嵌汇编
//MSR MSP, r0 意思是将r0寄存器中的值加载到MSP(主栈寄存器,
//复位时默认使用)寄存器中,r0中保存的是参数值,即addr的值
//BX r14 跳转到连接寄存器保存的地址中,即退出函数,跳转到函数调用地址
* @param
* @return
*
*******************/
__asm void MSR_MSP (uint32_t ulAddr)
{
MSR MSP,r0 //set Main Stack value
BX r14
}
/*******************
* @brief 跳转到应用程序
* @param ulAddr_App:应用程序的起始端地址
* @return
*
*******************/
void IAP_ExecuteApp(uint32_t ulAddr_App)
{
void (*pFunApp)(void);//定义一个函数指针
//检查栈顶地址是否合法
//if(((*(__IO uint32_t*)ulAddr_App) & 0x2FFE0000) == 0x20000000)
if(((*(__IO uint32_t *)ulAddr_App) & 0x2FFF5000) == 0x20000000)
{
printf("地址合法开始跳转\r\n");
pFunApp = (iapfun) *(__IO uint32_t *)(ulAddr_App + 4); //赋值函数指针、指向新APP的复位中断函数地址
MSR_MSP(*(__IO uint32_t *)ulAddr_App); //初始化APP堆栈指针,对APP程序的堆栈进行重构,就是重新分配RAM
pFunApp(); //执行APP的复位中断函数,最终便会跳转到APP的main函数
}
else
{
printf("地址不合法\r\n");
//错误栈顶地址不合法!
}
}
/********************************************************
End Of File
********************************************************/
IAP.h内容如下
#ifndef __IAP_H_
#define __IAP_H_
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
typedef void (* iapfun)(void); //定义一个函数指针(指向一个返回为空形参为空的函数)
#define APP_Start FLASH_BASE+0x400 //这是APP开始位置
void IAP_ExecuteApp(uint32_t ulAddr_App);
#endif
/********************************************************
End Of File
********************************************************/
然后主函数内容如下
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(500);
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
//跳转流程如下几步
/****关闭中断********/
HAL_SuspendTick();
/****清除中断位******/
/****加载栈地址******/
/****程序跳转********/
IAP_ExecuteApp(APP_Start);//程序跳转,里面有加载栈地址和程序跳转操作
}
然后这个就是我们的BootLoater程序了
我们需要使用MDK设置一下BootLoater的下载的位置和占用大小
先确定自己使用单片机的ROM(Flash)大小、
通过编译后的提示,把各个数据段和代码段加一起,然后就是最后程序大小,我们比这个分配更大一些
通过魔术棒设置大小、这里设置16K、用来保存boot程序
然后这个bootloater程序就可以下载到单片机了
然后设置一下APP1 程序
自己的APP程序需要的注意点
-
设置MDK生产bin文件。
-
设置中断向量偏移 SCB->VTOR = FLASH_BASE | 0x1000;//设置中断向量表地址偏移量。
-
设置程序下载的起始位置和大小。
-
设置脚本生成bin 文件
fromelf.exe --bin --output "@L.bin" "#L"
fromelf.exe –bin –output “@L.bin” “#L”
设置中断向量偏移
SCB->VTOR = FLASH_BASE | 0x1000;//设置中断向量表地址偏移量
设置程序下载的起始位置和大小
为了方便观察实验现象我们更改一下小灯的闪烁频率、还有添加串口输出
这里省略串口一初始化和重映射printf步骤
HAL_Delay(100);
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
printf("这是APP1正在执行中");
开始实验
把bootloater程序先通过MDK烧录到单片机,然后烧录APP1,然后按下复位键
是不是串口
先输出
printf(“地址合法开始跳转\r\n”);
然后输出
printf(“这是APP1正在执行中”);
作者:好家伙VCC