1.引言
单片机的应用非常广泛,在某些情况下,单片机内部程序的升级在所难免,但是往往需要对单片机产品进行收回才能实现,这样在一些远程设备的程序升级问题上就显得非常不方便。但是有些远程设备本身留有远程通讯的方式:例如某些远程数据传输模块,为了把数据上报总会留有通讯的接口,比如422、485甚至 GPRS或者局域网接口;又或者某些车载定位设备,为了和监控中心通讯会留有GSM、CDMA或者GPRS等通讯方式。在这种情况下就可以利用其现有的通讯方式对其内部单片机程序进行升级而不需要收回产品。
本文的主要内容就是来研究这种远程升级单片机程序的方法。
由于近年来凌阳科技的单片机,尤其是16位单片机,得到了越来越多的推广,其应用领域越来越广泛。本文选取一种常见的凌阳科技的16位单片机SPCE061A为例,来介绍单片机程序远程升级的方法。
SPCE061A里内嵌了32K字的闪存(FLASH),即可以作为程序存储空间又可以存储数据,并且有自读写任意闪存地址的能力,本文利用这一功能,提出了通过在单片机中驻留BootLoader程序的方法,来实现单片机程序的远程升级。
远程升级的实现,需要单片机自身的响应同时还需要远程服务器提供升级所需的代码。下文将通过这两个方面来分别介绍。
2.单片机程序
2.1 工作原理
为了使单片机可以响应远程升级,这里采用了在单片机里预设Bootloader程序的方法。
BootLoader是一段引导程序,它驻留在单片机中,当单片机上电/复位后在用户程序之前先运行。它运行后先判断当前是否需要进入升级状态。如果不需要升级,就直接运行Flash中原有的程序;如果需要升级,首先擦除旧的程序,然后从串口接收用户程序,同时写入Flash中。
在单片机正常运行过程中,当收到预先设置的升级指令时,即结束当前任务,修改升级标志位,然后自动复位转入BootLoader程序;当BootLoader程序检验到升级标志位时即可进行升级。在单片机正常启动、复位时,由于有标志位的作用,不会受到影响。
BootLoader程序可以从多种方式获取数据,包括485、422、GPRS、CDMA、网口、串口等等;虽然各种获取方式不同,但是在 BootLoader的设计上都大致相同,而且GPRS、GSM和CMDA等通讯方式都是使用串口;485、422等通讯方式与串口类似。为了节省篇幅,本文就以串口为例进行介绍。
在BootLoader设计过程中,需要注意下面方面问题:一是精简问题,为了使得用户程序可以获得最大的程序空间,就需要BootLoader程序尽可能的简短;再一个是中断问题:BootLoader应尽量不使用中断,以避免对用户程序的影响;还有就是标志位的问题,标志位的应该不受复位的影响,在本设计中,选取了单片机FLASH中的一个字节。
2.2设计思路
单片机系统上留有一个半串口通过232芯片与PC机的串口相连接。当单片机上电或者复位后BootLoader开始运行,并通过访问升级标志位来确定定当前是否需要进入升级状态。如果没有升级标志,就直接运行Flash中原有的程序;反之,则转入升级子程序,把从串口接收到的程序代码写入Flash 中。图1表示了BootLoader主程序的流程。
升级子程序中,为保证接收到的数据是正确的,避免将错误的程序写入到芯片中,本文提出的方法采取了固定的数据格式,并且采取了反复确认的方法。图2 表示了升级子程序的流程。在指令格式的选取上,本文采用了Motor S37格式,并在其基础上加上了确认机制,其具体格式将在PC机程序一段做详细介绍。
2.3 FLASH的擦写方法
SPCE061A是一个用闪存替代掩膜ROM的MTP(多次编程)芯片,具有32K字(32K*16bit)闪存容量。用户可用闪存来存储用户程序。为了安全起见,不对用户开放整体擦除功能。
此外,为保证程序的正确编写,用户必须在编程之前擦除页的内容。页大小为0x100。第一页地址范围:0x8000~0x80FF,最后一页的地址范围:0xFF00~0xFFFF。0xFC00~0xFFFF范围内的地址由系统保留,用户最好不要用本范围内的地址。 32K字的内嵌式闪存被划分为128个页(每个页存储容量为256个字),它们在CPU正常运行状态下均可通过程序擦除或写入。
闪速存储器芯片的编程操作是自动字节编程,既可以顺序写入,也可指定地址写入。编程操作时注意芯片的编程时间参数。Flash程序空间为 0x8000—0xFFFF,Flash命令用户接口地址为0x7555。第一页范围是[0x8000—0x80FF],最后一页[0xFF00— 0xFFFF]。1. 擦除一页流程是:先给命令用户接口地址0x7555里送0xAAAA,然后再给命令用户接口地址0x7555里送0x5511,再后给要擦除页地址送任意数,约20ms即可完成擦除操作,然后可以执行其它操作。例如擦除第6页[0x8500—0x85FF]流程如下:
(1)0x7555 ß0xAAAA(2) 0x7555ß0x5511(3) 0x85XXß0xXXXX (其中X为任意值) 2. 写入一个字流程是:先给命令用户接口地址0x7555里送0xAAAA,然后再给命令用户接口地址0x7555里送0x5533,再后给要写入字地址送数据,约40us即可完成写入操作,然后可以执行其它操作。例如向0x8000单元写入0xffff流程如下:(1)0x7555ß0xAAAA (2) 0x7555ß0x5533 (3) 0x8000ß0xffff 3. 写多个字流程是:
先给命令用户接口地址0x7555里送0xAAAA,然后再给命令用户接口地址0x7555里送0x5544,然后给要写入字首地址送数据,约40us即可完成1个字写入操作。再给命令用户接口地址0x7555里送0x5544,给要写入字地址送数据,等待40us即可,循环操作,即可完成多字的写入。
3. PC机程序
为了实现单片机程序的正确下载,需要有PC机程序配合,以提供升级程序的代码。PC机程序主要负责解释和发送Motor S37格式的程序代码,并完成与单片机进行代码传输的反复确认以保证程序的正确下载。
3.1 Motor S37 格式
凌阳单片机的程序代码可以是被编译成Motor S37格式和TSK两种格式。本文中所选取的代码格式是Motor S37格式。为了解释Motor S37格式的代码,就要先来看看它的格式,见表1。
字段 |
内容详细介绍 |
记录类型 |
表示文件记录的开始,记录类型有下列规定: ASCII码 S3-数据记录;ASCII码 S7-记录结束符。 |
记录长度 |
规定了包括地址、数据和检验和字段的记录长度。8位的记录长度值被转换成两个ASCII字符码,高位在前。 |
装入地址 |
这是由二进制地址码转换成的8个ASCII字符码,在此地址开始装入文件记录。其顺序依次为: 高字中的高字节中的高位数,高字中的高字节中的低位数, 高字中的低字节中的高位数,高字中的低字节中的低位数, 低字中的高字节中的高位数,低字中的高字节中的低位数, 低字中的低字节中的高位数,低字中的低字节中的低位数, 本字段在记录结束时给出记录的起始地址,或者连续的8个0的ASCII字符码。 |
数据 |
文件中实际的数据也被转换为每每两个ASCII字符码字节,高位在前。在出现记录结束符时意味着数据字节记录结束。 |
检验和 |
它是关于记录长度、装入地址及数据字段的总和;是以1的补码形式由一个8位二进制数转换成的两个ASCII字符码,也是高位在前。 |
表1 Motor S37 格式的代码文件格式
下面我们以一段实际的Motor S37 格式的代码来具体说明Motor S37 格式。
S31500010022237041941193227009B34000455E1BD798
S30B0001FFFA3B803B800980FB
S307000100000000F7
S70500000000FA
这段代码是从实际的程序代码中截取出来的几句。前面几行是以S3开头,表示数据记录;最后一行以S7开头,表示结尾。S3或者S7后面跟着的两位是数据长度,都是以16进制表示,15即表示十进制的20,其长度表示的是此行里8位数据的个数。后面的8个ASCII码是装入地址,这里要注意的是凌阳 SPCE061A是16位单片机,而S37文件中的地址是以8位来计算的,所以地址都要除2来计算实际地址。如第一行中的00010022,其在单片机中的实际地址是0x8011。地址的后面是数据,其数据表示也是按照8位来表示的,需要转换到单片机中的16位。拿第一行来举例,原来应写在 0x00010022上的0x23和写在0x00010023上0x37,就应改为写到0x8011上的0x3723。
3.2 确认机制
为了进一步的保证程序升级的可靠性,本文在Motor S37的基础上又加上了确认机制。即在单片机收到数据后,回传一遍数据,然后等待PC机确认;当PC机确认数据正确后,发送ACSII码S1作为ACK信号;否则发送S2作为DCK信号。确认机制牺牲了系统的效率,但是提高的可靠性,本文建议在一些链路状况较差的环境加上确认机制。
3.3 程序的偏移量
此处要说明的是,由于BootLoader代码占用了一定的程序空间,真正的用户代码的存放要从启动代码后开始,这就需要在编译程序的时候设置好偏移量,使得用户代码存储在BootLoader代码之后。在凌阳IDE184中,偏移量可以在 Project->Setting->Section(如图3)中设置。图中所示是设置了256字的偏移量,即0x100。因为 SPCE061A的程序空间是从0x8000开始,所以下图中代码段的起始地址为0x8100。
图3 偏移量的设置
针对本文的实现方法,把偏移地址设置在了0x8500,也就是说BootLoader运行后会自动启动0x8500处的代码。
4 结束语
本文所介绍的设计已经进行了实现,试验效果良好。在选取某些不稳定链路作为数据获取方式时或者是复位可能对链路造成影响的情况下,例如GPRS链路,为了进一步提高程序升级的可靠性,系统还可以外扩RAM,在系统复位之前下载全部的升级程序代码到RAM中,然后再复位启动直接改写程序空间。
本文创新之处在于提出了远程升级单片机系统内部程序的方法,方案可靠性高,容易实现,虽是以SPCE061A为例,但可普遍应用于各类可自我擦写程序空间的单片机;本文虽是以从串口获取数据为例介绍了单片机程序远程升级的思路和实现方法,但485、422等通讯方式与串口类似,而且GPRS、GSM 和CMDA等通讯方式归根到底都是使用串口,所以根据本文的设计理念可将获取数据的方式替换为GPRS或者485甚至网卡等等更加复杂传输手段。使得有以上各种接口的单片机产品都可以进行程序的远程升级,而不必对产品进行召回。有一定的实用价值。
参考文献:
[1] 罗亚非。凌阳16位单片机应用基础[M].北京:北京航空航天大学出版社,2003,31-32.
[2] 朱海君,敬岚,陆军。基于MSC1210单片机的串口通讯设计。《微机算计信息》。2004 No.4 P.48