前言
本文是对Autosar文档的翻译与解读,通过对规范的理解,加上实际的应用来一一对应,方便大家更好的理解。
注意:本文并非完全的按照【AUTOSAR_SWS_CANDriver.pdf】来进行翻译的。文章内容的标题与【AUTOSAR_SWS_CANDriver.pdf】保持一致。
一、导言和功能描述
1.CAN模块是最底层的一部分,负责硬件访问,并为上层提供独立于硬件的应用程序接口。
2.能访问CAN Driver模块的上层是CANIF模块
3.CAN模块提供启动传输的服务,并调用CanIf模块的回调函数来通知事件,与硬件无关,
五、与其他模块的依赖关系
5.5 文件结构
Can_GeneralTypes.h应包含AUTOSAR CAN 模块 Can、CanIf 和 CanTrcv 共享的所有类型和常量。
下图截取了一部分与CAN相关的内容,主要为CAN控制器状态的一些枚举值,以及数据传输的结构,还有故障状态的一些值。可以在这个头文件中查找到。
七、功能规格
7.2 驱动程序状态机
Can 模块的状态机非常简单,只有 CAN_UNINIT 和 CAN_READY 两种状态。
上电/复位后,Can 模块应处于 CAN_UNINIT 状态。
在初始化硬件单元内的所有控制器后,函数 Can_Init 应将模块状态更改为CAN_READY。
必须通过调用函数 Can_SetControllerMode(CAN_CS_STARTED)来分别启动每个 CAN 控制器。
即:在执行完Can_Init初始化之后,我们想要使用哪一个CAN硬件单元(CAN1,CAN2,CAN3等等),必须调用Can_SetControllerMode(CANn,CAN_CS_STARTED)来使能这个硬件单元。
7.3 CAN控制器状态机
CAN控制器有四种基本状态:未启动(UNINIT)、停止(STOPPED)、启动(STARTED)和休眠(SLEEP)。
7.3.1 CAN 控制器状态说明
UNINIT:CAN 控制器未初始化。CAN 模块的所有寄存器均处于复位状态,CAN 中断被禁用。
STOPPED:CAN 控制器被初始化,但不参与总线。此外,不得发送错误帧和确认信息。
STARTED:控制器处于具有完整功能的正常运行模式,这意味着它参与了网络。对于许多控制器
来说,离开 "初始化 "模式会导致控制器启动
SLEEP:当 CAN 硬件支持睡眠模式并被触发过渡到 SLEEP 状态时,Can 模块应将控制器设置为 SLEEP 状态,并可通过 CAN 总线从该状态唤醒硬件。(一般外部CAN控制器都支持休眠)
当 CAN 硬件不支持睡眠模式并被触发过渡到 SLEEP 状态时,CAN 模块应模拟逻辑 SLEEP 状态,只有当它被软件触发过渡到 STOPPED 状态时,才会从该状态返回。
7.3.2 CAN 控制器状态转换
这些状态的切换,都可以通过函数Can_SetControllerMode()来控制。回调函数(CanIf_ControllerModeIndication)会通知软件触发的成功状态转换。监控是否达
到所要求的状态是上层模块的一部分,而不是 Can 模块的一部分。
7.3.3 函数 Can_Init 引起的状态转换
函数 Can_Init 应将所有 CAN 控制器设置为 STOPPED 状态
当进入函数 Can_Init 时,如果 Can 模块未处于 CAN_UNINIT 状态,或者 CAN 控制器未处于 UNINIT 状态,则会出现 CAN_E_TRANSITION 错误。
7.3.4 函数 Can_SetBaudrate 引起的状态转换
如果调用 Can_SetBaudrate()会导致 CAN 控制器重新初始化,且 CAN 控制器未处于 STOPPED 状态,则应返回 E_NOT_OK
如果需要重新初始化,函数 Can_SetBaudrate 应将 CAN控制器保持在 STOPPED 状态。
7.3.5 函数 Can_SetControllerMode 引起的状态转换
软件可以通过函数 Can_SetControllerMode 触发 CAN 控制器状态转换,过渡到新的 CAN 控制器状态可能需要延迟一段时间。Can 模块会在状态转换成功后将新状态通知上层(
CanIf_ControllerModeIndication)。
Can_SetControllerMode (CAN_CS_STARTED) 引起的状态转换: ▪ 停止 🡪 开始 ▪ 软件触发
当进入 Can_SetControllerMode (CAN_CS_STARTED) 功能且CAN 控制器未处于 STOPPED 状态时,应检测到无效的状态转换, 引发错误 CAN_E_TRANSITION,返回E_NOT_OK.
Can_SetControllerMode (CAN_CS_STOPPED) 引起的状态转换:
▪ 开始 🡪 停止 ▪ 睡眠 🡪 停止 ▪ 软件触发
Can_SetControllerMode(CAN_CS_SLEEP)引起的状态转换:▪ 停止了 🡪睡眠 ▪ 软件触发
当进入 Can_SetControllerMode(CAN_CS_SLEEP)函数时,CAN 控制器既没有处于 STOPPED 状态,也没有处于 SLEEP 状态,它应检测到无效的状态转换,引发错误 CAN_E_TRANSITION,返回E_NOT_OK.
7.3.6 硬件事件导致的状态转换
硬件唤醒(支持改功能)引起的状态转换(由 CAN 总线的唤醒事件触发):▪ 睡眠 🡪 停止
7.3.7 函数 Can_DeInit 引起的状态转换
- STOPPED -> UNINIT;SLEEP -> UNINIT(适用于硬件单元中的所有控制器)
7.5 L-PDU 传输
在传输 L-PDU 时,Can 模块会将 L-PDU 内容 ID 和数据长度转换为硬件特定格式(如有必要),并触发传输。最先发送的CAN数据字节是数组元素0,最后发送的CAN数据字节是数组元素7,如果是CAN FD,则是数组元素63。
Can 模块应调用 CanIf_TxConfirmation 来表示传输成功。它应由相应硬件资源的 TX 中断服务例程调用,或在轮询模式下由Can_MainFunction_Write 内部调用。
下面为代码示例↓↓↓
在这个函数里,我们可以单独创立一个flag,并将传输的结果赋值给这个flag, 上层通过判断这个flag来确认CAN数据传输是否完成。
详细的关于【CanIf_TxConfirmation 】内容,会在【AUTOSAR_SWS_CANInterface】章节中有讲解。
7.5.1 优先级反转
内部优先级反转
"如果只使用一个发送缓冲器,可能会出现内部优先级倒置。由于优先级较低,存储在缓冲器中的信息需要等待 "总线上的流量平静下来"。在等待期间,该信息可能会阻止同一微控制器生成的优先级更高的信息通过总线传输"
外部优先级反转
"在某些 CAN 实现中可能会出现外部优先级倒置的问题。假设一个 CAN 节点希望传输一包具有高优先级的连续报文,这些报文存储在不同的报文缓冲区中。如果 CAN 网络上这些报文之间的帧间距长于 CAN 标准规定的最小间距,第二个节点就会开始传输优先级较低的报文。最小帧间距由 Intermission 字段决定,该字段由 3 个隐性比特组成。在传输另一条报文期间待处理的报文将在总线空闲期间启动,最早启动时间为 "中场休息 "字段后面的位。例外情况是,有等待传输报文的节点会将 Intermission 字段第三位的显性位理解为帧开始位,并从第一个标识符位开始传输,而不首先传输 SOF 位。CAN 模块的内部处理时间必须足够短,以便以最小的帧间空间发送连续报文,从而避免上述所有情况下的外部优先级倒置。
7.6 接收 L-PDU
接收到 L-PDU 时,Can 模块应调用 RX 指示回调函数CanIf_RxIndication,参数 Mailbox 中包含 ID、Hoh 和抽象 CanIf ControllerId,参数 PduInfoPtr 中包含数据长度和 L-SDU 缓冲区指针
如果是扩展 CAN 帧,Can 模块应将 ID 转换为标准格式,因为上层(CANIF)不知道接收到的 CAN 帧是标准 CAN 帧还是扩展 CAN 帧。如果是扩展 CAN 帧,接收到的 CAN 帧 ID 的 MSB 必须为 "1",以将接收到的 CAN 帧标记为扩展 CAN 帧。
在轮询模式下,相应硬件资源的 RX 中断服务例程或函数Can_MainFunction_Read 应调用回调函数 CanIf_RxIndication。这个跟【7.5】章节的类似。
CAN到内存的数据映射定义为:最先接收到的CAN数据字节是数组元素0,最后接收到的CAN数据字节是数组元素7或63(如果是CAN FD)。
7.7 唤醒概念
Can 模块可处理 Can 控制器本身而非通过 Can 收发器检测到的唤醒。通过中断唤醒或者通过轮询唤醒。对于中断唤醒,当硬件检测到唤醒时,会调用 Can 模块的 ISR。
如果调用了唤醒事件的 ISR,则应依次调用EcuM_CheckWakeup。传递给 EcuM_CheckWakeup 的参数应是CanWakeupSourceRef 配置参数引用的唤醒源的 ID。然后,ECU 状态管理器将设置 MCU,并通过 Can 接口回调 Can 模块,从而调用Can_CheckWakeup。
7.8 通知概念
Can 模块只为 CanIf 模块提供了一个事件触发通知接口。每个通知都由一个回调函数表示。
Can 模块轮询和不轮询的配置在驱动程序内部进行,模块外部看不到。轮询在 CAN主函数 (Can_MainFunction_xxx) 内部进行。此外,轮询事件会通过相应的回调函数进行通知。因此,调用上下文不是 ISR,而是 CAN 主函数。所有回调函数的实现都应按照调用上下文为 ISR 的方式进行。
7.11 错误分类
Can 模块应能检测下列错误和异常,具体取决于其配置
7.11.1 开发错误
7.11.2 运行时错误
Can 模块应指出因错误使用 Can 模块 API 而导致的错误。这包括 API 参数检查和调用顺序错误。
Can 模块的环境应仅在 DET 接通且函数提供返回值时,在Can 模块函数的返回值中显示开发错误。返回值为 E_NOT_OK。
7.11.3 瞬态故障
没有瞬时故障。
7.11.4 生产错误
CAN模块不会调用诊断事件管理器,因为没有为CAN模块定义生产错误代码。
7.11.5 返回值
CAN_BUSY 通过函数 Can_Write 的返回值报告。总线关闭和唤醒事件通过通知回调函数进行转发。
八、API 规格
8.2 类型定义
8.2.1 Can_ConfigType
8.2.2 Can_PduType
8.2.3 Can_IdType
8.2.4 Can_HwHandleType
8.2.5 Can_HwType
8.2.6 对 Std_ReturnType
8.2.7 Can_ErrorStateType
8.2.8 Can_ControllerStateType
8.3 功能定义
这是为上层模块提供的功能函数。
8.3.1 影响整个硬件设备的服务
8.3.1.1 Can_Init
如果启用了 Can 模块的开发错误检测:如果驱动程序未处于CAN_UNINIT 状态,函数 Can_Init 应引发 CAN_E_TRANSITION 错误。
如果启用了 Can 模块的开发错误检测功能:如果 CAN 控制器未处于 UNINIT 状态,函数 Can_Init 将引发 CAN_E_TRANSITION 错误。
8.3.1.2 Can_GetVersionInfo
如果 Can 模块的开发错误检测功能已启用:如果参数versionInfo 为空指针,函数 Can_GetVersionInfo 将引发错误CAN_E_PARAM_POINTER。
8.3.1.3 Can_DeInit
Can_DeInit 函数的调用者必须确保没有 CAN 控制器处于 STARTED 状态。
如果启用了 Can 模块的开发错误检测:如果驱动程序未处于CAN_READY 状态,函数 Can_DeInit 应引发错误 CAN_E_TRANSITION
如果启用了 Can 模块的开发错误检测:如果任何 CAN 控制器处于 STARTED 状态,函数 Can_DeInit 应引发 CAN_E_TRANSITION 错误
8.3.2 影响单个 CAN 控制器的服务
8.3.2.1 Can_SetBaudrate
可能有多种波特率配置可供选择。可以使用函数 Can_SetBaudrate 在不同配置之间进行切换。在运行期间,根据新旧波特率配置的不同,只有部分参数会发生变化,因此可以避免重新初始化 CAN 控制器。如果调用 Can_SetBaudrate 会导致 CAN 控制器重新初始化,则调用该函数时
CAN 控制器必须处于停止状态。
如果 Can 模块的开发错误检测功能已启用:如果驱动程序尚未初始化,函数 Can_SetBaudrate 应引发错误 CAN_E_UNINIT,并返回 E_NOT_OK
如果 Can 模块的开发错误检测功能已启用:如果参数BaudRateConfigID 的值无效,函数 Can_SetBaudrate 应引发错误CAN_E_PARAM_BAUDRATE,并返回 E_NOT_OK。
如果 Can 模块的开发错误检测功能已启用,函数Can_SetBaudrate 将引发错误 CAN_E_PARAM_CONTROLLER,如果参数Controller 超出范围,则返回 E_NOT_OK。
如果在不重新初始化 CAN 控制器的情况下无法执行所请求的波特率更改,则应返回 E_NO_OK。
8.3.2.2 Can_SetControllerMode
每次 CAN 控制器状态机被状态转换值 CAN_CS_STARTED 触发时,函数 Can_SetControllerMode应使用之前在函数 Can_SetBaudrate 或 Can_Init 中使用的控制器配置集重新初始化CAN 控制器。
在检查唤醒状态时,函数 Can_SetControllerMode 应禁用唤醒中断。
如果启用了 Can 模块的开发错误检测:如果模块尚未初始化,函数 Can_SetControllerMode 将引发开发错误 CAN_E_UNINIT,并返回 E_NOT_OK
如果启用了 Can 模块的开发错误检测:如果参数 Controller超出范围,函数 Can_SetControllerMode 将引发 CAN_E_PARAM_CONTROLLER 开发错误,并返回 E_NOT_OK。
如果启用了 Can 模块的开发错误检测:如果请求了无效的转换,函数 Can_SetControllerMode 应引发错误 CAN_E_TRANSITION,并返回E_NOT_OK。
8.3.2.3 Can_DisableControllerInterrupts
如果 CAN 控制器的中断已启用,函数Can_DisableControllerInterrupts 应访问 CAN 控制器寄存器,以禁用该 CAN 控制器的所有中断。
当 Can_DisableControllerInterrupts 被多次调用时,在重新启用中断之前,必须同样多次调用 Can_EnableControllerInterrupts。函数 Can_DisableControllerInterrupts 可以在每次执行时增加一个计数器,该计数器显示需要调用多少次 Can_EnableControllerInterrupts 才能启用中断(增量禁用)
如果 Can 模块的开发错误检测功能已启用:如果驱动程序尚未初始化,函数 Can_DisableControllerInterrupts 将引发错误 CAN_E_UNINIT
如果 Can 模块的开发错误检测功能已启用:如果参数Controller 超出范围,函数 Can_DisableControllerInterrupts 将引发错误CAN_E_PARAM_CONTROLLER。
8.3.2.4 Can_EnableControllerInterrupts
8.3.2.5 Can_CheckWakeup
函数 Can_CheckWakeup 应检查所请求的 CAN 控制器是否检测到唤醒。如果成功检测到唤醒事件,则应通过 API EcuM_SetWakeupEvent. ⌋() 向EcuM 报告。
Can_CheckWakeup 功能应在编译前通过配置参数进行开/关配置:CanWakeupFunctionalityAPI
8.3.2.6 Can_GetControllerErrorState
8.3.2.7 Can_GetControllerMode
8.3.2.8 Can_GetControllerRxErrorCounter
当调用以控制器 ID 为输入参数的 APICan_GetControllerRxErrorCounter 时,Can 驱动程序应读取 Rx 错误计数器。并应将 Rx 错误计数返回给上层。
8.3.2.9 Can_GetControllerTxErrorCounter
8.3.3 影响硬件处理的服务
8.3.3.1 Can_Write
函数 Can_Write 首先会检查 HTH 标识的硬件传输对象是否空闲,以及同一 HTH 是
否正在进行另一次 Can_Write
如果硬件发送对象是空闲的,函数 Can_Write 应执行以下操作:
▪ 该 HTH 的互斥设置为 "已发出信号"。
▪ 将 ID、数据长度和 SDU 转换成适合硬件的格式(如有必要),并复制到相应的硬件寄存器/缓冲器中。
▪ 启动发射的所有必要控制操作均已完成
▪ 该 HTH 的互斥已被释放
▪ 函数返回 E_OK⌋
如果硬件发送对象忙于处理另一个 L-PDU 的发送请求,函数Can_Write 不应执行任何操作:
1. 其他 L-PDU 的传输不会被取消,函数 Can_Write 也不会有任何操作。
2. 函数 Can_Write 应返回 CAN_BUSY。
如果已发出 Can_Write 的抢占式调用,但无法进行可重入处理(即具有相同 HTH 的调用),则函数 Can_Write 应返回 CAN_BUSY。
8.5 预定功能
这些函数由基本软件调度程序直接调用。下列函数应没有返回值和参数。所有函数均
为非可重入函数。对 CAN 主要处理功能的执行顺序没有要求
8.5.1.1 Can_MainFunction_Write
当 CanTxProcessing 执行时,函数 Can_MainFunction_Write应执行 TX 确认轮询。设置为 POLLING 或 MIXED。在 MIXED 处理情况下,只有CanHardwareObjectUsesPolling 设置为 "true "的硬件对象才会被轮询。
8.5.1.2 Can_MainFunction_Read
当 CanRxProcessing 设置为 POLLING 或 MIXED 时,函数Can_MainFunction_Read 应执行 RX 指示的轮询。在 MIXED 处理情况下,只轮询CanHardwareObjectUsesPolling 设置为 "true "的硬件对象。
8.5.1.3 Can_MainFunction_BusOff
8.5.1.4 Can_MainFunction_Wakeup
8.5.1.5 Can_MainFunction_Mode
九、顺序图
9.1 Can 和 CanIf 模块之间的互动
有关序列图,请参阅 CanIf 模块规范
9.2 唤醒顺序
有关唤醒序列图,请参阅《ECU 状态管理器规范》