CAN 收发器驱动经常被误认为只是CanSM下发NORMAL、STANDBY、SLEEP的薄封装。对 TJA1145 这类带 SPI 寄存器访问、局部网络(Partial Networking)和唤醒标志的器件来说,真正容易出问题的地方不在 API 名称,而在模式切换是否异步完成、唤醒事件由谁确认、SPI 请求是否还在 pending、以及 PN 配置什么时候才真正写入硬件。CanTrcv_30_Tja1145位于 AUTOSAR Classic 平台的基础软件(BSW)中,对上提供 CAN Transceiver Driver 接口,对下通过 SPI 访问收发器寄存器,并可借助 ICU 将 Rx/ERR 引脚上的电平变化转换为 ECU 唤醒路径。它支持 AUTOSAR 4.0.3,配置变体包括 Pre-compile、Post- build selectable 和 Post-build loadable。模块标识使用CANTRCV_30_TJA1145_VENDOR_ID、CANTRCV_30_TJA1145_MODULE_ID和CANTRCV_30_TJA1145_INSTANCE_ID,其中 instance ID 由配置工具中的 pre-compile 参数指定。这篇文章按工程集成路径拆解这个驱动:先说明硬件和功能边界,再看初始化、模式切换、唤醒检测、SPI/ICU 依赖,最后收束到 API、配置、DET 错误、限制和 AUTOSAR 偏差。
模块边界和硬件前提
虽然模块名带有Tja1145,这个驱动覆盖的硬件不只 NXP TJA1145,还包括 NXP UJA1168 和 Atmel ATA6570。硬件前提不能忽略,因为驱动只负责 CAN transceiver 功能,不会替应用处理 SBC 或 watchdog 的预置状态。
| 项目 | 约束 |
| 支持硬件 | NXP TJA1145、NXP UJA1168、Atmel ATA6570 |
| 控制路径 | 通过 SPI 控制 CAN 收发器 |
| 不支持路径 | 不支持通过 DIO 控制 CAN 收发器 |
| 支持功能 | 初始化、SPI 控制、唤醒检测、局部网络唤醒、模式获取和设置、自诊断 |
| MICROSAR 扩展 | Identity Manager with Post-build selectable、Post-build loadable |
UJA1168 出厂时FNMCbit 可能为 1,此时不能使用该驱动,使用前应确保该 bit 为 0。UJA1168 的 SPI 通信只在 SBC 处于NORMAL或STANDBY模式时可用,应用必须保证只在这两个模式下调用驱动 API。RESET 到 STANDBY 的转换还存在访问 SPI 前必须满足的时间约束,这个约束也由应用侧保证。ATA6570 的WDC符号控制 Window Watchdog,位于WDCR1寄存器 bit 7:5。驱动假定 watchdog 处于 disabled 状态,不会配置 watchdog;使用前需要确认WDC为001,对应默认的 Off mode。从相邻模块看,CanTrcv_30_Tja1145不是独立运行的 底层驱动 。它至少和CanSM、CanIf、EcuM、SPI、ICU、DET以及可选的 Time Service 发生关系。

初始化和模式状态
上电或复位后,初始化顺序分成两步。CanTrcv_30_Tja1145_InitMemory()先初始化驱动内存和必要值,必须在其他收发器驱动功能之前调用。随后CanTrcv_30_Tja1145_Init(ConfigPtr)初始化配置工具选中的所有 active channel,并把每个 CAN 收发器通道切到CANTRCV_TRCVMODE_NORMAL。如果初始化前已经有 wakeup event pending,驱动会保存该事件,并通过EcuM_SetWakeupEvent()通知 EcuM。局部网络相关数据也有一个容易踩到的边界:PN 的ID、MASK、DLC、DATA只有在初始化期间检测到 POR(Power-on-reset)或SYSERRflag 时才写入底层收发器硬件。也就是说,修改过的 PN 配置并不一定在普通重初始化后立即进入硬件,通常要等 CAN 收发器发生 power-on-cycle,或者初始化时进入相应错误恢复路径。收发器模式由CanTrcv_30_Tja1145_SetOpMode()切换,支持的主路径如下。
| 当前模式 | 目标模式 | 支持情况 | 说明 |
| NORMAL | STANDBY | 支持 | 常规降级到待机 |
| STANDBY | SLEEP | 支持 | 进入低功耗路径 |
| STANDBY | NORMAL | 支持 | 回到 active/NORMAL |
| SLEEP | NORMAL | 支持 | 唤醒后回到 active/NORMAL |
| NORMAL | SLEEP | 不支持 | 需要先进入STANDBY |
| SLEEP | STANDBY | 不支持 | 不由该服务直接完成 |

当某个通道的所有唤醒源都被禁用时,硬件不会真正进入 sleep。此时如果请求STANDBY -> SLEEP,驱动只把软件模式改为 sleep,底层收发器硬件仍停留在 standby。这种 sleep emulation 对上层状态机是可见的:上层看到的是软件 sleep,但硬件功耗和唤醒源语义不能按真实 sleep 推断。CanTrcv_30_Tja1145_GetOpMode()用来读取指定收发器当前模式。若此前已经请求过模式切换,直到模式切换完成并触发CanIf_30_Tja1145_TrcvModeIndication()之前,读取到的模式可能还不是稳定结果。SetOpMode()返回E_OK时,表示收发器状态接受了切换请求;通知函数可能在中断上下文、任务上下文,或者SetOpMode()调用上下文中发生,而且通知给CanIf的模式不保证一定等于请求模式。
active mode 启动时间
TJA1145 切到 active mode,也就是软件侧NORMAL,最大需要 220 us。默认情况下,驱动在设置并验证 Mode control 和 CAN control 寄存器后,就立即向CanSM报告 active mode 转换成功。随后CanSM启动 CAN controller,而 CAN controller 在检测到 11 个连续 recessive bit 后开始参与总线通信。这个时间关系在高速 CAN 网络上尤其明显:
| 波特率 | 11 个 recessive bit 对应时间 |
| 1000 kbit/s | 11 us |
| 500 kbit/s | 22 us |
| 250 kbit/s | 44 us |
如果 TJA1145 的 Rx pin 在 active mode 完成前保持 recessive,CAN controller 可能把这段电平误认为总线上的 11 个 recessive bit。等收发器真正反映 CAN bus 电平后,controller 可能把任意 dominant level 当作帧起始,从而在帧中间参与接收并产生 error frame。CAN 网络本身应能容忍 error frame,但如果项目要规避这种行为,需要使用 AUTOSAR Time Service,并把CanTrcvTimerType配成Timer_1us16bit。如果没有现成 Time Service,需要提供Tm.h、Tm.c并实现Tm_BusyWait1us16bit()。
唤醒检测和局部网络
如果配置工具中启用了 bus wakeup detection ,上层在唤醒场景下调用CanTrcv_30_Tja1145_CheckWakeup(CanTrcvIndex)。当收发器处于 sleep 或 standby,且检测到 bus wakeup 事件时,同步 SPI 模式下该函数可以返回E_OK;否则返回E_NOT_OK。在异步 SPI 模式下,E_OK只表示“检查唤醒的请求已被接受”,真正的唤醒有效性不能从返回值判断。局部网络选择性唤醒还有一个配置组合条件:同一 channel 上必须同时启用CanTrcvChannel\CanTrcvWakeupByBusUsed和CanTrcvChannel\CanTrcvPartialNetwork\CanTrcvPnEnabled。只开其中一个,不能得到选择性唤醒的完整语义。CanTrcv_30_Tja1145_GetBusWuReason()返回最近一次检测到的唤醒原因。如果期间发生多次唤醒,只报告最后一次。可返回的 wakeup reason 包括:
| 唤醒原因 | 含义 |
| CANTRCV_WU_INTERNALLY | 通过CanTrcv_30_Tja1145_SetOpMode()设置 NORMAL 导致内部唤醒 |
| CANTRCV_WU_ERROR | 未检测到唤醒,或未保存原因;函数返回E_NOT_OK |
| CANTRCV_WU_NOT_SUPPORTED | 收发器不支持唤醒检测;函数返回E_NOT_OK |
| CANTRCV_WU_BY_BUS | 外部 bus wakeup |
| CANTRCV_WU_RESET | reset 后检测到唤醒 |
| CANTRCV_WU_POWER_ON | power-on wakeup |
| CANTRCV_WU_BY_SYSERR | 内部硬件错误导致收发器唤醒 |
| CANTRCV_WU_BY_PIN | WAKE pin 边沿导致唤醒 |
CanTrcv_30_Tja1145_SetWakeupMode()控制 wakeup event 是否向上层报告:
| 模式 | 行为 |
| CANTRCV_WUMODE_ENABLE | 向上层报告 wakeup event |
| CANTRCV_WUMODE_DISABLE | 不向上层报告 wakeup event |
| CANTRCV_WUMODE_CLEAR | 清除 pending wakeup event |
如果配置中没有启用 wakeup handling,该函数始终返回E_NOT_OK。如果 wakeup reporting 处于DISABLE到ENABLE之间时检测到了唤醒,重新 enable 并不会主动上报这次事件;应在重新 enable 后调用CanTrcv_30_Tja1145_GetBusWuReason()检查是否已有唤醒原因。唤醒检查路径可以按下面理解。

CanTrcv_30_Tja1145_CheckWakeFlag()用于请求驱动检查底层收发器 wake flag。检测到的唤醒通过EcuM_SetWakeupEvent()报告,具体原因再通过GetBusWuReason()查询。请求完成后,驱动调用CanIf_30_Tja1145_CheckTrcvWakeFlagIndication();这个通知可能发生在中断上下文、任务上下文或CheckWakeFlag()调用上下文中。CanTrcv_30_Tja1145_ClearTrcvWufFlag()用来清除 wakeup flag,但受硬件架构影响,它会清除所有 wakeup flags,而不是只清除某一个来源。清除请求完成后,驱动调用CanIf_30_Tja1145_ClearTrcvWufFlagIndication()。PN activation 通过CanTrcv_30_Tja1145_SetPNActivationState()动态切换:
| 参数 | 硬件唤醒行为 |
| PN_ENABLED | 配置为只对匹配帧唤醒,即 WUF(Wakeup Frame) |
| PN_DISABLED | 配置为对任意 bus activity 唤醒,即 WUP(Wakeup Pattern) |
该 API 的前提是生成配置中已经为相关 channel 启用了 selective wakeup。PN_DISABLED的状态变化要到下一次 mode change 后才生效。对于 TJA1145,PN_ENABLE对硬件没有立即效果;重新启用 selective wakeup 需要重新初始化。驱动也明确建议该 API 只在CanTrcv_30_Tja1145_Init()之后直接使用,并且该 API 不能被其他 CanTrcv API 打断。
ICU 唤醒脚集成
当 CAN controller 不支持“wakeup by CAN bus”,但 ECU 又需要因为 CAN bus 通信被唤醒并启动自身通信时,可以借助 MCU 的 I/O port 和 ICU。该 I/O port 可以并联到 CAN Rx port,也可以直接接到收发器 ERR port,取决于具体收发器。驱动使用 ICU 的两个服务:
| ICU 服务 | 使用时机 |
| Icu_EnableNotification() | 切换到STANDBY期间使能 ICU notification |
| Icu_DisableNotification() | 上报 wakeup event 后关闭 ICU notification |
每个需要通过 CAN bus 唤醒的 CAN channel 都要配置对应 ICU channel,并绑定 signal notification function 和 transceiver wakeup source。ICU channel 的测量模式应配置为边沿检测。由于 wakeup event 由 Rx pin 或 ERR pin 从 recessive 到 dominant 的电平变化提供,IcuDefaultStartEdge建议配置为ICU_FALLING_EDGE。如果 transceiver 不只是唤醒 CAN channel,还要唤醒整个 ECU,则该 ICU channel 需要开启Wakeup Capability。signal notification function 由用户实现。使用 wakeup validation 时,典型实现是通知 EcuM 检查对应唤醒源:
void Icu_TrcvWakeUpNotification_0(void)
{
EcuM_CheckWakeup(ECUM_WKSOURCE_CAN0);
}如果对应 wakeup source 不使用 wakeup validation,可以直接调用EcuM_SetWakeupEvent()。
SPI 访问、排他区和周期任务
底层硬件访问通过 SPI 完成。驱动使用Spi_SetupEB()准备外部 buffer,再通过Spi_SyncTransmit()或Spi_AsyncTransmit()发送 sequence,读取或写入 CAN transceiver 寄存器。每个收发器硬件都需要配置 device、channel、job 和 sequence。
| SPI 对象 | 关键配置 |
| Device | chip select idle high,data edge 为 falling edge 有效,clock idle low |
| Channel | 每个硬件创建 4 个,external buffer,maximum length 4,单字节宽度 8 bit,默认发送数据0xFF,MSB first |
| Job | 每个硬件创建 4 个,priority 为最高0,job end call 为NULL_PTR,绑定对应 channel 和 device |
| Sequence N | 包含JOB_RW_REG_0;同步 SPI 时 end call 为NULL_PTR,异步 SPI 时使用CanTrcv_30_Tja1145_SpiIndicationN_ |
| Sequence M | 包含JOB_RW_REG_0..2;异步 SPI 时使用CanTrcv_30_Tja1145_SpiIndicationM_ |
| Sequence L | 包含JOB_RW_REG_0..3;异步 SPI 时使用CanTrcv_30_Tja1145_SpiIndicationL_ |
如果使用异步 SPI,SPI driver 必须在 interrupts locked 时也提供轮询事件的方法,例如Spi_MainFunction_Driving()。否则CanTrcv_Init或同步访问模拟路径可能无法推进 SPI sequence 状态。驱动使用CANTRCV_EXCLUSIVE_AREA_0保护通过 SPI interface 对收发器硬件的原子访问和内部状态更新。该排他区持续时间被定义为 LONG,因为它覆盖 SPI 调用和状态更新。涉及的服务包括Init()、SetOpMode()、GetOpMode()、CheckWakeup()、MainFunction()、诊断数据读取、WUF flag 清除、timeout/silence flag 读写、wake flag 检查以及 SPI indication 等。API 说明中反复出现的“not reentrant”不是形式要求,而是和这个共享 SPI 访问模型直接相关。异步 mode change 使用时,CanTrcv_30_Tja1145_MainFunction()必须尽可能快地周期调用。一次 mode change 可能需要多个周期才能完成。如果驱动以同步方式使用,则通常不需要调用MainFunction(),除非生成配置中把 Wakeup Support 配成 Polling。
API 矩阵
这些 API 大多可在 task 或 interrupt level 调用,但都不是 reentrant。初始化类和 PN activation 类 API 更严格,必须在 task level 调用。
CanTrcv_30_Tja1145_InitMemory(void)
主要参数:无返回值:无调用上下文和关键限制:task level,not reentrant;必须先于其他驱动功能调用
CanTrcv_30_Tja1145_Init(ConfigPtr)
主要参数:ConfigPtr指向配置结构;多配置时可选择对应CanTrcv_30_Tja1145_Config__Ptr返回值:无调用上下文和关键限制:task level,not reentrant;调用前必须完成InitMemory(),且 SPI driver 已初始化
CanTrcv_30_Tja1145_SetOpMode(CanTrcvIndex, OpMode)
主要参数:通道索引和目标CanTrcv_TrcvModeType返回值:E_OK表示切换请求被接受;E_NOT_OK表示状态不接受或参数越界,前一状态不变调用上下文和关键限制:task 或 interrupt level,not reentrant;并非所有模式转换都允许;进入 NORMAL 且 selective wakeup enabled 时会读取错误标志并可能调用CanIf_30_Tja1145_ConfirmPnAvailability()
CanTrcv_30_Tja1145_GetOpMode(CanTrcvIndex, OpMode*)
主要参数:通道索引和保存当前模式的指针返回值:E_OK表示模式已检测;E_NOT_OK表示未检测到模式调用上下文和关键限制:task 或 interrupt level,not reentrant;模式切换完成前读取值可能无效
CanTrcv_30_Tja1145_GetBusWuReason(CanTrcvIndex, Reason*)
主要参数:通道索引和保存唤醒原因的指针返回值:E_OK表示检测到 wakeup reason;E_NOT_OK表示未检测到或不支持调用上下文和关键限制:task 或 interrupt level,not reentrant;只报告最后一次唤醒原因
CanTrcv_30_Tja1145_SetWakeupMode(CanTrcvIndex, TrcvWakeupMode)
主要参数:通道索引和ENABLE、DISABLE、CLEAR返回值:E_OK表示 wakeup state 已切换;E_NOT_OK表示失败或参数越界调用上下文和关键限制:task 或 interrupt level,not reentrant;未启用 wakeup handling 时总是E_NOT_OK
CanTrcv_30_Tja1145_GetVersionInfo(VersionInfo)
主要参数:Std_VersionInfoType指针返回值:无调用上下文和关键限制:task 或 interrupt level,not reentrant;需要配置 Version Info Api
CanTrcv_30_Tja1145_CheckWakeup(CanTrcvIndex)
主要参数:通道索引返回值:同步模式下E_OK可表示检测到 bus wakeup;异步模式下E_OK表示请求被接受调用上下文和关键限制:task 或 interrupt level,not reentrant;有效唤醒应以EcuM_SetWakeupEvent()为准
CanTrcv_30_Tja1145_GetTrcvSystemData(CanTrcvIndex, TrcvSysData*)
主要参数:通道索引和uint32*诊断数据 buffer返回值:E_OK表示诊断寄存器读取成功调用上下文和关键限制:task 或 interrupt level,not reentrant;要求硬件支持 Selective Wakeup/PN;仍有 SPI 请求 pending 时返回E_NOT_OK
CanTrcv_30_Tja1145_ClearTrcvWufFlag(CanTrcvIndex)
主要参数:通道索引返回值:E_OK表示 WUF flag 清除请求成功调用上下文和关键限制:task 或 interrupt level,not reentrant;硬件支持 Selective Wakeup/PN;会清除所有 wakeup flags
CanTrcv_30_Tja1145_ReadTrcvTimeoutFlag(CanTrcvIndex, FlagState*)
主要参数:通道索引和 flag state 指针返回值:E_OK表示 timeout flag 状态读取成功调用上下文和关键限制:task 或 interrupt level,not reentrant;底层硬件不支持读取 timeout flag,因此FlagState不会被设置
CanTrcv_30_Tja1145_ClearTrcvTimeoutFlag(CanTrcvIndex)
主要参数:通道索引返回值:E_OK表示 timeout flag 清除请求成功调用上下文和关键限制:task 或 interrupt level,not reentrant;该驱动不支持 timeout flag,此 API 无实际效果
CanTrcv_30_Tja1145_ReadTrcvSilenceFlag(CanTrcvIndex, FlagState*)
主要参数:通道索引和 flag state 指针返回值:E_OK表示 silence flag 状态读取成功调用上下文和关键限制:task 或 interrupt level,not reentrant;该函数无实际效果
CanTrcv_30_Tja1145_CheckWakeFlag(CanTrcvIndex)
主要参数:通道索引返回值:E_OK表示 wake flag 检查请求被接受调用上下文和关键限制:task 或 interrupt level,not reentrant;检测到唤醒后通过EcuM_SetWakeupEvent()上报
CanTrcv_30_Tja1145_MainFunction(void)
主要参数:无返回值:无调用上下文和关键限制:task context,not reentrant;周期检查 wakeup,并在异步 SPI 时处理 pending requests
CanTrcv_30_Tja1145_SetPNActivationState(ActivationState)
主要参数:PN_ENABLED或PN_DISABLED返回值:E_OK表示 PN activation state 成功切换调用上下文和关键限制:task level,not reentrant;调用期间不得被其他 CanTrcv API 打断;建议只在Init()后直接调用CanTrcv_30_Tja1145_GetTrcvSystemData()返回的TrcvSysData是 32 bit 诊断数据,字段含义如下:
| 位范围 | 内容 |
| bit 07-00 | Main status register |
| bit 15-08 | Transceiver status register |
| bit 23-16 | Wake pin status register |
| bit 31-24 | reserved,读出值未定义 |
配置项和生成文件
交付文件分成静态文件和动态文件。静态文件包括CanTrcv_30_Tja1145.h和CanTrcv_30_Tja1145.c,前者供上层 include,后者为实现文件。动态文件包括CanTrcv_30_Tja1145_Cfg.h、CanTrcv_30_Tja1145_Cfg.c、CanTrcv_30_Tja1145_PBcfg.c和CanTrcv_GeneralTypes.h。其中PBcfg.c承载 Post-build loadable 配置数据,CanTrcv_GeneralTypes.h放置 SWS 定义的 CanTrcv 类型,也可被Can_GeneralTypes.hinclude。内存映射使用CANTRCV_30_TJA1145_START_SEC_*和CANTRCV_30_TJA1145_STOP_SEC_*成对宏,覆盖 code、const、noinit var、 init var 和 post-build configuration 等 section,例如:
| Section | 用途 |
| CANTRCV_30_TJA1145_START_SEC_CODE/STOP_SEC_CODE | 代码段 |
| CANTRCV_30_TJA1145_START_SEC_CONST_UNSPECIFIED/STOP_SEC_CONST_UNSPECIFIED | 常量段 |
| CANTRCV_30_TJA1145_START_SEC_VAR_NOINIT_UNSPECIFIED/STOP_SEC_VAR_NOINIT_UNSPECIFIED | noinit 变量段 |
| CANTRCV_30_TJA1145_START_SEC_VAR_INIT_UNSPECIFIED/STOP_SEC_VAR_INIT_UNSPECIFIED | init 变量段 |
| CANTRCV_30_TJA1145_START_SEC_PBCFG/STOP_SEC_PBCFG | post-build 配置段 |
部分配置只能通过 user configuration file 完成。
| 用户配置宏 | 默认行为 | 何时改写 |
| CANTRCV_30_TJA1145_SPI_MAINFUNCTION() | 默认映射到Spi_MainFunction_Driving() | 异步 SPI 下CanTrcv_Init期间需要轮询 SPI event;若 SPI driver 不支持也不需要轮询,可定义为空 |
| CANTRCV_30_TJA1145_SPI_SYNC_TRANSMIT(Ret, Seq) | 同步 SPI 时默认映射到Spi_SyncTransmit | 需要用自定义逻辑模拟同步发送,或在异步 SPI 上封装等待 sequence 完成 |
| CANTRCV_30_TJA1145_WAKE_PIN_EVENT_RISING | 默认STD_ON | 不希望 WAKE pin 上升沿触发唤醒时设为STD_OFF |
| CANTRCV_30_TJA1145_WAKE_PIN_EVENT_FALLING | 默认STD_ON | 不希望 WAKE pin 下降沿触发唤醒时设为STD_OFF |
| CANTRCV_30_TJA1145_AUTO_REINIT | 默认关闭 | 需要启用SYSERR自动恢复时定义为STD_ON |
同步发送宏的自定义形式类似下面这样:
#define CANTRCV_30_TJA1145_SPI_SYNC_TRANSMIT(Ret, Seq) \
(Ret) = Appl_DoSyncTransmit(Seq);如果项目使用 ASR 4.1.1 或更高版本 SPI driver,而 SPI 类型已经从Spi_DataType迁移到Spi_DataBufferType,需要在用户配置文件中加入:
#define CanTrcv_SpiDataType Spi_DataBufferTypePost-build loadable 可重新配置的 CanTrcv 参数集中在CanTrcvPartialNetwork和CanTrcvPnFrameDataMaskSpec相关内容:
| 容器 | 可在 Post-build 调整的参数 |
| CanTrcvPartialNetwork | CanTrcvBaudRate、CanTrcvPnCanIdIsExtended、CanTrcvPnEnabled、CanTrcvPnFrameCanId、CanTrcvPnFrameCanIdMask、CanTrcvPnFrameDlc、CanTrcvPowerOnFlag |
| CanTrcvPnFrameDataMaskSpec | CanTrcvPnFrameDataMask、CanTrcvPnFrameDataMaskIndex |
Wakeup source identifier 也可以在 Post-build 调整,但位置不在 CanTrcv 配置中,而在 EcuM 配置中。需要解除 CanTrcv 到 wakeup source 的引用,例如CanTrcvWakeupSourceRef、CanTrcvPorWakeupSourceRef、CanTrcvSyserrWakeupSourceRef,再调整 EcuM 的EcuMWakeupSourceId。
SYSERR 自动恢复
收发器支持从SYSERR状态自动恢复。若在STANDBY或SLEEP切到NORMAL期间检测到SYSERR,驱动会通过重写并校验 PN 配置来重新初始化底层硬件。同步 SPI 和异步 SPI 下恢复上下文不同:
| SPI 模式 | 自动恢复执行位置 |
| 同步 SPI | 在CanTrcv_30_Tja1145_SetOpMode()调用上下文中完成 |
| 异步 SPI | 在 task level 异步完成,依赖周期调度推进 |
重新初始化可能耗时。期间所有请求,包括新的模式切换请求,都会保持 pending。恢复完成后,驱动继续执行 pending requests。该功能默认关闭,需要在用户配置文件中加入:
#define CANTRCV_30_TJA1145_AUTO_REINIT STD_ON需要注意,AUTOSAR 偏差中还有一个与 POR 相关的边界:如果进入 NORMAL 时检测到 POR,CanTrcv_SetOpMode不执行重新初始化。因为这种情况通常意味着Vs和Vcc低于下限后又恢复,而 MCU 仍保持 active;此时正确功能无法保证,应执行整个 MCU 的完整重新初始化,并在过程中重新调用CanTrcv_Init()。
DET 错误和返回语义
当 pre-compile 参数CANTRCV_30_TJA1145_DEV_ERROR_DETECT == STD_ON时,开发错误通过Det_ReportError()上报。上报的 instance ID 由配置工具指定。
| Service ID | 服务 |
| 0x00 | CanTrcv_30_Tja1145_Init |
| 0x01 | CanTrcv_30_Tja1145_SetOpMode |
| 0x02 | CanTrcv_30_Tja1145_GetOpMode |
| 0x03 | CanTrcv_30_Tja1145_GetBusWuReason |
| 0x04 | CanTrcv_30_Tja1145_GetVersionInfo |
| 0x05 | CanTrcv_30_Tja1145_SetWakeupMode |
| 0x06 | CanTrcv_30_Tja1145_MainFunction |
| 0x07 | CanTrcv_30_Tja1145_CheckWakeup |
| 0x08 | CanTrcv_30_Tja1145_MainFunctionDiagnostics |
| 0x09 | CanTrcv_30_Tja1145_GetTrcvSystemData |
| 0x0A | CanTrcv_30_Tja1145_ClearTrcvWufFlag |
| 0x0B | CanTrcv_30_Tja1145_ReadTrcvTimeoutFlag |
| 0x0C | CanTrcv_30_Tja1145_ClearTrcvTimeoutFlag |
| 0x0D | CanTrcv_30_Tja1145_ReadTrcvSilenceFlag |
| 0x0E | CanTrcv_30_Tja1145_CheckWakeFlag |
| 0x0F | CanTrcv_30_Tja1145_SetPNActivationState |
| Error code | 错误宏 | 触发条件 |
| 0x01 | CANTRCV_30_TJA1145_E_INVALID_TRANSCEIVER | 函数参数中使用了非法 channel index |
| 0x02 | CANTRCV_30_TJA1145_E_PARAM_POINTER | 函数参数中使用了NULL_PTR |
| 0x11 | CANTRCV_30_TJA1145_E_UNINIT | CAN transceiver hardware 尚未初始化 |
| 0x21 | CANTRCV_30_TJA1145_E_TRCV_NOT_STANDBY | CAN transceiver hardware 不在 standby mode |
| 0x22 | CANTRCV_30_TJA1145_E_TRCV_NOT_NORMAL | CAN transceiver hardware 不在 normal operation mode |
| 0x23 | CANTRCV_30_TJA1145_E_PARAM_TRCV_WAKEUP_MODE | 请求的 wakeup mode 非法 |
| 0x24 | CANTRCV_30_TJA1145_E_PARAM_TRCV_OP_MODE | 请求的 operation mode 不被底层收发器硬件支持 |
| 0x25 | CANTRCV_30_TJA1145_E_BAUDRATE_NOT_SUPPORTED | 选择的 baudrate 不被底层收发器硬件支持 |
| 0x40 | CANTRCV_30_TJA1145_E_NO_TRCV_CONTROL | CAN transceiver 不受控制,保持在非法状态;这是 production error |
几个E_OK语义需要单独区分。SetOpMode()的E_OK是请求被接受,不代表通知的模式一定等于请求模式。异步 SPI 下CheckWakeup()的E_OK是检查请求被接受,不代表已检测到 wakeup。唤醒是否有效,应以EcuM_SetWakeupEvent()是否被调用为准。
标准符合性、限制和偏差
驱动增加了CanTrcv_30_Tja1145_InitMemory(),用于实现独立的 BSW module memory initialization。这是 AUTOSAR 标准 API 之外的扩展,但它也是该模块初始化顺序的一部分。明确限制如下:
| 限制 | 工程影响 |
| CanTrcv_ReadTrcvTimeoutFlag和CanTrcv_ClearTrcvTimeoutFlag无实际效果 | 底层硬件限制导致 timeout flag 相关功能不可用 |
| 不支持CanTrcv_MainFunctionDiagnostics | 无法区分 local errors 和 bus errors,因此不做 bus error polling |
| 旧 SPI 类型为Spi_DataType | 使用 ASR 4.1.1 或更高 SPI driver 时,需要把CanTrcv_SpiDataType映射到Spi_DataBufferType |
与 AUTOSAR SWS 的主要偏差如下:
| 偏差 | 驱动行为 |
| CanIf notification function 使用模块专用名称 | 使用CanIf_30_Tja1145_TrcvModeIndication、CanIf_30_Tja1145_ConfirmPnAvailability、CanIf_30_Tja1145_ClearTrcvWufFlagIndication、CanIf_30_Tja1145_CheckTrcvWakeFlagIndication;这些函数内需要把本地CanTrcvIndex换算为 CanIf 全局 index |
| CanIf_CheckTrcvWakeFlagIndication总是调用 | 即使未检测到 wakeup 也调用,避免锁住CanSM;真正检测到 wakeup 时再调用EcuM_SetWakeupEvent() |
| CanTrcv_SetOpMode中 POR 不触发重新初始化 | POR 场景要求 MCU 完整重新初始化,并在过程中调用CanTrcv_Init() |
| CanTrcv_GetTrcvSystemData参数去掉const | TrcvSysData需要由驱动写入,因此使用可写uint32* |
| CanTrcvSPICommRetries和CanTrcvSPICommTimeout不是强制使用 | 因 SWS 未说明使用位置,BSWMD multiplicity 设为0..1 |
| CanTrcv_CheckWakeup返回值语义调整 | 异步 SPI 下E_OK表示请求被接受,完成动作可能在MainFunction中发生 |
| 初始化模式不使用CanTrcvInitState | 每个 CAN transceiver channel 均初始化到NORMAL |
集成关注点
这类驱动集成时,首先要把启动顺序固定下来:CanTrcv_30_Tja1145_InitMemory()在所有 CanTrcv 功能之前,CanTrcv_30_Tja1145_Init()之前 SPI driver 已初始化。如果使用 UJA1168,还要保证 SBC 处于允许 SPI 通信的模式,并满足 RESET 到 STANDBY 后的访问等待时间。其次要把 SPI 同步/异步策略和 OS 调度策略一起确认。异步 SPI 下,CANTRCV_30_TJA1145_SPI_MAINFUNCTION()、SPI sequence indication、CanTrcv_30_Tja1145_MainFunction()的周期调用共同决定 mode change、wakeup check 和自动恢复能否推进。排他区持续时间为 LONG,调用方不应假定这些 API 是短临界区函数。PN 和唤醒配置要按硬件写入时机理解。修改 PN frame ID、mask、DLC、data mask 后,底层硬件并不一定立即获得新配置;只有 POR 或SYSERR相关初始化路径才会写入 PN 数据。对于 selective wakeup,同一 channel 上CanTrcvWakeupByBusUsed与CanTrcvPnEnabled必须同时成立。最后,唤醒有效性不要直接绑定 API 返回值。CheckWakeup()在异步路径中返回E_OK只是请求确认,CheckWakeFlag()的 indication 也可能在没有 wakeup 时被调用。真正的 wakeup 事件以EcuM_SetWakeupEvent()为准,最近一次唤醒原因再由GetBusWuReason()读取。
小结
CanTrcv_30_Tja1145的核心不是简单地“把收发器切到 NORMAL”,而是在 SPI 访问、模式异步完成、PN 配置写入、ICU 唤醒脚和 EcuM/CanIf 通知之间维持一致性。集成时最值得盯住的点是初始化顺序、异步 SPI 推进机制、sleep emulation、PN 配置生效条件、SYSERR自动恢复以及CheckWakeup()返回值语义。把这些边界处理清楚,CanSM、EcuM和收发器硬件之间的状态才不会在低功耗和唤醒路径上相互误判。








TJA1145这两年用得挺多,SPI去配置寄存器的注意点讲得很清楚。
唤醒机制这块,不同配置的理解容易混,文章写得明白。
NXP这颗收发器细节多,能这样逐项解析的确实少,好评。