BootLoader就是单片机在复位后首先执行的一小段引导程序,通过此段程序可以实现硬件初始化、进行“用户程序”更新等功能,本文主要讨论的是通过BootLoader对“用户程序”进行动态更新。
在使用单片机进行产品开发及使用过程中,不可避免的存在更新程序的问题,正常的程序下载是通过单片机仿真器与单片机的特殊I/O口连接来实现。在产品的开发阶段,通过仿真器可以实现程序下载及调试。产品开发完成后,由于单片机已被封装在产品内部,若要进行更新则需要重新打开产品外壳,连接数据线。这对已经批量生产甚至产品已经在最终用户手中的情况下几乎是不可能的,一方面由于这样做效率很低、成本高,另一方面也使用户对产品的整体性能带来很大的负面影响。
1 Flash操作及程序存储区结构功能划分
1.1 Flash基本操作和存储结构
C8051F410对Flash只支持0操作,故在写入数据前首先应擦除扇区(擦除只能整页操作,操作完成后每一位都为1)。软件写和擦除FLASH受FLASH锁定和关键码功能的保护。在进行FLASH操作之前,必须按顺序向FLASH锁定和关键码寄存器(FLKEY)写入关键码:0xA5,0xF1。写关键码的时序并不重要,但必须按顺序写。
要实现BootLoader首先要了解存储程序的Flash结构,如表1。C8051F410共有32kFlash程序存储器,该存储器以512为一个扇区(页),可以在系统内部编程操作(IAP)。这就给实现BootLoader功能提供了充要前提条件。
1.2 存储区的功能划分
BootLoader程序和“用户程序”分别存储于Flash不同区域内,在本文中做如下划分:BootLader程序占用地址0x6000~0x7FFF,其中页0x7C00来保存用户程序的入口地址,这样真正的BootLoader的程序大小就不能超过7 k(0x6000~0x7A00)。“用户程序”占用地址0x0000~0x5FFF,这样对“用户程序”的编写除大小不能超过24 k外就没有其他特殊要求。
1.3 定位BootLoader的存储位置
使用Keil软件在程序开发时很容易实现程序的定位,这里介绍一种操作最为简便的方法,在BootLoader工程的设置窗口的BL51 Locate面板内输入程序的地址范围即可,如下图示。
2 BootLoader程序工作流程描述
2.1 关键过程描述
上电复位:复位后单片机首先执行地址0x0000处的跳转指令跳转到BootLoader程序的入口地址并进行诸如关闭看门狗、晶振频率、UART串口波特率设置等操作,为了使程序更新速度更快,本应用中系统时钟频率设置一个较大的通讯波特率为115200bps。
升级握手:根据预先定义的握手规则,通过URAT与上位机(一般是计算机)进行一些数据交换,收到正确回复后即认为握手成功,并通过串口发送准备好接收数据的指示,若不成功则进行用户程序的跳转操作。
用户程序判断:若存在则立即跳转到用户程序入口地址(这也是最为普通的正常启动过程)。
跳转到用户程序入口:BootLoader任务完成,将单片机的控制权交由用户程序接管直到下次复位才能重新进入BootLoader。
接收数据:在BootLoadler内没有使用中断函数,从而减少了对中断向量的重新映射操作,也增加了程序的稳定性,这里采用查询的方式实现数据接收。
指令类型分析:由上位机传来的数据帧有多个功能,协议由BootLoader的开发人员自行规定,主要包括的指令类型有:写入数据、读取数据并上传、结束数据传输过程。
发送“xxxx”提示:通过UART向上位机发送一些操作结果信息反馈给上位机,如“操作成功”、“操作失败”等,以告知上位机如何继续进行下步操作。
2.2 BootLoader流程图
3 关键操作的程序处理
数据接收:BootLoader程序中不要使用中断函数,使用后会导致“用户程序”的相同中断处理函数失效,所以这里使用查询的方式实现UART串口数据接收。
BootLoader程序入口地址的保存:单片机复位后总是从Flash存储区的0x0000地址处开始执行,这里占用3个字节保存了一条跳转指令,地址0x0000内容为0x02,即为机器码的跳转指令,后面紧跟的两个字节保存的是要跳转到的地址值,为了保证能正确跳转到BootLoader区,需要在擦除本页前保存跳转的地址值,待擦除完成后重新写入这3个字节,其实现代码如下:
BootAddr[0]=FlASH_ByteRead(0x0001);
BootAddr[1]=FLASH_ByteRead(0x0002);
FLASH_PageErase(0X0000);//擦除0页
FLASH_ByteWrite(0x0000,0x02);//跳转指令0x02
FLASH_ByteWfite (0x0001,BootAddr [0]);//写入bootloader的开始地址
FLASH_ByteWrite(0x0002,BootAddr[1]);
“用户程序”入口地址的保存:“用户程序”入口地址在程序文件内标示保存在程序的前3个地址字节内,在生成的程序的Hex文件内显示为:
:03000000021ECC11
:0C1ECC00787FE4F6D8FD7581700216A046
第1行内的内容表示在地址0x0000及向后的两个字节内的内容为0x02ECCC,即为要跳转到Flash地址0x1ECC处去执行“用户程序”的第1条指令,这里我们就要把这个地址保存起来,以便让BootLoader程序在执行完后跳转到这里来运行“用户程序”,即把“用户程序”文件内原来指向地址0x0000~0x0002的3个字节保存到BootLoader指定的一个页单独保存,本应用中是保存到了0x7A00页的前3个字节,实现代码如下:
#define APP_ADDR_PAGE 0x7C00L∥用户程序的入口地址……
startAddr=RecData[2]*256+RecData[3];
if((startAddr+i==0)‖(startAddr+i==1)‖(startAddr+i==2))
FLASH_ByteWrite(APP_ADDR_PAGE+i,RecData[5+i]);
startAddr为上位机传来的数据帧内指明的数据应保存的地址
BootLoader程序区的保护:在更新“用户程序”过程中要防止上位机传来的数据包含与BootLoader程序保存区地址重复的地址段,如果将BootLoader区覆盖将导致下次复位后不能正确执行引导程序。通过以下程序段实现引导区的保护:
if(startAddr>=0x6000)//与BootLoader冲突
SendString(“Code overflow! ”);
绝对地址的跳转:当升级完成或在复位后上位机未响应升级握手时,程序即跳往“用户程序”的入口地址,此地址保存于Flash的0x7C00处。
4 上位机软件开发
为了配合单片机内BootLoader的功能实现,需要在计算机端编写对应的下载程序来共同完成固件升级,按照BootLoader的通讯协议,上位机服务程序使用Delphi开发,程序主要针对串口操作,完成握手协议、用户程序文件读取并按照固定格式打包、下载及进度监测等功能,程序的运行界面如图4所示。
5 结束语
BootLoader是一个完善产品应该具备的基本功能,其为基于单片机的产品程序升级提供了很好的解决途径。
通过C8051F410单片机内核的实际产品使用,很好的验证了本文所述方法的实用性、可靠性,同时这种方法也同样适用于其他相似结构的单片机。
当程序具有重要保密需求时,可考虑将原Hex文件进行加密,在下载过程中按照加密规则进行解密,以使程序升级更加安全、通用。
为了使程序功能更加完善,在更新程序前应将单片机内原有旧版本的“用户程序”下载并保存,然后再进行更新,当新升级的程序不能使用时还可恢复为旧版本。
上一篇:基于红外对射技术的安全警示系统设计
下一篇:基于MMA8452Q传感器的计步器抗干扰设计
推荐阅读最新更新时间:2024-03-16 13:39