TJA1145 CAN收发器SPI驱动与唤醒机制

2026-09-211

CAN 收发器驱动经常被误认为只是 CanSM 下发 NORMALSTANDBYSLEEP 的薄封装。对 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_IDCANTRCV_30_TJA1145_MODULE_IDCANTRCV_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 出厂时 FNMC bit 可能为 1,此时不能使用该驱动,使用前应确保该 bit 为 0。UJA1168 的 SPI 通信只在 SBC 处于 NORMALSTANDBY 模式时可用,应用必须保证只在这两个模式下调用驱动 API。RESET 到 STANDBY 的转换还存在访问 SPI 前必须满足的时间约束,这个约束也由应用侧保证。

ATA6570 的 WDC 符号控制 Window Watchdog,位于 WDCR1 寄存器 bit 7:5。驱动假定 watchdog 处于 disabled 状态,不会配置 watchdog;使用前需要确认 WDC001,对应默认的 Off mode。

从相邻模块看,CanTrcv_30_Tja1145 不是独立运行的 底层驱动 。它至少和 CanSMCanIfEcuMSPIICUDET 以及可选的 Time Service 发生关系。

原文图示 1

初始化和模式状态

上电或复位后,初始化顺序分成两步。CanTrcv_30_Tja1145_InitMemory() 先初始化驱动内存和必要值,必须在其他收发器驱动功能之前调用。随后 CanTrcv_30_Tja1145_Init(ConfigPtr) 初始化配置工具选中的所有 active channel,并把每个 CAN 收发器通道切到 CANTRCV_TRCVMODE_NORMAL

如果初始化前已经有 wakeup event pending,驱动会保存该事件,并通过 EcuM_SetWakeupEvent() 通知 EcuM。局部网络相关数据也有一个容易踩到的边界:PN 的 IDMASKDLCDATA 只有在初始化期间检测到 POR(Power-on-reset)或 SYSERR flag 时才写入底层收发器硬件。也就是说,修改过的 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 不支持 不由该服务直接完成

原文图示 2

当某个通道的所有唤醒源都被禁用时,硬件不会真正进入 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.hTm.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\CanTrcvWakeupByBusUsedCanTrcvChannel\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 处于 DISABLEENABLE 之间时检测到了唤醒,重新 enable 并不会主动上报这次事件;应在重新 enable 后调用 CanTrcv_30_Tja1145_GetBusWuReason() 检查是否已有唤醒原因。

唤醒检查路径可以按下面理解。

原文图示 3

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_<Channel Name>
Sequence M 包含 JOB_RW_REG_0..2;异步 SPI 时使用 CanTrcv_30_Tja1145_SpiIndicationM_<Channel Name>
Sequence L 包含 JOB_RW_REG_0..3;异步 SPI 时使用 CanTrcv_30_Tja1145_SpiIndicationL_<Channel Name>

如果使用异步 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_<IdentityName>_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)

  • 主要参数:通道索引和 ENABLEDISABLECLEAR
  • 返回值: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_ENABLEDPN_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.hCanTrcv_30_Tja1145.c,前者供上层 include,后者为实现文件。动态文件包括 CanTrcv_30_Tja1145_Cfg.hCanTrcv_30_Tja1145_Cfg.cCanTrcv_30_Tja1145_PBcfg.cCanTrcv_GeneralTypes.h。其中 PBcfg.c 承载 Post-build loadable 配置数据,CanTrcv_GeneralTypes.h 放置 SWS 定义的 CanTrcv 类型,也可被 Can_GeneralTypes.h include。

内存映射使用 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_DataBufferType

Post-build loadable 可重新配置的 CanTrcv 参数集中在 CanTrcvPartialNetworkCanTrcvPnFrameDataMaskSpec 相关内容:

容器 可在 Post-build 调整的参数
CanTrcvPartialNetwork CanTrcvBaudRateCanTrcvPnCanIdIsExtendedCanTrcvPnEnabledCanTrcvPnFrameCanIdCanTrcvPnFrameCanIdMaskCanTrcvPnFrameDlcCanTrcvPowerOnFlag
CanTrcvPnFrameDataMaskSpec CanTrcvPnFrameDataMaskCanTrcvPnFrameDataMaskIndex

Wakeup source identifier 也可以在 Post-build 调整,但位置不在 CanTrcv 配置中,而在 EcuM 配置中。需要解除 CanTrcv 到 wakeup source 的引用,例如 CanTrcvWakeupSourceRefCanTrcvPorWakeupSourceRefCanTrcvSyserrWakeupSourceRef,再调整 EcuM 的 EcuMWakeupSourceId

SYSERR 自动恢复

收发器支持从 SYSERR 状态自动恢复。若在 STANDBYSLEEP 切到 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 不执行重新初始化。因为这种情况通常意味着 VsVcc 低于下限后又恢复,而 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_ReadTrcvTimeoutFlagCanTrcv_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_TrcvModeIndicationCanIf_30_Tja1145_ConfirmPnAvailabilityCanIf_30_Tja1145_ClearTrcvWufFlagIndicationCanIf_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*
CanTrcvSPICommRetriesCanTrcvSPICommTimeout 不是强制使用 因 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 上 CanTrcvWakeupByBusUsedCanTrcvPnEnabled 必须同时成立。

最后,唤醒有效性不要直接绑定 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() 返回值语义。把这些边界处理清楚,CanSMEcuM 和收发器硬件之间的状态才不会在低功耗和唤醒路径上相互误判。


作者:不脱发的程序猿。本文同步自作者 CSDN 博客。

原文:https://handsome-man.blog.csdn.net/article/details/162554095

创作许可协议

本项目采用 CC BY(署名) 进行许可。

评论(0)
- 没有更多了 -