剖析汽车ECU的bootloader程序

bootload(简称boot)是一种启动加载程序,或者称为引导程序,我们在操作系统和嵌入式开发中经常用到,因为汽车ecu也是一种嵌入式系统,boot程序主要用于ecu软件更新,汽车ota升级,本文主要讲述汽车bootloader程序的工作原理和设计方法。
01
bootloader的功能
bootloader,通常是驻留在ecu非易失性存储器(nvm,none valitale momory)中的一段程序加载代码,每次ecu复位后,都会运行bootloader。它会检查是否有来自通信总线的远程程序加载请求。
如果有,则进入bootloader模式,建立与程序下载端(通常为pc上位机)的总线通信并接收通信总线下载的应用程序、解析其地址和数据代码,运行nvm驱动程序,将其编程到nvm中,并校验其完整性,从而完成应用程序更新。
如果没有来自通信总线的远程程序加载请求,则直接跳转到应用程序复位入口函数(复位中断isr,也称作entry_point()–使用processor expert的codewarrior 工程或者startup()函数–普通codewarrior 工程),运行应用程序。
因此,汽车ecu的bootloader三个主要的作用:
与远程程序下载端建立可靠的总线通信以获取要更新应用程序;
解析应用程序编程文件(s19/hex/bin)获得其在nvm中的地址和程序代码及数据;
运行nvm驱动将应用程序的代码和数据编程到nvm中并校验;
下面就围绕这三个方面展开讲述。
02
如何建立可靠的总线通信?
汽车ecu常见的数据总线有can和lin,因此通常汽车ecu的bootloader都是通过can或者lin下载数据的。当然也可以基于其他总线,比如基于spi总线或者i2c总线(典型如一些带有安全监测的功能安全ecu,通过主mcu对功能安全监测mcu的程序进行升级)以及以太网(基于enternet通信的中控或者全液晶仪表的ecu以及下一代高速网关和adas ecu)。
注意事项:
不同的ecu通信总线不一样,具体需要用到某种通信总线取决于实际应用;
通信总线由ecu的mcu外设实现,所以在bootloader中必须开发相应的通信总线外设驱动程序,实现基本的数据发送和接收功能;
为了保证通信的可靠性,必须开发一个基于通信总线完善的通信协议,应用程序下载端和bootloader之间需要建立请求命令(request command)、确认(acknowledge)、等待(block wait)、错误重传(errorre-send)等机制----bootloader根据不同的请求命令完成不同的任务并确认操作是否完成(ack)以及数据是否正被确完整的传输,若出现数据错误(通过校验和或者ecc实现),需要进行自动重传;
应用程序下载端通过需要在pc上基于vc或者c#、qt、labview等开发gui软件,实现中要求的总线通信协议,一般在其底层都是通过调用相应的总线设备,如usb转can/lin的转发器设备的动态库(dll)的api接口来实现数据的收发,相应的总线usb转发设备都会提供相应的驱动库(dll)。因此bootloader开发者一般还需具备一定的pc上位机软件开发能力;
为了实现数据的可靠传输,一般在总线通信协议中添加信源编码,即在发送是对有效数据进行校验和或者ecc计算并将结果在通信数据帧中和有效数据一起发送,bootloader接收端,接收到数据帧后对有效数据域进行发送端同样的校验和或者ecc计算,得出结果与接收到的校验和或者ecc计算结果值进行比较从而判断数据的完整性。应用程序编程文件(s19/hex/bin)都具有相应的校验机制,所以可以采取直接传送程序编程文件行的方式;
否则,用户需要在上位机软件中首先解析编程文件,再将其中的地址和数据及代码封装打包成某种定制的通信协议,在bootloader中还得对其进行解包,这样一来,略显麻烦,但有些主机厂为了知识产权保护,有自己的bootloader协议,这种情况下,bootloader开发者就必须按照主机厂的要求来开发;
一些正规的大主机厂要求其ecu供应商开发放入ecu bootloader必须基于uds等总线诊断协议,在uds中规定了相应的can id给bootloader使用,那么就必须在该类ecu中的bootloader工程中加入相应的uds协议栈;
3和5的注意事项都是为了满足boot程序设计的安全要求,要特别重视。
03
解析编程文件(s19/hex/bin)
不同的mcu软件开发ide编译链接生成的编程文件格式可能不同,但s19、hex和bin文件之间是可以相互转化的,所以只需要在bootloader中开一种编程文件的解析程序就可以了,其他的可以使用相应的转换工具(convert tool)在上位机上进行转换;mcu的软件开发ide一般都集成不同编程文件之间的转换工具:比如s32ds的objcopy(create flash image )以及keil的motorola s-record to binary file converter 。
解析编程文件的目的在于获得应用程序的程序代码和数据及其在nvm中的存储地址;
为了解析编程文件必须先了解其中的编码格式和原理,常用的s19、hex和bin文件的格式说明请自行查阅。
s19和hex文件都是可以直接使用文本编辑器(比如记事本,notepad++)打开的,只需要将包含地址和数据代码的s1、s2和s3开始的s19文件行合并即可,可以手动拷贝,也可以编写window批处理脚本来处理;当然也有专门的可以支持两个s19文件的合并,网上可以找到很多开源软件,比如常见的srecord等;
04
nvm驱动程序开发
ecu的nvm一般包括:
mcu片内集成的用于存放数据的eeprom或者data-flash;
用于存储程序代码/数据的code-flash/program-flash;
mpu扩展的片外norflash或者nand-flash;
nvm驱动程序 的作用包括
对nvm的擦除(erase)、编程(program)和校验(verify)等基本操作;
对nvm的加密(secure)/解密(unsecure)和加保护(protection)/解保护(unprotection)操作。
注意事项:
mcu片上集成的nvm中eeprom/d-flash和c_flash/p-flash一般属于不同的block,所以可以直接在flash上运行nvm驱动对eeprom/d-flash进行擦除和编程操作;
nvm驱动一般都是通过运行一个nvm command序列,在其中通过nvm控制器寄存器给出不同的nvm操作命令代码、nvm编程数据和目标地址的方式完成,典型的nvm command序列有(freescale的s12(x)系列mcu flash write command 序列);
由于nvm的工作速度一般较cpu内核频率和总线频率低,所以运行nvm驱动前必须对nvm进行初始化,将设置分频器其工作频率设置为正常工作所需频率范围;
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);
由于以上2的要求,通常需要将bootloader的nvm驱动拷贝到mcu的ram中运行,其可以将其完成的nvm拷贝到ram中运行,也可以只拷贝nvm command launch到等待command完成的几条指令到ram执行即可,因为nvm驱动中其他操作(比如填写nvm操作命令、写入编程地址和数据等)并不会往占用数据总线上往nvm中写入数据;
nvm的驱动程序驻留在flash中,如果出现堆栈溢出等意外程序跑飞意外运行nvm驱动程序则会造成nvm内容意外擦除丢失或者修改的情况。因此需要对关键数据或代码(比如bootloader本身)进行保护以防止意外修改,或者更为安全的方法是**不将nvm驱动程序存放在nvm中,而是在bootloader最开始通过上位机将其下载到ram中运行,bootloader结束后将该区域ram清除,**从而避免由于意外运行nvm驱动程序造成的nvm数据丢失和修改。
一般mcu厂商都会给出其mcu的nvm驱动库,用户可以使用该类库实现nvm操作,如果是freescale/nxp的汽车级mcu,还可以使用codewarrior ide集成的processor expert生成相应的nvm驱动程序;
02
bootloader开发的其他要点
1. bootloader与应用程序的关系:
bootloader和应用程序分别是两个完整的mcu软件工程,各自都由自己的启动代码、main()函数、链接文件、外设驱动程序和中断向量表;
因此bootloader和应用程序的链接文件中,对nvm的地址空间分配必须分开独立,不能重叠(overlap),但其ram分配没有约束,两者都可以使用整个ram空间,因为跳转到应用工程后,将启动代码将重新初始化ram;
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);
注意:
如果应用程序新过程中断电或者意外复位,则应用程序更新失败,相应的应用程序完整性校验通不过,当然得重新下载,为了避免这种情况下应用程序丢失,常常bootloader需要对应用程序进行双备份,即使用两个不同的nvm分区来保存应用程序,只有新的应用程序更新成功之后,才擦除老的应用程序,否则下次复位之后还是运行老的应用程序
2. 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)的看门狗复位则属于硬件复位,其会将绝大部分外设(模拟、时钟和外设)电路复位,更接近直接运行应用程序的情况。


3G对中国意味着什么?
回流焊的发展趋势
2020年上半年,中兴通讯营收和利润一直保持上涨状态
PCB射频电路的布局设计
AAF为国产第6代AMOLED项目提供全套解决方案
剖析汽车ECU的bootloader程序
边缘运算正在成为主流趋势
五款电动车充电器电路图讲解
5G将成为三大运营商走向多元化与提质保量的捷径吗
基于RF2514的915MHz AM/ASK发射电路设计
一款用MAX4410的高保真耳放
开关电源的输出电流如何决定_跟什么有关?
第二十二届中国高速公路信息化大会在重庆拉开序幕
华为P30 Pro和iQOO的快充和续航能力对比分析
TME Solution已成为最可靠的长期定制和标准泄漏测试仪器
iic通信协议是什么
燃气报警器电路图大全(六款模拟电路设计原理图详解)
新唐科技推出内置2Vrms驱动器的立体声DAC-NAU8402
全文详解IIR滤波器原理与设计方法
AMD处理器现在真的超越英特尔处理器了吗