基于飞思卡尔的Bootloader程序下载更新前言写这篇文档是因为大三暑假时在一家公司实习,做一个基于飞思卡尔的bootloader远程更新项目,刚开始定的技术指标是基于MC9S12XS128单片机的Bootloader程序、远程(基于GSM网络)和CAN总线通信。
但因为我只是一个本科实习生而且实习时间只有一个多月,所以只完成了基于SCI的本地写入.S19文件的更新。
这大概也就是这篇文档所包含的内容啦。
整个程序是存在瑕疵甚至基本上可以说是不成功的,但是我觉得自己在做这个项目的过程中确实也解决了网上没有提到或者没有答案的一些问题,特写此文档,希望大家各取所需,如果有什么高见或者发现了我明显错误的地方,也非常欢迎大家给我指出。
欢迎大家前来指教。
小目录一、Bootloader的含义---------------------------------------------------------2二、SCI串口的使用------------------------------------------------------------3三、Flash的擦除和写入--------------------------------------------------------5四、.S19文件的写入-----------------------------------------------------------13五、心得体会-----------------------------------------------------------------14一、Bootloader的意义与作用关于Bootloader的意义网上非常之多,这里针对单片机的Bootloader程序进行说明。
Bootloader是在单片机上电启动时执行的一小段程序。
也称作固件,通过这段程序,可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用应用程序准备好正确的环境。
Boot代码由MCU启动时执行的指令组成。
这里的loader指向MCU的Flash中写入新的应用程序。
因此,Bootloader是依赖于特定的硬件而实现的,因此,在众多嵌入式产品中目前还不可能实现通用Bootloader。
Bootloader的最大优点是:在不需要外部编程器的情况下,对嵌入式产品的应用代码进行更新升级。
它使得通过局域网或者Intemet远程更新程序成为可能。
例如,如果有5000个基于MCU的电能表应用程序需要更新,电能表制造商的技术人员就可以避免从事对每一个电能表重新编程的巨大工作量,通过使用Bootloader的功能,由控制中心通过电能表抄表系统网络,远程对5 000个电表重新编程。
可见,Bootloader功能对于嵌入式系统的广泛应用具有十分重要的意义。
再举一个例子。
就拿我自己做这个程序的目的来说,我所在的公司将自己的产品卖到全国各地,如果哪一天公司的底层软件工程师(单片机工程师)想要升级底层软件,就可以借助GSM网络直接通过单片机中的Bootloader程序进行底层软件的自我更新,而不是派出售后人员一台一台的进行更新,节省了大量的人力物力。
注意点:平时我们最常用到的下载程序的方法是通过USB数据线或其他数据线进行程序的烧写,这个方式是通过外界提供给单片机高电压来对flash擦除和写入完成的。
而Bootloader不需要外界提供高电压仅靠正常工作电压便可完成对flash的擦除和写入,从而达到更新程序的目的。
二、SCI串口的使用前面也提到,我做的是通过SCI串口的本地更新。
SCI(Serial Communication Interface,串行通信接口)是最常用、最经典的串行通信接口方式。
通信双方除了要按照约定的真个是进行数据通信外,还要约定相同的通信速率,在SCI通信中使用波特率来表示。
串行通信的波特率被定义为每秒内传送的位数,单位为b/s或bps,常用的波特率有1200bps,4800bps,9600bps,19200bps,38400bps等。
SCI的使用主要注意两点:波特率的设置和工作方式的选择,我选择的是中断工作方式。
波特率:设置波特率的主要目的是使单片机和上位机(上位机在这里就指将信息发给单片机的PC端)保持同步。
MC9S12XS128的波特率寄存器是SCIBDH和SCIBDL,总共16位但是只有13位可以写入。
SBR[12:0]:波特率常数,取值1~8191.波特率发生器的时钟输出是由MCU内部总线时钟BUSCLK分频而来,SBR[12:0]就是分频系数,而SCI模块需要的工作时钟为波特率的16倍。
SCI的波特率计算公式如下:SCI=f BUS/(16*SBR[12:0])波特率的计算数结果些许误差可以忽略,以约等于常见通用的串行通信波特率数值。
说了一大堆,到底如何设置不同的波特率呢,通过具体的程序代码来体现一下。
#define SCIBusClock 8000000// MC9S12XS128的总线时钟是8MHz #define SCI38400bps (unsignedint)((unsignedlong)(SCIBusClock)/(unsignedlong)(614400))//38400 * 16 38400波特率#define SCI19200bps (unsigned int)((unsigned long)(SCIBusClock) / (unsignedlong)(307200))//19200 * 16 19200波特率#define SCI9600bps (unsigned int)((unsigned long)(SCIBusClock) / (unsigned long)(153600))// 9600 * 16 9600波特率#define SCI4800bps (unsigned int)((unsigned long)(SCIBusClock) / (unsigned long)(76800))// 4800 * 16 4800波特率#define SCIBaudRate SCI9600bps //大多数情况下用9600波特率中断工作方式:选择中断的工作方式,一有数据从SCI串口输出,单片机便立马进行接收处理。
主要对SCI0CR1和SCI0CR2进行操作。
SCI0CR2=0x2C; //0010 1100 RIE=1,TE=1,RE=1//RIE=1 接收数据寄存器满和重叠中断请求使能//TE=1 发送器使能//RE=1 接收器使能具体的数据接收代码为://SCIReceiveN:串行接收N个字节数据------------------------------------------*byte SCIReceiveN(void){while (!SCI0SR1_RDRF);//如果SCI0SR1_RDRF为1则表示数据起存器接收到的数据有效return SCI0DRL;//返回接收到的值,即SCI数据寄存器SCIDRL中的数据}温馨提醒:SCI程序到底对不对,有没有正常的工作,还是要通过上位机来观察。
这就牵扯到用什么软件来作为单片机和上位机的接口。
网上很多资料推荐一款很经典的软件“超级终端”,但是我个人认为这款软件太“经典”啦,太老啦,导致我一直不知道怎么用的。
如果大家也遇到了这个问题,那么我向大家推荐“友善串口调试”,完全的免费,而且界面简洁,使用简单,英文名为“Serial Port Utility”。
三、Flash的擦除和写入关于Flash的擦除和写入,真的是让我最费力的一部分,网上的相关资料很少,好不容易找到了一点相关代码,却发现程序不能正常的运行,而且更令人无解的是程序本身怎么检查都检查不出错误。
好啦,一点一点的说说我的辛酸史。
首先,如果你在寻找飞思卡尔的flash擦除写入操作,很遗憾的告诉你,如果你用的不是MC9S12XS系列,那么很有可能,你所需要的flash擦除写入操作和我接下来将要说明的擦除写入操作基本上不沾边(除了原理上),因为飞思卡尔不同系列的单片机对flash的擦除写入操作的定义差别很大,不注意型号的话反而会被误导。
至于擦除和写入的原理是什么,这个不是我们关心的,我也不去赘述,我主要说明一下相关的具体操作。
我们主要是对飞思卡尔Flash中的PFlash即存放程序段的Flash进行操作。
如图,步骤大概分为:1、设置Flash分频寄存器:Flash的操作对频率有一定的要求,过低擦除不成功,过高会损毁Flash如图为MC9S12XS128的FCLKDIV寄存器,所有位都是可读的但是只有7位可写入。
至于应该如何设置分频数,有一张表格可以参考:如表格说明,分频数是根据外部时钟来定的,MC9S12XS128的外部时钟是16MHz,所以我选择了0x10作为分频数。
给出一一些具体的代码:/************************************************************* 名称:void PFlash_Init(void)** 功能:PFlash初始化** 入口参数:无** 出口参数:无** 使用说明:无************************************************************/void PFlash_Init(void){while(FSTAT_CCIF==0);//等待正在处理的Flash操作,即CCIF=1时,操作完成FCLKDIV=0x10;//外部晶振为16MHz,Flash时钟设置为1MHzFCNFG=0x00; //禁止中断while(FCLKDIV_FDIVLD==0); //等待时钟设置成功,即FDIVLD为1时设置成功}这里补充一下对FCLKDIV_FDIVLD的说明:说明很简单,一看就看懂。
2、FSTAT状态寄存器在上面的代码中出现了一行,这就涉及到一个很重要的寄存器,就是Flash操作的状态寄存器,就像是Flash操作步骤中的“红绿灯”一样,告诉程序什么时候可以执行什么操作,什么时候必须要等待一下。
如图:其中我们比较关心的是CCIF位、ACCERR位和FPVIOL位,这三位也都是可读可写的。
CCIF:指令完成标志位,当CCIF位为1时,表示上一个Flash操作完成了。
注意图中的高亮部分,如果想要使当前操作的指令完成,需要手动将CCIF清零(标志位置位就是令标志位为0,但具体操作是令标志位等于1),才能触发指令,令指令完成,也就是前面流程图中说明的,才能launch指令。
ACCERR和FPVIOL:这两位主要标志是否有错误操作发生,当为1时,说明检测到错误。