3. CAN驱动与CanIf配置实战
在MICROSAR通信栈中,CAN驱动(Can Driver)与CAN接口层(CanIf)是报文进出ECU的第一道关口。CAN驱动直接操作CAN控制器寄存器与收发器引脚,负责位定时、邮箱管理、中断与唤醒;CanIf则位于驱动之上,向上为PduR、Com、CanTp等模块提供统一的报文收发服务,向下屏蔽不同CAN控制器与收发器的差异。本节围绕“硬件抽象—句柄配置—ID过滤映射—回环验证”这条主线,把配置参数与真实报文路径对应起来。
一、CAN控制器与收发器的硬件抽象
CAN驱动对硬件的抽象分为两层:控制器抽象与收发器抽象。控制器抽象由Can模块完成,它把CAN控制器的邮箱(Mailbox/Message Object)抽象为硬件对象(Hardware Object,HO),每个HO对应一个发送或接收邮箱,并带有唯一的Handle。收发器抽象由CanTrcv模块完成,它把收发器的模式引脚(STB、EN、NSTB等)抽象为CanTrcv_SetOpMode接口,支持NORMAL、STANDBY、SLEEP等模式切换。
以常见的CAN控制器为例,其位定时参数由CanControllerBaudRateConfig给出。假设CAN时钟为40 MHz,目标波特率500 kbit/s,采样点取80%,则位时间TQ总数为:40 MHz / 500 kbit/s = 80 TQ。按采样点80%划分,SYNC_SEG=1 TQ,PROP_SEG+PHASE_SEG1=63 TQ,PHASE_SEG2=16 TQ。若BRP=5,则每TQ为5个时钟周期,TSEG1=63、TSEG2=16,采样点=(1+63)/(1+63+16)=80%。这些参数在CanControllerBaudRateConfig中体现为CanControllerBaudRate、CanControllerPropSeg、CanControllerSeg1、CanControllerSeg2、CanControllerSyncJumpWidth。
收发器抽象的关键是模式与唤醒。CanTrcv模块通过CanTrcvChannelId区分通道,通过CanTrcvHwPnPort、CanTrcvHwPnPolarity描述引脚极性。当ECU进入SLEEP时,CanTrcv_SetOpMode(TRCV_MODE_STANDBY)拉低STB引脚;当总线出现显性位唤醒时,收发器通过RXD引脚产生唤醒事件,CanIf再调用CanIf_CheckWakeup通知EcuM。硬件抽象的价值在于:上层Com、CanTp只关心PduId,不关心是哪个控制器、哪个收发器、哪个邮箱。
二、CanIf的HOH、HRH、HTH配置
CanIf用三类句柄描述报文路径:HOH(Hardware Object Handle)是驱动层邮箱句柄,HRH(Receive Handle)是接收句柄,HTH(Transmit Handle)是发送句柄。三者关系是:一个HRH对应一个或多个HOH,一个HTH对应一个HOH。配置时先定义CanIfRxPduCfg与CanIfTxPduCfg,再通过CanIfRxPduHrhIdRef、CanIfTxPduHthIdRef绑定到HRH/HTH,最后通过CanIfHrhCanIdRef、CanIfHthCanIdRef关联到具体CAN ID。
典型配置片段如下(示例参数,非实测):
CanIfRxPduCfg:
CanIfRxPduId = 0x10
CanIfRxPduCanId = 0x123
CanIfRxPduCanIdMask = 0x7FF
CanIfRxPduHrhIdRef = HRH_0
CanIfRxPduDlc = 8
CanIfTxPduCfg:
CanIfTxPduId = 0x20
CanIfTxPduCanId = 0x456
CanIfTxPduHthIdRef = HTH_0
CanIfTxPduDlc = 8
CanIfHrhCfg:
CanIfHrhId = HRH_0
CanIfHrhCanIdRef = HOH_0
CanIfHrhSoftwareFilter = TRUE
CanIfHthCfg:
CanIfHthId = HTH_0
CanIfHthCanIdRef = HOH_1
这里HRH_0绑定HOH_0(接收邮箱),HTH_0绑定HOH_1(发送邮箱)。若一个HRH绑定多个HOH,则这些邮箱共享同一接收句柄,CanIf在CanIf_RxIndication中按CanId分发给不同上层PduId。HTH则通常一对一,因为发送邮箱需要独立的状态机管理发送确认。
三、CAN ID过滤与映射
CAN ID过滤分两级:硬件过滤与软件过滤。硬件过滤由CAN控制器邮箱的验收滤波器完成,配置CanIfHrhRangeCfg中的CanIfHrhRangeRxPduLowerCanId与UpperCanId,只有落在范围内的报文才会被邮箱接收。软件过滤由CanIf在CanIf_RxIndication中执行,通过CanIfRxPduCanId与CanIfRxPduCanIdMask做掩码比较,例如Mask=0x7FF表示精确匹配,Mask=0x7F0表示忽略低4位。
映射关系是:CAN ID → HRH → CanIfRxPduId → 上层PduId。例如0x123映射到HRH_0,HRH_0再映射到CanIfRxPduId=0x10,PduR根据0x10路由到Com的RxPdu。发送方向则是:上层PduId → CanIfTxPduId → HTH → HOH → 邮箱。若映射错误,典型现象是CanIf_RxIndication不触发,或Com收不到信号,而总线示波器上报文正常。
四、基于真实ECU的CAN通信回环测试
回环测试用于验证驱动、CanIf、ID过滤与映射是否贯通。测试拓扑有两种:内部回环(Controller Loopback)和外部回环(External Loopback)。内部回环由CAN控制器自身把发送邮箱的报文回送到接收邮箱,不依赖收发器和总线;外部回环需要收发器与总线,通常用CANoe或CANalyzer模拟对端节点。
以内部回环为例,操作步骤如下:将CanControllerLoopbackMode设为CAN_LOOPBACK_INTERNAL;配置HTH_0发送0x456,HRH_0接收0x456;调用CanIf_Transmit(0x20, &PduInfo)触发发送;在CanIf_RxIndication中打断点,观察是否收到CanIfRxPduId=0x10、CanId=0x456、Dlc=8。若收到,说明HOH、HRH、HTH、ID过滤与映射全部正确;若未收到,先检查CanIfRxPduCanIdMask是否把0x456过滤掉,再检查HRH是否绑定了正确的HOH。
外部回环则需把收发器切到NORMAL模式,用CANoe发送0x123,观察ECU是否回发0x456。此时可用CANoe的Trace窗口查看报文周期、DLC与数据场,用Bus Statistics查看错误帧计数。若出现Error Frame,优先检查波特率与采样点是否与总线一致;若出现Form Error,检查DLC与数据长度是否匹配。
回环测试的判据可以归纳为三点:第一,发送调用返回E_OK,说明HTH与HOH绑定正确;第二,CanIf_RxIndication被调用且CanId、Dlc与预期一致,说明HRH、ID过滤与映射正确;第三,若使用外部回环,CANoe Trace中无Error Frame且周期稳定,说明位定时与收发器模式正确。若第一点失败,检查CanIfTxPduHthIdRef是否指向有效HTH;若第二点失败,检查CanIfRxPduCanIdMask与CanIfHrhRangeCfg是否把目标ID排除;若第三点失败,检查CanControllerBaudRate与采样点是否与总线一致。
把上述配置与测试串起来看,CAN驱动与CanIf的配置本质是“硬件资源—句柄—ID—上层Pdu”的四层映射。硬件抽象保证可移植性,HOH/HRH/HTH保证路径可追踪,ID过滤与映射保证报文只进入正确的上层,回环测试则用最小闭环验证这四层是否一致。掌握这条链路后,后续CanTp分段传输、Com信号打包与E2E保护才有可靠的底层基础。