MCU IAP

简介: MCU IAP

/* 开头寒暄 */

   白驹过隙,光阴如梭,转眼间半年过去了,也很久没有更新公众号文章,有愧于公众号的粉丝,现在他又来了。最近半年比较忙,也不知道在忙啥,就是没时间写公众号。


/* 正文前言 */

   最近完成了一个项目,使用的是国产的32 + FreeRTOS + lwIP实现网络唤醒和其他七七八八的功能。项目代码转测后基本也没啥问题,但是我们公司的产品比较大,带来的困扰就是给主板上的MCU升级软件的时候就比较麻烦,还需要拆开设备,找到主板的烧录口,插上Jlink才能升级软件,多有不便,因此在代码基本完成后添加了IAP功能,原本这个功能很常见,也没什么可以写的,但是本文将要介绍的方式应该会比较少有人使用,所以想发个文章记录分享一下。


/* MCU基本情况介绍 */

   ·    项目代码:148K

   ·    MCU Flash:512K

   ·    MCU SRAM:144K

   ·    没有外挂SRAM


/* IAP的几种方案 */

   ·    1、更新的程序存在MCU内部的SRAM

   ·    2、更新的程序存在外部的SRAM

   ·    3、更新的程序存在未使用的Flash空间


   前面两种方式应该是最简单的,进入Bootloader之后把接收到的新的程序放到Buff中即可,同时使用GNU C关键字__attribute__((at(0x........)))定义在SRAM里面,接收完成后直接把SRAM的数据写到APP程序的起始地址即可,然后跳转运行,就能实现IAP升级,但是奈何我这个项目上内部的SRAM空间不够,硬件上又没有外挂SRAM因此前两种方式都用不了,因此,就把目光放在了第三种方案上。确定方案后就准备开始动手。


/* 项目介绍 */

   本项目的设备会有一个Winddows和MCU进行串口通讯,因此就设定使用和这个串口在Win下做个小软件和MCU通讯进入IAP流程,实现软件的升级。而Bootloader就实现这个串口的初始化,并使用这个串口接收新的程序即可。


/* 做IAP前期考虑的几个问题 */

   ·    怎么确保传输的程序不会出错?

   ·    即便出错了怎么保证能揪出这个错误并过滤?

   ·    升级失败后会不会成砖?需不需要拆设备?

   ·    怎么保证接收的新程序不会丢包?


   考虑到上述几个问题就比较头大了,但是困难总比办法多嘛。不然现在也不会在这里分享这篇文章了。

   ·    怎么确保传输的程序不会出错?

       增加校验机制,校验失败后返回给上位机

    ·    即便出错了怎么保证能揪出这个错误并过滤?

       把校验结果返回给上位机,上位机收到校验错误后就重新发送这一帧数据

    ·    升级失败后会不会成砖?需不需要拆设备?

       升级失败默认进入Bootloader中等待重新接收新的程序

    ·    怎么保证接收的新程序不会丢包?

       接收部分使用双缓冲区或者环形缓冲,实现边收边升级,进而保证数据不会丢包。


/* 详细逻辑 */

   由于本项目的代码有148K,因此无法一下全部接收再整个擦除Flash更新程序,所以想到了要把148K的代码分段发送,由于这个MCU的Flash页的大小是2K,因此就准备接收到2K新程序后就擦写一次,擦写完成后再继续接收,实现边收边写。

   本项目的设计是把148K的程序,每128个字节作为一组,并在这一组增加一字节帧头、一字节帧长度、两字节的当前帧编号 + 128Bytes程序 + Sum校验。因此每个程序帧的组成大概是这样的。

       F0  Len  Num_H  Num_L  128Bytes  SumCheck

   且把上面这样的一帧数据叫做程序帧,因此每个程序帧的长度就为133字节(这里有个细节要注意,最后一帧不一定是刚好的133字节,后面会说到)。简单点来说就是把148K的程序每次发送128字节,并每个程序帧做Sum校验,保证这一个程序帧数据的正确性。每次发送128字节的程序,那么每收到16帧这样的数据就能刚好组成2K的大小,此时就可以把这2K一并写到Flash中去。148K分128字节发送,需要发送148 * 1024 / 128 = 1184个程序帧,1184刚好能整除16,即最后一帧也是128字节的程序,如果不能整除16就表示最后一帧数据接收完成也不够2K,这种情况就是上面说的小细节,需要考虑进去并作出应对。(这里好好理解理解,应该能明白,毕竟没法保证是那么刚好的每次最后一帧程序帧是128个字节,因此最后一个16帧组成的程序就不是2K)


/* 正式撸代码 */

   有了上面的思路之后,就准备开始撸代码了,首先列一下将要做的工作。

   ·    1、写Bootloader并确定Bootloader的空间

   ·    2、修改APP的代码,并给APP代码分配Flash空间

   本项目最终Bootloader编译后是18K左右,为了预留点空间因此给Bootloader分配了32K的空间,再拿出来200K空间作为APP程序的空间,剩下的就做一个Flash标志位的空间等。那么MCU内部的Flash分配就是这样的


Bootloader:

   这部分的代码很简单,初始化时钟、串口,写好串口接收的逻辑,本项目中使用的双缓冲区接收的数据,也可以使用小编之前写过的环形缓冲去接收(有需要的可以再去翻一下,源码都给出来了,并且代码已经在项目上量产应用),只要不丢包哪种方式都差不多。要注意的就是设置下Bootloader的起始地址和大小,在Keil中如下:


下面是Bootloader下几个关键函数的实现:

跳转函数:    


更新2K代码:


擦写Flash Page:


APP程序:

   这部分的代码改起来就更简单了,在原先的基础上设置偏移量,重新分配下起始地址和空间大小即可,在收到特定命令后写标志位然后复位进入Bootloader即可。

还有一个要修改的就是在编译完成后生成bin文件

框起来的内容是:

D:\Application\Keil_V5.36\Install\ARM\ARMCLANG\bin\fromelf.exe --bin --output  ./Objects/BlackBoard.bin ./Objects/BlackBoardMCU.axf

意思是在编译完成后调用Keilde fromelf.exe生成bin文件,前面是路径(要根据你的安装路径修改)后面是生成bin文件的路径和axf文件的路径


/* 和上位机配合 */

   现在万事俱备,只欠东风,更新程序的传输协议也制定好了,哪里来这样的上位机和我通讯传输数据呢,于是想到了我们公司的C#工程师,因此找了我的领导,提了这个需求,领导一听这个很有必要,就安排了一个人去做这个事情,那么上位机的问题也解决了(后台回复“MCU IAP”可以获取中性版本的上位机,拿到后根据这个协议就能实现你的MCU软件升级,会附有IAP流程图)。他联调了两天目前已经完成了上位机更新MCU程序。和上位机之间的通讯会先有一个握手的过程,收到MCU Update命令之后我就跳转到Bootloader执行,并接收程序,由于每一帧做校验,加上帧数比较多,更新148K的程序大概需要12秒的时间,后面还可以优化的更快,预计可以缩短一半的时间。

   我和上位机之间在更新程序的时候基本都是一问一答的形式,保证了数据准确性同时也确保不会丢包,实现了稳定的更新程序,即便真存在特殊情况,比如更新的时候断电了,也不会成砖,能再次在Bootloader中重新接受新的程序进行程序更新。

   最后放一张上位机的界面,傻瓜式操作。


   说了这么多,相信大家对这个过程和实现方案理解的比较透彻了,想要资料的可以后台发送“MCU IAP”获取中性版本的上位机软件(界面简单易操作)及IAP流程图,详细的介绍了MCU和上位机之间的通讯过程。

相关文章
|
数据格式
STM32外设系列—红外遥控
本文详细介绍了红外通信的应用,原理。介绍了一种常用的二进制脉冲码形式。最后,给出了红外遥控的实现思路和程序设计。
402 2
STM32外设系列—红外遥控
|
7月前
|
IDE 物联网 开发工具
【瑞萨MCU】玩转 HMI-Board 之 MDK + RASC 点灯
【瑞萨MCU】玩转 HMI-Board 之 MDK + RASC 点灯
|
7月前
|
存储 安全 物联网
MCU
MCU
58 1
|
7月前
|
存储 传感器 算法
【Arduino环境下驱动合宙esp32c3单片机基本外设】
【Arduino环境下驱动合宙esp32c3单片机基本外设】
465 1
MicroPython 玩转硬件系列7:OLED显示
MicroPython 玩转硬件系列7:OLED显示
|
传感器 存储 芯片
STM32F407硬件I2C实现MPU6050通讯(CUBEIDE)
STM32F407硬件I2C实现MPU6050通讯(CUBEIDE)
337 0
野火F1开发板STM32-USART使用
野火F1开发板STM32-USART使用
131 0
|
存储 Linux API
ZYNQ裸板:串口篇
使用 PS 的时候,通常会添加 UART 控制器,用于打印信息和调试代码。除此之外, PS 在和外部设备通信时,也会经常使用串口进行通信。先从UART控制器开始讲起吧,从简单的测试再到工程实例。
927 0
ZYNQ裸板:串口篇