【STM32+cubemx】0024 HAL库开发:IAP(在应用编程)的实现

IAP在应用编程(In-Application Programming),指的是MCU在运行应用程序时,能接收新的烧写文件,并更新到自身的程序存储器中。即可以在应用程序运行时在线升级。

本节我们通过一个简单的例子,来实现STM32的IAP功能。这个例子有两部分程序,boot部分包含IAP功能,运行后可在线升级;app部分则和普通的应用程序一样。我们使用boot程序来在线升级app部分的程序。

程序运行的硬件环境为stm32f103c8t6最小系统。

(本文中的所有代码都可通过文末关注公众号获取)

1)stm32的IAP原理简介

由于IAP的功能需要在线升级程序,所以我们最核心的功能需求就是改写程序存储区中的内容。

首先,我们需要了解stm32的程序存储区的地址划分,在本系列的《0015 HAL库开发:内部flash读写》一节中,我们已经讲过,stm32的flash存储区从0x08000000开始,根据不同芯片类型,其总容量大小不同。本节的例子中使用的stm32f103c8t6,flash总容量为64KB,每页为1KB。

由于IAP的程序是boot和app同时存在于flash中的,我们需要规划一下二者所在的地址区域;一般复位后最先运行的是boot部分,所以我们可以把从0x08000000起始的0x3000字节大小的区域作为boot程序的存储区,0x08003000之后的作为app程序的存储区。也就是前12KB用作boot存储区,后52KB作为app的存储区。

这样,MCU复位后,先从0x08000000地址开始运行boot程序;如果需要更新app程序,则由boot程序获取app程序的烧写文件,将其写入到0x08003000开始的地址中;如果需要运行app程序,则从boot程序中跳转到0x08003000地址执行。

学习本节内容,建议先了解本系列的《0015 HAL库开发:内部flash读写》的内容。

2)cubemx工程配置

如下图配置,选择了Uart1(用于打印信息),PC13作为输出(驱动一个LED):

生成keil的工程文件。

2)boot部分的程序编写

Boot部分的功能主要是接收app的烧写文件,并写入到对应的地址中。

首先定义几个地址和数值:

 

这里用到的几个关键数值:

NVIC_VectTab_FLASH定义的是flash的起始地址;

BOOT_SIZE定义的是boot程序存储区的大小(字节);

ApplicationAddress定义的是app程序的起始地址;

USER_FLASH_PAGES定义的是app程序的可用页大小;

FLASH_USER_END_ADDR定义的是app程序的地址最大值,用于判断是超出地址范围。

接着看flash擦除部分的代码:

 

因为对flash区的改写,必须先擦除。所以,在程序起始时,提升用户输入指令来擦除flash。

这里使用了基本的串口接收函数HAL_UART_Receive来接收指令,超时设置为1s,循环10次。每次到1s后,检测是否接收到“era flash”字符串,如果接收到,则擦除flash。

擦除flash的过程,需要先解锁flash、设置擦除起始地址、擦除大小,然后调用HAL库的擦除flash函数HAL_FLASHEx_Erase(具体用法参见《0015 HAL库开发:内部flash读写》章节)。

擦除完成后,设置一个标志位boot_flag = 1;用于进入后续的写入flash部分。

接着看接收app的烧写文件、写入flash部分的代码:

这里先等待30s,通过串口接收app程序的烧写文件;每接收到256字节,写入到flash中。

注意,这里写入flash时,是以每32bit为一个字写入的,所以只需要循环写入64个字,就处理完了256字节。

对于传输完毕的判定,由超时来确定。由于app烧写文件的长度不确定,可能最后一包的数据不满256字节,会产生超时。所以,第一次超时出现时,不退出,继续下次循环,把数据写入到flash中。等到第二次超时,才是真正的未收到数据,认为文件传输完毕。

最后看一下,如果用户没有选择擦除app程序如何处理,本文的例子中,如果用户选择不更新flash,则最终会默认运行flash中原有的app程序,代码如下所示:

先判定0x08003000地址中,起始位置是否是可能的堆栈地址,如果是,则设置app程序入口、堆栈入口,跳转到app程序运行。

这里需要注意两点:

一是jump2app的赋值和调用,例子中先定义了一个函数指针jump2app,然后把app程序的入口地址赋值给它,最后直接调用jump2app()函数就可以跳转到app程序执行了;这里涉及到C语言的函数指针相关的内容;

二是被注释的关中断的几行,这几行实现的效果是一样的,都是关闭总中断,如果这里调用了关闭总中断,在app程序的起始,需要加上,否则app程序里的中断无法使用;如果boot程序里使用了中断,而这里不调用,可能app程序的中断在初始化时会失败。

到这里,boot程序的部分就实现完了。

3)app部分的程序编写

App部分的程序编写,主要需注意,它的起始地址为0x08003000,所以它的中断向量表地址都与默认的起始地址0x08000000有偏移,必须在系统运行最初就设置这个偏移量。

初始化部分主要的代码如下所示:

核心部分就是在main函数的起始,调用NVIC_SetVectorTable这个函数,来设置中断向量表的偏移量。

至于app函数的主体部分,就随意了,实现任何你想要的功能都可以。本文例子中,实现的是每秒打印一行信息,并闪一下LED:

App的工程,在keil中需要修改以下设置:

把程序存储区的起始地址,修改为我们划分好的app程序起始地址0x08003000(严格来讲,后面的大小0x10000也需要修改,但是如果我们的app程序不大,不会超过flash的最大地址,不修改也无妨)。

最后,还需要设置bin文件:

因为我们通过串口传输给boot程序写入到flash中的文件必须是bin文件格式,所以要在keil中设置编译后自动生成bin文件。这样,之后编译完成,会自动将axf文件转换为bin文件,可以在工程目录下找到生成的bin文件。

如果不这里不设置,也可以在生成hex或者axf文件后,使用工具转换为bin文件格式。

4)测试IAP程序

我们先将boot程序编译、下载到开发板,然后上电运行:

首先boot程序运行,通过串口调试助手监测,可看到打印提示信息,用户在10s内输入era flash,则进入擦除flash流程,否则运行已有的app程序。

如果用户输入了era flash,则提升等待30s,由用户发送app程序的烧写文件(bin文件):

设置一下发送延时,因为flash的写入比较耗费时间,所以,我们使用sscom的发送文件延时功能,每发送256字节,延时100ms,以便MCU有足够的时间把这256字节数据写入flash:

设置好后,选择app程序的烧写文件,发送即可:

烧写完成后,也会自动跳转到app程序执行。

至此,app的更新也就完成了,可以检查是否运行的是最新烧写进去的app程序。

欢迎关注我的公众号,可留言“资料”获取所有源码和参考资料:

  • 9
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值