AUTOSAR Classic 平台 CAN Transceiver Driver(CanTrcv)详解
AUTOSAR Classic 平台 CAN Transceiver Driver(CanTrcv)详解
AUTOSAR Classic 平台中的 CAN Transceiver Driver(CanTrcv)模块 是通信硬件抽象层的一部分,负责管理ECU上独立的 CAN 收发器硬件芯片,为上层提供统一的接口。本篇文章将以友好而专业的语言,分章节深入讲解 CanTrcv 模块的各个方面,包括基础概念、API 接口、内部状态机与唤醒机制、与其他模块的交互关系、具体收发器硬件(如 NXP TJA1040/TJA1043/TJA1145)的适配方法、配置要点、调试技巧,以及量产项目中的实践经验。文章内容全面系统,并提供代码片段、配置示例和流程图(Mermaid 图表)来帮助读者理解。希望本文对 AUTOSAR 初学工程师和从事量产项目开发的同行有所裨益。
一、基础概念
CAN 收发器(CAN Transceiver) 是一种将微控制器的 CAN 控制器与物理 CAN 总线相连接的独立硬件器件。它负责在总线和微控制器逻辑之间转换信号电平:将 MCU 输出的数字信号转换为 CAN 总线上的差分电平,以及将总线上的信号还原为 MCU 可识别的逻辑电平0。此外,CAN 收发器通常具备故障检测能力,能够识别诸如总线短路、接地偏移、电压异常等物理层故障,并通过特定引脚(错误指示引脚)或 SPI 接口提供故障状态信息1。
在汽车应用中,常见的 CAN 收发器按照物理层标准可分为三种:高速 CAN(High-Speed CAN,ISO 11898-2),低速容错 CAN(Low-Speed/Fault-Tolerant CAN,ISO 11519-2)以及单线 CAN(SAE J2411)。其中高速 CAN 应用最广泛(典型波特率 500kbps~1Mbps),低速 CAN 常用于需要容错的场合(波特率 125kbps 左右),单线 CAN 则主要用于车身等非关键网络。针对不同物理层,需选择对应标准的收发器芯片23。需要注意的是,AUTOSAR 标准的 CanTrcv 驱动模块不支持 SAE J2411 单线 CAN 收发器的控制4。
随着车载网络的发展,一些收发器芯片还集成了电源管理和看门狗等功能,形成系统基础芯片(SBC,System Basis Chip)。SBC 将电源稳压、唤醒控制、CAN 收发器、看门狗等封装在一体,通过 SPI 接口由 MCU 控制5。这种芯片可以大幅减少ECU上分立器件的数量,提高集成度。但无论是否为 SBC,其中的 CAN 收发器部分通常仍符合标准的 CAN 收发器功能,只是控制方式从简单的引脚信号变为 SPI 指令。
CAN 收发器驱动(CanTrcv)模块在 AUTOSAR 基本软件架构中属于通信硬件抽象层(Communication Hardware Abstraction)6。它的主要作用是抽象具体收发器硬件差异,为上层提供统一的 API 操作收发器,实现与硬件无关的控制。例如,上层通过 CanTrcv 模块将某个 CAN 通道切换到休眠模式,而底层具体如何控制某型号收发器进入低功耗(例如设置某个 Standby 引脚、电源引脚、电压等)由 CanTrcv 驱动内部适配。这种抽象使得同一套上层通讯服务(如网络管理)可以兼容不同品牌型号的收发器芯片,只需更换 CanTrcv 的底层适配即可。CanTrcv 模块通过 MCU 的 MCAL 层服务(如 DIO 口驱动或 SPI 驱动)来控制收发器硬件7。
值得一提的是,AUTOSAR 定义的 CanTrcv 模块着眼于通用性和前向兼容。其规范覆盖了当前以及未来大多数 CAN 收发器的特性和行为8。因此,CanTrcv 模块支持多种收发器的供电模式切换、远程唤醒检测、部分网络(Partial Networking)选择性唤醒等功能点。并非所有具体收发器芯片都实现了这些高级特性,对于不支持的功能,CanTrcv 模块在实现时需要进行适配处理(例如如果底层硬件不支持选择性唤醒,则 CanTrcv 对应API可以直接返回未支持的状态)9。
总之,在 AUTOSAR Classic 平台中,CAN Transceiver Driver 模块承担着 “CAN收发器硬件接口” 的职责,为上层提供标准化的控制接口,实现在通讯总线物理层的模式管理与唤醒管理。它与 CAN Driver(CAN 控制器驱动)共同协作,确保ECU能够可靠地控制CAN网络的收发和休眠唤醒。
二、接口详解
CanTrcv 模块提供了一组 API 接口函数,用于初始化、模式切换、状态查询以及处理唤醒事件等。根据 AUTOSAR SWS(软件规范)定义,这些接口大体可分为以下几类:
- 初始化与去初始化接口:模块初始化和反初始化函数。
- 模式控制接口:设置或获取收发器的当前工作模式(正常、待机、休眠)。
- 唤醒管理接口:获取唤醒原因、设置唤醒事件通知模式、检查唤醒事件、清除唤醒标志等。
- 版本信息接口:获取驱动模块的版本信息。
- 周期任务接口:主函数(MainFunction)用于定期执行轮询任务(如唤醒检测)。
- 扩展接口:只有在收发器硬件支持选择性唤醒(PN)的情况下才存在的额外接口,如读取/清除特定标志等。
下面逐一介绍每个主要 API 的功能、用法和注意事项,并给出部分函数的代码原型或伪代码示例。
2.1 CanTrcv_Init
void CanTrcv_Init(const CanTrcv_ConfigType* ConfigPtr);
功能:初始化 CAN 收发器驱动模块。
描述:CanTrcv_Init 函数用于对 CanTrcv 模块进行初始化配置。它会根据传入的配置指针初始化所有已配置的 CAN 收发器通道。典型的初始化动作包括:配置收发器的默认模式、电源状态,以及检查是否有遗留的唤醒事件需要处理等。当函数调用完成后,CanTrcv 模块进入 ACTIVE 工作状态,可以响应其他API请求。
细节:
如果某收发器在上次关机前产生过唤醒事件(例如收发器内部有唤醒标志未清除),CanTrcv_Init 在初始化该通道时应检测到这一情况,并调用 EcuM_SetWakeupEvent() 通知 ECU 管理层有唤醒源。这样可以处理“上电即唤醒”的场景,例如 ECU 因 CAN 唤醒而上电时,需要立即告知系统唤醒原因。
对于支持选择性唤醒(Partial Networking)的收发器,如果在初始化时检测到 上次上电是由于总线唤醒(POR,Power On Reset flag)或者收发器报告了系统错误引起的唤醒(SYSERR flag),CanTrcv_Init 也应通过调用 EcuM_SetWakeupEvent() 将这些事件报告给 EcuM。配置中通常会将这些标志关联到特定的 EcuM 唤醒源(例如“ECU由CAN总线电源唤醒”)。
CanTrcv_Init 通常由 EcuM 在系统启动初始化阶段调用。在调用之前,应确保底层依赖的模块(如 DIO 或 SPI 驱动等)已经初始化完毕,以免初始化收发器硬件时出现无效访问。
调用 CanTrcv_Init 后,各收发器通道通常会被设置为配置指定的初始模式(通常是 Standby 模式,保持总线静默但可侦听唤醒)。随后模块进入正常工作状态。如后续需要改变收发器模式,可使用 CanTrcv_SetOpMode 接口。
错误处理:初始化过程中如果检测到参数指针无效(ConfigPtr=NULL)等,会触发开发错误(DET)的报告。若底层硬件通信失败(例如通过 SPI 无法与收发器对话),CanTrcv_Init 应报告运行时错误(比如 CANTRCV_E_NO_TRCV_CONTROL)并采取适当措施。
2.2 CanTrcv_SetOpMode
Std_ReturnType CanTrcv_SetOpMode(uint8 Transceiver, CanTrcv_TrcvModeType OpMode);
功能:设置指定收发器的工作模式。
描述:CanTrcv_SetOpMode 用于将编号为 Transceiver 的 CAN 收发器切换到目标模式 OpMode。OpMode 是一个枚举类型,典型取值包括 CANTRCV_TRCVMODE_NORMAL(正常模式)、**CANTRCV_TRCVMODE_STANDBY(待机模式)**和 CANTRCV_TRCVMODE_SLEEP(休眠模式)。不同模式下收发器的行为和功能有所区别,具体如下:
NORMAL 模式:正常通信模式。在该模式下,收发器可以收发 CAN 报文,与总线完全交互。通常此时收发器的低功耗功能关闭,例如保持 INH(抑制)引脚激活不断电,收发器不会监测总线唤醒模式帧(因为已经在正常通信)。进入 Normal 模式通常意味着 ECU 打算参与总线通信。
STANDBY 模式:待机模式。在该模式下,收发器不主动发送报文,通常也不再将总线信号传递给 MCU 的 CAN 控制器(即收发器的 TX/RX通道被隔离),从而 effectively 不参与通信。但与 Sleep 模式不同,Standby 模式下收发器保持部分电路激活(如唤醒检测电路),并保持 INH 引脚激活(ECU电源保持供电)。ECU 在 Standby 模式下通常仍然上电运行,但 CAN 通信处于休眠状态。收发器能够监测总线活动,一旦检测到符合条件的唤醒帧,就会设置内部唤醒标志并通知 MCU(通过硬件引脚中断等方式)。
SLEEP 模式:睡眠模式。该模式下收发器关闭了尽可能多的电路以降低功耗。它通常类似 Standby 模式,但进一步可以关闭 INH 引脚(使其不再维持ECU电源)。Sleep 模式通常用于 ECU 完全断电的场景,此时 MCU 停止运行。收发器仍保留总线唤醒检测功能,一旦检测到总线唤醒模式(Wake-up Pattern, WUP),会激活 INH 等输出以重新上电 MCU。这种情况下的唤醒属于“冷启动”类型(因为MCU之前完全无电)。一些收发器(如带有“Go-To-Sleep”命令的)在进入 Sleep 前需要特定时序或确认,在 AUTOSAR 框架下由 CanTrcv 驱动处理。
调用 CanTrcv_SetOpMode 会触发驱动对底层硬件执行相应操作,如通过 Port/DIO 引脚或 SPI 指令切换收发器模式。当模式切换成功并且收发器进入请求状态后,函数应返回 E_OK;若请求无法执行(例如参数无效或硬件不支持该模式),返回 E_NOT_OK。
实现要点:
模式切换前,驱动需检查当前收发器的内部状态,以判断请求是否合法。如果重复请求切换到相同模式,规范要求应视作成功且不报错。如果请求从不支持的模式或到不支持的模式,则返回 E_NOT_OK 或报告开发错误。
硬件操作:对于通过 GPIO 控制的收发器(如 TJA1040,仅一个 STB 引脚控制),SetOpMode 内会执行类似 Dio_WriteChannel(STB_PIN, level) 的操作以置位或清除待机引脚,从而实现 Normal/Standby 切换。对于通过 SPI 控制模式的收发器(如部分 SBC),则需要发送 SPI 命令切换模式。驱动应按硬件 datasheet 要求执行必要的延时或检查确认。
Icu 配合:当收发器模式从 Normal 切换到 Standby 或 Sleep 时,应启用对应的唤醒中断通知,以便后续捕获总线唤醒事件;反之从 Standby/Sleep 切换到 Normal 时,应禁用唤醒中断以避免不必要的中断。因此,CanTrcv_SetOpMode 内通常会根据 OpMode 调用 ICU 驱动的 Icu_EnableNotification() 或 Icu_DisableNotification() 来打开/关闭唤醒引脚的捕获。
PN相关:如果收发器支持选择性唤醒(PN)且在配置中启用了该功能,当驱动检测到收发器内部的 POR 标志为真(即上次上电由总线唤醒导致),则应执行一次收发器的重新初始化过程,以确保其配置的唤醒过滤器等正确加载。另外,在 PN 模式下,如果请求将收发器置为 Normal 模式且硬件确认 PN 功能正常(无系统错误标志),驱动应调用 CanIf_ConfirmPnAvailability() 通知上层 CanIf/CanSM 模块选择性唤醒功能已启用。这样网络管理模块可以得知此 ECU的收发器具备过滤任意帧唤醒的能力。该调用通常发生在从低功耗返回 Normal 的过程中。
模式通知:每次模式切换完成后,CanTrcv 驱动应通过 CanIf_TrcvModeIndication() 回调通知 CanIf 模块当前的模式状态。CanIf 汇总各通道状态并可能触发进一步的BswM规则。但需要注意,如果切换失败,一般不调用指示。
返回值:Std_ReturnType,E_OK 表示模式切换请求已成功受理,E_NOT_OK 表示请求未受理。例如,如果硬件不支持请求的模式(如要求进入 Sleep 但该收发器无Sleep模式),应直接返回 E_NOT_OK。
错误与边界情况:
调用前未初始化模块,则应触发开发错误 CANTRCV_E_UNINIT。
参数 Transceiver 越界或 OpMode 值不在允许范围,触发开发错误 CANTRCV_E_PARAM_TRCV 或 CANTRCV_E_PARAM_TRCV_OPMODE。
请求从非法状态切换,如当前不在 Standby却要求 Sleep,应报告相应的错误码(如 CANTRCV_E_TRCV_NOT_STANDBY)。
底层硬件通信故障(例如 SPI 无响应),报告运行时错误 CANTRCV_E_NO_TRCV_CONTROL 并返回 E_NOT_OK。
下面给出一个伪代码片段,展示 CanTrcv_SetOpMode 的典型实现逻辑:
Std_ReturnType CanTrcv_SetOpMode(uint8 TrcvId, CanTrcv_TrcvModeType OpMode) {
if (!CanTrcv_IsInitialized) {
Det_ReportError(CANTRCV_MODULE_ID, CANTRCV_INSTANCE_ID,
CANTRCV_SET_OPMODE_SID, CANTRCV_E_UNINIT);
return E_NOT_OK;
}
if (TrcvId >= CANTRCV_CHANNEL_COUNT || OpMode > CANTRCV_TRCVMODE_SLEEP) {
Det_ReportError(CANTRCV_MODULE_ID, CANTRCV_INSTANCE_ID,
CANTRCV_SET_OPMODE_SID, CANTRCV_E_PARAM_TRCV_OPMODE);
return E_NOT_OK;
}
/* 获取当前模式 /
CanTrcv_TrcvModeType currentMode = CanTrcv_InternalState[TrcvId];
if (currentMode == OpMode) {
return E_OK; // 请求模式与当前模式相同,直接成功
}
/ 根据目标模式执行硬件操作 */
Std_ReturnType result = E_OK;
switch(OpMode) {
case CANTRCV_TRCVMODE_NORMAL:
result = CanTrcv_HwToNormal(TrcvId); // 具体硬件操作,如拉低STB引脚等
Icu_DisableNotification(WakeupChannel[TrcvId]); // 关闭唤醒中断
break;
case CANTRCV_TRCVMODE_STANDBY:
result = CanTrcv_HwToStandby(TrcvId); // 硬件操作,如拉高STB引脚进入待机
Icu_EnableNotification(WakeupChannel[TrcvId]); // 开启唤醒中断
break;
case CANTRCV_TRCVMODE_SLEEP:
result = CanTrcv_HwToSleep(TrcvId); // 硬件操作,进入睡眠模式
Icu_EnableNotification(WakeupChannel[TrcvId]); // 开启唤醒中断(睡眠期间保持监听)
break;
}
if (result == E_OK) {
CanTrcv_InternalState[TrcvId] = OpMode;
CanIf_TrcvModeIndication(TrcvId, OpMode); // 通知上层模式已切换
} else {
Det_ReportRuntimeError(CANTRCV_MODULE_ID, CANTRCV_INSTANCE_ID,
CANTRCV_SET_OPMODE_SID, CANTRCV_E_NO_TRCV_CONTROL);
}
return result;
}
上述伪代码中,根据目标模式执行不同的硬件操作函数(这些函数内部对不同收发器硬件采取GPIO或SPI指令)。进入 Normal 则禁止唤醒中断,进入 Standby/Sleep 则启用唤醒中断。此外在切换成功后,通过回调通知 CanIf 模块。如果底层操作失败,则报告运行期错误。
2.3 CanTrcv_GetOpMode
Std_ReturnType CanTrcv_GetOpMode(uint8 Transceiver, CanTrcv_TrcvModeType* OpMode);
功能:获取指定收发器当前的工作模式。
描述:CanTrcv_GetOpMode 用于查询编号为 Transceiver 的收发器当前所处的模式,并将该模式存入输出参数 OpMode。常见的模式值包括 NORMAL、STANDBY、SLEEP,与 SetOpMode 中的定义相同。调用此函数可以让上层模块(如 CanSM 或诊断模块)了解收发器的当前状态。
用法:当上层需要确认收发器状态时调用该函数。例如,CanSM 在执行状态迁移过程中可能使用 GetOpMode 验证收发器是否已经进入期望模式。又或者调试时,开发者可以通过调用此接口读取收发器状态寄存器映射的值。
注意:
正常情况下,GetOpMode 只是返回驱动模块中维护的软件状态。CanTrcv 内部通常会缓存每个收发器的当前模式(如上面的 CanTrcv_InternalState[]),因此 GetOpMode 可直接返回该缓存值,速度很快。必要时也可读取硬件寄存器以核实,但大多数实现不需要这么做。
如果模块尚未初始化,或参数 Transceiver 无效,应返回 E_NOT_OK 并不修改 OpMode 指向的值。开发错误可能不会在该API中报告(按照AUTOSAR规范,Get类函数通常不触发DET,以免影响调试),但实现上可以增加保护。
当函数成功返回 E_OK 时,OpMode 才能认为有效,调用者应检查返回值再使用输出模式值。
返回值:E_OK 表示获取成功,OpMode 输出有效;E_NOT_OK 表示获取失败(例如输入参数错误)。
2.4 CanTrcv_GetBusWuReason
Std_ReturnType CanTrcv_GetBusWuReason(uint8 Transceiver, CanTrcv_TrcvWakeupReasonType* reason);
功能:获取总线唤醒事件的原因/来源。
描述:当收发器检测到一次 CAN 总线唤醒事件后,上层可以通过调用此函数获取唤醒的具体原因(Reason)。CanTrcv_TrcvWakeupReasonType 是一个枚举类型,用于表示唤醒类型,例如:
CANTRCV_WU_BY_BUS:表示由于 CAN 总线活动引发的远程唤醒;
CANTRCV_WU_BY_PIN:表示由于本地唤醒引脚(例如外部 Wake 引脚)引发的唤醒;
CANTRCV_WU_INTERNALLY:表示由于内部条件(比如POR上电)导致的唤醒;
CANTRCV_WU_NOT_SUPPORTED:收发器不支持唤醒检测;
CANTRCV_WU_RESET:可能表示复位标志等;
等等(具体枚举值可能因版本不同稍有差异)。这些枚举值在AUTOSAR定义中涵盖了唤醒来源的各种可能。
调用 CanTrcv_GetBusWuReason 通常在 ECU 从低功耗恢复后的启动阶段进行,用于判断上一休眠周期中是哪种唤醒触发了 ECU 上电。例如区分“被总线上的远程帧唤醒”还是“本地产生的唤醒”等,对后续策略有帮助。EcuM模块在复位后可能调用这个函数并依据结果采取不同处理。
要求:只有当收发器支持唤醒原因检测时,该接口才有意义。如果硬件不支持,规范可能要求:
如果配置参数 CanTrcvWakeupByBusUsed 为 FALSE(即不使用总线唤醒功能),CanTrcv_GetBusWuReason 直接返回 CANTRCV_WU_NOT_SUPPORTED 或相应标识。
某些实现中,只有特定支持PN功能的收发器才提供详细唤醒原因寄存器,否则只能报告简单的“有/无唤醒”。
实现:通常驱动在检测到唤醒事件时,会保存唤醒来源。例如:如果通过 ICU 捕获了唤醒引脚的中断,则可能是本地唤醒(Wake pin);如果通过检查收发器寄存器发现总线活动标志,则是远程唤醒。驱动可在内部保存一个 LastWakeupReason[Trcv] 变量。当上层调用 GetBusWuReason 时,返回该变量并清除之(可选)。
返回值:E_OK 表示获取成功且 *reason 输出有效;E_NOT_OK 表示获取失败(模块未初始化或参数错误等)。调用成功后,一般驱动可以重置内部记录的唤醒原因,以避免重复读取到旧值。
2.5 CanTrcv_GetVersionInfo
void CanTrcv_GetVersionInfo(Std_VersionInfoType* versionInfo);
功能:获取 CanTrcv 驱动模块的版本信息。
描述:此函数将驱动模块的版本号信息(模块ID、供应商ID、软件版本、发布版本等)填入提供的 versionInfo 结构体中。其作用主要用于版本一致性检查和调试。AUTOSAR 要求每个 BSW 模块都提供 GetVersionInfo 接口(如果配置允许)。VersionInfo 通常包括:
.vendorID:供应商ID(例如 Vector 的可能是 0x001C 等);
.moduleID:模块ID(CAN Transceiver Driver 模块ID 一般是常数,例如 0x2A 等);
.sw_major_version / .sw_minor_version / .sw_patch_version:软件版本号(对应AUTOSAR发布版本)。
用法:该函数通常在开发调试或生成的版本校验中使用。比如在系统初始化时,可调用 CanTrcv_GetVersionInfo 并将返回的版本与预期版本比较,确保链接的库正确。由于其参数是输出形式,没有返回值,如果传入空指针会引发开发错误(CANTRCV_E_PARAM_POINTER)。
实现:此函数通常是一个宏或直接内联代码,将编译时定义的版本常量赋予 versionInfo。无其他复杂逻辑。
注意:如果 CanTrcvVersionInfoApi 配置为 FALSE,则可能不生成此函数代码。在配置允许下才提供。
2.6 CanTrcv_SetWakeupMode
Std_ReturnType CanTrcv_SetWakeupMode(uint8 Transceiver, CanTrcv_TrcvWakeupModeType WakeupMode);
功能:设置收发器的唤醒事件通知模式。
描述:CanTrcv_SetWakeupMode 用于控制驱动如何处理收发器的唤醒事件,有三个可选模式:ENABLE、DISABLE、CLEAR。
WUP 模式 ENABLE(启用):允许收发器唤醒事件上报。设置为 ENABLE 后,如果收发器检测到总线唤醒,将立即通知上层(通常通过 EcuM_SetWakeupEvent)。在配置成 ENABLE 的瞬间,如果此时已经有未上报的唤醒事件,也应立即上报。
WUP 模式 DISABLE(禁用):暂时屏蔽收发器的唤醒事件通知。收发器如果在该模式下检测到唤醒,不会立刻通知上层,而是暂存该事件。当后续切换回 ENABLE 时,再立即报告(相当于延迟报告机制)。这个模式通常在系统准备进入休眠的过程中使用,防止休眠期间重复的唤醒抖动触发反复通知。
WUP 模式 CLEAR(清除):清除驱动内部存储的唤醒事件状态。一般在休眠准备就绪且不打算处理先前捕获的唤醒时调用,用于复位唤醒记录。通常要求在唤醒通知被禁止(DISABLE)时才使用 CLEAR。CLEAR 执行后,即使先前有暂存的唤醒事件也会被丢弃。
使用场景:EcuM 在管理睡眠流程时会用到此接口。在进入休眠前,EcuM 会通过 CanIf 调用 CanTrcv_SetWakeupMode(ENABLE) 确保收发器驱动进入唤醒监视状态,然后再令 MCU休眠。如果想防止某段时间的误报,可以临时 DISABLE,然后在适当时机ENABLE。CLEAR 则用于在睡眠前清理旧事件。例如在关闭唤醒通知期间检测到了若干唤醒事件,但确定它们无效,就可以 CLEAR 清掉。
注意:
并不是所有收发器都支持该功能。如果 CanTrcvWakeUpSupport 配置为 NOT_SUPPORTED,则此函数的调用应返回 E_NOT_OK 或做空操作。
此函数与 CanIf 和 EcuM 紧密配合使用。通常通过 CanIf 提供的 SetTransceiverWakeupMode 接口调用,后者再调用到底层的 CanTrcv_SetWakeupMode。
设置 ENABLE 时可能需要启用相关硬件中断,DISABLE 时则可能暂时屏蔽中断或标志。CLEAR 一般清除软件标志,对于硬件寄存器里的唤醒标志,需要调用下面介绍的 ClearTrcvWufFlag 才能真正清掉硬件状态。
返回值:E_OK 表示设置成功,E_NOT_OK 表示不支持或设置失败。
2.7 CanTrcv_GetTrcvSystemData
Std_ReturnType CanTrcv_GetTrcvSystemData(uint8 Transceiver, uint32* TrcvSysData);
功能:读取收发器的系统状态数据。
描述:这个接口通常仅在收发器硬件支持特定的系统状态寄存器时才实现。其作用是从收发器获取一些原始的状态数值(通常为一个寄存器值),并返回给调用者。TrcvSysData 可以包含多个信息位,例如收发器的故障状态、配置信息等。
使用:如果 CanTrcvHwPnSupport 配置为 TRUE 且底层芯片支持,调用该函数可以得到收发器内部例如“选择性唤醒配置寄存器”的值或者其他诊断信息。在调试复杂问题时可能会用到。
注意:大部分场景下,上层并不会直接使用这个接口,因为这些数据对高层意义不大,而更多用于Driver内部或测试。若硬件不支持,本函数可以不实现或直接返回 E_NOT_OK。
2.8 CanTrcv_ClearTrcvWufFlag
Std_ReturnType CanTrcv_ClearTrcvWufFlag(uint8 Transceiver);
功能:清除收发器硬件中的“Wake Up Flag”(唤醒标志)。
描述:许多支持部分网络唤醒的收发器,在检测到一次总线唤醒帧(WUF, Wake-Up Frame)后,会在内部置位一个唤醒标志位。该标志通常需要软件显式清除才能复位。CanTrcv_ClearTrcvWufFlag 提供清除这个硬件标志的功能。
重要性:在进入低功耗模式之前,上层应调用此函数清除收发器先前残留的唤醒标志,以避免遗漏后续真正的唤醒事件。如果不清除,收发器可能因为旧标志而认为早已“被唤醒过”从而不再报告新的唤醒。
典型流程:网络管理模块在决定休眠前,会通过 CanIf 调用 ClearTrcvWufFlag 清标志,然后再将收发器设入 Standby 模式等待新的唤醒事件。清除成功后,CanTrcv 驱动应调用 CanIf_ClearTrcvWufFlagIndication() 回调通知 CanIf,表示标志已清除。这个通知接口(如 CanIf_30_ClearTrcvWufFlagIndication)是 AUTOSAR 预留给 OEM/BswM 用的扩展,可用来触发相应策略。
硬件实现:对于通过 SPI 控制的芯片,驱动需要发送特定命令清除标志寄存器。对于通过引脚的芯片(极少,大多PN功能芯片都有SPI),如果无接口则可能无法实现此功能。
返回:E_OK 表示清除成功,E_NOT_OK 表示清除失败(比如通信故障)。如果硬件不支持PN,则该函数可能不存在。
2.9 CanTrcv_ReadTrcvTimeoutFlag
Std_ReturnType CanTrcv_ReadTrcvTimeoutFlag(uint8 Transceiver, CanTrcv_TrcvFlagStateType* FlagState);
功能:读取收发器的“超时标志”(Timeout Flag)状态。
描述:部分高级收发器芯片(常是SBC)有“远程唤醒帧过滤超时”概念。当配置了选择性唤醒过滤器后,如果在一定时间内未检测到匹配的唤醒帧而收发器又检测到了其他通信,会设置一个超时标志。CanTrcv_ReadTrcvTimeoutFlag 用于读取这个标志的当前状态(FlagState 返回 ACTIVE 或 INACTIVE)。
用途:这个标志在少数情况下帮助判断唤醒失败的原因。如果FlagState为ACTIVE,表示曾发生过唤醒帧超时,可提示应用层可能需要调整过滤策略。一般在调试PN功能时才会读取。
注意:AUTOSAR 将这个接口定义为 可选(只有硬件支持才实现)。FlagState 通常是一个简单的TRUE/FALSE枚举。函数成功返回后,可以配合 ClearTrcvTimeoutFlag 来复位状态。
2.10 CanTrcv_ClearTrcvTimeoutFlag
Std_ReturnType CanTrcv_ClearTrcvTimeoutFlag(uint8 Transceiver);
功能:清除收发器的超时标志。
描述:对应上面的 ReadTrcvTimeoutFlag,此接口用于将 Timeout 标志复位。清除后,收发器可以重新开始计算唤醒帧超时。
使用:通常在读取到 TimeoutFlag 之后,如果希望重新监测唤醒过程,可以清除标志。或者在每次进入休眠前做一次清除,确保标志状态干净。
实现:和 ClearWufFlag 类似,通过 SPI 写特定寄存器位实现。
2.11 CanTrcv_ReadTrcvSilenceFlag
Std_ReturnType CanTrcv_ReadTrcvSilenceFlag(uint8 Transceiver, CanTrcv_TrcvFlagStateType* FlagState);
功能:读取收发器的“静默标志”(Silence Flag)。
描述:有些收发器/SBC可以检测到总线长时间静默(无活动),或者检测到自身进入静默模式的状态位。这个接口用于读取该状态。
意义:通常静默标志在收发器进入“Listen-Only”或“Silent”模式时出现,用于诊断CAN总线是否空闲等。一般使用场景不多。
注意:仅硬件支持情况下实现,大多数标准收发器无此特性。
2.12 CanTrcv_CheckWakeup
Std_ReturnType CanTrcv_CheckWakeup(uint8 Transceiver);
功能:检查收发器是否有总线唤醒事件发生,必要时通知ECU管理器。
描述:该函数通常由 CanIf 模块在检测到唤醒信号时调用,用于让收发器驱动确认并报告唤醒事件。其典型流程如下:当收发器处于唤醒通知启用状态(WUMODE_ENABLE)且检测到唤醒(例如通过硬件中断或定期轮询发现),CanTrcv 模块会将此唤醒事件上报给 EcuM。具体实现是调用 EcuM_SetWakeupEvent(唤醒源)。
两种模式:根据配置的 CanTrcvWakeUpSupport,不同模式下 CheckWakeup 的用法稍有不同:
POLLING 模式:如果 WakeUpSupport 为 CANTRCV_WAKEUP_BY_POLLING,则收发器驱动不会通过中断实时报告唤醒,而是在主函数 CanTrcv_MainFunction 中定期调用 CheckWakeup 来轮询检查。CanIf 会在合适的时机周期性地调用 CanTrcv_CheckWakeup(通常由 EcuM/ComM 驱动),一旦函数发现唤醒标志,就会调用 EcuM_SetWakeupEvent 通知。
NOT_SUPPORTED 模式:如果不支持唤醒,则 CheckWakeup 可能什么都不做,直接返回。规范要求即便不支持唤醒,此函数也需存在以满足接口,但其中无实际功能。
直接中断唤醒:某些实现,在 MCU 处于停止模式被唤醒中断唤醒时,会直接在中断里调用 EcuM_CheckWakeup(),后者进而调用 CanIf_CheckWakeup -> CanTrcv_CheckWakeup 一路下传。这种情况下,CheckWakeup 需要尽快处理并返回,不宜有阻塞操作。提到,如果 MCU之前是休眠模式,那么在 MCU 被唤醒的中断里,会直接调用 EcuM_CheckWakeup 检查收发器唤醒标志。
注意:CheckWakeup 只应在有唤醒事件待处理时调用。一旦 EcuM_SetWakeupEvent 成功上报,收发器驱动内部应清除相应标志,以防重复报告。同时由于 EcuM_SetWakeupEvent 可能切换系统状态,调用该函数后 ECU 管理器将进入唤醒处理流程。
返回:一般始终返回 E_OK(除非模块未初始化或参数错误)。可以认为CheckWakeup本身不需要返回有用信息——它的作用主要是触发后续处理。
2.13 CanTrcv_SetPNActivationState
Std_ReturnType CanTrcv_SetPNActivationState(CanTrcv_PNActivationType ActivationState);
功能:配置收发器的部分网络(PN)功能启用状态。
描述:PNActivationType 通常是一个两值枚举:PN_ENABLED 或 PN_DISABLED。调用该函数可以在运行时启用或禁用收发器的选择性唤醒功能。其效果是决定收发器在 Standby/Sleep 模式下是否按照配置的过滤规则来选择性唤醒。
使用场景:某些系统可能需要动态切换 PN 策略。例如,当网络管理决定采用“任意消息唤醒”策略时,可以禁用 PN;当决定仅允许特定消息唤醒ECU时,则启用 PN 并提前配置好滤波帧。
实现:对于支持 PN 的芯片,驱动通过 SPI 设置寄存器来打开/关闭过滤功能。若禁用 PN,收发器将退化为传统的 WUP 模式(任何活动都唤醒);启用 PN,则只有匹配的 WUF 才唤醒。该函数可以影响 CanTrcv_SetOpMode 进入 Standby 时的行为(如启用PN则要配置芯片进入选择性唤醒模式)。
注意:要使能 PN,一般还需要在配置(arxml)中提供唤醒帧的ID/Mask等参数,并确保 CanTrcvHwPnSupport 为 TRUE。如果硬件不支持,此函数调用应返回 E_NOT_OK 或未实现。通常在初始化后或休眠前调用,以设定接下来休眠期的唤醒策略。
2.14 CanTrcv_CheckWakeFlag
Std_ReturnType CanTrcv_CheckWakeFlag(uint8 Transceiver);
功能:请求收发器检查其唤醒标志状态,并可能通知上层。
描述:这是一个扩展接口,通常用于当上层需要主动确认收发器是否接收到唤醒事件时调用。调用后如果收发器发现内部存在唤醒标志置位,且条件允许,则返回 E_OK 并调用 CanIf_CheckTrcvWakeFlagIndication() 通知 CanIf。
使用:这个接口并不常用,更像一种主动检测机制,而 CheckWakeup 更偏被动通知。可能在某些特殊场景或调试时,由上层周期性调用 CheckWakeFlag 来探测有没有错过的唤醒。
注意:只有配置允许时(WakeupByBusUsed = TRUE 等)才有意义。实现上,它可能直接读取收发器寄存器的 WUF 标志位,如果发现已置位就通知上层并清除硬件标志,之后返回 E_OK。
2.15 CanTrcv_DeInit
Std_ReturnType CanTrcv_DeInit(uint8 Transceiver);
功能:反初始化(去初始化)CAN收发器驱动模块或特定通道。
描述:CanTrcv_DeInit 将指定的 Transceiver通道或整个模块(取决于实现)进行反初始化,释放资源。调用后,指定收发器进入 NOT_ACTIVE 状态,不再受驱动管理。对硬件而言,DeInit 通常会将收发器置于一个安全状态(例如 Standby 模式),以防止反初始化后仍留在Normal造成总线通信异常。
使用:此函数在AUTOSAR中通常是可选的。一些实现可能不提供逐通道的DeInit,而只提供模块级别的停止操作。如果提供,该函数可在关闭通讯或 ECU 关闭时由 EcuM调用,以关闭收发器。一般Vector等实现未强调单通道DeInit,因为多个通道配置时,大多一次性初始化/去初始化整个模块。
注意:DeInit 后对应通道允许重新配置(可再次Init)。若之后不Init就直接调用其他接口,应该报错(未初始化状态)。在DeInit过程中,可释放内部缓存、关闭中断等。
返回:E_OK 成功,E_NOT_OK 失败(比如硬件无法进入所需状态)。
2.16 CanTrcv_MainFunction
void CanTrcv_MainFunction(void);
功能:CanTrcv 主函数,周期性执行任务。
描述:MainFunction 是由 BSW 调度器定期调用的函数,用于处理需要周期轮询的事项。如果 WakeUpSupport 配置为 POLLING,则在 Standby/Sleep 模式下,MainFunction 会检查收发器是否有唤醒事件发生,如果检测到则调用 EcuM_CheckWakeup() 触发上层处理。这样即使在 MCU 正常运行(非停止模式)但需要通过轮询来检查唤醒时,也能报告事件。
此外,如果规范或配置定义了诊断定期读取(如某些驱动实现 CanTrcv_MainFunctionDiagnostics 作为单独函数),MainFunction 也可能负责调用读取收发器诊断状态,设置相应错误标志等。
使用:需要在 Os 或 SchM 中按配置的周期(CanTrcvMainFunctionPeriod)调用该函数。典型周期可能是 10ms 或根据系统休眠反应要求设定。如果WakeUpSupport=NOT_SUPPORTED,则MainFunction可以空实现而不被调度。
注意:如果MCU完全停止低功耗(如停止时钟),则无法调用MainFunction。这种情况下唤醒由硬件中断直接触发 EcuM_CheckWakeup,所以MainFunction 主要是为MCU未完全停止但仍需检测唤醒的情形准备。
以上接口涵盖了 CanTrcv 模块的主要功能点。在AUTOSAR实现中,CanIf 模块会调用这些接口来完成对收发器的控制和事件处理。例如,CanIf.SetTransceiverMode 会调用 CanTrcv_SetOpMode;CanIf.CheckWakeup 会调用 CanTrcv_CheckWakeup 等。驱动开发者在实现这些接口时,需要严格遵守AUTOSAR SWS对行为和错误处理的要求,以保证与上层模块的契合同步。
三、状态机与唤醒机制
本章我们关注 CanTrcv 模块的内部状态机和 CAN 收发器的唤醒工作机制。理解状态和唤醒流程有助于正确配置和使用收发器驱动。
3.1 模块状态机概述
AUTOSAR CanTrcv 模块可以用状态机描述其运行状态。根据规范和典型实现,状态机包含如下几个主要状态:
NOT_ACTIVE(未激活状态):表示 CanTrcv 模块未初始化,或者通道已反初始化。在该状态下,驱动不应调用任何操作接口(除了 Init)。收发器硬件在此状态下未受驱动控制,通常处于上电初始状态或者前一轮使用后的未配置状态。
ACTIVE(激活状态):表示 CanTrcv 模块已初始化并运行正常。在 ACTIVE 状态下,又细分以下子状态(对应收发器的操作模式):
CANTRCV_TRCVMODE_NORMAL(正常模式):收发器处于正常工作,可以进行总线通信。不监测远程唤醒帧,INH引脚保持激活(不断电)。
CANTRCV_TRCVMODE_STANDBY(待机模式):收发器处于低功耗待机,停止通信但保持唤醒检测功能,INH引脚仍激活(ECU有电)。
CANTRCV_TRCVMODE_SLEEP(休眠模式):收发器处于深度休眠,停止通信并关闭部分电源,INH引脚可能不激活(ECU断电或MCU停止运行)。
状态转换发生于调用对应的接口,例如 CanTrcv_Init 从 [*] 初始状态进入 ACTIVE/Standby 子状态,CanTrcv_SetOpMode 导致 NORMAL<->STANDBY<->SLEEP 之间转换,CanTrcv_DeInit 则返回 NOT_ACTIVE 等。下图用 Mermaid 状态图表示了状态机的简化模型:
图 1:CanTrcv 模块状态机示意图。初始状态为 NOT_ACTIVE,Init 后进入 Standby(默认)。ACTIVE 状态下收发器可在 Normal/Standby/Sleep 间切换。DeInit 后返回 NOT_ACTIVE。
上图中假定初始化后收发器进入 Standby(典型配置),实际也可配置初始进入 Normal 等。ACTIVE_STATES 作为选择节点,表示在 ACTIVE 的子状态之间根据函数调用进行转换。
需要强调的是,NOT_ACTIVE vs ACTIVE 是模块控制层面的状态,而 NORMAL/STANDBY/SLEEP 是收发器硬件工作模式。只有在 ACTIVE 状态下,收发器模式才有意义。NOT_ACTIVE 时硬件未受控,可以认为不属于上述任何模式。
3.2 收发器模式切换与行为
不同模式下收发器的行为在前文2.2节已做介绍,这里再补充Standby和Sleep的一些细微区别以及模式切换时硬件的典型行为:
Standby vs Sleep:两者都是低功耗模式,但Standby一般用于MCU依然上电但想停止通信的情况,此时收发器保持唤醒检测且供电状态未完全关闭。而Sleep用于MCU断电或深度睡眠,需要收发器负责唤醒上电。以 TJA1043 收发器为例,在 Standby 模式下其 INH(抑制)引脚始终为高电平,维持外部电源开启,ERR_N(错误)引脚可用来指示唤醒事件;而在 Sleep 模式下 INH 引脚会被释放(可能拉低),收发器进入真正休眠,只能通过总线活动重新激活 INH。
模式切换控制线:许多收发器通过特定引脚组合控制模式。例如:TJA1043有 STB_N 和 EN 两个引脚,TJA1040 只有 STB,一个引脚高低电平决定 Normal/Standby。一般拉低 STB_N表示工作模式,拉高 STB表示待机。对于带 SPI 控制的则通过命令。模式切换可能需要一定延时,AUTOSAR驱动配置里通常有一个 CanTrcvWaitTime 参数,用于插入模式切换后的等待时间,典型值例如几十微秒。
Wake-up Pattern:CAN 总线远程唤醒采用 ISO11898 定义的唤醒模式(WUP),它指的是总线上出现至少一个突发的显性位(dominant)持续一定时间,然后回到静默。收发器内部的滤波电路检测到这种模式即判定为唤醒事件。Normal模式下通常忽略WUP,Standby/Sleep模式下监视 WUP。一旦WUP被检测,收发器会设置 Wakeup Flag。如果芯片有 INH 引脚,在 Sleep模式下还会拉高INH以开始上电过程。
图 2:NXP TJA1043 收发器的状态迁移图示例。该芯片具有 Normal、Listen-Only、Standby、Go-to-Sleep 和 Sleep 五种模式,通过 STB_N 和 EN 引脚组合进行模式控制,并具备唤醒标志(Wake-up flag)机制。当 TJA1043 处于 Standby 或 Sleep 模式且总线上出现唤醒模式时,会置位唤醒标志并进入 Standby模式,拉高 INH 引脚输出以通知外部电路电源开启。
上图展示了一个实际收发器(TJA1043)的模式控制逻辑和转换条件。比如:当 STB_N 拉低且 EN 引脚为高时,TJA1043进入 Standby模式;而如果 STB_N 保持低、EN 从高变低,则芯片执行 Go-to-Sleep 序列随后进入 Sleep模式。一旦在 Sleep状态检测到总线唤醒(Wakeup flag置位),芯片会自动切换到 Standby模式,并等待MCU响应。这些硬件细节由 CanTrcv 驱动在实现时加以利用,例如在决定进入 Sleep 前需要先通过 SPI 发送“GoToSleep”命令,然后再拉某引脚。
3.3 三种典型唤醒场景
AUTOSAR 文档中描述了 ECUs 的三种唤醒情形:
MCU未上电的冷启动:即 MCU 处于断电状态,只有收发器及极少部分硬件有待机电源。当 CAN 收发器在 Sleep 模式下检测到总线唤醒帧(WUP)时,它将拉高 INH 等信号开启主电源,使 MCU 和其他硬件上电。此场景下,从 AUTOSAR 角度称为 冷启动(Cold Start) 而非唤醒,因为对 EcuM 来说这是一次新的上电。这种情况下 EcuM 不会认为是已有ECU的唤醒,而是正常的启动流程,只是启动原因可以记录为 “由CAN总线事件触发上电”。
MCU处于低功耗模式:即 MCU 保持待机电源但处于深度睡眠(如STOP模式),收发器等仍上电。收发器此时通常配置在 Standby 模式。当它检测到总线唤醒帧后,通过硬件引脚触发 MCU 的唤醒(如连接到 MCU 的某个中断引脚)。在 TJA1043 示例中,Standby模式下 INH 引脚本就为高保持MCU电源,唤醒时收发器将 ERR_N 引脚拉高、RXD 引脚出现变化,这些可连至MCU中断引脚以唤醒之。AUTOSAR 将这种场景视为 来自MCU休眠状态的唤醒,由 MCU 的低功耗模式退出以及 CAN 通道唤醒共同构成。
MCU处于运行模式:MCU并未真正睡眠(只是没有进行通信),ECU上的设备都上电,但 CAN 收发器可能在 Standby 模式(停止通信但监控总线)。当收发器检测到唤醒帧,它通过引脚或标志通知 MCU发生了唤醒事件,或者 MCU 定期轮询收发器状态。这种情况下,AUTOSAR 视之为 CAN 通道的唤醒(因为MCU本身在运行,只是网络从安静变为活跃)。例如 TJA1043 Standby下 INH一直高,MCU可以通过定期查询 ERR_N 或其他寄存器方式得知收发器有唤醒标志。
针对上述唤醒,AUTOSAR 定义了枚举类型 CanTrcv_TrcvWakeupReasonType,如 CANTRCV_WU_BY_BUS(总线唤醒),CANTRCV_WU_BY_PIN(本地唤醒),CANTRCV_WU_INTERNALLY(内部),CANTRCV_WU_POWER_ON(上电)等,用以表征一次唤醒的来源。驱动会在适当时候将这些信息报告给 EcuM。对于唤醒源,配置里还要映射到 EcuM 唤醒源ID,例如上电唤醒映射为某个 EcuM_WksSource。
3.4 唤醒通知与唤醒验证
当收发器检测到唤醒后,如何通知系统?AUTOSAR 使用了一套唤醒通知机制:
直接通知:在 MCU未休眠的情况下,收发器通过中断触发 ICU,进而 MCU调用 EcuM_CheckWakeup -> CanTrcv_CheckWakeup,如前面 2.12 节所述,最终调用 EcuM_SetWakeupEvent(EcuMWakeupSource) 报告唤醒来源。EcuM_SetWakeupEvent 会标记相应唤醒源(一个位标志)为 待验证 状态,并启动ECU的唤醒过程。如果系统配置了唤醒验证(Wakeup Validation),EcuM 会在短时间窗口内等待看此唤醒源是否有效(例如必须接收到预期的NM报文才算真正唤醒)。若验证通过,则真正切换系统至运行态,否则如果是虚假唤醒则可能重新睡眠。
Wakeup Validation:很多网络管理策略要求唤醒验证,即不是任意报文唤醒都算数,需要确认是网络管理帧/NM帧导致的唤醒才进行通信恢复。AUTOSAR ComM/CanSM 与 EcuM 协同实现这一过程。如果收发器不支持PN,即任何报文都会唤醒ECU,那么第一帧唤醒收发器和MCU,第二帧到来时MCU才准备好判断它是不是NM。如果发现不是NM,也许又要休眠,造成误唤醒的功耗损失。而若使用了支持PN的收发器并只配置NM报文为唤醒帧,则只需一帧NM即可唤醒整个ECU。这就是部分网络在能耗优化上的价值所在。
ComM_EcuM_WakeUpIndication:一旦 EcuM 最终确认唤醒事件有效(可能不需要验证,或验证通过),它将调用 ComM 提供的 ComM_EcuM_WakeUpIndication(NetworkHandle)接口通知通信管理模块该网络(Channel)被唤醒。ComM据此知道某网络通道从无通信转为请求通信。随后 ComM 可以发起网络重新上线流程。
下面通过一个时序图来综合展示睡眠和唤醒的交互流程:
sequenceDiagram
participant ComM as ComM (通讯管理)
participant CanSM as CanSM (CAN状态管理)
participant CanIf as CanIf (CAN接口)
participant CanTrcv as CanTrcv (收发器驱动)
participant EcuM as EcuM (ECU管理)
participant ICU as ICU (输入捕获驱动)
Note over ComM, EcuM: (1)网络进入休眠:
ComM->>CanSM: 请求网络模式 = NoComm(无通信)
CanSM-->>ComM: 确认进入无通信模式
CanSM->>CanIf: SetControllerMode(CAN_CONTROLLER, SLEEP)
CanSM->>CanIf: SetTrcvMode(Transceiver, STANDBY)
EcuM->>CanIf: CanTrcv_SetWakeupMode(ENABLE)
EcuM->>ICU: Icu_EnableWakeup(收发器_WAKE引脚)
Note over ComM, EcuM: MCU此时进入低功耗等待唤醒
===
Note over ComM, EcuM: (2)远程唤醒发生:
alt 收发器检测到总线唤醒帧
CanTrcv->>ICU: 触发唤醒中断 (如INH或ERR引脚变动)
else MCU未停机,仅Standby模式
EcuM->>CanIf: CanIf_CheckWakeup(Transceiver)
CanIf->>CanTrcv: CanTrcv_CheckWakeup(Transceiver)
end
Note over ComM, EcuM: MCU被中断唤醒,开始处理唤醒源验证
ICU->>EcuM: EcuM_CheckWakeup(ECUM_WKSOURCE_CANxx)
EcuM->>CanIf: CanIf_CheckWakeup(Transceiver)
CanIf->>CanTrcv: CanTrcv_CheckWakeup(Transceiver)
CanTrcv->>EcuM: EcuM_SetWakeupEvent(ECUM_WKSOURCE_CANxx)
EcuM-->>ICU: Icu_DisableWakeup(收发器_WAKE引脚)
Note over ComM, EcuM: EcuM开始Wakeup Validation(若配置有验证)
opt 唤醒事件有效 (验证通过或无需验证)
EcuM->>ComM: ComM_EcuM_WakeUpIndication(NetworkHandle)
ComM->>CanSM: RequestComMode(FULL_COMM)
CanSM->>CanIf: SetTrcvMode(Transceiver, NORMAL)
CanSM->>CanIf: SetControllerMode(CAN_CONTROLLER, STARTED)
end
Note over ComM, EcuM: 网络恢复通信,ECU进入正常运行
图 3:CAN 网络休眠和唤醒的交互时序图。第一部分展示网络进入休眠时,各模块的调用顺序;第二部分展示唤醒事件发生时,从收发器硬件中断一直到网络重新启动的流程。
上述流程中,收发器驱动(CanTrcv)在休眠前被设置为允许唤醒(ENABLE),进入待机模式监听总线。唤醒发生后,通过 CheckWakeup 确认事件并调用 EcuM_SetWakeupEvent 报告。EcuM 再通过 ComM_EcuM_WakeUpIndication 通知 ComM,最终由 CanSM 将收发器和控制器切回正常模式开始通信。
3.5 部分网络(Selective Wakeup)的机制
部分网络(Partial Networking, PN)指ECU在休眠时仅对特定的“选择性唤醒帧”有反应,而对其他无关报文忽略,从而实现网络唤醒的更精细控制。实现PN需要收发器硬件支持选择性唤醒功能,典型的是符合 ISO11898-6 标准的收发器,如 NXP TJA1145。
支持PN的收发器工作机制与普通WUP有区别:
上电后,需通过 SPI 配置唤醒滤波器参数(通常包括一个报文ID或ID掩码,以及期望的远程唤醒帧数据字节)。这些参数告诉收发器“什么样的CAN帧可以唤醒我”。
收发器进入待机/休眠后,监听总线数据。当检测到总线活动时,会对照已配置的ID和数据模式进行匹配:若匹配,则产生唤醒;不匹配则不产生唤醒(总线信号被视为噪声忽略)。
如果在一个超时时间窗口内收发器一直听到CAN通信但始终没有匹配帧,则可能触发 Timeout Flag,这时它通常也会唤醒(毕竟总线一直有消息而没等到匹配的,可能意味着策略需要调整)。这种情况下唤醒ECU后,由软件判断唤醒原因是“超时触发”还是“真的匹配”。
AUTOSAR 为 PN 支持增加了若干机制:
配置参数 CanTrcvHwPnSupport 用于声明硬件是否支持选择性唤醒。只有设为 TRUE 时,PN 相关的API和配置容器才有效。
如果硬件支持,配置中会有 CanTrcvPartialNetwork 子容器,内含要匹配的唤醒帧ID、蒙版、字节过滤等参数。驱动在初始化时应将这些参数通过 SPI 下发给收发器。
在应用使能 PN 时,前述的 CanTrcv_SetPNActivationState(PN_ENABLED) 需调用,将收发器切换为选择性唤醒模式。对于某些芯片,这可能只是内部标志开关;对于另一些,则需要实际发送命令启动PN功能。
当 ECU 从休眠醒来进入 Normal 模式后,如果 PN 功能是启用的,CanTrcv 将调用 CanIf_ConfirmPnAvailability() 告知上层网络管理,表示该节点的选择性唤醒功能生效。上层(CanSM/CanNM)据此认知网络状态。例如 CanNM 在有PN功能时,知道首帧NM即可唤醒所有PN节点,无需双帧机制。
PN 的局限:目前大多数收发器不支持通过 CAN FD 帧唤醒,即如果总线上发送的是CAN FD格式的帧,休眠的收发器不会识别为唤醒帧。不过有一些策略:如果没有PN功能,那么CAN FD帧因为协议不匹配也会引发错误帧,这本身可以触发传统唤醒(错误计数到达阈值);如果开启了PN功能,收发器遇到CAN FD帧会将其视为格式错误帧,错误计数满后同样产生唤醒。总之,CAN FD 下的唤醒需要特殊对待,目前通常要求网络管理上确保不会用FD帧做唤醒信号。
综上,唤醒机制是CanTrcv模块中较为复杂但非常关键的部分。良好的唤醒策略可以有效降低车辆静态电流,保证需要的时候又能及时唤醒ECU。在量产项目中,这一部分往往需要大量测试和验证,我们在后面的章节还将从实践角度讨论唤醒相关的问题。
四、与 ComM/EcuM/CanIf/CanSM 的交互逻辑
CAN 收发器驱动并非孤立运行,它与AUTOSAR通信栈中的其它模块共同配合完成车辆网络管理任务。下面我们梳理 CanTrcv 与主要相关模块的交互关系和逻辑。
4.1 与 CanIf 的关系
**CanIf(CAN Interface)**模块位于 CAN Driver/CanTrcv 与上层(如 CanSM、PduR、ComM)之间,充当接口适配层。CanIf 对上提供统一API,对下调用具体的CAN硬件驱动和收发器驱动。它与 CanTrcv 的交互主要体现在以下方面:
模式控制:CanIf 提供 CanIf_SetTransceiverMode(Trcv, Mode) 接口给上层调用。当上层(如 CanSM 或 BswM)需要切换收发器模式时,调用 CanIf 的该接口。CanIf 内部会调用相应的 CanTrcv_SetOpMode 来完成实际切换。同理,CanIf_GetTransceiverMode 则调 CanTrcv_GetOpMode。
唤醒使能:CanIf 提供 CanIf_SetTransceiverWakeupMode(Trcv, WakeupMode),上层(通常EcuM)用它来启用/禁用唤醒通知。CanIf 内会转调用 CanTrcv_SetWakeupMode。
唤醒事件检查:当 EcuM 需要检查某CAN通道是否有唤醒时,调用 CanIf_CheckWakeup(ControllerOrTrcv). CanIf 实现上会找到对应的收发器并调用 CanTrcv_CheckWakeup。
被动唤醒标志检查:如果配置需要,上层可调用 CanIf_CheckTransceiverWakeFlag(Trcv), CanIf 里再调用 CanTrcv_CheckWakeFlag。
通知回调:CanTrcv 有若干回调通知会调用 CanIf 提供的函数。例如 CanTrcv 在每次模式切换完成后,调用 CanIf_TrcvModeIndication(Trcv, Mode) 通知 CanIf。再如 ClearWufFlag 成功后调用 CanIf_ClearTrcvWufFlagIndication 通知等。这些回调函数由 CanIf 实现,通常只是记录状态或者进一步通知其他模块(比如 BswM)决策。
错误处理:CanTrcv 内部如发生严重错误(通信失败等),可以通过 Det 或 Dem 报告错误。CanIf 本身对这些错误不直接处理,但如果收发器不工作,CanIf上层通信也会受影响。典型做法是在 Dem 配置中,CanTrcv的DemEvent(若有)会联动一些安全反应。
因此,CanIf 与 CanTrcv 关系类似控制与被控制:CanIf是指挥者,根据上层请求决定何时让收发器进入什么模式、何时启动唤醒监控;而CanTrcv则执行具体操作并反馈执行结果或异步事件给CanIf。两者通过明确的接口契约解耦,这使得上层不需要关心具体收发器类型,也为Simulink模型等提供模拟钩子。
4.2 与 CanSM 的关系
**CanSM(CAN State Manager)**模块管理CAN网络通道的整体状态,包括通讯状态(通信的开关)和网络模式。CanSM 不直接操作硬件,而是通过 CanIf 间接控制 CAN Controller 和 Transceiver。主要交互点:
进入/退出通讯:当 ComM 要求某CAN网络 Full Communication 时,CanSM 会通过 CanIf 将对应CAN控制器设置为 NORMAL(STARTED),同时如果需要也将收发器设置为 NORMAL 模式;反之要求 No Communication 时,将 CAN控制器设置为 STOPPED,收发器设置为 Standby/Sleep。这些调用都是由 CanSM 调用 CanIf 接口引发的。
网络唤醒:CanSM 会订阅网络唤醒事件。当收发器唤醒发生后,EcuM通知ComM,ComM再通知CanSM网络需要重启通信(ComM_RequestComMode(FULL_COMM)调CanSM)。CanSM 接到指示后,先让收发器回到 NORMAL 模式,再启动CAN控制器,从而恢复通信。在此过程中,CanSM 本身也可能触发一些等待时序,但总体来说依赖 CanTrcv 提供的唤醒指示。
部分网络控制:CanSM(结合CanNM)在支持PN的网络中,还负责在网络静默阶段根据NM状态决定是否启用PN功能。比如,在进入准备休眠时,如果当前网络管理状态需要PN,则通过 BswM 调用 CanTrcv_SetPNActivationState(PN_ENABLED) 等。AUTOSAR提供了 CanSM_CheckTransceiverPNAvailability() 等接口供确认PN状态(由CanIf->CanTrcv调用 ConfirmPnAvailability 时触发)。总之,CanSM 作为高层逻辑,利用 CanTrcv 来实现细节动作。
一句话,CanSM 确保**“当需要通信时收发器已打开,当需要休眠时收发器已关闭监听”**。它是制定网络睡眠/唤醒策略的模块,而具体执行由CanTrcv实现。
4.3 与 ComM 的关系
**ComM(通信管理器)**是更上层的模块,它管理应用需求与网络状态之间的转换。ComM 控制多个网络(包含CAN、LIN、FlexRay等),当应用请求某网络通信时就要求对应CanSM切换至Full Com,当应用都不需要通信则允许网络休眠。
ComM 与 CanTrcv 的间接关系体现在:
ComM 通过 CanSM 控制通讯开启/关闭,CanSM 再控制收发器模式,如上所述。
EcuM 检测到唤醒时,会调用 ComM_EcuM_WakeUpIndication 通知 ComM。ComM 收到某网络Channel被唤醒的通知后,会向上通知相应应用(Nm或者直接App),并将该网络对应的 ComM 通信模式设置为 RUN 状态。这样应用就知道 CAN 网络恢复了。
在有些架构中,ComM 还负责协调总线唤醒事件的允许性:例如在某些模式下ComM可能阻止网络唤醒(通过BswM设置唤醒屏蔽),那么 ComM 可以通知 EcuM 或 BswM 关闭收发器唤醒(即调用 CanTrcv_SetWakeupMode(DISABLE))。不过一般做法是通过配置让 EcuM 决定WakeupMode,ComM不直接控制收发器唤醒,但可透过通讯模式影响。
ComM 还有 WakeUp睡眠时间管理功能,但主要对收发器无直接接口,它更多管控的是网络管理报文发送和SNA(silent communication)。
总的来说,ComM 是触发条件:应用说“我要休眠”,ComM推进各CanSM去关收发器;应用说“我需要通信”,ComM通知CanSM去开收发器。如果没有 ComM_EcuM_WakeUpIndication 这一步,ComM甚至不知道谁把它唤醒的,但有了它 ComM 可以顺势执行一些策略比如通知应用层。
4.4 与 EcuM 的关系
**EcuM(ECU Manager)**负责整个ECU的电源模式和唤醒处理。它与 CanTrcv 的交互非常关键,因为 EcuM 决定何时进入休眠、从何唤醒。
睡眠准备:EcuM 在决定让整个ECU进入睡眠模式时,会按照顺序调用各模块的休眠准备接口。其中针对CAN通信,EcuM会通知 ComM准备下线各网络(ComM_PrepareSleep),这会导致ComM/CanSM关闭通信、设置收发器Standby等。一旦各通信都表示可以休眠,EcuM 会调用 CanIf_SetTrcvWakeupMode(Trcv, ENABLE) 打开收发器唤醒通知;然后调用 Icu_EnableWakeup 激活唤醒源捕获。完成这些后,EcuM通过调度表关闭系统时钟或者进入MCU低功耗。
检测唤醒:当MCU收到任一唤醒中断时,会跳转到 EcuM 的 Wakeup ISR。EcuM 在中断中调用 EcuM_CheckWakeup(source) 对各潜在源标记唤醒请求。对于CAN总线,EcuM_CheckWakeup 内部会调用 CanIf_CheckWakeup(channel),进而调用 CanTrcv_CheckWakeup 检查收发器标志。若有则 EcuM_SetWakeupEvent。这个过程在上面的时序图已有反映。需要指出,EcuM_CheckWakeup 可能被调用多次(每个唤醒源一次),它负责把事件分发给各驱动检查。
唤醒反应:EcuM_SetWakeupEvent 被调用后,EcuM 将该唤醒源置为“待验证”状态。EcuM 随即退出低功耗,让调度重新跑起来。接着 EcuM 会启动 Wakeup Validation 窗口(可能0~几百毫秒),在此期间如果有上层验证(如NM消息到达)就确认,否则超时则认为无效唤醒。
确认唤醒:如果唤醒源有效,EcuM 调用 ComM_EcuM_WakeUpIndication(或者通过 BswM间接通知 ComM,也取决于配置),通知通信栈继续唤醒流程。EcuM 也负责重新打开各时钟、调度启动各模块的正常模式运行。此时ECU完全唤醒。
无效唤醒处理:若验证失败,EcuM 会调用各模块接口重新进入睡眠准备。这包括通知 CanTrcv 清除这次错误唤醒标志(ClearWakeupFlag/CLEAR模式)以避免重复。然后再度进入MCU低功耗,收发器仍在监听。
上电初始化:EcuM 在开机初始化时,也会调用 CanTrcv_Init,并在Finish后检查是否有 EcuM_GetPendingWakeupEvents() 指示有收发器报告的上次唤醒(可能CanTrcv_Init调了EcuM_SetWakeupEvent)。如果有,EcuM会当作冷启动唤醒记录日志,但不会阻止正常启动流程。
EcuM 和 CanTrcv 的配合是保障休眠/唤醒可靠的核心。例如错一步可能导致唤醒丢失或误唤醒。因此 EcuM配置里明确列出了每个收发器通道的WakeupSource ID,并由 CanTrcv config引用,以确保 EcuM_SetWakeupEvent 用正确的ID。
4.5 与其他模块
Det(Default Error Tracer):属于开发错误检测模块。如果 CanTrcv_Config中 DevErrorDetect=True,驱动在检测到参数错误、非调度状态调用等开发期错误时,会调用 Det_ReportError 上报。DET不干预逻辑,只记录日志。
Dem(Diagnostic Event Manager):收发器驱动可能定义了一些诊断事件(例如收发器通信失败、唤醒故障等)。如果配置了 Dem event,驱动在运行时错误发生时调用 Dem_ReportErrorStatus。这可以在诊断内存中生成一条DTC供售后分析。
Port/Dio:CanTrcv需要通过 Port/Dio 来控制收发器的引脚(如 Standby 控制线、Enable线等)。这些通常在驱动初始化时配置,通过调用 Dio_WriteChannel 或 Port_SetPin等实现引脚操作。Icu 模块则负责监视收发器Wake引脚(ERR或RXD等)的电平变化以生成中断。
Spi:对于SBC类收发器,CanTrcv 与 SPI Driver 模块交互非常密切。比如在切换模式、配置PN过滤时,需要组装 SPI 帧,通过 Spi_SyncTransmit 发送给收发器。Spi驱动返回后,CanTrcv根据返回数据判断命令是否成功。如果Spi通信失败,也要报告运行时错误。值得注意,AUTOSAR 提供了同步和异步两种模式下DeInit的序列图,,确保Spi与CanTrcv协调。
概括而言,CanTrcv 是AUTOSAR网络管理链中的一环,下接硬件上联管理层。它接受来自管理层(CanSM/EcuM)的指令改变硬件状态,也向管理层反馈硬件检测到的事件。各模块之间分工明确又紧密协作,这也是AUTOSAR架构的魅力所在——通过标准接口实现模块解藕,但又确保系统行为整体一致。开发者在调试休眠唤醒问题时,往往需要跨模块追踪事件的传递,这时理解这些交互逻辑就非常重要了。
五、收发器硬件适配(TJA1040/1043/1145)
不同的 CAN 收发器芯片在引脚接口和功能上存在差异。AUTOSAR CanTrcv 模块通过配置和代码适配,可以支持多种收发器。在本章,我们以三款常见的 NXP 收发器为例,说明硬件差异和驱动适配要点。
5.1 NXP TJA1040
TJA1040 是经典的高速CAN收发器,不支持选择性唤醒。它只有一个主要的控制引脚:STB(Standby)。当 STB 引脚为高电平时,收发器进入待机模式;STB 为低电平时,进入正常工作模式。TJA1040 的 STB 引脚内部有上拉,如果MCU未驱动则默认待机。除此之外,它的TxD、RxD引脚连接MCU CAN控制器,另有SPLIT引脚可选用于稳定总线共模(很多应用中未使用直接NC)。
特性:TJA1040具有低功耗待机模式,在待机时接收器关闭,仅保持一个低功耗监听电路,电流约10 μA量级。当总线出现唤醒模式(WUP)时,TJA1040自动从待机切换到正常模式。注意:TJA1040 并无专门的INH或唤醒通知引脚,因此无法在MCU断电情况下自行唤醒ECU。它适合MCU一直有待机电源,只需要唤醒MCU运行即可的场景(即上述唤醒场景2或3)。如果ECU需要完全断电睡眠,用TJA1040则必须借助外部电路实现从总线到电源的唤醒,例如使用模拟开关或LIN收发器的WAKE引脚。
驱动适配:针对TJA1040,CanTrcv驱动实现较简单:
将 CanTrcv_SetOpMode 映射为对 STB 引脚的操作:NORMAL->拉低 STB,STANDBY/SLEEP->拉高 STB。由于TJA1040无区别Standby和Sleep(都由STB高表示),所以驱动可以将 Sleep 请求同样当作 Standby处理(或者可以不支持Sleep模式直接返回E_NOT_OK)。
不支持 PN:配置 CanTrcvHwPnSupport=FALSE,则PN相关API不生成。
Wakeup 机制:TJA1040的远程唤醒原理是总线活动使器件从待机转回正常并在RXD上输出数据。当MCU低功耗时,通常将 CAN 控制器配置成监听模式+滤掉所有报文只产生wake中断。但AUTOSAR标准Wakeup里,通常不用TJA1040做完全断电唤醒。因此,如果项目用TJA1040,一般ECU不做完全掉电睡眠,而是MCU进入STOP模式,CAN控制器关闭,只依赖收发器的模式切换中断不可靠,需要周期检测总线。实践中,可以配置 CanTrcvWakeupSupport=Polling,让 MCU 每隔几十毫秒唤醒检查总线,这不是最优方案,但TJA1040硬件限制如此。
典型应用:早期很多车身ECU使用TJA1040,因为便宜且无须复杂唤醒。不过现在逐渐被升级版如TJA1042(带 Vio 引脚)或TJA105x(容错CAN)取代。这些芯片驱动类似,不支持复杂唤醒。
5.2 NXP TJA1043
TJA1043 是NXP推出的一款支持远程唤醒的高速CAN收发器。与TJA1040相比,它增加了INH、EN、ERR_N等引脚,实现更丰富的电源管理功能,也支持“部分网络”的前身——仅标准唤醒模式但功耗更低。
引脚:
STB_N(Standby控制,低有效):与TJA1040类似,但逻辑相反(低=工作,区别命名用了_N)。
EN(使能,高有效):需要与 STB_N 配合使用,控制 Sleep/Standby 的进入。EN=1且STB_N=0时正常模式;EN=1且STB_N=1时 Standby模式;EN=0 时执行Go-to-sleep序列然后 Sleep模式。这样设计是为了提供一个软控位(EN)去触发Sleep。
INH(Inhibit输出):当芯片处于 Normal或Standby模式时,此引脚为高电平,可以用于驱动外部主电源。当芯片进入 Sleep模式或无电时,INH变为高阻/低电平,断开电源控制。
ERR_N(错误/唤醒标志输出,低有效):通常用来指示总线错误或唤醒事件。当收发器检测到远程唤醒时,在 TJA1043 中会将 ERR_N 拉低一段时间,此引脚可接MCU中断引脚,配置为下降沿中断,实现唤醒通知。此外 RXD 引脚在唤醒时也输出一个特定的低脉冲序列,可选用作中断。
还有 Vio 引脚用于逻辑电平,SPLIT/WAKE 引脚等这里不展开。
模式特性:TJA1043具备5种模式:Normal、Listen-Only(仅监听一种诊断模式)、Standby、Go-to-Sleep、Sleep。Go-to-Sleep是从Standby进入Sleep的过渡模式,执行后进入Sleep。收发器在 Sleep或Standby模式下均可由总线唤醒:收到 WUP 后,Wakeup Flag置位,芯片转入Standby模式,同时INH拉高保持电源,等待MCU响应。如果MCU从未唤醒,它将保持Standby以防电源反复开关。
驱动适配:对于 TJA1043:
模式控制:驱动需控制两个引脚。因此通常配置在 CanTrcvChannel 下有两个 DIO通道:一个对应 STB_N,一个对应 EN。CanTrcv_SetOpMode 实现时,要根据请求模式设置这两根线组合。例如:
请求 Normal:STB_N=0,EN=1
请求 Standby:STB_N=1,EN=1
请求 Sleep:先STB_N=1, EN=1 (Standby),然后EN=0触发Go-to-Sleep,再短暂延时后释放STB_N或持续?按datasheet要求。常Simplify: STB_N=1, EN=0即可让其睡眠。
另外TJA1043在上电复位后默认Standby,需要EN上一个正跳变才能真正Sleep,所以驱动需要小心顺序。
Wakeup处理:TJA1043提供ERR_N和RXD两种唤醒提示。常用ERR_N引脚。驱动配置应将 ERR_N 连接到 ICU 模块某通道,并在配置中将 CanTrcvIcuChannelRef 指向它。这样当 ERR_N 由高变低时(注意N极性),MCU中断捕获->Icu通知->EcuM_CheckWakeup->CanTrcv_CheckWakeup。CanTrcv_CheckWakeup 里可以通过读取TJA1043一个status寄存器确认是否Wakeup(不过通常ERR_N已经说明一切,驱动也可不再多读,直接EcuM_SetWakeupEvent)。
需要注意的是,ERR_N同时也用于报告总线错误(如TxD被卡显性),驱动需分辨事件类型。幸运的是在休眠场景下没有总线通信,不会出错,ERR_N低基本就是唤醒。同理,芯片POR导致ERR_N也会拉低一次。为保险,可在初始化时清除一次ERR_N标志或读取寄存器。
PN支持:严格来说,TJA1043不支持选择性唤醒帧过滤(ISO11898-6),只能对任意总线活动唤醒。所以 CanTrcvHwPnSupport=FALSE。因此对驱动来说,它不需要实现ClearWufFlag等PN接口。TJA1043相当于“部分网络 lite版”——支持低功耗和远程唤醒,但不能筛选帧。
功耗控制:在 Sleep模式下TJA1043的静态电流非常低(典型 < 15μA),INH关闭。Standby模式下稍高一些(典型 50μA),INH开。很多ECU选择Standby模式而非Sleep,以便MCU保持通电低功耗运行,因为完全断电会丢失RAM等。当然可以根据系统需要调整。CanTrcv驱动要允许两种模式的切换。
案例:假设我们用 TJA1043,开发时配置如下伪代码表示:
// 配置示例:使用两个DIO控制TJA1043模式
CanTrcvChannelConfig ch0 = {
.TrcvId = 0,
.HwPnSupport = FALSE,
.WakeupByBusUsed = TRUE,
.TrcvWakeupSourceRef = ECUM_WKSOURCE_CAN0,
.TrcvIcuChannelRef = &IcuChannel_ERRN_CAN0,
.DioAccess = {
.StbPort = PortC_Pin5, // STB_N
.EnPort = PortC_Pin6 // EN
}
};
驱动实现片段:
// 针对TJA1043模式切换
Std_ReturnType CanTrcv_HwToNormal_TJA1043(void) {
Dio_WriteChannel(PortC_Pin5, STD_LOW); // STB_N = 0 (normal)
Dio_WriteChannel(PortC_Pin6, STD_HIGH); // EN = 1
return E_OK;
}
Std_ReturnType CanTrcv_HwToStandby_TJA1043(void) {
Dio_WriteChannel(PortC_Pin5, STD_HIGH); // STB_N = 1
Dio_WriteChannel(PortC_Pin6, STD_HIGH); // EN = 1 (standby)
return E_OK;
}
Std_ReturnType CanTrcv_HwToSleep_TJA1043(void) {
Dio_WriteChannel(PortC_Pin5, STD_HIGH); // 准备 standby
Dio_WriteChannel(PortC_Pin6, STD_LOW); // EN由1->0, 触发Go-to-sleep
// 等待片上Sleep确认, 可以延时等待ERR_N或直接等待固定时间
return E_OK;
}
以上只是示意,实际需要考虑时序,如EN的脉冲需要持续一段时间,不能立即拉高,否则Chip可能又回Standby状态。
5.3 NXP TJA1145
TJA1145 是NXP针对 Partial Networking 推出的高速CAN收发器,支持选择性唤醒(符合ISO11898-6)。它也经常作为 SBC(如UJA1168)的CAN部分出现。TJA1145在功能上更复杂,采用SPI接口进行模式控制和PN过滤配置。
引脚与接口:TJA1145 除TXD/RXD之外,主要通过 SPI 来配置模式和读取状态寄存器。它有INH引脚用于电源控制,NWAKE(本地唤醒)引脚,STB_N引脚等等,但PN相关多数通过内部逻辑处理。典型引脚:
CSB,SCK,SDI,SDO:SPI总线引脚,用于与MCU通信。
EN/STB:有的版本有EN引脚,也可能通过SPI命令Sleep。
INH:和TJA1043类似,控制外部电源。
WAKE:本地唤醒引脚(如连接门锁信号,可唤醒ECU)。
ERR_N/INT_N:中断引脚,用于报告事件,包括唤醒、错误、SBC看门狗等。
PN功能:TJA1145内部有寄存器用于存储PN过滤ID、过滤掩码、过滤帧字节等。使用时序如下:
配置阶段:上电初始化时,MCU通过 SPI 向 TJA1145 写入一系列寄存器,包括 CAN滤波ID、掩码、期望字节(选配)等,以及启用Selective Wake功能位。每次写入后芯片会清除一个 PNCOK(PN Config OK)标志,全部配置完毕再置位,这样芯片知道PN配置有效。CanTrcv_Init 实现需要完成这些步骤。
进入休眠:切换收发器模式为 Standby (或Sleep),并确保 PN功能启用。如果 ActivationState=PN_ENABLED,那么芯片会以Selective模式监听总线。
唤醒判定:当总线有帧出现时,芯片硬件对比ID和特征:匹配则产生唤醒(Wake flag=1,INT引脚中断),不匹配则忽略。如果一直有帧但都不匹配,芯片内部的PN Timeout Timer会累计时间,超过一定值则认为也要唤醒以防错过网络上线(此时会设置 Timeout Flag)。
MCU处理:芯片INT引脚拉低通知MCU,有可能是Wake,也可能别的事件。MCU通过 SPI 读状态寄存器,发现 Wake Flag=1,则进一步读出Wake Event信息,如识别出是CAN唤醒、是过滤匹配还是Timeout等。然后软件调用 EcuM_SetWakeupEvent,对应地可以把Wakeup Source区分为正常PN唤醒还是超时唤醒。
清除标志:MCU唤醒后需要通过 CanTrcv_ClearTrcvWufFlag SPI命令清掉 Wake Flag,以准备下一次休眠。TimeoutFlag和其他Flag也有相应清除命令。
驱动适配:TJA1145的适配主要体现在SPI通信:
在配置(ARXML)上,需要有 CanTrcvAccess 子配置指明此通道使用 SPI 类的SBC控制。一种常见配置方式:引用一个 SbcDriver 模块(Vector架构中存在Sbc驱动配置)。在 DaVinci 配置中,CanTrcvChannel 会有 SbcDeviceRef 指向一个SBC,并配置具体的 SPI Channel、CS 引脚、SBC种类等。
CanTrcv_SetOpMode:对于 TJA1145,不再通过DIO引脚而是发送 SPI 帧。例如:
NORMAL: 发送 “Normal Mode” 命令(通常SBC命令字写某寄存器)。
STANDBY: 发送 “Standby Mode” 命令。
SLEEP: 发送 “Sleep Mode” 命令。TJA1145的Sleep与Standby的差别在于是否保持Vio之类,通常Standby即可满足大多数情形。
CanTrcv_SetWakeupMode(ENABLE/DISABLE):可能对应使能或禁止Wake中断输出,或者配置寄存器某标志(TJA1145允许禁用唤醒请求存储)。实现时如果DISABLE,则驱动在检测到Wake Flag时不立刻上报,而是暂存,需要ENABLE后才上报——这可以在软件层实现,即维护一个软开关,或者利用芯片提供的Wake-up Request存储功能。TJA1145有寄存器可以屏蔽wake-up请求输出。
ConfirmPnAvailability:当驱动把 TJA1145置Normal且检测到其内部寄存器指示Selective wake active并无错误时,调用 CanIf_ConfirmPnAvailability 通知上层 CanNM。这通常在SetOpMode(NORMAL)执行成功后进行。
ClearTrcvWufFlag/ClearTrcvTimeoutFlag:通过 SPI 写相应命令位(TJA1145的Frame DLC Byte4位)实现。驱动调用后,还应等待芯片确认标志清零(可以立即读状态或下次CheckWakeFlag时验证)。
CheckWakeup:由于 MCU醒来后通常立即读取了状态寄存器并调用EcuM_SetWakeupEvent了,所以CheckWakeup在PN模式下更多用于Polling模式方案。如果采用中断则CheckWakeup可能只是配合EcuM框架形式上调用一下EcuM_SetWakeupEvent,因为标志已知。
其他如 GetBusWuReason:TJA1145提供特定寄存器指示唤醒来源(比如CAN或Local Wake),驱动可在CheckWakeup里区分并记录,GetBusWuReason返回相应枚举。
注意点:
TJA1145/TCAN1145 这类器件相对复杂,要确保上电后首先通过SPI解锁模式。一些SBC默认上电处于Standby锁定,需要写特定键值才允许进一步配置。驱动需要参考数据手册在Init时正确初始化。
SPI 通信容错:为防止一次SPI传输失败,AUTOSAR提供 CanTrcvSPICommRetries 参数允许重试次数配置。如果配置>0,驱动应在通信失败时尝试重发命令。
时间要求:在休眠过程中,TJA1145从Wake到INT触发有个延时(几十微秒),MCU醒来又要时间,所以Wakeup过程通常能成功。但若MCU响应太慢,也许会错过某些事件,需要评估。
5.4 硬件适配小结
通过以上例子,可以看到 AUTOSAR CanTrcv 模块通过灵活的配置和差异化的底层实现,可以适配从简单收发器到复杂SBC的各种硬件。对开发者而言,需要根据所选收发器芯片的数据手册和应用笔记来实现驱动函数。在配置上,充分利用 AUTOSAR 提供的容器:
使用 CanTrcvDioAccess 配置直接GPIO控制的芯片(如TJA1040/1043)。
使用 CanTrcvSbc(或Access=SPI)配置通过SPI控制的芯片(如TJA1145)。
针对PN,提供 PartialNetwork子配置以及 WakeupSourceRef,将硬件事件正确映射到 EcuM唤醒源。
硬件适配的核心是在抽象的接口下,把引脚时序、通信协议等细节封装进去,让上层不用操心。例如,不管是拉一个引脚还是发一串SPI命令,上层都只需调用 SetOpMode(NORMAL) 而得到相同的效果。这也是 AUTOSAR 驱动开发的魅力所在。当然,为保证代码质量,要认真处理不同硬件的corner case,例如某些收发器对模式切换顺序敏感,需要驱动中加入延时或多次尝试,这些都属于工程经验,会在下一章讨论。
六、配置模板(ECUC 配置)
AUTOSAR 将 CanTrcv 模块的配置抽象定义在 ECUC(ECU Configuration)模型中。通常我们使用配置工具(如 Vector DaVinci、EB Tresos、ARCCORE工具等)来生成配置参数。下面介绍 CanTrcv 相关配置项及一个示例。
6.1 配置结构概览
CanTrcv 的配置在 ECUC 架构中属于独立的模块配置,顶层容器名为 CanTrcv。其下通常包含:
CanTrcvGeneral:全局配置参数容器。包括:
CanTrcvDevErrorDetect:BOOL,是否启用开发错误检测(DET)。
CanTrcvVersionInfoApi:BOOL,是否生成版本信息API。
CanTrcvWakeUpSupport:ENUM,唤醒支持模式,全局选择 CANTRCV_WAKEUP_BY_POLLING 或 CANTRCV_WAKEUP_NOT_SUPPORTED。它决定是否生成 CanTrcv_MainFunction 等以及模块对唤醒的支持类别。
CanTrcvMainFunctionPeriod:FLOAT,主函数轮询周期(单位秒)。若 WakeupSupport=Polling 则需要配置一个 >0 值,如 0.01 表示10ms;否则可为0或不配置。
CanTrcvMainFunctionDiagnosticsPeriod:FLOAT,诊断主函数周期,通常不使用可留空。
可能还有一些预留参数如 TimerType/WaitTime等在4.x标准中很少用到(面向特定硬件的等待定时)。
CanTrcvConfigSet:配置集容器,一般包含具体的通道配置等。可能有参数:
CanTrcvSPICommRetries:UINT,SPI通信失败重试次数。如果使用SPI类硬件,可配置如1或2次。
CanTrcvChannel(复用容器,可多个实例):每个实例代表一个收发器通道的配置。重要子项:
CanTrcvChannelId:该通道的ID编号(0,1,2...)。通常与对应的 CanIf/CanController通道号保持一致关系。配置工具确保唯一。
CanTrcvChannelUsed:BOOL,此通道是否启用。有时可能配置了备选通道但未用,为FALSE时驱动不生成代码。
CanTrcvInitState:ENUM,上电初始化后该收发器应进入的模式。可能值: NORMAL、STANDBY。大多数情况设为 STANDBY,表示上电后总线静默。
CanTrcvHasPowerSupplyControl:BOOL,该收发器是否控制 ECU 电源。例如如果某通道INH引脚直接控制整车电源,则设TRUE。这影响EcuM对待此唤醒源的方式。在配置上,也用于文档说明哪个通道负责唤醒整个ECU电源。
CanTrcvHwPnSupport:BOOL,硬件是否支持选择性唤醒。工具根据芯片库可能自动填充。例如 TJA1145 通道会设TRUE,TJA1040设FALSE。这个参数会决定 PartialNetwork子容器是否可配置。
CanTrcvBaudRate(或MaxBaudRate):UINT,可选配置,指收发器支持的最高波特率(kbps)。像TJA1145支持CAN FD 5000kbps,就可以填5000。一些工具可能用它来检查CAN FD兼容性或留空。
CanTrcvWakeupByBusUsed:BOOL,该通道是否启用总线唤醒功能。如果False,表示此收发器不需要监测唤醒(例如某车门ECU永不断电,可不监听总线睡眠),驱动会忽略唤醒处理。这也关系全局WakeUpSupport不能是Polling,否则必须全局支持。
CanTrcvWakeupSourceRef:引用,指向 EcuM 配置中的唤醒源(WakeupSource)。当该收发器检测到远程唤醒时,驱动将用此引用对应的 EcuM 唤醒源ID 调用 EcuM_SetWakeupEvent。例如配置为 ECUM_WKSOURCE_CAN0。
CanTrcvPorWakeupSourceRef:引用,指向 EcuM 唤醒源,用于上报**PowerOn(上次上电由CAN引起)**事件。收发器若支持POR检测,例如TJA1145可检测上次有无CAN唤醒上电,则配置一个特殊唤醒源ID用于标识这种情况。
CanTrcvSyserrWakeupSourceRef:引用,用于上报系统错误唤醒事件。某些SBC有SYSERR标志,如因掉电恢复触发的唤醒等,可单独标识。一般很少用,没有可不配。
CanTrcvIcuChannelRef:引用,指向 ICU 模块某个通道。如果 WakeupByBusUsed=true,则需要关联一个ICU输入捕获通道以检测唤醒信号(如ERR_N)。配置时通常选定一个“ICU_Channel_CANx_Wakeup”。
CanTrcvAccess子容器:定义对收发器的硬件访问方法。里面可能细分:
CanTrcvDioAccess:如果通过DIO引脚控制模式,则在此容器下配置一个或多个 DIO 引用。例如一个 boolean值 CanTrcvDioLine 指向 STB 管脚对应的 Port/Dio channel;或者进一步细分 CanTrcvDioChannelAccess 列表,可配置多个引脚,每个有属性如功能类型(STB/EN/WAKE等)和通道引用。具体取决于AUTOSAR版本实现。有的实现简单用几个参数表示,如 CanTrcvPortPin1, CanTrcvPortPin2。
CanTrcvSbcAccess:如果是通过SBC(SPI)控制,可以在这配置一个对 SBC 驱动的引用。Vector工具里叫 SbcDeviceRef。也可能有 CanTrcvSpiSequenceRef 引用某个 Spi序列。
CanTrcvSpiDeviceRef/CanTrcvSpiChannel:有些配置项直接关联Spi。如果使用通用SPI驱动而非专门SBC模块,则需要提供Spi通道号、Chip Select等信息。
CanTrcvWakeFlagSupported 等:甚至能配置一些标志支持与否,使相应API生成。
CanTrcvPartialNetwork子容器:仅当 HwPnSupport=TRUE 时出现。其中包含:
CanTrcvPnWakeupFilterMask:32位掩码,用于过滤CAN ID。
CanTrcvPnWakeupFilterId:32位ID,用于匹配CAN ID(与掩码结合)。
可能还有 CanTrcvPnExpectedDl、CanTrcvPnDataPattern 等,用于匹配帧的数据长度和特定数据字节(ISO11898-6允许基于前8字节做过滤)。
CanTrcvPnTxFilter 列表:有的收发器支持多个ID过滤,配置工具可能允许配置多个过滤条目。
CanTrcvChannelEcucPartitionRef:如果使用多ECU Partition,此处可关联分区。一般单分区系统不用管。
CanTrcvPublishedInformation(可能存在):一些工具生成的参考信息,不需要手工配置。
以上配置挺多,手工填写容易出错,实际工作中都借助工具图形界面。下面通过一个假想的配置例子(XML片段)来串联:
<AUTOSAR>
...
<CanTrcv>
<CanTrcvConfigSet>
<CanTrcvGeneral>
<CanTrcvDevErrorDetect>true</CanTrcvDevErrorDetect>
<CanTrcvVersionInfoApi>true</CanTrcvVersionInfoApi>
<CanTrcvWakeUpSupport>CANTRCV_WAKEUP_BY_POLLING</CanTrcvWakeUpSupport>
<CanTrcvMainFunctionPeriod>0.01</CanTrcvMainFunctionPeriod><!-- 10ms -->
</CanTrcvGeneral>
<CanTrcvChannel>
<CanTrcvChannelId>0</CanTrcvChannelId>
<CanTrcvChannelUsed>true</CanTrcvChannelUsed>
<CanTrcvInitState>CANTRCV_TRCVMODE_STANDBY</CanTrcvInitState>
<CanTrcvHasPowerSupplyControl>false</CanTrcvHasPowerSupplyControl>
<CanTrcvHwPnSupport>false</CanTrcvHwPnSupport>
<CanTrcvWakeUpByBusUsed>true</CanTrcvWakeUpByBusUsed>
<CanTrcvWakeupSourceRef>ECUM_WKSOURCE_CAN_CHANNEL_0</CanTrcvWakeupSourceRef>
<!-- 本例无 POR/SYSERR 额外源 -->
<CanTrcvIcuChannelRef>/Icu/IcuConfigSet/IcuChannel_CAN0_Wakeup</CanTrcvIcuChannelRef>
<CanTrcvAccess>
<CanTrcvDioAccess>
<CanTrcvDioChannelAccess>
<CanTrcvDioPortRef>/Port/PortConfigSet/PortPin_PC5</CanTrcvDioPortRef>
<CanTrcvDioChannelPurpose>STB_CONTROL</CanTrcvDioChannelPurpose>
</CanTrcvDioChannelAccess>
<CanTrcvDioChannelAccess>
<CanTrcvDioPortRef>/Port/PortConfigSet/PortPin_PC6</CanTrcvDioPortRef>
<CanTrcvDioChannelPurpose>EN_CONTROL</CanTrcvDioChannelPurpose>
</CanTrcvDioChannelAccess>
</CanTrcvDioAccess>
</CanTrcvAccess>
</CanTrcvChannel>
<CanTrcvChannel>
<CanTrcvChannelId>1</CanTrcvChannelId>
<CanTrcvChannelUsed>true</CanTrcvChannelUsed>
<CanTrcvInitState>CANTRCV_TRCVMODE_NORMAL</CanTrcvInitState>
<CanTrcvHasPowerSupplyControl>true</CanTrcvHasPowerSupplyControl><!-- 此通道控制整车电源 -->
<CanTrcvHwPnSupport>true</CanTrcvHwPnSupport><!-- 例如TJA1145 -->
<CanTrcvWakeUpByBusUsed>true</CanTrcvWakeUpByBusUsed>
<CanTrcvWakeupSourceRef>ECUM_WKSOURCE_CAN_CHANNEL_1</CanTrcvWakeupSourceRef>
<CanTrcvPorWakeupSourceRef>ECUM_WKSOURCE_CAN1_POWER_ON</CanTrcvPorWakeupSourceRef>
<CanTrcvSyserrWakeupSourceRef>ECUM_WKSOURCE_CAN1_SYSERR</CanTrcvSyserrWakeupSourceRef>
<CanTrcvIcuChannelRef>/Icu/IcuConfigSet/IcuChannel_CAN1_Wakeup</CanTrcvIcuChannelRef>
<CanTrcvAccess>
<CanTrcvSbcAccess>
<CanTrcvSbcDeviceRef>/Sbc/SbcConfigSet/SbcDevice_CANTransceiver</CanTrcvSbcDeviceRef>
</CanTrcvSbcAccess>
</CanTrcvAccess>
<CanTrcvPartialNetwork>
<CanTrcvPnWakeupFilterMask>0x7FF</CanTrcvPnWakeupFilterMask>
<CanTrcvPnWakeupFilterID>0x100</CanTrcvPnWakeupFilterID><!-- 仅ID=0x100的帧可唤醒 -->
<CanTrcvPnExpectedDl>8</CanTrcvPnExpectedDl>
<CanTrcvPnDataPattern>1122334455667788</CanTrcvPnDataPattern><!-- 匹配8字节 -->
</CanTrcvPartialNetwork>
</CanTrcvChannel>
</CanTrcvConfigSet>
</CanTrcv>
</AUTOSAR>
上面XML只是示意可能的配置内容,实际AUTOSAR配置会更繁琐。但从中可以看出:通道0用了DIO控制两个引脚,没有PN;通道1用了SBC(SPI),支持PN,配置了唤醒帧ID=0x100且数据匹配特定模式,关联了电源控制。这种配置映射到代码,将指导生成的初始化结构和驱动行为。
值得一提的是,一般工具还要求配置 EcuM 模块里增加相应的 EcuMWakeupSource 定义,与上面引用的 ID 匹配。例如 EcuM要有 之类。这确保 EcuM_SetWakeupEvent 参数合法。
6.2 DaVinci 配置界面要点
以 Vector DaVinci Configurator 为例,CanTrcv 配置通常与 SBC 模块放在一起。在配置界面中会看到:
CanTrcv General:可以设置 DET 开/关,WakeupSupport下拉选Polling或NotSupported,MainFunction周期。
Channels 列表:每个Channel可以Enable/Disable,选择对应的 Transceiver Driver Type(DirectGPIO, Tja1145 via SBC, etc)。这个会决定Access子容器内容。
如果选 "Direct GPIO",则下面可以填 Standby Pin(选择一个Port Pin),可能还有 Enable Pin 等。
如果选 "Via SBC", 则会出现一个下拉选项让你关联一个已经在 SBC模块里配置的 device,比如 "FS65 on SPI2" 等,并让选择对应的通道。
Wakeup settings:可以勾选 "Wakeup by Bus"。若勾上,就要求填写 Icu Channel 和 EcuM Wakeup Source references。
PN:如果上面标记HwPnSupport,就会显示 PN配置子页面,可填写Filter Mask/ID/Data等。有的工具只让输入十六进制ID和Mask。
最后SBC配置:在SBC模块处,需要配置Spi通道号、帧格式等,以及哪些功能开启,看门狗timeout等。这些由SBC模块代码来完成init。CanTrcv与SBC通过API交互。例如 DaVinci 提供 Sbc_Init 初始化SBC,包括CAN transceiver部分的配置。
Vector工具在CAN GM(General Module)里也提供一些配置可视图表帮助,比如Wakeup Channel mapping。其他厂商工具类似。值得提醒的是,一定要确保配置一致性:
一个CAN控制器channel如 CAN0,如果用了外部收发器,则必须有对应CanTrcv Channel并启用WakeupByBusUsed,否则ComM的Wakeup不会生效。
EcuM、CanIf、CanSM、ComM各处关于channel的配置引用都需对应同一个物理channel概念,否则可能造成唤醒通知不到或模式切换冲突。
6.3 常见配置问题
漏配置唤醒源:忘记在 EcuM 中定义或链接 WakeupSource,导致 CanTrcv 报告 EcuM_SetWakeupEvent 时无效。症状是唤醒发生但 EcuM无反应。解决:检查 CanTrcvWakeupSourceRef 指向的 EcuM源是否存在且启用。
Icu通道冲突:Icu的某通道可能被错误配置,比如极性不对(需要下降沿却配置上升沿),或一个Icu通道被多个收发器引用。要保证一一对应,极性正确(ERR_N一般为低有效中断)。
Pin配置错误:DIO 引脚配置成输入而希望输出,或忘设初始电平导致一上电收发器进错误模式。比如TJA1040 STB需要上电拉低,否则一直待机。应在 Port配置中设置Pin为输出且Reset值为期望状态。
PN数据配置:Filter Mask/ID 要与网络消息对应。如果搞错位号(11-bit还是29-bitID),将导致永远匹配不到。Mask要正确,比如只想按ID匹配则Mask=0x7FF对于11位ID全部位有效。另外ExpectedDL要是实际NM帧长度,否则即使ID匹配但长度不同也不会唤醒。
SBC看门狗:有些SBC如 UJA1168 开启了看门狗,如果软件不定期喂狗,SBC会复位自己和收发器,可能造成莫名唤醒或错误。配置时可选择关闭WD或增加喂狗逻辑。CanTrcv本身不管WD,但SBC模块管。
CommRetries:当SPI线路信噪差时,可考虑配置CommRetries=1或2,让驱动自动重发,避免一次失败导致模式切换失败。不过滥用重试也可能掩盖硬件问题,应慎用。
MainFunctionPeriod:若选择 Polling唤醒,一定要配置合理的MainFunction周期。太大可能错过及时报告唤醒,太小则浪费CPU。一般10~100ms,看休眠期间电流敏感度决定。NotSupported模式则应不调用MainFunction,可设0或不调度。
通过严谨的配置,配合正确的驱动实现,我们可以让AUTOSAR CanTrcv模块稳定运行于实际工程中。配置完成后,生成的 CanTrcv_Cfg.h 等文件里会有配置结构,如 CanTrcv_ChannelConfigType,里面正是上述参数值。驱动代码会用这些值执行逻辑,例如判断 WakeupSupport 用Polling还是不支持分支,循环多少通道初始化相应引脚或Spi序列等等。
七、调试策略
集成CAN收发器驱动后,在调试阶段可能会遇到一些问题。本章提供若干调试CanTrcv相关问题的策略和技巧,帮助工程师定位故障根因。
7.1 唤醒不起作用
问题表现:ECU休眠后,总线发送唤醒帧,但ECU未能被唤醒。可能的原因和调试方法:
硬件信号路径:首先检查收发器的唤醒信号是否传到 MCU。用示波器监测收发器的唤醒输出引脚(如 ERR_N、INH、电源线)在发送唤醒帧时是否有变化。如果没有,则硬件层面就未检测到唤醒。可能是收发器未正确进入待机监听状态。
检查 Standby 引脚电平:是否收发器真的处于 Standby/Sleep?例如 TJA1043 的 STB_N 应为低才能Standby监听,如果误为高会持续Normal模式,收发器反而可能忽略WUP或已经是Normal无需唤醒。
检查 Icu 连接:示波器测 MCU 接收到的中断引脚是否翻转。如果收发器输出变了但MCU引脚没反应,可能引脚没正确配置为中断输入,或者极性设置反了。
软件调用链:如果硬件输出正常(如 ERR_N拉低),却没引起 EcuM 后续动作,查看软件调用流程:
断点或Tracing:在 Icu ISR 里加断点或LED,确认中断服务触发。若未触发,Icu_EnableWakeup 可能没被调用或被错误禁用了。确保 EcuM 在休眠前调用了 Icu_EnableWakeup 针对该通道。也要检查 NVIC配置和中断优先级。
检查 EcuM_CheckWakeup 调用:可在 CanIf_CheckWakeup 或 CanTrcv_CheckWakeup 中加日志,看看睡眠后有没有执行。如果Icu中断触发,应调用到 CheckWakeup。如没有,说明 EcuM配置可能遗漏将该 ICU通道映射为WakeupSource。检查 EcuM配置的 WakeupSource 的 IcuChannelRef 等。
看 EcuM_SetWakeupEvent:在 CanTrcv_CheckWakeup 里应该调用了 EcuM_SetWakeupEvent。在调试模式下,可跟踪EcuM内部的 wakeupFlags 变量是否设置。如果SetWakeupEvent未被调用,可能驱动里CheckWakeup有条件未满足(例如 WakeupMode被Disable状态)。检查在休眠前有没有错误地把 WakeupMode 设成 DISABLE 没再ENABLE回来。
验证策略:EcuM可能配置了Wakeup Validation。如果唤醒进来了但又很快ECU回睡眠,可能是验证失败。
检查 ComM/CanSM/NM:确认网络上在ECU醒来后有没有发送NM帧。如果上层一直静默,EcuM将在验证超时后回到睡眠,误以为假唤醒。
解决方法:测试时确保有至少2帧(如果无PN)来触发NM交流,或者临时关闭Wakeup Validation来独立验证收发器唤醒能力。
案例:某项目用 TJA1145,发现节点总是收不到唤醒。调试发现原来配置上把 WakeupByBusUsed 错设为 FALSE,导致驱动即使WUP也不处理。修正配置并生成代码后,唤醒正常。
7.2 无法进入休眠或电流偏大
问题:尝试让ECU休眠,但测量发现待机电流仍然偏高,似乎收发器没真正进入低功耗。可能原因:
模式未切换:检查 CanTrcv_SetOpMode 是否被调用。通过调试器看 CanTrcv_InternalState(如果有)是否变为 Standby/Sleep。也可监测收发器引脚,如 STB 在休眠时应拉对应电平。若未切换,看看 ComM/CanSM 是否执行了 RequestComMode(NO_COMM) 流程。可能 ComM 有锁阻止休眠(某模块还在要求通讯)。这时需检查 ComM 通信模式要求,确保应用层释放通讯请求。
收发器持续被唤醒:可能总线上有干扰帧不断唤醒收发器。例如若未启用PN,任何报文都会唤醒而MCU又迅速睡眠,形成唤醒抖动。这会体现在INH引脚频繁拉高拉低、ECU电流时高时低。解决方法:若无法避免总线报文,则必须启用PN或改变网络管理策略(如网络保持short stop模式)。
INH设计:有的ECU使用INH脚控制主电源,如果INH一直为高说明ECU未断电。例如 TJA1043 Standby模式INH高,所以MCU还通电。要完全断电需进入Sleep让INH低。若配置上把Sleep模式禁用了,那ECU就永远不断电。所以根据设计目标选择模式:如果期望ECU真正掉电,那驱动要能执行Sleep模式(TJA1043需要EN=0)。调试时可强制调用SetOpMode(SLEEP)试一下电流变化。
剩余模块没关:除了收发器,其他硬件也会耗电。如保持CAN控制器未进睡眠(CAN模块不Sleep,收发器虽然Standby但MCU还维持其时钟)。确保 CanIf_SetControllerMode(SLEEP) 被调用成功。Use Case: 某次发现电流高是因为CAN控制器一直在STOPPED而非 SLEEP模式,在某MCU上STOPPED并不关闭全部CAN时钟,导致电流增加。调整为 SLEEP后降低了电流。
MCU低功耗设置:确认MCU真的进入了深度低功耗模式,否则MCU自身耗电也可能掩盖问题。通过调试寄存器或使用低功耗测试模式来验证。
收发器特殊:个别收发器有额外低功耗配置,比如ATA6560之类需要特定处理。若遇到,应仔细阅读datasheet的低功耗章节。
7.3 CAN通信中断或异常
场景:收发器驱动集成后,发现CAN总线通信有异常:比如车辆偶尔报CAN故障、或一段时间后节点无法发送报文。可能与收发器驱动有关的因素:
误切换模式:检查是否在通信过程中不小心调用了 CanTrcv_SetOpMode。例如某BswM规则错误地在不该Sleep时切换了Standby。这会导致瞬间通信中断甚至BusOff。可以在驱动SetOpMode加日志输出每次调用和参数,看看调用序列。如果发现异常调用,应追溯是谁调用的(ComM? BswM?)然后修正逻辑。例如确保ComM只有在Ignition off才NoComm。
线性错误:有时收发器检测到错误将ERR_N拉低并不释放,例如总线短路。若ERR_N接到Icu可能产生伪唤醒。调试中可以读取收发器诊断标志看看是否报告错误。例如TJA1043 ERR_N低也用于表示TxD被卡故障。如果是这种硬件故障,应修理线路或更换器件,而不是驱动问题。
驱动逻辑Bug:如上所述,在 Standby进入Normal时驱动禁用了Icu,这应该发生在SetOpMode内部。如果驱动实现有误,如没有在进入Normal时禁用中断,则可能导致ERR_N的一个下降沿在进入Normal时被捕获当成Wakeup(其实只是错误状态),这也可能干扰系统流程。解决:对照SWS检查驱动实现每一步,尤其WakeupMode=Enable时应在Normal时DisableNotification是否做到了。
多收发器交互:多个CAN通道同时唤醒或休眠时,确保驱动处理正确的通道。调试时区分channel上下文。例如如果有2个Transceiver,用日志打印TrcvId和操作,以确认不会串线。曾有案例:因为配置或实现错误,导致CanTrcv调用Dio时使用了错误的通道index,让收发器A的动作作用在B引脚上。结果A休眠也关掉了B,使B通信中断。
7.4 部分网络调试
PN功能调通需要精心测试:
滤波验证:在实验室,用CANoe或其他工具发送匹配帧和不匹配帧,确保收发器仅对匹配帧唤醒。可以通过测INH或INT脚判断。如果不匹配帧仍唤醒,检查掩码ID设置是否正确。可以尝试不同ID组合确定有效性。
唤醒超时:测试当只有不匹配帧持续发送时,收发器是否会在超时时间后唤醒ECU。如果ECU被唤醒,应能通过 GetBusWuReason 得知 reason=TIMEOUT。这个超时时间在芯片datasheet通常有说明(比如100ms)。可以通过调节发送频率验证,如每50ms一帧则不会超时,每5ms一帧持续则超时唤醒。
误报:注意某些情况下,本地唤醒(NWAKE引脚)或电源波动也会引发WakeupFlag。调试时如果遇到收发器“无故”唤醒,需区分是CAN总线导致还是本地因素。可以临时断开CAN总线测试看是否还醒来,排除总线影响。再看NWAKE引脚有无干扰信号。实车中,有时配电或邻近电路会耦合脉冲到NWAKE,这是硬件问题需要添加滤波。
Cross-talk:在有多个收发器的ECU中,要确保每个WakeupSource独立。调试中如果发现一个通道唤醒导致整个ECU所有网络都认为唤醒,可能是 EcuM 配置的WakeupSource使用了通配的“ECUM_WKSOURCE_ALL_CAN”之类,而不是每通道独立。这样不利于判断来源。应使用独立唤醒源id。
实际电流:最终检验PN效果的最好指标是静态电流。在整车休眠测试时,启用PN的ECU应该比不启用时电流低(因为少了很多不必要的唤醒)。可以对比试验验证驱动PN是否真的在起作用。
7.5 工程经验与建议
充分利用日志:在开发板上跑代码时,可以在关键的 CanTrcv APIs 中打印调试信息,比如“CanTrcv_SetOpMode(CH1, STANDBY) called”以及函数返回值。尤其是在调试睡眠唤醒流程时,将 EcuM、ComM、CanSM、CanIf、CanTrcv 每步的调用顺序打印,有助于发现调用次序或遗漏问题。
DET检查:如果打开了开发错误检测(Det),观察串口/调试输出中是否有 CANTRCV 相关的错误上报。例如 CANTRCV_E_UNINIT、CANTRCV_E_PARAM.. 之类。一旦有报错,就按照错误码对应的条件去修正调用方式或配置。
逐步测试:在综合测试休眠前,先测试基本通信OK,再测试单次休眠唤醒,再测试多次循环、长时间停放。逐步增加复杂度。测试PN时,最好专门设置实验场景:其他节点正常通讯,但ECU设为PN模式然后测试其不被普通报文唤醒,只被特定报文唤醒。
参考示例:寻找芯片厂商或社区提供的参考驱动代码。比如 NXP的应用笔记通常有关于 TJA1145 在AUTOSAR中的使用建议。对比自家实现,看看有没有配置遗漏(如某寄存器位)。
与硬件工程师合作:收发器的调试往往牵涉硬件。例如确认PCB连线、终端电阻、总线状态。这需要软硬件协同分析。特别是唤醒电路,如果有外部管脚组合,硬件工程师可提供线路图说明,避免软件理解偏差。
调试的目标是使收发器驱动在各种场景都稳定:不漏报真正唤醒,不误报干扰,不阻碍正常通信,不在不该唤醒时唤醒,也不在不该休眠时保持活动。这需要反复测试和边界情况验证。一旦调试通过,可以显著提高ECU的休眠可靠性和车辆的电源管理水平。
八、常见问题及量产工程实践
在实际量产项目中,CAN收发器驱动的应用会遇到一些共性的问题和挑战。本章总结几个常见问题并给出实践经验。
8.1 部分网络与网络管理的协调
问题:有些项目在引入PN收发器后,发现网络管理策略需要调整。例如:传统非PN收发器上,网络休眠策略往往允许接受任意报文唤醒,然后节点判断是否NM报文,不是则再休眠。这导致需要两帧NM才能真正唤醒网络(第一帧唤醒收发器和ECU,第二帧唤醒后ECU判断是NM)。而使用PN收发器,可以要求只有NM帧才能唤醒,这样单帧NM即可唤醒ECU。但是网络上其他节点也许并未使用PN,它们可能仍旧需要两帧NM。因此,整车网络策略需统一:比如决定所有ECU都启用PN,否则一个NM帧只唤醒一部分ECU反而不一致。量产时建议:
全网PN:如果成本许可,整车CAN网络所有节点都采用PN收发器并配置NM帧唤醒,实现最佳功耗。需要确保网络管理算法针对单帧NM唤醒做调整,如NM超时设置可能要缩短以适应单帧唤醒。
混合PN:若只有部分ECU用PN,必须考虑兼容性。可采用折衷方案:PN节点配置唤醒帧为NM,非PN节点依然需要两帧NM。这样第一帧来时PN节点醒,第二帧时其他也醒,最终都醒。但这个过程中PN节点会比其它节点提早若干ms启动,有轻微不同时序,但通常无碍。如果时间差太大,可在PN节点WakeupIndication后人为插入一点延迟等。
禁用PN:有时开发进度紧或者对PN可靠性存疑,也可以统一禁用PN功能,让PN收发器当普通收发器用(配置PNSupport=FALSE)。这样牺牲了功耗优势但简化问题。不过建议充分测试PN再决定,毕竟节能越来越被看重。
8.2 唤醒可靠性和防误唤醒
问题:在复杂环境下,收发器可能产生误唤醒(False Wakeup)。如静态电磁干扰或者毗邻线束串扰,让收发器错误地判断有WUP。这在车身ECU等长期带电的部件上会导致电瓶电压缓慢下降。对策:
硬件滤波:许多收发器内部已有滤波,但仍可在总线收发器上增加共模扼流圈、RC滤波器降低干扰。特别关注WAKE本地唤醒引脚,需上拉和滤波,防止抖动。
软件二次验证:AUTOSAR已经有Wakeup Validation机制。对重要ECU,可以设定稍严格的验证,如要求两次周期NM或上位机指令确认才保持唤醒,否则自动睡回。这样即使误唤醒,也很快又休眠,避免长时间耗电。代价是有时真的边缘情况下可能错过真实唤醒,但总体利大于弊。
调参数:一些收发器可调WUP滤波时间窗(通过外接电容等)。比如设置稍长的滤波时间,让短暂尖脉冲不被当有效WUP。要根据实际测试干扰频谱来调整,不可过长以免真的WUP也被忽略。
监控抖动:在标定阶段,用电流探头监视ECU电流,看看是否存在频繁唤醒-睡眠抖动。如果有,记录其发生条件(例如附近某模块动作时)。再针对性排查干扰源并改善。
日志留存:可以考虑在CanTrcv驱动中,对于每次唤醒事件打印唤醒原因以及收发器状态。例如记录“WU by CAN at 12:00:00, reason=timeout or id match etc”。在长时间测试后分析日志,判断是否有异常频繁的超时唤醒(可能是误唤醒)。
8.3 休眠前清理工作
工程中一个常见教训是:进入休眠前的准备不充分。比如忘记清某标志或关闭某外设,造成睡眠不稳。针对CanTrcv,特别要注意:
Clear WUF Flag:如前所述,在每次睡眠前务必调用 CanTrcv_ClearTrcvWufFlag 清除遗留唤醒标志。有的项目忽略这步,结果上次唤醒的Flag一直置着,下次睡眠刚开始MCU就又被这个旧Flag唤醒,相当于无法进入休眠。这一步可以在 EcuM进入PrepShutdown阶段,通过BswM调用CanIf_ClearTrcvWufFlag统一触发。
禁用不必要中断:除了CAN收发器的Icu,其他不需要的Wakeup源也要Disable,否则别的噪声也会干扰。确保EcuM按配置调用了所有 Icu_DisableWakeup 对未用的源。
确认Standby模式:睡眠前检查收发器真的被置Standby/Sleep。可以在断电前通过诊断服务读取CanTrcv_GetOpMode确认。如果发现没切过去,查ComM状态机。
上电源时序:部分SBC需要在休眠时关闭Main电源但保持Vbackup,这要硬件确保。软件上只需正确进入Sleep模式让INH释放。大项目通常有电源时序要求,软件按此执行例如调用EcuM_AL_SwitchOff()之类(这个函数通常由OEM提供,实现为切断电源GPIO)。CanTrcv要配合,在SwitchOff前切收发器Sleep。
多通道顺序:如果ECU有多个CAN通道,可能允许不同时间唤醒。通常所有通道WakeupSource OR在一起控制ECU电源。因此休眠前要所有收发器都清Flag。如果有一个没清,它依然可以拉高INH导致其他通道以为有唤醒。实践中养成每个CAN通道ClearWufFlag再Sleep的习惯即可避免此隐患。
8.4 量产中的诊断与故障处理
在量产后,通过诊断(UDS)或售后分析,也可能发现与CanTrcv相关的问题:
无法唤醒的故障:如果某次OTA或维修后发现ECU不唤醒,怀疑收发器坏了,可以做如下诊断:尝试发送诊断唤醒帧多次不成->读取收发器错误寄存器(若实现了GetTrcvSystemData)看有无Flag->最后可能换硬件。建议在Dem中添加“收发器唤醒失败”事件,例如若一段时间内收到总线唤醒但MCU没醒,则存储DTC。这需要车上另一个模块监视,有难度,一般不做。但可以在收发器本地实现counter,万一SetWakeupEvent多次没人理,可以在下次醒来上报。这个思路仅在安全关键需要。
误唤醒统计:车厂关心睡眠质量,可以统计ECU被唤醒次数(夜晚8小时内比如不应醒超过N次)。可在EcuM或CanTrcv层增加计数器,每次WakeupEvent就+1,并通过UDS可读。这样售后检查电瓶馈电问题时,能看出某ECU是不是频繁被CAN唤醒从而怀疑网络上有噪声或错误节点。
收发器故障诊断:某些高端SBC带诊断寄存器,可以检测LIN短路、CAN短路、TXD驱动故障等。如果有,可以将这些接口打通至Dem事件。例如TJA1145的INErr标志之类,可映射到一个DTC“收发器通信故障”。这样当收发器自我检测异常时,通过Dem报告,售后读DTC可以指导更换收发器或检查线路。表明DeInit序列图甚至考虑了Spi错误情况,由此可见有诊断的必要。
软件更新注意:如果ECU通过OTA更新基础软件,尤其涉及CanTrcv配置变更,一定要验证休眠唤醒在新软件下依然可靠。曾有案例:新版本错将WakeupSupport设为NotSupported,结果车辆无法被网络唤醒(除点火外都不醒)。这种重大问题需要在台架仿真验证后才能放车,所以每次变更基础配置,都应该回归测试休眠场景。
8.5 其他实践建议
对照标准:Autosar规范提供了很多要求(SWS_CanTrcv_xx),实现和配置时最好逐条核对。虽然厂商提供的MCAL可能已经满足,但如果自己实现CDD驱动,要确保关键行为一致。例如 R4.3标准规定 "在Standby模式应调用 Icu_EnableNotification",这点若遗漏就不符合标准,可能导致问题。
定期复查静态电流:即使进入量产,也要在每个软件版本对整车休眠电流进行回归测试,因为一点逻辑修改可能影响休眠路径。特别地,CAN收发器是经常翻动的模块,每次OTA都需注意它有没有引入隐患。
文档记录:将本ECU使用的CAN收发器类型、其低功耗行为、驱动设置等在开发文档中记录清楚,以便后续维护人员了解。例如注明“TJA1043 Standby模式MCU并未掉电,仅MCU停止通信;Sleep模式才会断电”等。这种信息对系统工程师也很重要,他们据此设计唤醒策略。
冗余设计:对于安全关键ECU,可以考虑双唤醒路径:除了CAN唤醒,还可以有LIN或IGN线作为备用。例如万一CAN收发器故障,还能通过点火信号唤醒ECU进入limp home模式。软件上实现就是EcuM配置多个WakeupSource,只要有一个来就醒。这样虽增加成本,但保险。这个在ADAS、底盘域ECU中会考虑,但车身小ECU通常不需要。
芯片选型:最后从实践看,合理选择收发器芯片也很关键:如果车辆对静态电流极敏感,尽量选带PN的;如果要降低成本,车身网络或次要网络也可选便宜的非PN收发器,但要包容高一点电流。选型一旦定下,软件就要围绕它的特性设计。软件无法改变硬件硬性,比如TJA1040唤醒能力有限,那就别期待它做断电唤醒。
通过以上各种经验的积累和遵循AUTOSAR规范,工程师能够更游刃有余地应对CAN收发器驱动在项目中的挑战。从基础概念、接口细节,到状态机原理、跨模块交互,再到硬件适配、配置调优以及调试和实践,我们已经系统地剖析了 AUTOSAR CanTrcv 模块。希望读者在实际工作中,能充分运用这些知识,实现可靠高效的车辆网络休眠唤醒功能,为降低整车能耗和提升网络稳定性做出贡献。