历史上的今天
返回首页

历史上的今天

今天是:2024年08月23日(星期五)

正在发生

2019年08月23日 | 一步一步实现STM32-FOTA系列教程之Bootloader编写

2019-08-23 来源:eefocus

前言

上一篇文章《一步一步实现STM32-FOTA系列教程之FLASH静态区读写》实现了对FLASH静态区读写的操作,有了这部分功能之后,就可以实现一个非常简单的Bootloader代码了。


转载请注明出处


Bootloader 功能说明

这里提供的Bootloader功能就非常的简单了,就是在Bootloader启动之后,读取FLASH静态区的参数信息,然后判断启动分区标志位的值,然后进入相应的分区,运行该分区的程序。


注意这里的教程中没有在 Bootloader 中编写联网获取新版本的代码,这部分的实现会放到主分区和备份分区的代码中实现。


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大小,如下图所示。

Bootloader-ROM配置

2、在使用JLINK仿真器下载代码的时候,注意下载时擦除 FLASH 扇区的方式不要选择全片擦除,这里选择擦除部分块,选择方式如下所示。

jlink


测试验证

验证说明

本次测试验证主要是验证该 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固件的设置如下。


Firmware1固件MDK配置设置

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固件的设置如下。

Firmware2固件MDK配置设置

验证步骤

首先将 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...



推荐阅读

史海拾趣

Deltron / DEM Manufacturing公司的发展小趣事

DEM Manufacturing深知品牌对于企业发展的重要性。因此,公司注重品牌塑造和宣传,通过广告、公关等多种手段提升品牌知名度和美誉度。同时,公司还积极参与公益事业和社会活动,履行社会责任,树立了良好的企业形象。

Electro Adapter Inc公司的发展小趣事

作为一家以技术为核心的企业,EA公司始终将技术创新作为公司发展的重中之重。公司不断引进新技术、新工艺,加强与高校、科研机构的合作,共同研发具有自主知识产权的新产品。在智能电源适配器领域,EA公司率先推出了一系列具有智能化、网络化功能的产品,引领了行业潮流。这些产品的推出不仅提高了公司的市场竞争力,也为客户提供了更加便捷、高效的使用体验。

DAVE Embedded Systems公司的发展小趣事

随着公司的发展,DAVE Embedded Systems不断投入研发力量,致力于技术创新和产品创新。他们基于最新技术(如多核ARM Cortex、PowerPC和X86)设计了一系列高端嵌入式系统模块,这些产品不仅满足了客户对性能的需求,还提供了更好的可靠性和可扩展性。此外,公司还积极开发基于Android和Windows平台的嵌入式系统模块,以满足不同客户的需求。

APX Technologies公司的发展小趣事

面对日益激烈的市场竞争,APX Technologies积极寻求与其他企业的合作。公司与一家知名的电子设备制造商达成战略合作协议,共同开发一款具有创新功能的新型智能手机。这款手机的成功上市不仅提升了APX Technologies的品牌知名度,也为其带来了可观的利润。

DECON公司的发展小趣事

随着公司规模的扩大和市场份额的增加,DECON公司开始积极拓展国际市场。公司成立了专门的海外市场部,积极参加国际电子展会和论坛,与全球各地的客户建立了紧密的合作关系。同时,DECON还与国际知名电子企业展开合作,共同开发新产品,推动了公司的国际化进程。

Bliley Technologies Inc公司的发展小趣事

在Bliley的发展历程中,技术创新始终是推动其不断前进的重要动力。从最初的石英晶体生产,到后来的恒温控制晶体振荡器(OCXO)、温度补偿晶振(TCXO)和压控晶体振荡器(VCXO)等先进产品的开发,Bliley始终站在行业技术的最前沿。公司拥有一支专业的研发团队,致力于开发更高效、更稳定、更精确的频率控制产品。这些技术创新不仅提升了Bliley的产品竞争力,也推动了整个电子行业的发展。

问答坊 | AI 解惑

WinCE 系统访问Eboot参数

您好,我用的是WinCE 5.0,使用Eboot(三星2440平台),我想在系统起来后访问Eboot的配置参数,不知道有没有办法,谢谢! …

查看全部问答>

单片机C51设计与调试,用哪些工具比较好。(本人是初学者)

单片机C51设计与调试,用哪些工具比较好。(本人是初学者)…

查看全部问答>

串口接收数据问题

我的板子上有一个MAX232,要让MCU控制一个DSP模块,我将其DSP模块的UART输入输出端对应的接在MCU的输入输出端上,将MXA232的TXD,RXD相短接,这样MCU发出的数据DSP模块就可以接收到了,并返回了值,但是好像这个时候MCU不能正确的接收返回值。 我想 ...…

查看全部问答>

ARM串口通讯丢包问题,急!!!

      各位,我最近调试一个东东,LPC2114用串口Uart0与电脑通讯。上位机程序是VC++6.0编的。工作顺序如下:首先电脑定时发送8字节读数指令,2114收到后返回8字节数据。问题是无论2114内的串口程序是中断的还是轮询的,电脑收 ...…

查看全部问答>

WinCE6.0 和 Wince5.0 差别很大,请介绍一下WinCE6.0 (包括: 目录结构....)

WinCE6.0 和 Wince5.0 差别很大,请介绍一下WinCE6.0 (包括: 目录结构....)…

查看全部问答>

谁能发BSP给我

我想要2440的BSP,WINCE5 ,最好能是WINCE6 发到我邮箱rudang741@163.com 标明论坛ID,我好加分。谢谢。 发一个10分,如果多人,每人10分,发到我结贴为止。谢谢。…

查看全部问答>

EVC中怎样使弹出的对话框不能移动?

最近弄一个窗口,是有标题栏的;但是鼠标拖动窗口的标题栏,则窗口会跟着鼠标移动,我不想让窗口移动,要让他固定在某个位置;这个该怎么弄啊?那位大哥给点代码让我试一下;我也试过:ON_WM_NCLBUTTONDOWN()和ON_WM_NCHITTEST();但是一编译就 ...…

查看全部问答>

请教,关于中断嵌套的问题(内有例子)!!

我的中断时使用两个,一个事外部中断PA8,另一个timer3产生10ms中断,设置如下:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//配置为:先占优先级(0-1),从优先级(0-7)// Enable the EXTI9_5 Interrupt NVIC_Ini ...…

查看全部问答>

外接时钟信号不工作问题

用MSP430F2101开发的系统,定时器由ACLK作为时钟,能工作。因发现ACLK使用的32768振荡器太弱,极易受到干扰,故打算使用外接晶振来解决,即用外部晶振电路然后由XIN脚接入,用示波器看,振荡很大,可是系统就是不工作,不知何故,请高手帮忙。…

查看全部问答>

【我的blueNRG】1 初步体验

双11除了让人剁手,还能让人跺脚。11号发出的,今天才拿到,整整9天。 另外,这个网络图片就是能忽悠人,看着挺大,结果到手一看,好迷你啊,就是半个鼠标那么大嘛。 整块板子也很简单,从BOM看,就是两个芯片:blueNRG和eeprom。 这个eeprom是s ...…

查看全部问答>