最近做一个产品,由于是新品不了解现场环境,导致仪表到现场安装完了还要改程序。这样就悲剧了要把仪表拆开,断开看门狗连上电脑才能修改程序。所以想要使用IAP(通俗的说就是程序下修改ROM的内容)来修改程序,这样就可以避免以上问题。
带着这样的问题在网上搜索相关内容,首先搜索到的是战舰开发板串口升级程序,
www.openedv.com/posts/list/11494.htm这是一篇非常好的文章。通过这个教程我们可以了解STM32的启动过程,以及调用中断函数的过程这里我就不多说了。但是实验下来发现这个是一个好的教程但不是一个好的方案。主要问题有三点
1、升级程序不能离开电脑(或者自己串口发送设备)‘;
2、要升级的程序是先通过串口写到RAM再写道ROM中的,这样就有很大的局限性。比如代码的大小不能大于RAM的大小等;
3、无校验功能,串口通讯存在一定的不可靠性可能会出现 错误的代码文件。
带着以上三个问题继续思考,要解决第一个问题首先需要一个程序的载体(存储器)。这个载体需要通用型强,携带方便这样SD卡和U盘就在我的考虑范围之内了。选哪一个呢我们看看他们的优缺点
1、首先不管是SD卡还是U盘都需要移值文件系统;
2、SD卡在接口方面是SPI驱动比较简单(无SPI口也可以通过IO口模拟实现);
3、U盘的接口为USBHOST接口(无法模拟)。
考虑到通用(部分单片机不带USB—OTG)和易用性最终选择了SD作为程序的载体升级程序。
第二个问题RAM大小的局限性,可以通过数据流的方式解决,简单说就是把数据分段搬到RAM中再写到ROM中。
第三个问题校验的问题,校验的问题想到两个方案
1、使用上位机程序处理BIN文件加上头尾以及校验码,这样感觉是一个新的文件格式了呵呵;
2、使用HEX文件直接烧写程序(HEX文件自带校验)。
考虑到简单易用选用了HEX的文件烧写解决校验的问题。
这样通过以上方案论证得出最终的方案为,使用SD卡作为文件的载体 ,数据分段写入ROM中采用带校验的HEX文件作为烧写的源文件进行IAP更新程序。
////////////////////////////以上为方案论证///////////////////////////////
//////////////////////////////////方案实现/////////////////////////////////////
SD卡的驱动以及文件系统的移植网上的资料比较多,大家可以搜一下。战舰的例程就是非常好的这里不多讲。本文要着重讲一下HEX文件,HEX文件无法直接写到ROM中要转为BIN可以。那么如何转换呢,这样我们首先就要学习HEX文件的编码格式。看一下KEIL的官方说明
www.keil.com/support/docs/1584.htm在这个网页里面详细的说明了了HEX文件的编码格式。
[size=1.125em] [size=1.125em]简单说一下HEX文件格式:
一个Intel HEX文件可以包含任意多的十六进制记录,每条记录有五个域,下面是一个记录的格式.
:llaaaatt[dd...]cc
每一组字母是独立的一域,
每一个字母是一个十六进制数字,
每一域至少由两个十六进制数字组成,
下面是字节的描述.
:
冒号是每一条Intel HEX
记录的开始
ll
是这条记录的长度域,
他表示数据(dd)
的字节数目.
aaaa
是地址域,
他表示数据的起始地址
tt
这个域表示这条HEX
记录的类型,
他有可能是下面这几种类型
00 ----
数据记录
01 ----
文件结束记录
02 ----
扩展段地址记录
04 ----
扩展线性地址记录
05 ----启动地址记录行(只有MDK-ARM下才有)
dd
是数据域,
表示一个字节的数据,
一个记录可能有多个数据字节,
字节数目可以查看ll
域的说明
cc是效验和域,表示记录的效验和,计算方法是将本条记录冒号开始的所有对字母所表示的十六进制数字都加起来然后模除256得到的余数最后求出余数的补码即是本效验字节<span lang="EN-US" style="font-size:10.5pt;mso-bidi-font-size:12.0pt;font-family:"Tahoma","sans-serif";mso-fareast-font-family:宋体;color:#333333;mso-font-kerning:1.0pt;mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA">cc.
='0'&&l='a' && l='A' && l='0'&&h='a' && h='A' &&h = nSize)
{
return false;
}
for(nPos=nStart; nPos=60)
{
return false;
}
memcpy(strLine, pBuff+nStart, len);
strLine[len] = '\0';
nStart = nPos+2;
nRemain = 0;
return TRUE;
}
}
//最后一行没"\r\n"
len = nPos-nStart;
if(len >=60)
{
return false;
}
memcpy(strLine, pBuff+nStart,len); //拷贝数据
strLine[len] = '\0';
// printf("%s\n",strLine);
nRemain = len;
nStart = nSize;
return false;
}
对数据校验
BOOL CheckHexFile(char *source, UINT MaxDataSize ,char *hexLineBuffer)
{
char binBuffer[30];
U16 lenTemp,loopTemp;
U16 checksum ;
U32 bootAdd;
//static char hexLineBuffer[60];
if(MaxDataSize == 0 || source == NULL)
{
return false; //无有效存储空间
}
ReadLineInBuff(hexLineBuffer, source, MaxDataSize, true);//初始化
while(ReadLineInBuff(hexLineBuffer, source, MaxDataSize, false))
{
lenTemp = strlen(hexLineBuffer);//printf("%x %d",hexLineBuffer[0],lenTemp);
if(hexLineBuffer[0] != ':' || lenTemp