尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

HIL测试中的总线与通信协议:从CAN到车载以太网实战指南

HIL测试中的总线与通信协议:从CAN到车载以太网实战指南 从事汽车电子相关开发这么多年一个项目从模型在环MIL到软件在环SIL再到硬件在环HIL和实车路测越到后面越会发现一个事实HIL测试里你真正在测的一半是控制器逻辑另一半是总线和通信协议。如果总线环境搭建得不对控制器之间的对话根本就是对牛弹琴哪怕你模拟出来的信号再精确也大概率是白忙一场。这篇文章我想把HIL测试中的总线和通信协议这部分内容好好梳理一遍。不聊那些高大上的“全栈仿真”概念就讲我们平时在测试台架上真正会遇到的总线类型、协议细节、搭建方法和调试经验。适合刚接触HIL测试的测试工程师也适合那些想搞明白“为什么我模拟的CAN报文明明发出去了控制器就是不响应”的嵌入式开发朋友。1. HIL测试里为什么总线和通信协议是头等大事1.1 HIL测试的原理本质让“假”ECU参与真实对话先花一分钟对齐一下HIL测试的本质。HIL测试把真实的控制器ECU接入一个模拟的车辆环境里通过实时仿真机模拟传感器信号、执行器负载和整车动力学模型让ECU以为自己真的装在一台车上。这个过程中最复杂、最容易出问题的并不是模拟一个水温传感器的电压值而是让ECU与“车上其他节点”通过总线正常通信。之所以说总线是HIL测试的头等大事原因不复杂你在台架上放了一个真ECU这个ECU里跑着完整的应用层软件它源源不断地通过CAN或者LIN向车上其他节点发送信息同时也在等待其他节点回传信息。如果你不把这些“其他节点”在HIL系统中模拟出来ECU就会陷入“孤立无援”的状态它发出的报文没人应答它期待的信号永远等不来。轻则报故障码重则直接进入降级模式甚至下电。总线仿真做得好不好直接决定HIL测试能不能反映真实工况。1.2 HIL与MIL、SIL、PIL的差异总线是从MIL开始就缺席的“主角”很多从模型开发转过来的朋友会有个误区觉得MIL阶段模型里明明也建了总线信号啊到了HIL怎么就这么难。这个实际上是仿真层次决定的测试层级被测对象总线参与方式总线关键度MIL被控对象模型 控制模型模型内部的数据总线无真实物理信号低SIL生成代码后的软件虚拟总线只有逻辑时序中PIL代码运行在目标处理器芯片内的伪并行无外部物理设备中高HIL真实ECU硬件真实物理总线真实收发器实时网络最高到了HIL这一层通信协议不再是“软件里定义的一个结构体”而是要变成实实在在的电平翻转、帧间隙、仲裁场和错误帧。CAN收发器、LIN收发器、以太网PHY芯片都在真实工作任何协议细节上的疏忽都会暴露出来。2. 核心协议拆解从CAN到以太网2.1 CAN与CAN FD搞懂RTR位和SRR位才算入门CAN总线在汽车圈的地位不用多说几乎所有的动力总成、车身控制、底盘系统都建立在CAN通信基础上。HIL测试中超过一半的总线模拟工作都在和CAN打交道。CAN协议里有两个关键位很多新手看帧结构时容易混淆一个是RTR位一个是SRR位。RTR位全称是Remote Transmit Request在标准帧11位标识符CAN 2.0A中位于RTR位置。这个位用来区分当前帧是数据帧还是远程帧数据帧的RTR位为显性0远程帧的RTR位为隐性1。远程帧的作用是请求另一个节点发送某个特定ID的数据。SRR位全称是Substitute Remote Request出现在扩展帧29位标识符CAN 2.0B中。这里有一个很经典的坑扩展帧的仲裁场被分成基址仲裁场11位标识符 SRR位 IDE位和扩展仲裁场18位扩展标识符两部分。SRR位的作用是为了保证在标准帧和扩展帧竞争总线时标准帧具有优先级——因为SRR位设计为隐性替代了标准帧中RTR位的位置所以当标准帧的RTR位为显性数据帧时标准帧在SRR位处赢得仲裁。很多资料直接说“SRR位是扩展帧用来替代RTR位的”这其实不够准确它替代的只是位置仲裁优先级的不同才是设计意图所在。在实际HIL测试中我们经常会用到远程帧来模拟“请求型”节点。比如模拟一个网关节点向某个ECU请求故障码信息就会发一个远程帧。这时候RTR位和SRR位的极性如果配错接收端ECU根本不会把帧当作远程帧处理测试就会卡在“无响应”上。CAN FD在HIL测试中这几年越来越常见。CAN FD引入了BRS位Bit Rate Switch允许从仲裁段到数据段进行速率切换数据段最高可以跑到8Mbps。在HIL仿真环境里CAN FD节点和普通CAN节点混用的时候要特别注意控制器是否开启了FD容错模式。很多ECU在“CAN 2.0节点”和“CAN FD节点”同时存在时会自动切换到混合模式仿真端如果只发了经典CAN流量ECU可能根本不会进入FD通信状态。2.2 LIN总线低速但是一点不能含糊LIN总线在车窗、天窗、座椅调节、后视镜控制这些车身小节点上仍然是绝对主力。LIN是单主多从架构一个主节点最多挂15个从节点通信速率最高20kbps。HIL测试中LIN的仿真相对CAN来说工作量小但问题反而更隐蔽。LIN协议的关键在于调度表。主节点按照调度表周期性发送帧头由同步间隔场、同步场、PID场组成从节点在帧头后面填充响应。HIL仿真LIN主节点时最容易出的问题是同步间隔场的时序做得不对。标准LIN要求在同步间隔场保持至少13位的显性电平然后还要有一个间隔界定符至少1位隐性电平。有些仿真板卡的LIN IP核在做同步间隔场时长度不够或者时序有偏差结果就是从节点的同步逻辑直接崩掉。另一个LIN的坑是PID的奇偶校验位。PIDProtected Identifier由6位帧ID加上两位校验位组成。如果你通过脚本手写PID很容易想当然地把数据段的值替代PID然后去问从节点——从节点返回的自然是“不响应”甚至“响应错误”。正确做法是严格按照LIN规范计算奇偶校验PID ID[5:0] P0 P1其中P0 ID0 xor ID1 xor ID2 xor ID4P1 非(ID1 xor ID3 xor ID4 xor ID5)。HIL仿真LIN的时候做一个简单的查表或者算校验的函数能省去后面一堆排查时间。2.3 FlexRay与车载以太网下一代总线的HIL支持现状FlexRay虽然这些年有些“走下神坛”的感觉但在底盘线控和部分混动系统中还是能看到。FlexRay的高可靠性来自双通道冗余和时间触发机制。在HIL测试里模拟FlexRay节点比CAN要麻烦不少因为它涉及静态段和动态段的时隙分配那个“通信周期矩阵”Communication Cycle配置不好节点之间的消息收发就会错位。好在主流HIL设备厂商都有现成的FlexRay模块按协议规范配置好静态帧ID和时隙数量基本能跑起来需要自己开发的部分主要是应用层状态机的仿真。车载以太网100BASE-T1 / 1000BASE-T1在ADAS和域控制器测试中已经是标配了。HIL测试中的以太网和普通办公网络完全是两码事车载以太网使用单对非屏蔽双绞线支持PHY级别的睡眠/唤醒而且依托SOME/IP、DoIP、AVB等上层协议。HIL系统中模拟一个以太网节点的成本比CAN高得多通常需要专门的以太网仿真板卡并且配合Wireshark抓包分析。如果你在HIL台架上要测一个带有车载以太网的域控制器建议先确认测试设备的PHY芯片是否支持100BASE-T1的唤醒事件否则ECU的以太网端口可能一直处在休眠状态。2.4 周边低速协议UART、I2C、SPI一样逃不掉除了整车总线HIL测试还经常涉及板级通信协议。比如ECU内部MCU与传感器之间通过SPI/I2C通信或者某些控制模块用UART做调试口。这些低速协议看起来简单在HIL环境里往往用通用IO口来模拟时序难度在于它们的工作频率高、时序敏感。举个例子I2C协议中有个“时钟拉伸”机制从设备可以在某个传输阶段拉低SCL线让主设备暂停通信。如果你用HIL的通用IO板卡模拟一个I2C从设备时序完全靠软件控制就很容易出现时钟拉伸导致的死锁问题。一个经验是对于I2C模拟直接选用硬件定时器足够精确的板卡而不是靠上位机脚本去翻转IO。SPI同理主从模式的极性CPOL和相位CPHA组合一旦配错通信必然失败。3. 搭建HIL总线模拟环境从硬件到模型3.1 板卡选型别只看通道数要看协议IP的完整度在HIL系统里总线板卡是最不能省的部分。市面上的主流方案一类是NI的PXI系列加上FlexRay/CAN/LIN接口模块另一类是Vector的VT系列配合CANoe使用还有dSPACE的HIL系统自带DS1005/DS1006等处理板和总线接口。选型的时候容易掉进一个误区只看通道数量。比如一个CAN板卡有4路或者8路CAN通道很多供应商会把“支持CAN2.0和CAN FD”“最高8Mbps”作为卖点。但真正到了使用阶段你关心的是板卡的CAN控制器IP是否完整支持错误帧检测和注入是否支持在应用层直接读取总线负载率是否支持多板卡之间的时间同步驱动器是否能方便地定义DBC文件和ARXML文件的导入如果板卡自带的协议栈不完整你就不得不在上位机层面做很多“土办法”比如用定时器控制报文周期带来的抖动会毁掉整个测试的可重复性。我自己用过的一套组合是NI PXI NI-XNET CAN/LIN接口板卡配合VeriStand做实时仿真。NI-XNET的设备驱动对DBC和LDF文件支持得比较完整可以直接加载总线数据库文件来定义帧和信号不用写一行代码省了不少事。如果有更多客户定制需求Vector的CANoe加VT板卡更是汽车通信测试领域的标准配置特别是在做诊断测试时它的CAPL脚本支持让诊断服务的模拟变得非常顺手。3.2 实时仿真系统中的总线任务调度HIL仿真系统里总线通信任务和车辆动力学模型的运算是并行进行的。为了保证仿真的确定性实时机上通常会为每个总线通道建一个独立的任务按照总线周期里的微任务划分去收发报文。比如一个CAN通道的任务周期是1毫秒车辆模型的任务周期是100微秒两者的数据交换通过实时机的数据池比如共享内存区域完成。模型计算出的车速值会被数据池实时刷新CAN发送任务在每个周期把最新的车速打包成报文发出去。这里的关键在于数据一致性如果数据池里的车速正在被模型写入而CAN任务恰好在读取要不要做互锁大多数情况下底层驱动做了缓存不会出现“读到半个变量”的问题但如果涉及到跨周期数据对齐比如模型在1毫秒的周期更新一次而CAN任务也在1毫秒的周期发送最好做一个“数据快照”避免模型更新和报文采样之间的相位差导致信号抖动。从HIL机型选择上目前主流平台都支持CPU多核负载调度一个核跑模型另一个核跑总线通信第三方核跑故障注入和自动化脚本。分配任务时要注意均匀分配否则总线任务抢占模型任务会带来极大的运行时间抖动。3.3 节点模型的构建方法与实践在HIL中模拟一个“假的ECU节点”本质上是写一个通信节点模型。这个模型做的事情是在总线上周期发送指定的报文正确响应诊断请求根据输入信号模拟的传感器值调整发送的报文内容出现某些故障状态时让总线进入“异常”状态比如持续发送错误帧如果采用CANoe直接用CAPL脚本写节点模型是最灵活的如果采用NI VeriStand可以通过“总线流量发生器”加载DBC后定义每个信号的值也可以用Python脚本写自定义节点模型然后挂到通信接口上。我在用VeriStand时比较喜欢把“节点模型”做成一个独立的Simulink模型专门当作总线仿真控制器模型里输入是需要的状态量输出是总线上各帧的每个信号值。这样做的优势在于节点逻辑里面的时序逻辑、状态机都可以用Simulink来可视化便于团队里缺失CAPL编程经验的人也参与调试。举一个实打实的例子模拟一个车身BCM节点的车门状态上报报文DBC里的信号定义大概是这样DoorStatus_LeftFront状态值0为关闭1为打开DoorStatus_RightFront同上DoorStatus_LeftRear同上DoorStatus_RightRear同上BCM_LifeCounter从0到15循环模型里用四个输入端口模拟四个门的状态在模型内部合成8位的状态字节再配合一个“模16”的计数器信号组成了CAN报文的数据场。编译成动态链接库后用总线接口加载这个DBC对应的帧ID把信号映射到模型端口上一个能用的BCM节点模型就出来了。4. 实操技术同步、诊断与错误注入4.1 错误帧的制造让ECU体验“真实的崩溃”HIL测试最重要的一项能力是故障注入而总线故障注入正是通信协议层面最值得深挖的部分。我们经常模拟的故障有几类位错误、填充错误、CRC错误、应答错误。位错误的模拟比较底层通常需要板卡硬件的支持在软件层只能做到把整帧数据改掉或者不发无法模拟物理层的一位翻转。比较实用的是CRC错误注入和应答错误注入。CRC错误注入的做法是把报文数据场或CRC场的某些位强制反转接收端ECU通过CRC校验就会发现帧无效而丢弃。应答错误注入则是把应答场ACK Slot的显性位保持为隐性表示总线上没有一个节点应答ECU的发送状态机会检测到这个错误并进入错误恢复流程。这些错误注入功能在CANoe的IG模块中可以图形化操作NI-XNET也有对应的nxSignalSetRecord和错误帧注入接口。测试人员在写测试用例时不用每一条都写代码可以做一个通用的故障注入面板用按钮和下拉菜单直接触发各类总线故障。4.2 总线负载与时序为什么你的报文延迟了HIL台架上的总线时序问题和实车环境非常接近。最常见的现象是你按10ms的周期发一帧报文但ECU实际收到的报文到来时间间隔是不均匀的有时候8ms有时候12ms。这个抖动可能来自仿真任务的调度抖动也可能来自总线仲裁冲突。当总线上有多个节点同时争抢总线时优先级高的帧会先被发送优先级低的帧被迫等待这时候低优先级报文的实际发送周期就会被拉长。在HIL测试里如果你同时模拟了好几个高优先级节点比如发动机转速100ms周期发送但优先级很高就会挤压你被测ECU报文的时间窗口。这种场景其实和实车非常类似可以通过提高总线负载率来验证ECU处理总线繁忙工况的鲁棒性。总线负载率的计算方法很简单单位时间内总线上实际传输的位数除以信道带宽。以500kbps的CAN为例一帧标准数据帧最少需要约44位开销SOF、仲裁场、控制场、CRC、ACK、EOF等加上数据场长度一帧11字节的报文约需要4464108位考虑位填充后要乘一个约1.2的填充系数实际占用130位左右。如果这条总线上总共有20帧报文总传输时间为2600位在10ms窗口内总线负载率就是2600 / (500000 * 0.01) * 100% 52%。在HIL测试中我们通常会设定一个较高的负载率如80%以上来测试ECU在总线拥堵情况下是否会出现丢帧或延迟升高这种测试对验证通信协议栈的鲁棒性非常有效。4.3 诊断协议模拟UDS on CAN的HIL实践诊断协议是HIL测试里绕不开的通信环节。现在大多数ECU支持UDS统一诊断服务基于CAN的UDSISO 15765和金年车载以太网上的DoIP是主流。在HIL仿真中诊断方面的工作量主要集中在三块模拟诊断仪作为Tester发送诊断请求验证ECU的诊断应答是否合规模拟其他ECU成为诊断服务的“目标”响应被测ECU发起的诊断请求模拟21服务按地址读数据和22服务按标识符读数据保证诊断数据的返回值和实际物理量一致在CANoe中CAPL可以用diagRequest和diagResponse对象来定义诊断请求和应答。在NI VeriStand里诊断部分可以用自带的诊断协议栈支持ISO 14229来配置。一个特别容易被忽略的点是诊断会话切换后的应用层行为。比如ECU从默认会话切到扩展会话后部分周期报文会暂停或者改变发送周期。如果你的HIL环境只仿真了应用层没有仿真诊断状态机就永远发现不了“切了会话之后报文停发”这类非常典型的集成问题。5. 常见问题与排查技巧实录5.1 明明在发报文ECU就是不响应这个现象在HIL调试中出现的概率极高而且原因可以五花八门。我按经验优先级排列一下排查点检查方法典型原因报文ID范围对照整车通信矩阵确认ID被测ECU的接收ID和仿真节点发送ID不在同一ID段报文周期总线负载或周期设置碰撞导致周期抖动ECU丢弃超时帧信号字节序DBC中Byte Order设置大端/小端定义和ECU内部打包不一致信号起始位DBC中Start Bit设置起始位数值错误导致信号被错误解析网络管理状态检查网络管理报文ECU处于网络睡眠状态不响应应用报文节点是否掉线看总线错误计数高错误率导致节点进入Bus-off状态有一次排查客户反馈“ECU不响应转向灯指令”我们抓了三天最后发现原因是信号打包时把小端信号起始位定义在了第6位但DBC文件里按大端方式定义到了第7位。而报文的另一个信号恰好跨越了字节边界解析结果完全错位ECU收到了一个“不合逻辑”的信号值就完全不执行动作。这类问题往往不是协议栈层的问题而是数据库文件定义不严谨。5.2 CAN总线上的错误帧风暴错误帧在HIL总线上偶尔出现可以忽略但如果出现“错误帧风暴”基本可以断定HIL仿真节点的收发器配置有问题。常见的原因包括仿真节点配置的波特率和被测ECU不匹配哪怕差0.5%累积到同步段也会出问题CAN收发器和终端电阻配置错误。HIL机箱内部一般都有一个120欧姆终端电阻的拨码开关如果两端都配了终端电阻、但测试治具上又跨接了一个外置电阻导致总线等效阻抗过低信号幅值不达标就会频繁产生位错误采样点设置不合适。CAN波特率采样点通常设置为75%-85%如果靠近位末尾信号边缘抖动明显时非常容易采错排查错误帧的思路是先确认哪些节点在产生错误帧。许多分析工具CANoe、PCAN、ZLG CANPro都能按照“错误节点ID”来过滤总线错误帧如果错误帧的发送节点ID能看出来基本能锁定是哪个仿真通道出了问题。再用示波器抓取CAN_H和CAN_L的差分波形确认位定时是否满足要求问题一般就能迎刃而解。5.3 上位机与实时机之间的总线数据不同步在分析从HIL台架保存下来的数据时经常有人问“为什么CAN信号的时间戳和模型变量对不上”。原因通常是上位机记录的CAN报文时间戳来自板卡本地的晶振而模型变量的时间戳来自实时机的确定性时钟。如果这两个时钟没有做同步PTP同步或者时钟校准在长时间测试后偏差会越来越大。解决办法是在测试配置中明确用主站时间作为统一时基。NI PXI平台里可以用PXI的背板时钟来同步各板卡的时钟Vector平台里通过vGenerateTimestamp等方式可以获得全局时基。同时建议在做后处理时以CAN报文的时间戳为基准对模型变量做最近的“零阶保持”对齐而不是做线性插值。CAN报文是事件触发的插值会引入本不存在的信号变化趋势导致分析误判。5.4 总线舵机与机械臂控制里的串行总线协议——顺带一提的HIL变种有一些朋友问过我像“总线舵机控制板”这类用到“自定义串行总线协议”的设备能不能也纳入HIL测试的范畴。我理解这个问题的本质是当被测对象不是标准汽车ECU而是内部总线舵机机械臂之类产品时测试思路是否需要完全不同。在非汽车领域如机器人控制器测试也常需要把真实的MCU接入HIL系统。此时总线往往是UART、RS485或者CAN但协议可能是厂商自定义的串行通信协议。这时候的做法和车载总线测试并没有本质区别重点依然是先解析协议帧格式帧头、长度、命令字、数据、CRC再用HIL板卡模拟对端节点去“对话”。唯一的差异是自定义协议没有现成的DBC文件你需要自己做一套“信号数据库”或者干脆在脚本里用字节数组直接收发。但只要把协议理解透HIL测试方法论是完全可以平移的。6. 从总线调试中积累的几个实用经验写到这里把自己在总线调试上的一些小经验记录一下也许能帮到正在踩坑的朋友。第一测试前先把通信数据库文件DBC/LDF/ARXML做静态检查。这个动作花不了5分钟却能省掉大半天。用工具打开DBC检查信号起始位、字节顺序、值的范围、帧周期是否和通信矩阵一致。很多总线不响应问题其实是DBC文件和代码里信号定义不一致等排查到协议栈层就把问题复杂化了。第二在HIL环境中把“总线抓包”的能力当成标配。不管是用CANoe还是第三方总线记录仪在测试执行时同步抓包记录总线上的真实总线数据测试后把这份总线数据和HIL系统内部的模型数据进行交叉对比往往能定位很多“看起来像是模型算错了实际是总线数据传错”的问题。第三错误注入要分级进行。我自己的习惯是先从应用层错误注入比如停发某帧报文、修改某个信号值开始再逐步深入到数据传输层错误注入CRC错误、应答错误最后才做物理层相关测试总线短路、总线断路、终端电阻断开。这样的分级保证在每个层级都能快速定位测试用例本身的问题而不是一上来就把所有错误全部注入导致ECU进入混乱状态测试结果无法分析。第四用版本管理工具管理你的总线数据库和仿真节点模型。总线协议是会被迭代的。CAN矩阵、LIN调度表、以太网ARXML文件在项目不同阶段几乎都在变。如果没有把DBC、LDF、ARXML文件纳入版本管理你很难回溯到在某一个测试周期里到底是哪个信号的定义变了导致测试结果趋势突变。这是很多测试团队忽视但实际非常值得投资的一个点。第五重视HIL环境的启动时序。台架上电后先让总线通信建立起来再给ECU上电还是先ECU上电再让仿真节点开始发报文这两种顺序对应完全不同的实车工况。在很多实车场景中CAN收发器都是在ECU的电源管理芯片上电后才开始工作的如果仿真节点提前把大量报文发出去ECU启动时可能错过“握手报文”导致通信永远建立不起来。建议在你的HIL测试环境里把通信启动时序也当作一个可以配置的参数而不是每次都固定一种顺序。总线协议测试这种东西理论看十遍不如上手调一轮。面对HIL台架上总线不通、报文丢帧、错误帧风暴这些问题先把协议帧格式吃透再把仿真节点模型和真实节点区分清楚然后一步步加故障你就能慢慢摸清套路。以后在测试中再遇到类似的问题心里会更有底。
返回列表