大家好,我是川楠,最近,在问答频道上看到有人对IAP升级心存疑惑。恰好,我本人在这方面的做过功课,也实战使用到很多的项目上,所以我就来为大家做个抛砖引玉吧。
本次例程,我用的是STM32F103VET6单片机开发板,这个是我2012年买的,有没有人和我用的一样的呢?
所谓的IAP( In Application Programming)即在线应用编程。其主要的应用就是对程序的在线升级更新。比如,我们开发的产品,在已经大量出货的情况下,突然发现我们产品的程序有个BUG,在这种情况下,总不能把所有的产品都召回吧,这样成本太高了。IAP就可以很好避免这个问题。
如果你的设备上有IAP功能,你可以要求把你的产品接到网口、USB、插个有新程序的TF卡、或者串口等等,就能对产品设备进行固件升级。就像我们的手机刷机一样。
IAP升级原理
STM32单片机,根据BOOT电平的设置,其上电启动的地址也是部一样的,常用的是从Flash启动。对应的BOOT电平设置如下:
在FLASH启动模式下,上电的启动地址是:0x0800 0000,也是FLASH的起始地址。
比如,本次使用的STM32F103VET6单片机,其FLASH大小为512K,RAM尺寸为64K。这里我将程序设计成两个BOOT程序和APP程序。
BOOT程序:位于FLASH的起始地址,及0x0800 0000.主要进行对后面APP程序的FLASH扇区经行编程,上电默认执行。
APP程序:位于FLASH的后半段,为用户实现功能的程序。
所以这里将512K的FLASH分成了两部分从0x0800 000 -0x0800 FFFF 为BOOT程序区,合计64K;剩下的从0x0801 0000-0x0808 0000为用户APP程序区,合计448K。
程序的启动流程是:
单片机上电之后,首先从0x08000000启动,运行BOOT程序,在BOOT程序中检测是否需要进行固件升级:
如果需要升级,则按照规定的方式,从串口接收数据对单片机的FLASH进行改写,改写完成之后,需要对改写的固件进行校验。校验通过后,则进行程序跳转。
如果不需要升级,则判断APP程序的起始地址是否正常,若正常,则进行程序跳转,运行APP即可。
说了这么多,下面开始实操。
BOOT程序设计
BOOT程序的核心功能有两个:
1、程序跳转
2、对APP程序的FLASH扇区内容进行改写
程序跳转很简单,也就几句话:
其中的 APP_START 就是我们APP程序的起始地址:0x0801 0000
而FLASH的改写稍微麻烦些,需要将0x0801 0000 后面的FLASH扇区进行擦除和重写。重写的类容为我们新的APP程序类容。
这里说明下,新的APP程序数据,有多种来源方式:可以将新的APP程序的BIN文件放到TF卡中,BOOT程序根据TF卡的BIN文件,去改写APP扇区。也可以用过CAN、RS485、串口、USB等串行接口接收新的APP程序数据包,并把数据包依次写到APP扇区。本次使用的是串口。
配置工程:默认的是ROM1的起始地址为0x0800 0000 SIZE 为0x8 0000
而本次我们分配的BOOT程序为64K,所以需要修改SIZE为0x1 0000
其他的地方编程和我们平时编程是一样的。
程序编写成功之后,点击“LOAD”下载就可以了。
这里需要主要的是:
1、每个单片机的FLASH大小和扇区是不一样的,两个程序的分割点,一定要选择某个扇区的起始地址。
2、本次是使用的单片机有256个扇区,每个扇区为2K,但是并不是所有单片机的PAGE都是一样大小的,比如STM32F407的扇区就不是平均分配的。
3、BOOT的功能建议设计为越简单越好,其主要功能就是为了下载程序。所以,越简单,其可能出问题的几率就越小。如果BOOT程序出了问题,那一般只能进行产品召回了。
4、安全很重要。在BOOT程序里,一定要记得,要将其他的控制引脚保持在合适的电平。比如:做小车控制板,在BOOT程序升级的时候,忘记了把运动控制引脚的电平拉低,导致在升级的时候,小车乱跑,容易撞到东西。
========================示例:我设计的BOOT程序升级流程=====================
正常情况下,程序上电启动之后从MCU起始地址0x0800 0000直接启动,读取BKP_DR1寄存器,判断是否需要固件升级,如果不要升级,则进入固件跳转,运行APP程序。
当需要更新固件的时候,需要严格按照如下的步骤和通讯要求进行操作,具体操作如下:
l 目标设备上电之后(程序已经完成了跳转),上位机发送“固件更新命令”,目标设备重新复位启动,在这个过程中目标设备不能断电(此时固件更新命令将保存到BKP_DR1备份寄存器中)。
l 上位机可以使用相关的命令获取设备的MCU型号、内存、ID、版本、固件起始地址(主要是固件起始地址参数,如果知道可以跳过此步骤)等相关信息。
l 上位机发送“开始更新固件”命令,该命令包含固件的起始地址,目标设备收到后需要应答。
l 上位机开始分包发送固件数据帧,目标设备校验并保存固件数据,同时需要应答上位机;如果数据校验失败,可以要求上位机重传。
l 上位机收到应答数据帧之后,才能继续发送固件数据帧。当上位机发送完整个固件数据帧之后,上位机需要发送固件数据更新完毕命令,目标设备应答,开始重启,此刻目标设备固件更新完成。
具体流程如下图所示:
在BootLoader程序中,固件的起始地址、BootLoader版本都在程序的代码中固化好了;CPUID、内存尺寸直接读取MCU相关的寄存器即可。
=========================================================================
APP程序设计
APP程序与我们平时编写的程序稍微有点差别了,因为其程序的起始地址发生了变化,所以需要修改两个地方:程序的起始地址和中断向量偏移地址。
1、程序起始地址修改.
划分的APP程序起始地址为0x0801 0000;APP占用空间大小为448K。SIZE=0x70000
2、修改中断向量偏移地址
在system_stm32f10x.c文件中,修改VECT_TAB_OFFSET的值为0x10000
默认程序定义的值为0;
需要修改为:
完成上面的修改之后,按照正常的程序设计编程即可。
========================示例:我设计的APP程序===========================
我的APP程序很简单,就是点灯。
=========================================================================
经过上面的程序设计,我们拿到两个HEX文件,分别是BOOT和APP的HEX文件。BOOT程序需要通过下载器下载到单片机中,这里使用的是JLINK。
APP程序则需要按照我们约定的固件升级协议,通过串口下载下去。
为了更好的验证和提高自己,这里使用C#自己编写了一个上机软件。这个上位机软件的主要功能,就是将我的APP的HEX文件,解析出来,把升级数据,按照BOOT程序的协议和流程,分包把固件数据依次发到单片机中。
也是这个实验,让我一只脚又跨入了C#的桌面窗口程序编程中。整个例程前前后后花了我两个多月的下班休息时间,也熬了太多个白天和黑夜。单片机程序也就1-2周就搞定了,但是C#上位机软件设计花了2个月。主要是我C#都是从零开始的,不论窗口程序控件还是定期、串口控件等,我都是现学现用,看视频和别人的代码,慢慢的搞定的。
界面写的有点LOW,大家将就看下就可以,毕竟不是专业的美术UI设计。
最后实际检验一下:
1、先将BOOT程序使用下载器下载到开发板。
2、程序运行起来之后,使用我写的上位机软件,将开发板与PC通过串口连接起来。
3、这个我自己做的读取信息。
读信息:这个是我自己设计的一个功能,通过读信息:可以读出单片机型号(字符串信息,BOOT程序固化好的);内存尺寸MCU内部有寄存器表示;版本信息是程序固化好的,包含硬件版本和软件版本;APP起始地址和CPUID;
APP起始地址,我在上位机软件里面,并没有设计成为固定的偏移量。主要是希望这个上位机软件能够适应更多的MCU。比如我用STM32F103C8T6,这个单片机的内存本来小,BOOT占用的空间可能就不能按照现在的分配方式,所以使用可以灵活配置的方式会更好。
CPUID这个很重要,我可以读出MCU的唯一序列号,传给上位机软件,上位机利用这个序列号计算出加密结果,写到特定的位置,或者更改APP特定位置的代码,保证每台设备的APP代码的唯一性;这样即使别人读出MCU的代码,复制抄板出硬件,也不能拿到另外的单片机中使用。
4、下载程序。
固件更新的时候,加载文件是HEX文件,同样我的这个上位机也支持BIN文件的加载;如果是HEX文件,则需要按照特定的方式去除地址信息,只要固件数据,然后将固件数据发到单片机。详情可以自行查阅HEX文件格式方面的资料。
更新完成之后程序重启一下即可,当然也可以不用重启,一切都看你BOOT程序是怎么设计的。
相关资料下载:
原创作品,未经权利人授权禁止转载。详情见转载须知。 举报文章
我要举报该内容理由
×