前言
上一篇文章《一步一步实现STM32-FOTA系列教程之FLASH静态区读写》实现了对FLASH静态区读写的操作,有了这部分功能之后,就可以实现一个非常简单的Bootloader代码了。
转载请注明出处
Bootloader 功能说明
这里提供的Bootloader功能就非常的简单了,就是在Bootloader启动之后,读取FLASH静态区的参数信息,然后判断启动分区标志位的值,然后进入相应的分区,运行该分区的程序。
注意这里的教程中没有在 Bootloader 中编写联网获取新版本的代码,这部分的实现会放到主分区和备份分区的代码中实现。
Bootloader 启动流程
这个启动流程之前已经说过了,这里贴出来,方便对比代码。
函数实现
FLASH 分区宏定义
// FLASH 分区 配置
#define FLASH_BASE_ADDR ((uint32_t)0x08000000)
#define NLEDBOOTLOADER_SIZE (64*1024) // Bootloader 大小为 64KB
#define FIRMWAR_ONE_SIZE (80*1024) // 固件1 大小为 80KB
#define FIRMWAR_TWO_SIZE (80*1024) // 固件2 大小为 80KB
#define NLED_CONFIG_PARAM_SIZE (224*1024)
#define BOOTLOADER_START_ADDR (FLASH_BASE_ADDR) //Bootloader 启动地址
#define FIRMWAR_ONE_START_ADDR (FLASH_BASE_ADDR + NLEDBOOTLOADER_SIZE ) // 固件 1 启动地址
#define FIRMWAR_TWO_START_ADDR (FLASH_BASE_ADDR + NLEDBOOTLOADER_SIZE +FIRMWAR_ONE_SIZE) // 固件 2 启动地址
#define CONFIG_PARAM_START_ADDR (FLASH_BASE_ADDR + NLED_CONFIG_PARAM_SIZE) // FLASH 静态区参数 起始地址
程序跳转代码
在之前的 FLASH静态区参数读写的基础上。增加了对启动分区的判断还有加载启动分区的代码。
//跳转到应用程序段
//appxaddr:用户代码起始地址.
void iap_load_app(u32 appxaddr)
{
if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法.
{
jump2app=(iapfun)*(vu32*)(appxaddr+4); //用户代码区第二个字为程序开始地址(复位地址)
MSR_MSP(*(vu32*)appxaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
for(int i = 0; i < 8; i++)
{
NVIC->ICER[i] = 0xFFFFFFFF; /* 关闭中断*/
NVIC->ICPR[i] = 0xFFFFFFFF; /* 清除中断标志位 */
}
jump2app(); //跳转到APP.
}
}
//判断进行固件升级还是跳转APP
void LoadingFirmware(void)
{
if(bootflag ==1)
{
printf("Jump To Firmware First 0x%08Xrn",FIRMWAR_ONE_START_ADDR);
iap_load_app(FIRMWAR_ONE_START_ADDR);
}
else if(bootflag ==2)
{
printf("Jump To Firmware First 0x%08Xrn",FIRMWAR_TWO_START_ADDR);
iap_load_app(FIRMWAR_TWO_START_ADDR);
}
else
{
printf("boot errorrn");
}
LED0 = 0;
}
主函数实现
int main()
{
ledInit();
uart1_init(9600);
delay_init();
printf("-----------------------------------rn");
printf("------------Bootloader-------------rn");
printf("-----------------------------------rn");
LOG_COMPILE();
printf("Version: V1.0rn");
LED0_Blink(100);
GetDeviceInfo();
LoadingFirmware(); /*判断加载启动分区*/
}
至此,如此简单的一个Bootloader 就编写完成,下面开始测试验证一下吧。
注意事项
1、由于Bootloader所占用的FLASH空间大小为64KB,如果在MDK中进行调试仿真时,注意修改MDK工程的ROM大小,如下图所示。
2、在使用JLINK仿真器下载代码的时候,注意下载时擦除 FLASH 扇区的方式不要选择全片擦除,这里选择擦除部分块,选择方式如下所示。
测试验证
验证说明
本次测试验证主要是验证该 Bootloader 能否加载指定分区中的程序,由于还没有编写远程获取固件的代码,因此这里采用调试编译仿真的方式将主分区和备份分区的代码烧写到 FLASH 中。
为了测试方便,这里仅仅提供两个最简单的分区代码,其中主分区的代码会在串口1循环打印Firmware1 running…,循环间隔为1秒;备份分区的代码则会在串口1循环打印Firmware2 running…,循环间隔为2.5秒。
Firmware1固件main文件实现
#include #include "sys.h" #include "delay.h" #include "led.h" #include "usart.h" #include "logdebug.h" #include "fotaprotocol.h" //运行指示灯 void LED0_Blink(int xms) { LED0 =0; delay_ms(xms); LED0 =1; delay_ms(xms); LED0 =0; delay_ms(xms); LED0 =1; delay_ms(xms); LED0 =0; delay_ms(xms); } int main() { NVIC_SetVectorTable(FIRMWAR_ONE_START_ADDR,0); delay_init(); ledInit(); uart1_init(9600); printf("-----------------------------------rn"); printf("------------Firmware1--------------rn"); printf("-----------------------------------rn"); LOG_COMPILE(); printf("Firmware-1-Version: V1.0rn"); while(1) { printf("Firmware1 running...rn"); LED0_Blink(200); } } 注意,代码编写完之后,还要修改MDK工程中ROM区域的设置,Firmware1固件的设置如下。 Firmware2固件main文件实现 #include #include "sys.h" #include "delay.h" #include "led.h" #include "usart.h" #include "logdebug.h" #include "fotaprotocol.h" //运行指示灯 void LED0_Blink(int xms) { LED0 =0; delay_ms(xms); LED0 =1; delay_ms(xms); LED0 =0; delay_ms(xms); LED0 =1; delay_ms(xms); LED0 =0; delay_ms(xms); } int main() { NVIC_SetVectorTable(FIRMWAR_TWO_START_ADDR,0); delay_init(); ledInit(); uart1_init(9600); printf("-----------------------------------rn"); printf("------------Firmware2--------------rn"); printf("-----------------------------------rn"); LOG_COMPILE(); printf("Firmware-2-Version: V1.0rn"); while(1) { printf("Firmware2 running...rn"); LED0_Blink(500); } } 注意,代码编写完之后,还要修改MDK工程中ROM区域的设置,Firmware2固件的设置如下。 验证步骤 首先将 Bootloader 利用 Jlink 烧写到 FLASH 中。 然后将 Firmware1 和 Firmware2 固件分别按照同样的方法烧写到FLASH中。 烧写完成后,按复位按钮查看启动日志。 烧写完成后,正常的测试现象是,首先启动 Bootloader 打印 Bootloader 相关信息,然后根据启动分区标志位加载不同的固件。 注意,由于在 Bootloader中加入了交替修改启动分区标志位的代码,因此每次重启单片机,Bootloader就会从不同的分区执行代码。这样也达到了测试Bootloader加载启动分区的效果了。 测试日志记录 下面附上测试验证的日志,注意单片机重启是手动硬件复位的,日志如下。 ----------------------------------- ------------Bootloader------------- ----------------------------------- Compile Time: Nov 13 2018,19:24:50 Version: V1.0 Static Params Address :0x08038000 start to boot firmware one Testing... set updateflag 2 Jump To Firmware First 0x08010000 ----------------------------------- ------------Firmware1-------------- ----------------------------------- Compile Time: Nov 13 2018,19:39:26 Firmware-1-Version: V1.0 Firmware1 running... Firmware1 running... Firmware1 running... Firmware1 running... Firmware1 running... Firmware1 running... Firmware1 running... Firmware1 running... Firmware1 running... Firmware1 running... Firmware1 running... Firmware1 running... Firmware1 running... ----------------------------------- ------------Bootloader------------- ----------------------------------- Compile Time: Nov 13 2018,19:24:50 Version: V1.0 Static Params Address :0x08038000 start to boot firmware two Testing... set updateflag 1 Jump To Firmware First 0x08024000 ----------------------------------- ------------Firmware2-------------- ----------------------------------- Compile Time: Nov 13 2018,19:33:58 Firmware-2-Version: V1.0 Firmware2 running... Firmware2 running... Firmware2 running... Firmware2 running... Firmware2 running... Firmware2 running... Firmware2 running...
上一篇:一步一步实现STM32-FOTA系列教程之FLASH静态区读写
下一篇:stm32控制舵机旋转到不同角度
推荐阅读最新更新时间:2024-11-08 16:34
设计资源 培训 开发板 精华推荐
- 报名2019年ST全国巡回研讨会,赢三重好礼
- 有奖问答|ADI应用之旅——工业大机器健康篇
- Littelfuse 高效 • 可靠 • 精准的功率控制和电路保护方案在工业、交通、通讯、医疗及新能源中的应用
- 【ST板卡来了(下)】 品读STM32实战经验,汲取FAE经验闯关去抽奖
- 【在线研讨会讲义下载】TOF 技术介绍及产品应用
- 【TI.com线上采购专场——智能楼宇篇】畅聊火爆的智能电子锁、可视化门铃、智能传感器和网络摄像头方案
- 有奖学习|泰克 MSO6B 探索营:应用案例深度解析
- MPS 隔离式稳压 DC/DC 模块——MIE系列首发,邀你一探究竟!
- 有奖直播 | 微软 Azure Sphere助力稳定,安全和灵活的物联网解决方案
- 邀你参加DIY,大家一起“搞事情”!