内容提要
引言
一方面,随着半导体技术的不断进步(按照摩尔定律),MCU内部集成的逻辑功能外设越来越多,存储器也越来越大;另一方面,消费者对于汽车节能(经济和法规对排放的要求)型、舒适性、互联性、安全性(功能安全和信息安全)的要求越来越高,特别是近年来新能源电动车、车联网和自动驾驶技术的兴起,更大大加速了汽车电子技术的发展。汽车电子ECU(Electronic Control Unit--电控单元)集成的功能日益复杂,为了应对软件远程(在线)功能升级(增加新的功能)和bug修复的需求、对bootLoader(启动加载程序)的需求越来越多。本文将详细介绍汽车电子ECU BootLoader的开发要点,以供大家学习。
1. bootloader的功能
BootLoader,顾名思义,就是驻留在ECU非易失性存储器中的一段程序加载代码,每次ECU复位后,都会运行bootloader。它会检查是否有来自通信总线的远程程序加载请求,如果有,则进入bootloader模式,建立与程序下载端(通常为PC上位机)的总线通信并接收通信总线下载的应用程序、解析其地址和数据代码,运行NVM(None Valitale Momory--非易失性存储器)驱动程序,将其编程到NVM中,并校验其完整性,从而完成应用程序更新。如果没有来自通信总线的远程程序加载请求,则直接跳转到应用程序复位入口函数(复位中断ISR,也称作Entry_Point()--使用Processor Expert的CodeWarrior 工程或者Startup()函数--普通CodeWarrior 工程),运行应用程序。
基于此,汽车ECU的bootloader三大主要概念如下:
与远程程序下载端建立可靠的总线通信以获取要更新应用程序;
解析应用程序编程文件(S19/HEX/BIN)获得其在NVM中的地址和程序代码及数据;
运行NVM驱动将应用程序的代码和数据编程到NVM中并校验;
2. 如何建立可靠的总线通信?
汽车ECU常见的数据总线有CAN和LIN,因此通常汽车ECU的bootloader都是通过CAN或者LIN下载数据的。当然也可以基于其他总线,比如基于SPI总线或者I2C总线(典型如一些带有安全监测的功能安全ECU,通过主MCU对功能安全监测MCU的程序进行升级)以及以太网(基于Enternet通信的中控或者全液晶仪表的ECU以及下一代高速网关和ADAS ECU)。
Tips:
a. 不同的ECU通信总线不一样,具体需要用到某种通信总线取决于实际应用;
b.通信总线有ECU的MCU外设实现,所以在bootloader中必须开发相应的通信总线外设驱动程序,实现基本的数据发送和接收功能;
c.为了保证通信的可靠性,必须开发一个基于通信总线完善的通信协议,应用程序下载端和bootloader之间需要建立请求命令(request command)、确认(acknowledge)、等待(block wait)、错误重传(error re-send)等机制----bootloader根据不同的请求命令完成不同的任务并确认操作是否完成(ACK)以及数据是否正被确完整的传输,若出现数据错误(通过校验和或者ECC实现),需要进行自动重传;
d. 应用程序下载端通过需要在PC上基于VC或者C#、QT、Labview等开发GUI软件,实现c中要求的总线通信协议,一般在其底层都是通过调用相应的总线设备,如USB转CAN/LIN的转发器设备的动态库(DLL)的API接口来实现数据的收发,相应的总线USB转发设备都会提供相应的驱动库(DLL)。因此bootloader开发者一般还需具备一定的PC上位机软件开发能力;
e.为了实现数据的可靠传输,一般在总线通信协议中添加信源编码,即在发送是对有效数据进行校验和或者ECC计算并将结果在通信数据帧中和有效数据一起发送,bootloader接收端,接收到数据帧后对有效数据域进行发送端同样的校验和或者ECC计算,得出结果与接收到的校验和或者ECC计算结果值进行比较从而判断数据的完整性。应用程序编程文件(S19/HEX/BIN)都具有相应的校验和机制,所以可以采取直接传送程序编程文件行的方式;否则,用户需要在上位机软件中首先解析编程文件,再将其中的地址和数据及代码封装打包成某种定制的通信协议,在bootloader中还得对其进行解包,这样一来,略显麻烦,但有些主机厂(Car OEM)为了知识产权保护,有自己的bootloader协议,这种情况下,bootloader开发者就必须按照主机厂的要求来开发;
f. 一些正规的大主机厂要求其ECU供应商开发放入ECU bootloader必须基于UDS等总线诊断协议,在UDS中规定了相应的CAN ID给bootloader使用,那么久必须在该类ECU中的bootloader工程中加入相应的UDS协议栈;
3. 解析编程文件(S19/HEX/BIN)
不同的MCU软件开发IDE编译链接生成的编程文件格式可能不同,但S19、HEX和BIN文件之间是可以相互转化的,所以只需要在bootloader中开一种编程文件的解析程序就可以了,其他的可以使用相应的转换工具(convert tool)在上位机上进行转换;
对编程文件的解析,目的在于获得应用程序的程序代码和数据及其在NVM中的存储地址;
为了解析编程文件必须先了解其中的编码格式和原理,常用的S19、HEX和BIN文件的格式说明请参考如下维基百科链接:
S19文件:https://en.wikipedia.org/wiki/SREC_(file_format)
HEX文件:https://en.wikipedia.org/wiki/Intel_HEX
BIN文件:https://en.wikipedia.org/wiki/Binary_file
Tips:
S19和HEX文件都是可以直接使用文本编辑器(比如记事本,notepad++)打开的,只需要将包含地址和数据代码的S1、S2和S3开始的S19文件行合并即可,可以手动拷贝,也可以编写window批处理脚本来处理;当然也有专门的可以支持两个S19文件的合并,网上可以找到很多开源软件,比如常见的Srecord等;
MCU的软件开发IDE一般都集成不同编程文件之间的转换工具:比如S32DS的objcopy(Create Flash Image )
以及Keil的Motorola S-Record to BINARY File Converter http://www.keil.com/download/docs/10.asp
4. NVM驱动程序开发
ECU的NVM一般包括其MCU片内集成的用于存放数据的EEPROM或者Data-Flash和用于存储程序代码/数据的Code-Flash/Program-Flash以及MPU扩展的片外NOR Flash或者NAND-Flash;NVM驱动程序包括对NVM的擦除(erase)、编程(program)和校验(verify)等基本操作,也包括对NVM的加密(secure)/解密(unsecure)和加保护(protection)/解保护(unprotection)操作。
Tips:
a. MCU片上集成的NVM中EEPROM/D-Flash和C_Flash/P-Flash一般属于不同的block,所以可以直接在Flash上运行NVM驱动对EEPROM/D-Flash进行擦除和编程操作;
b. NVM驱动一般都是通过运行一个NVM command序列,在其中通过NVM控制器寄存器给出不同的NVM操作命令代码、NVM编程数据和目标地址的方式完成,典型的NVM command序列如下(Freescale的S12(X)系列MCU Flash write command 序列):
c. 由于NVM的工作速度一般较CPU内核频率和总线频率低,所以运行NVM驱动前必须对NVM进行初始化,将设置分频器其工作频率设置为正常工作所需频率范围;
d. MCU片内的NVM同一个block上不能运行NVM的驱动对其自身进行擦除和编程操作,否则会传出read while write的总线访问冲突(每个NVM block只有一条数据总线,一个时刻只能进行读出或者写入,不支持同时读出和写入)。因此对于仅有一个block Flash的MCU来说,就必须在RAM中调用其NVM驱动,来对其自身进行擦除和编程操作,同时在launch Flash command到等待command完成期间必须关闭CPU全局中断,禁止外设中断响应,否则取中断向量和运行中断ISR都会访问Flash。要使能中断,就必须将中断向量表偏移到RAM或者NVM block(EEPROM/D-Flash)并将响应的中断ISR也拷贝到其他RAM或者NVM block上(当然该中断向量表也必须更新指导新的中断ISR);
e. 由于以上b的要求,通常需要将bootloader的NVM驱动拷贝到MCU的RAM中运行,其可以将其完成的NVM拷贝到RAM中运行,也可以只拷贝NVM command launch到等待command完成的几条指令到RAM执行即可,因为NVM驱动中其他操作(比如填写NVM操作命令、写入编程地址和数据等)并不会往占用数据总线上往NVM中写入数据;
f. NVM的驱动程序驻留在Flash中,如果出现堆栈溢出等意外程序跑飞意外运行NVM驱动程序则会造成NVM内容意外擦除丢失或者修改的情况。因此需要对关键数据或代码(比如bootloader本身)进行保护以防止意外修改,或者更为安全的方法是不将NVM驱动程序存放在NVM中,而是在bootloader最开始通过上位机将其下载到RAM中运行,bootloader结束后将该区域RAM清除,从而避免由于意外运行NVM驱动程序造成的NVM数据丢失和修改。(PS:后续我会专门写一篇文章介绍相关的方法,尽请关注阅读)
g. 一般MCU厂商都会给出其MCU的NVM驱动库,用户可以使用该类库实现NVM操作,如果是Freescale/NXP的汽车级MCU,还可以使用CodeWarrior IDE集成的Processor Expert生成相应的NVM驱动程序;
5. bootloader开发的其他要点
a. bootloader与应用程序的关系
bootloader必须使用MCU默认的中断向量表,因为每次复位后MCU都是从其默认中断向量表的复位向量取地址执行的;应用程序的中断向量必须进行偏移(通过相应的中断向量偏移寄存器,如S12(X)系列MCU的IVBR寄存器或者ARM Cortex M系列MCU的SCB->VTOR寄存器);而NVM(P-Flash)的擦除都是按照sector进行的,所以为了充分利用NVM(P-Flash)空间,都将bootloader分区到包含默认中断向量表的若干NVM(P-Flash)sector(S12(X)系列MCU的NVM最后若干sector, ARM Cortex M系列MCU从0地址开始的若干sector);
Tips:
如果应用程序新过程中断电或者意外复位,则应用程序更新失败,相应的应用程序完整性校验通不过,当然得重新下载,为了避免这种情况下应用程序丢失,常常BootLoader需要对应用程序进行双备份,即使用两个不同的NVM分区来保存应用程序,只有新的应用程序更新成功之后,才擦除老的应用程序,否则下次复位之后还是运行老的应用程序
b.bootloader到应用程序的跳转方法
开发使用bootloader后,每次ECU复位之后都将首先运行bootloader,若无远程应用程序下载请求则直接跳转到应用程序复位函数地址,这里面有两个问题需要考虑:
如何获得应用程序复位函数地址:方法有:1)通过链接文件固定应用程序的复位启动函数地址;2)从应用程序中断向量表的复位向量地址获取;推荐方法2):因为其灵活性好,每次应用程序变化后无需关心应用程序复位函数被编译到了NVM的具体地址,只需要将应用程序中断向量表中的复位向量取出运行即可:
典型方法如下(假设S12(X)系列MCU的应用程序中断向量表基地址寄存器IVBR=0x7F):
typedef void (*near tIsrFunc)(void);/* ISR prototype definition */
word *Ptr; /*pointer used for ISR vector fecth*/
Ptr = (word *)0x7FFE; /*get the ISR vector from the interrupt vector table of APP project */
((tIsrFunc)(*Ptr))(); /*covert and run*/
跳转时机:方法有:1)bootloader更新完应用程序并校验其完整性OK之后,将用到的外设(比如CAN/LIN通信总线模块、定时器、GPIO等)寄存器恢复到复位后的默认状态,然后直接跳转;bootloader更新完应用程序并校验其完整性OK之后,等待看门狗定时器超时溢出复位,在bootloader最开始判断无远程应用程序下载请求而跳转;推荐使用方法2):因为方法1)相对于软件复位,其跳转至应用程序复位启动函数时MCU的硬件环境与直接运行应用程序可能存在差异,而方法2)的看门狗复位则属于硬件复位,其会将绝大部分外设(模拟、时钟和外设)电路复位,更接近直接运行应用程序的情况。
c. 开发bootloader需要掌握的知识和调试方法技巧
首先,开发bootloader需要对ECU所用的MCU的RAM和NVM资源十分清楚,然后对其进行分区,保证应用程序和bootloader的NVM分配没有重叠。所以必须了解所用软件开发工具IDE的链接文件的使用方法和编写规则;
然后,需要判断中断向量表偏移是否成功,NVM驱动拷贝的地址和大小等信息,所以必须掌握所用软件开发工具IDE的编译链接结果中map文件的具体信息;
此外,掌握如何将NVM函数重定向(将函数程序代码的存储地址和运行时地址分开)到RAM中执行的方法也十分有用;
Tips:
在开发应用程序时,需要先对其进行单独调试以保证其功能正常,这时虽然其外设中断向量表已经进行了偏移,但其复位向量必须的放置在默认中断向量表中复位向量所在的地址,否则下载后无法运行,进行正常调试,因为如果把应用程序的复位向量放在偏移后的应用程序中断向量表中,则默认的复位向量内容为0xFFFF(Flash擦除后的状态),CPU内核就会到0xFFFF的地址取指运行,显然不是真实的工程启动函数,所以无法运行,其结果跟一个新MCU未写入任何程序时上电运行的情况一样,会不断的出现非法地址复位;而在应用程序开发完成后,再将其偏移到应用程序中断向量中,以避免与bootloader工程的Flash地址冲突;
最后,掌握利用调试器的Hotsync或者attach方法加载elf文件中的调试信息对bootloader和应用程序进行无缝调试也是非常实用的,可以大大提高bootloader的调试效率;
d.量产时bootloader和应用程序的下载方法
推荐将bootloader和应用程序编译链接生成的编程文件进行合并,一次性使用量产工具(如Cyclone编程器)下载以提高生产效率。
总结
本文详细介绍了汽车电子ECU bootloader的一般性工作原理和开发要点,其适用于所有的汽车电子ECU bootloader开发,当然不同的MCU其软件开发工具IDE和CPU内核对中断的处理机制等各不相同,所以后续我还将继续推出系列公众号文章,介绍S12(X)系列MCU、MagniV S12Z系列MCU和Qorivva MPC56xx/57xx系列MCU以及KEA/S32K系列MCU的bootloader开发实例介绍,并提供相应的demo工程供大家参考学习,敬请关注!
以上就是今天跟大家分享的内容。希望对大家有用。
本微信公众号已经发布的个人原创精品----嵌套嵌入式系统技术文章链接如下,欢迎大家参考学习,并转发分享:
汽车电子expert成长之路公众号系列文章列表
浅谈嵌入式MCU开发中的三个常见误区
浅谈嵌入式 MCU 软件开发之应用工程的堆与栈
浅谈嵌入式MCU软件开发之中断优先级与中断嵌套
浅谈嵌入式MCU软件开发之代码风格与代码优化
浅谈嵌入式MCU软件开发之startup过程详解(从复位向量到main函数之前的准备工作)
浅谈嵌入式MCU软件开发之startup过程详解(在CodeWarrior 5.1 中实现RAM自定义初始化)
浅谈嵌入式MCU软件开发之S12(X)系列MCU 中断ISR在CodeWarrior 5.1 IDE 中的三种写法
浅谈嵌入式MCU硬件设计之MCU最小系统电路
S12(X)系列MCU的片上存储器资源与分页访问机制详解(一)
S12(X)系列MCU的片上存储器资源与分页访问机制详解(二)
S12(X)系列MCU的加密(Secure)原理和解密(Unsecure)方法
使用 Cyclone 离线编程器对 S12(X)和 MagniV S12Z 系列 MCU 片上 NVM 编程
Qorivva MPC56xx/57xx系列MCU的模式控制与切换(片上外设资源使能与功耗控制)
外设使用Tips之MSCAN接收ID滤波器设置
外设使用Tips之TIM定时器使用FAQ和使用经验
外设使用Tips之MPC574xP系列汽车级MCU的SWT看门狗定时器配置与使用
S32DS 使用 tips--使用Flash from file下载S19或elf文件
S32DS 使用tips--S32DS for ARM v1.3工程到S32DS for ARM V2.0迁移升级方法和注意事项
S32DS 使用 tips--工程属性配置(编译选项和C编译器、汇编器及链接器设置)
CodeWarrior IDE使用tips之map文件详解
CodeWarrior IDE使用tips之prm链接文件详解(自定义存储器分区以及自定义RAM数据初始化与在RAM中运行函数)
CodeWarrior IDE使用tips之bug定位绝技--hotsync与attach调试
CodeWarrior IDE 版本选择与 License功能(feature)和价格,授权形式差异、激活方法与安装使用
如果你喜欢本公众号的文章,请点击文章最开始的公众号关注或微信直接长按扫描识别下方二维码关注,你也可以在微信添加朋友-->公众号-->输入"汽车电子expert成长之路"搜索-->点击关注。若对本文观点有任何意见和建议也欢迎留言指出。您的关注、点赞、转发分享是对我辛勤写作的最大肯定。
胡恩伟
NXP汽车电子FAE
2017年9月17日于山城重庆
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。