前言
车辆开发过程中软件是会不断迭代更新,新款车辆更是在SOP后可以通过OTA的方式发送给用户更新车载控制器软件,那么在开发过程中如何实现下载并保证安全,本文就以目前本人实际软件开发中遇到过的一些情况进行梳理,目标是理解原理和目的。
软件存储方式
在了解软件下载之前,先对软件如何运行及存储画一个粗略的框架,确认我们下载的是什么东西:
下面是infineon TC36X芯片的存储地址说明
可以看到,里面分了很多模块,为了方便后面说明我们去掉不要的一些东西将其简化一下:
将其抽象成三块存储空间:
- RAM:堆栈,全局变量等存储空间。掉电数据丢失
- DFlash:Data Flash,用于存储一些数据信息,类似故障信息,snapshot,版本选择信息等,写入后掉电数据会保留
- PFlash:Program Flash 用于存储编译后软件,实际软件运行位置,掉电数据保留。
综上,我们的软件运行处于PFlash,因此我们升级的目也是将PFlash部分的程序擦除写入新的软件。
这里要说明一下,一般车载动力域部分各个ECU(例如VCU,BMS,MCU)的相互通信方式一般采取的是CAN通信协议,因此下述的下载方式也都是基于CAN通信进行下载。
软件启动
我们在上面已经了解到软件存储在PFlash中,那么软件是如何运行起来的呢?我们先将PFlash单独拿出来观察:
首先,芯片会说明软件运行的首地址,在英飞凌中就是0x80000000(英飞凌芯片中0x80000000与0xA0000000地址相互映射,因此可能会发现运行地址在0xAXXXXXXX的情况。并且由于有SOTA功能可能导致其实运行位置不一样,此处先不予考虑)。软件启动后首先需要引导程序引导进入软件进入主程序,我们将其命名为IBL(Initial Bootloader)
为什么我们需要IBL呢?
这个就涉及到我们希望自己设计的系统做什么工作了,比如我们只是希望做一个亮灯1s的软件,那么直接在启动时将亮灯时间逻辑加入就行不需要这种引导软件。
但是在绝大多数情况下需要运行的程序是持续性的,这也就需要我们有能够将程序引导进这个持续性运行的loop中的工具,IBL就此而生,而持续运行的程序我们称之为APP(Application)。
在IBL中做什么?
在IBL能做的事情很多,例如初始化各种参数,读取NVRAM(DFlash)的值,使能各种外设,做各种故障诊断等,总之大部分都是些一次性执行的初始化操作。
程序运行至APP后一般OS就已经启动,之后就是将各种功能模块挂载在OS Task中形成调度来实现各个功能。
UDS升级
这也是OEM最常使用的升级方式,借助UDS定义的服务内容及流程进行软件刷写。关于UDS中各种服务及下载过程前后校验关闭故障这里不进行说明,只对存储如何擦写执行进行说明。
在这里先说明下载方式在讨论为什么要这么做
总的来说根据UDS协议,软件在进入APP后要先下载flash driver,再使用flash driver更新APP程序
我们将下载Flash driver的程序命名为FBL(First Bootloader),Flash driver命名为SBL(Secondary Bootloader),我们在boot中加入FBL,将SBL单独拿出来,那么这部分的存储如下图所示:
下面我们一步一步解释这个下载步骤,总体流程如下图所示:
注:虚线部分表示访问数据而不是操作
- ①APP接收到上位机发送的UDS session跳转请求(10服务programming
session),ECU将该服务请求写入NVRAM(图中③所示),ECU执行reset重新进入IBL。 - ②在IBL中判断是否存在下载请求(图中③所示),若有下载请求进入FBL并回复上位机,若没有进入APP。
- ④上位机收到回复判断ECU已经进入下载模式,发送Flash Driver下载包(SBL)。ECU接收到下载包数据将其存储在RAM区域。
- ⑤上位机判断SBL被成功下载,继续发送需要升级的Software。ECU首先擦除PFlash中的APP部分,在将接收到新的软件下载进APP的存储区域。
- 上位机发送reset请求,ECU reset后RAM数据被丢弃。
综上我们可以发现,SBL的数据是单独存放的,并且软件升级成功后会进行删除。为什么需要这种操作呢?
这点与我们软件安全要求有关,SBL中有非常危险的操作就是会删除APP部分的程序,对于这种有删除程序的代码我们都要保持一个十分谨慎的态度对待,并且在正常运行的软件中是不允许这种逻辑存在的,因此这部分内容都是要有外部去管控。
最后说明一些可以注意的点:
- FBL,SBL使用的也是UDS协议,因此一般APP内容要求的UDS协议在这里面也要满足
- FBL下载过程中如果下载中断,重新上下电不会对软件有任何影响,但是SBL下载过程中断电就可能导致ECU成砖。但是由于只擦除了APP的领域,因此可以使用FBL再次重新下载
- 由于SBL只会擦写APP领域,因此IBL部分或FBL部分的软件如果有更新就无法使用这种方法,需要另外重新刷写
- 关于③中写入NVRAM的方式不一定只有这种实现方式,只要控制器Reset后能读到Reset前数据即可,可以有多种设计方式
- 可以看出进入programming session需要跳转到FBL,因此回复应在ECU reset后进入FBL后发送。即先reset在回复响应而不是先回复在reset
XCP升级
我们可以观察到,按照UDS的升级方式虽然能够满足大部分的功能升级,但是有关IBL或FBL的变化更新是无法进行覆盖的,而一般情况下有这种升级需求的只有在开发阶段,因此这就需要我们在开发阶段中有一种新的升级方式来满足开发阶段的要求,用现成的XCP协议就能很好满足。
一般情况下我们使用XCP用于整车标定,例如方向盘标定, ADAS数据标定,电机控制器标定等,不同Tire1对标定内容调教也会有各自不同的经验。一般比较好用的工具就是CANape,当然目前支持这种标定工具的厂商也多起来了,类似CANoe也可以单独购买XCP模块,国产例如同型,虹科等也有自己的解决方案。
我们做类似这种升级可以参考UDS升级去做类似升级应用,但是由于这次我们需要升级到更多的内容模块,因此对应的刷写地址会与UDS升级不同,下面同样以存储方式说明一种设计方法。
首先还是观察一下整体的内存结构
将Boot部分的领域再次划出一块,作为XFBL(XCP First Bootloader)与XSBL(XCP Secondary Bootloader)作为下载程序。
那么按照UDS下载方式类似,我们看下XCP下载有何不同
- ①APP接收到上位机发送的XCP升级请求,ECU将该服务请求写入NVRAM(图中③所示),ECU执行reset重新进入IBL
- ②在IBL中判断是否存在下载请求(图中③所示),若有下载请求进入XFBL并回复上位机,若没有进入APP
- ④在XFBL中将存储的Flash Driver软件(XSBL)复制到RAM区域,完成后跳转至RAM继续执行接下来操作
- ⑤上位机识别到软件进入XSBL,发送整个新的软件包下载,此时升级所有区域的PFlash软件
可以观察到和UDS升级不同,我们将SXBL放到了PFlash区域,并且升级的时候将整个PFlash区域部分全部擦除重新写了,为什么要这样呢?
首先基于我们之前了解为了保证软件安全性,代码中是不能存在擦除PFlash的逻辑存在的,但是这个前提是进入量产阶段,在实际开发过程中难免会遇到这种需要更新的情况,开发过程中过多的操作也会有不同问题,因此我们直接将Flash Driver直接拷贝进RAM做升级会节省很多步骤操作,在真的SOP前需要将这部分逻辑删除保证车辆只能以UDS升级即可。
其次将整个PFlash重新刷写会涉及到刷写软件自身的情况,因此刷写的软件肯定也不能放到PFlash中运行而要单独拿出到RAM中执行。
XCP升级需要注意的几个点:
- 既然整个刷写软件都是放到RAM执行的,那么若中途因为通信干扰等原因导致软件刷写失败了,建议不要断电,否则RAM里程序丢失PFlash中程序也被擦除,可能会导致板子成砖不得不采用其他方式刷写。若不断电RAM中的程序还是存在,还有可能可以继续重新刷写。
- 由于使用的是XCP协议,在最开始会有一个连接步骤,其他XCP工具若同时使用可能会有比较奇怪的问题,例如不同工具同时回复等,因此下载时尽量避免其他CAN上位机干扰。