前言:
前阵子做项目时需要IAP升级,遇到了很多问题,我在此总结一下,避免后面再次踩到同样的坑。这个过程还是有些学问的,有时往往理论正确但是实践起来却遇到各种bug,需要好好研究,特别是对应单片机型号不同,也有很多地方需要修改。
本人使用的芯片型号是AT32F413CB,FLASH空间为128K,一个扇区1K。
有纰漏请指出,转载请说明。
学习交流请发邮件 1280253714@qq.com
一、为什么产品需要IAP升级
有些高端一点的消费电子产品可能需要升级,但是产品发布后就不太可能让用户插个烧录线去重新烧写程序,所以需要预留一下有线或无线的接口提供给用户去升级。
比较合理的方式是产品连上蓝牙或WiFi,通过手机APP进行升级(后文会提到,也可以叫做OAT技术)。
二、IAP升级是什么
IAP(In Application Programming,应用编程)
ISP(全称 In System Programming,即系统编程)
ISP 一般都是通过专业的调试器或者下载器对单片机内部的 Flash 存储器进程编程(如JTAG等),而 IAP 技术是从结构上将 Flash 储存器映射分为两个或者多个分区,在一个分区中对其他分区进行编程,这个分区通常称为 bootloader。
OTA(全称 Over The Air Technology,即云端下载技术,也叫做“空中下载技术”),其基础是 IAP 技术, 可以简单理解为 IAP 的另一种实现方式,通常采用的是无线升级方式(串口、CAN 等属于“直接线控升级”),如通过蓝牙近距离无线升级、ESP8266 网络升级等
三、IAP技术将FLASH至少分为两个分区,不同的分区方式有什么区别?
我们当然希望分区相对多一些比较好,可操作的空间也大,但是在产品开发中,要评估单片机的资源,如果FLASH空间为128K,APP需要近100K的空间,那么此时剩余的空间基本上只能留给bootloader,只能分为两个区。
划分两个分区,只有bootloader和app分区,这个是最简单也是最基本的功能;而在实际产品开发过程中,需要考虑多种因素和需求,如:升级失败了该怎么办?想恢复出厂的版本怎么办?等等一系列的问题。
两个分区的情况如下:
程序首先从bootloader空间执行,检查写进FLASH用户空间的标志位,当没有固件需要升级时,此时跳转到APP,APP程序有一个checkFirmWareUpdate()函数,时刻检测是否有升级命令,若有,则写需要升级的标志位,跳到bootloader接收新APP写进APP FLASH空间,当校验无误(MD5校验文件完整性、特殊标志位加密升级),升级完成。
| booloader Flash | app Flash |
三个分区与两个分区情况类似:
但在bootloader接收新APP时写进的是空白FLASH空间,且空间大小合适时写进APP FLASH空间,升级完成。
| booloader Flash | app Flash | 空白Flash |
接下来为了讲解方便,先讲两个分区的方案。
四、APP如何跳到bootloader?
首先提个问题,APP接收到升级命令后如何跳到bootloader?
如果通过指针跳转到bootloader,那么之前在APP对外设的配置,进入到IAP后会继续生效,需要重新配置,XXX_Reset()或者XXX_DeInit()
而如果是通过复位操作,则无需考虑这个问题。
我们把bootloader的程序放在FLASH的起始地址,当程序复位后(这里只能用软件复位),会执行bootloader程序。但是前面从app跳转到bootldoader,为了正常跳转,所以需要__set_FAULTMASK (1)屏蔽所有中断,所以在bootloader刚开始时要__set_FAULTMASK (0)。
软件复位反应在硬件上就是发了一个信号给硬件复位端
所以之前在APP对外设的配置全部失效,bootloader需要重新配置
五、在bootloader接收APP程序,如果在升级过程因为烧写时断了连接/芯片断电该如何处理?
有个比较好的方法是,通过标志位来判断,如果升级未完成,则标志位始终为升级未完成状态,下次重新接收到升级命令后继续按照升级流程走。
这里的标志位应该放在用户FLASH空间里(后面会讲)
六、如何判断更新的APP是我要的APP?
为什么会提这个问题呢?
假如APP升级的接口被获取了,那么程序就能被任意烧写,假如有人恶意写些病毒程序进单片机导致功能异常,若出现重大事故,开发者要负责任。
为了避免这个问题,需要通过加密的方式来判定更新的APP是开发者要的APP。
最简单的方式是在APP前加一段固件包头(可由上位机自动添加),包头中含加密标志位,在接收更新APP程序时进行判断,如果错误则不再接收APP程序,或者是已经接收到的APP程序失效(丢弃)。
所以实际FLASH空间的分配情况应该是这样:
| booloader Flash | firmware header FLASH | app Flash |
七、怎么保证用户数据不因为APP的升级而被丢失?
实际上,有些用户数据需要保存(如睡眠时长、每日步数),这些数据我们不希望随着APP的升级而被删除,此时就需要FLASH再开辟一块空间来保存用户数据,所以前面的两种分区的方式只是简化版,实际情况应该如下:
| booloader Flash | firmware header FLASH | app Flash | User Flash |
八、FLASH只能按页擦除,但是写用户数据时一般只写几个字节,怎么比较好地保存用户数据?
其实这个问题跟IAP升级无关,但是IAP升级时需要在用户FLASH写标志位,如果按照传统方式,先按页擦除再写标志位,那么可能会误把其他用户数据擦除掉。
比较好的方法是把用户FLASH空间分为两块,块里有一个读写标志位、一个长度标志位,然后根据这两个标志位将用户数据在这两块空间进行挪腾。
九、升级成功后,BootLoader如何跳转到APP?
通过函数指针跳转
IAP Bootload 和 App 间跳转的代码实现
十、三个分区(BootLoader、APP1、APP2)有什么用?
- 一种是APP1里存放出厂程序,永不删除,APP2作为升级后的程序
- 一种是只有APP2正确接受到程序且校验无误,把APP2的程序搬移到APP1中,保证每次都有APP程序
- 一种是当APP程序过大时,此时可把APP1和APP2合并为一个分区,那么此时这种方式跟前面两个分区道理一样
以上方法根据产品需求灵活调整
十一、怎么确保重复升级/升级过程中不变砖?
为什么会无法重复升级?原因是升级的接口没了。
为什么升级会变砖?本来旧版本固件/最新固件/无固件等标志位,对应着要不要升级,升级时跳到IAP,升级完跳到APP的情况。但是程序跳转的状态机跟实际程序存储情况矛盾,就可能会发生异常。
1.首先要确保每次要升级的APP都有可供升级的接口,不然可能出现烧了新的APP程序后,当外部升级的命令到来时,却无法接收升级指令,导致无法跳转到IAP去进行升级。
2.升级时,接收到的帧写进FLASH中,要保证写地址正确,如果把IAP给覆盖了,就可能导致升级失败,升级的接口也没了。或者是写到未知区域,当升级完成时,IAP跳到APP,但是跳到未知区域导致程序出错卡死。
3.IAP和APP的地址设置要正确,不然跳转时跳到未知存储区域时,就可能变砖。
4.IAP程序设计时,要保证正确接收到完整的APP包且校验无误后,才能跳转到APP,这样,即使是掉电或者升级失败,也能保证再次升级无误。那么,在发送端(发送升级指令和固件包的一端)就要发一个帧总数,同时每一个帧要标注帧编号,且不能丢帧/重复发帧;接收端(升级的一端)不能丢帧/重复写帧。当接收完时,接收端要判断帧总数和接收的帧的数量一致,且校验无误后,才能跳转到APP。
十二、一个不容易排除的bug
问题:
全速运行就会进入硬错误中断
解决方案:
擦除app程序后要加一个延时函数
参考文档
STM32中NVIC_SystemReset()函数的作用?什么时候用?_nvic_systemreset();_魏波.的博客-CSDN博客
常用的几种 IAP 升级技术方案 - 知乎
STM32固件升级的一点经验 - 知乎
电子产品如何使用IAP方式升级程序_iap升级_白杨qq_44597856的博客-CSDN博客
IAP固件升级原理及实现详解文章来源:https://www.toymoban.com/news/detail-769222.html
STM32单片机IAP程序升级方法_iap升级_fflanfj的博客-CSDN博客文章来源地址https://www.toymoban.com/news/detail-769222.html
到了这里,关于单片机IAP升级的一些问题与经验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!