多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

AUTOSAR CAN通信栈配置指南:基于EB tresos从信号到报文

AUTOSAR CAN通信栈配置指南:基于EB tresos从信号到报文 做AUTOSAR基础软件配置的工程师几乎没人能绕开EB tresos。这个工具界面看着不复杂但要真正把CAN通信信号收发的全流程从头到尾配通很多刚入行的朋友都被卡住了——不是某个参数不会填而是没搞清楚模块与模块之间的关系。我见过不少人把Can模块里的硬件对象配好了结果在CanIf层找不到映射入口也见过COM信号配置了周期发送但底层PDU根本没跑起来。这篇配置指南我会从工程创建开始顺着AUTOSAR CAN通信栈的分层逻辑把信号从应用层一路配置到CAN收发器再从总线上把数据收回到信号里完整走一遍流程。适合刚接触EB tresos的BMS、VCU、T-BOX等控制器开发工程师也适合学校里学过CAN协议但没接触过AUTOSAR工具链的同学。看完之后你对信号怎么从一个节点发出去、另一个节点怎么收回来这件事会有一个非常扎实的掌控。1. 配置前的工程准备与整体认知1.1 EB tresos工程创建与版本差异先说工程创建这一步。不同版本的EB tresos现在也叫EB tresos AutoCore界面布局有些区别但核心操作路径是近似的。打开软件后新建一个工程关键是要选对基础软件版本和芯片型号对应的MCAL微控制器抽象层。比如你用NXP的S32K1系列或者英飞凌的TC2xx/TC3xx系列需要挂到对应的EB插件包。插件包版本一定要和tresos工程版本匹配常见的问题就是插件包版本过新或过旧导致加载工程时模块列表是空的或者生成代码时报一堆找不到头文件的错误。工程创建后左侧的模块列表里会出现你需要的AUTOSAR基础软件模块。做CAN通信信号收发至少要关注以下几个模块CanCAN驱动、CanIfCAN接口、PduRPDU路由、Com通信服务以及配套的EcuCECU配置、Os操作系统如果要用定时调度、Mcu与Port等底层模块。有些工程还会用到CanTpCAN传输协议做诊断或UDS刷写但这里先聚焦基础信号收发CanTp可以暂时不管。配置顺序上我个人的习惯是自底向上先把底层时钟、Can驱动、引脚和收发器使能理清楚再配置CanIf的PDU属性接着走PduR路由最后到COM信号。这样每层都有确定的配置结果上层引用下层的句柄或ID时才不会悬空。反过来从COM往下配也可以但新手容易迷失在未知的映射关系里。所以本文的章节顺序就是自底向上的实际配置流程。1.2 CAN通信栈的分层结构与配置顺序理解CAN通信栈的分层是配置一切的前提。打个比方你要通过快递寄一个包裹COM信号是包裹里的实物PDU是包装盒CAN报文是快递单CAN收发器是快递车。应用层只需要关心包裹里装了什么也就是信号值但到了总线上必须把信号封装成一帧带CAN ID、DLC数据长度和8字节数据的报文。AUTOSAR把这件事拆成了几层软件模块每个模块只干自己那一份活Com是通信服务层负责把应用层信号打包成IPDU或者从IPDU里解出信号给应用层PduR是PDU路由器根据路由表把IPDU从上层送到下层或者从下层收上来CanIf是CAN接口层管理发送请求、接收指示、PDU模式控制屏蔽掉底层硬件细节Can是CAN驱动层直接操作控制器寄存器负责仲裁、错误处理、硬件收发邮箱管理MCAL之外还要有收发器初始化代码通常是CanTrcv模块处理CAN收发器的唤醒、正常/待机模式。这也是为什么EB tresos配置不是只配一个模块就完事一个发送信号要同时配置COM的周期发送、PduR的路由目标、CanIf的TxPduCAN ID和DLC、Can的硬件发送对象一个接收信号要配置Can的接收滤波和硬件接收对象、CanIf的RxPdu、PduR的路由源、COM的接收信号缓冲。任何一个环节断了信号就收发不通。理解了这条链路配置时就不会东一榔头西一棒槌。下面按实际执行顺序展开。2. Can驱动层从控制器到硬件收发对象的配置2.1 控制器参数与波特率计算Can驱动层是整个通信链路的底座。进入EB tresos的Can模块配置界面第一步要新增一个CanController其实就是CAN控制器实例。比如用一个CAN0通过CanControllerBaudRate配置波特率。这里有一个比较尴尬的地方AUTOSAR版本不同EB的配置容器结构也不同。较早的版本里波特率直接在控制器里填一个值比如500000新版本则分成CanControllerBaudRateConfigSet除了波特率还包含采样点、同步跳转宽度、位时间相关参数。我实际用下来建议至少把波特率设为目标值采样点尽量靠近80%比如经典CAN的常见配置是500kbps、采样点75%到80%对线缆较长的车载网络更稳定。波特率的计算本质是CAN控制器根据外设时钟分频后在每一个位时间段内做同步和采样。位时间由同步段SYNC_SEG、传播段PROP_SEG、相位缓冲段1PHASE_SEG1和相位缓冲段2PHASE_SEG2组成加上波特率预分频器BRP。采样点 (SYNC_SEG PROP_SEG PHASE_SEG1) / (SYNC_SEG PROP_SEG PHASE_SEG1 PHASE_SEG2)。这个公式很重要因为如果你手动调采样点最后填进配置容器里的时间段值必须满足这个比例。EB tresos会在你填入波特率和采样点后自动计算寄存器参数但底层时钟源头一定要先确认。比如TC3xx的CAN外设时钟来自系统时钟分频如果Mcu模块里时钟没配好CAN波特率就会和期望值偏差很大。还有一个实操细节如果同一个总线上有多个节点所有节点的波特率和采样点必须一致或者至少在容差范围内。实测中发现采样点差异过大时总线上的报文经常出现偶发错误帧用CANoe看错误帧计数器会持续上涨但报文内容看起来又是对的。所以新项目调试时先统一确认每个节点的采样点配置再排查其他问题。2.2 硬件收发对象和报文滤波器配置控制器配好之后紧接着要配置硬件收发对象CanHardwareObject。这是CAN驱动层最容易出问题的区域。先解释概念现代CAN控制器内部有多个硬件邮箱发送邮箱和接收邮箱分开管理。在AUTOSAR Can模块里每个硬件对象都对应一个邮箱资源带一个HTH硬件发送句柄或者HRH硬件接收句柄。配置时你要为每一个要发送或接收的报文分配一个硬件对象并把它和CanIf层定义好的PDU挂钩。但这里有个理解难点Can层配置的CanHardwareObject其实并不直接引用CanIf的PDU ID而是通过CanIf层配置的CanIfTxPdu里的CanIfTxPduCanId和CanIfTxPduHrhId关联到硬件对象。也就是说硬件层只看到我要用哪个邮箱发一个ID为0x123的帧至于这个帧里装的是什么信号它不关心。接收路径上收到一帧后通过硬件对象编号上抛给CanIfCanIf再根据PDU的CAN ID查找对应的接收PDU。硬件对象需要配置的核心参数有硬件对象类型发送还是接收、关联的CAN控制器、CAN ID类型标准帧11位还是扩展帧29位、是否使能硬件过滤。对于接收对象还要配置滤波器。滤波器的原理是硬件层根据报文ID的匹配结果决定是否把帧写入邮箱避免所有帧都进中断增加CPU负担。最常见的滤波配置是直接匹配某个CAN ID也就是掩码全为1期望值等于目标ID。如果某个控制器要接收多个不同ID的报文需要配置多个接收对象或者用掩码做一组ID的匹配。我踩过一个坑接收滤波器配置成掩码0时本来以为是全接收结果发现有些芯片的硬件行为是全不接收或者只接收扩展帧。原因是不同MCU的CAN控制器对滤波器掩码的语义有差异有的把掩码位为0视为不关心有的则相反。所以配完之后最好先用CANoe或同轴电缆把真实报文灌进去确认每个接收对象都能正确触发。滤波器配置表建议写成一张清晰的清单方便后续和DBC文件对照。3. CanIf与PduR打通上层路由的关键桥梁3.1 CanIf的收发PDU配置与映射关系CanIfCAN Interface层是连接COM上层协议栈和Can驱动的桥梁它最大的作用是让上层不必关心硬件邮箱的细节。进入CanIf模块配置界面重点看CanIfInitCfg这个容器里面有两个重要子项CanIfRxPdu和CanIfTxPdu。每个PDU都要配置几个关键参数CanIfPduIdPDU的唯一句柄CanIf层用它来向上层区分不同报文CanIfPduCanId总线上真实传输的CAN ID也就是你在DBC里看到的报文IDCanIfPduDlc数据长度经典CAN里最大8字节CAN FD可以更长CanIfPduCanIdType标准帧还是扩展帧对于TxPdu还必须配置CanIfTxPduCanId、CanIfTxPduHrhId关联到Can驱动的发送硬件对象对于RxPdu配置CanIfRxPduHrhId关联到Can驱动的接收硬件对象。这里最容易混淆的是PDU ID和CAN ID。很多初学者把这两个值搞混结果在调试时发现CanIf层上报的PDU ID对不上COM里的IPDU导致数据一直不更新。记住一句话CAN ID是总线上跑的内容PDU ID是软件内部用来寻址的编号。同一帧报文从接收到应用层CAN ID会被CanIf转换成PDU ID然后PduR再根据路由表转成IPDU ID。所以你用CANoe看到总线上报文是0x123但在软件内部它可能是一个编号为5的RxPdu再映射到COM的IPDU 3。CanIf里还有一个经常被忽视的配置项CanIfPrivateCfg下的错误检测开关。开发调试阶段建议把CanIfDevErrorDetect打开这样一旦PDU配置有逻辑错误比如TxPdu没有关联硬件对象在编译后运行时会直接抛出开发错误提醒省得瞎猜。量产版本再关掉减少代码体积和运行开销。发送方向的配置在原子里很简单应用层调用Com_SendSignal后COM把信号打包成IPDU通过PduR_ComTransmit把数据交给CanIfCanIf再调用Can_Write写入硬件邮箱。整个过程需要CanIf的TxPdu已经正确关联了Can驱动的发送对象且对象是就绪状态。如果Can_Write返回错误码CanIf会通过回调向COM报错应用层看到的发送结果就是失败。所以调试发送流程时不仅要在EB配置里检查PDU映射还要在代码里看Can_Write的返回值。3.2 PduR路由配置要点PduRPDU Router名字很直白就是PDU的十字路口。AUTOSAR里上层模块COM、DCM等和下层模块CanIf、LinIf、FrIf等之间的PDU传输完全依赖PduR。在EB tresos里PduR配置主要分两部分PduRSrcPdu和PduRDestPdu。PduRSrcPdu定义PDU从哪个模块进入PduRPduRDestPdu定义PDU从PduR出去到哪个模块。对于一条发送路径COM的IPDU作为源PduRSrcPduCanIf的TxPdu作为目标PduRDestPdu接收路径反过来CanIf的RxPdu作为源COM的IPDU作为目标。每条路由还需要显式配置发送确认和接收指示的传递关系比如发送完成后CanIf通过CanIf_TxConfirmation通知PduRPduR再把确认转给COM。这些回调关系在PduR里也有配置项一般是PduRTransmit、PduRTriggerTransmit之类的函数指针列表EB会自动生成对应的接口但必须保证源和目标模块的模块ID已正确配置。配置PduR时最常出的问题是对接不上的错误由于COM的IPDU句柄和CanIf的PDU句柄没有形成有效路由编译时不出错但运行时代码会在PduR内部找不到路由表项直接返回E_INVALID。排查方法就是回到PduR的图形化路由视图看有没有孤立的PDU。EB tresos的路由视图会把所有已经建立连接的源和目标用线连起来一眼就能看出谁没连上。不过我实际用过的版本里这个视图偶尔刷新不及时所以更可靠的方式还是检查生成的PduR_PBcfg.c文件看路由表数组里是不是真的包含了目标PDU。另外提醒一点如果一个报文既要做周期发送又要支持诊断或应用层的触发发送PduR层面可能会用到上传/下载表项的组合。不要把PduR路由做成多对多除非你明确知道自己在做什么——因为多源到同一目标报文的路由优先级和缓冲管理会变得难以预测调试难度成倍上升。4. COM模块信号级配置与收发逻辑4.1 创建信号与IPDU并建立映射走到COM模块AUTOSAR里叫Com这一步才是真正和信号打交道的地方。COM是AUTOSAR通信栈里最贴近应用层的模块。它的功能简单说就两件发送时把应用层写好的多个信号打包成一个IPDU接收时把一个IPDU里的各信号拆开放到应用层能读到的缓冲区里。在EB tresos的Com模块配置界面里先建信号Signal再建IPDU然后把信号映射进IPDU。信号的核心属性包括信号长度位宽、字节顺序Intel还是Motorola也就是小端还是大端、起始位StartBit、初始值、是否带符号。这些参数必须和DBC文件CANoe等工具生成的CAN数据库保持一致。如果DBC里是Motorola格式的信号你在COM里配成了Intel字节序那收到的数据就会乱成一团数值完全对不上。IPDU的核心属性包括IPDU方向发送还是接收、长度、数据更新机制ComIPduSignalProcessing对应直接处理还是周期处理、发送模式周期、事件、混合。发送模式的差异很大周期发送代码里周期调用Com_MainFunctionTx时间到了就把IPDU发出去。大多数车辆控制报文都是周期发送比如50ms、100ms、10ms事件发送只有当信号值更新时才发送配合超时重传可以降低总线负载混合发送既按周期发又有事件触发条件时立即发。对于周期发送有一个容易被忽略的关键参数ComTxModeTimePeriod单位是秒比如0.01就是10ms。你还要确保对应的调度器OS或裸机循环真的在按这个周期调用Com_MainFunctionTx。我之前调试过一个项目COM配置成10ms周期发送但主循环里Com_MainFunctionTx被放在了一个100ms的任务里结果总线上的报文周期变成100ms数据时效性完全不对。这个问题在配置界面里根本看不出来只能靠逻辑分析仪或者CANoe确认。接收方向上IPDU不需要发送周期但要关注Com_RxIndication回调的产生条件。当CanIf收到底层上报的PDU后会通过PduR触发COM的接收指示COM把PDU数据拷贝到接收缓冲区再更新对应的信号值。这个过程中如果DLC和PDU长度不一致COM可能直接丢弃数据。所以IPDU的DLC、CanIf的PDU DLC、CAN报文的实际DLC三者务必保持一致。4.2 信号属性与收发逻辑细节信号本身也有一些影响收发行为的属性这里展开讲几个容易踩坑的点。第一个是信号字节序Endianness和起始位的关系。很多工程师第一次配置时分不清Intel格式和Motorola格式下StartBit的区别。简单理解Intel格式下信号的各字节以低地址在前的方式存放起始位就是最低位所在的bit位置Motorola格式下信号的起始位通常是最高位所在的位置后续bit按逆序排列。AUTOSAR在配置界面里会让你选ByteOrder但具体到StartBit的计算不同工具也有不同展示方式。最稳妥的做法是拿CANoe的DBC编辑器打开对应报文把一个信号的实际位位置截图然后在COM里按照工具自动生成的值填入。如果手头没有DBC也可以先发一帧已知数据用CANoe的Data字段对照字节来看这样最直观。第二个是更新位Update Bit和滚动计数器Rolling Counter。整车通信里很多应用报文为了安全会带一个计数器每发一帧加1接收端校验连续性。在COM里这可以通过配置滚动计数器信号和对应的错误处理机制来实现但这里的配置并不复杂真正的复杂度在于应用层的判断逻辑。EB只负责把计数器值按普通信号打包和解析连续性检查要应用层自己做或者在COM模块里配置ComSignaleInvalidation与Timeout处理。如果你需要接收超时检测比如10ms的报文100ms没收到就要报故障还需要在COM里使能接收超时监控并配置对应的超时时间。这段逻辑配置在EB里叫ComTimeoutDuration单位秒。第三是信号无效化和发送失效行为。AUTOSAR允许将IPDU的接收超时状态映射到一个或多个信号上比如超时后把信号无效标志位置位应用层读取信号时能感知到数据不可信。在EB的Com配置里可以在信号属性中使能ComInvalidationOnTimeout。这个功能对BMS的SOC、VCU的踏板开度等安全相关信号非常重要。我见过不少项目开始时没配这个故障诊断时查不到数据是旧值还是无效值全靠应用层自己计时判断费用很高。直接在COM里配置反而简单可靠。5. 代码生成、集成与实测排查5.1 生成代码并接入应用层所有配置完成后点击生成代码。EB tresos通常按模块生成独立的源代码比如Can_PBcfg.c、CanIf_PBcfg.c、PduR_PBcfg.c、Com_PBcfg.c以及对应的头文件和导出API。生成时如果没有报错通常意味着配置数据在静态层面是自洽的。但这里说的自洽不包含语义正确性比如波特率配错、CAN ID配错这些都是合法的错误工具没法帮你发现。生成代码后把代码文件加入工程并编译。集成时要注意如果项目里有部分代码是手写的比如底层启动代码一定要把EB生成的头文件路径和源文件路径加入编译器的include搜索路径。很多编译错误未定义类型就是路径没加全导致的。另外生成代码里经常包含一些条件编译宏比如CANIF_PDU_RX_INDICATION_ENABLE、COM_ERROR_DETECT_ENABLE这些宏可以在EB配置里勾选对应功能后自动生成也可以手动在编译器命令行里定义。排查奇怪的不执行现象时先检查这些功能宏是否被意外关闭。应用层访问信号的方式是固定的发送信号前调用Com_SendSignal(ComConf_Signal_xxx value)接收信号后调用Com_ReceiveSignal(ComConf_Signal_xxx value)。这里的ComConf_Signal_xxx是EB根据配置自动生成的一个枚举值也就是信号在COM模块内部的Handle。你不需要关心这个数字具体是多少只要保证在应用中引用的是生成的头文件里的名字。有些项目需要批量收发信号也可以直接用Com_SendSignalGroup/Com_ReceiveSignalGroup把同一IPDU里的多个信号一次提交或一次拉取效率更高。5.2 常见问题排查与实测心得最后这部分我把这几年用EB配CAN实际踩过的坑和排查思路集中说一下。很多问题不是配置界面能看出来的但排查路径有很强的共性。第一个是总线只见错误帧没有任何正常报文。这种情况十有八九是波特率不一致。停车总线上所有节点的波特率/采样点必须对应先用CANoe或示波器确认目标节点的实际波特率再回EB里查CanControllerBaudRate。如果波特率看起来是对的再查Mcu时钟配置看看CAN外设的时钟输入是否正确。记住CAN波特率是分频后的结果任何一级时钟源不对都会导致最终误差。第二个是发送时在应用层返回值正常但总线上没报文。先查CanIf的TxPdu是否映射到了正确的CanHardwareObject尤其是HRH和HTH是否对应错一个TxPdu映射到了接收对象上也会出现无声发送。再查Can_Write返回的错误码如果在调试器里看到CAN_BUSY说明邮箱被占满通常是把多个TxPdu映射到同一个硬件发送对象同时触发发送导致冲突。第三个是接收方向总线上能看到报文但应用层读信号一直是初始值。依次排查三个环节Can层接收对象有没有正确滤波用CANoe发送该ID测试看HRH是否触发CanIf层RxPdu的CAN ID是否和报文一致PduR有没有把CanIf的RxPdu路由到COM的IPDU。如果这三层都对再查COM的接收信号起始位和字节序用CANoe发一个全FF的报文看应用层读到的值是不是对应模式下的全F。如果值不对基本就是位配置错了。第四个是周期发送报文总线上周期不准。在EB里确认ComTxModeTimePeriod再确认调度器调用Com_MainFunctionTx的周期。可以用示波器或CANoe的统计功能看真实周期如果偏差是整数倍就是调度周期不匹配。下面顺手做一张排查速查表方便现场对照排查环节 | 检查项目 | 常见原因 Can驱动层 | 波特率、采样点、硬件对象类型 | BRP分频错误、发送接收邮箱混淆 CanIf层 | Tx/RxPdu的CAN ID与DLC | CAN ID定义错误、DLC比实际发送小 PduR层 | 路由源目标是否连接 | PDU Handle不匹配、回调函数缺失 COM层 | 信号起始位/字节序/发送周期 | 与DBC不一致、MainFunction未被周期调用最后再分享一点小经验EB tresos配置CAN通信最忌讳一上来就对着配置界面乱填。先把DBC文件里的报文ID、DLC、信号布局整理成一张表再按照CAN驱动、CanIf、PduR、COM这个顺序逐一对应去填。配置过程中每完成一层就用CANoe和调试器做一次最小验证Can层用寄存器直接发一帧测试CanIf层用PDU的触发函数发一帧测试COM层用应用层接口发包测试。这样做看起来多花了一些时间但实际排障的时候会让你少熬好几个通宵。工具只是把静态配置变成代码真正的可靠性一定是在一层一层的验证过程中累积起来的。
返回列表