目录
前言
1.CAN Driver模块详细设计
1.1关键概念理解
1.2 Drive状态机
1.3 CAN Controller状态机
1.3.1 UNINIT状态
1.3.2 STOPPED状态
1.3.3 STARTED状态
1.3.4 SLEEP状态
1.2 CAN Controller状态切换
1.2.1 CAN_Init切换状态
1.2.2 CAN_SetBaudrate切换状态
1.2.3 Can_SetControllerMode切换状态
1.2.3 硬件事件切换状态
1.3 Can Controller初始化
1.4 L-PDU发送
1.5 发送数据的一致性
1.6 L-PDU接收
1.7 Wakeup Concept
1.8 关键API解析
1.8.1 Can_Init
1.8.2 Can_SetControllerMode
1.8.3 Can_DisableControllerInterrupts
1.8.4 Can_EnableControllerInterrupts
1.8.5 Can_CheckWakeup
1.8.6 Can_Write
2. RH850-U2A16 RS-CANFD模块简介
2.1 CAN通道数
2.2 时钟选择
2.3中断通知
2.4 MB邮箱配置
3. 总结
纵向来看,CAN Driver属于CAN通信协议栈的底层驱动模块,横向来看CAN Driver属于MCAL层(microcontroller abstraction layer)。CAN Driver驱动模块执行硬件访问操作,给上层模块提供独立于硬件的API访问接口。CAN Interface模块是唯一能够直接访问CAN Driver模块的上层模块。 此外,它还提供服务来控制属于同一CAN硬件单元的CAN控制器的行为和状态。一个CAN模块可以控制多个CAN控制器,只要它们属于同一个CAN硬件单元。
为了较详细的接收CAN Driver,本文将从以下四个大的方面展开叙述:CAN Driver AUTOSAR详细设计文档详解、RH850芯片CAN模块简介、MCAL配置工具CAN Driver配置、CAN Driver模块代码分析。
完成以上分析后,能回答以下问题:
--数据怎么完成收发功能?
--怎么保证数据传输的一致性?
--CANDriver怎么实现CAN Controller状态机?
CAN总线协议推荐参考这篇博文:
CAN总线协议详解
CAN controller: 一个CAN controller对应一路物理通道,也就是说一个ECU接了几路CAN就有几个CAN controller
CAN Hardware Unit: 一个CAN硬件单元可以由一个或多个相同类型的CAN控制器和一个或多个CAN RAM区域组成。CAN硬件单元可以是芯片上的,也可以是外部设备。CAN硬件单元由一个CAN驱动程序表示。
CAN L-PDU: Data Link Layer Protocol Data Unit数据链路层协议数据单元。也就是包含帧头的在CAN报文数据,包括报文ID,数据长度DLC,及报文数据SDU。
CAN L-SDU: Data Link Layer Service Data Unit: 数据链路层服务数据单元。也就是CAN报文的数据部分。
Hardware Object: CAN硬件对象定义为CAN硬件单元/ CAN控制器的CAN RAM内部的PDU缓冲区。一个硬件对象被定义为在CAN硬件单元的CAN RAM内的L-PDU缓冲区。理解上,一个Hardware Object对应一个邮箱Maiboxes,可以设置为发送或者接收邮箱,而Maiboxes其实就是一段硬件RAM缓存。
Harware Receive Handle(HRH): 硬件接收句柄(HRH)由CAN驱动程序定义和提供。每个HRH通常只代表一个硬件对象。HRH可用于优化软件滤波。
Hardware Transmit Handle(HTH): 硬件传输句柄(HTH)是由CAN驱动程序定义和提供的。每个HTH通常只代表一个或多个被配置为硬件传输缓冲池的硬件对象。
CAN模块只有两个非常简单的状态机,CAN_UNINIT和CAN_READY状态。ECU上电或者重启后,CAN模块进入CAN_UNINIT状态,ECM调用Can_Init函数后进入CAN_READY状态。
CAN Driver模块为每一个CAN Controller(每一路CAN)维持一个硬件状态机,状态机有UNINIT,STOPPED,STARTED,SLEEP四种状态。对应在CanIf模块也维持一个CANIF_CS_UNINIT, CANIF_CS_STOPPED, CANIF_CS_STARTED, CANIF_CS_SLEEP四个状态的软件状态机。在状态切换期间,CAN Driver模块的状态和CanIf模块的状态可能是不一样的(传输可能失败或被延迟,因为硬件CAN控制器还没有参与总线,Can模块没有为这种情况提供通知到CanIf模块)。
CAN Driver模块提供的Can_Init,Can_SetBaudrate,Can_SetControllerMode服务可以切换CAN Controller的状态。外部的Bus-Off事件和HW wakeup事件也本可以切换状态机。
外部事件可以通过中断或者MainFunction轮询的方式被监控到,事件切换状态机发生在事件发生后调用的callbakc回调函数当中。
CAN Controller没有被初始化,CAN模块的所有的寄存器都是reset状态,CAN相关中断都被disable的。CAN Controller没有参与CAN到CAN-Bus总线活动中。
在这种状态下,CAN控制器被初始化,但不参与总线。此外,错误帧和ACK不能发送。
控制器处于正常运行模式,功能完整,参与CAN总线网络。
CAN硬件(收发器)区分支持休眠和不支持休眠的硬件,不同的CAN硬件的SLEEP状态不一样。
支持休眠的CAN硬件,如果切换到SLEEP状态,CAN模块就会设置CAN Controller进入SLEEP状态,这SLEEP状态下CAN新建能够被CAN总线唤醒。
不支持休眠的CAN硬件,如果切换到SLEEP状态,CAN模块设置一个逻辑SLEEP状态,只能通过软件切换到STOPPED状态。
CAN硬件应保持在STOPPED状态,当逻辑SLEEP状态被触发后。
上层模块调用Can_SetControllerMode函数切换CAN Controller状态。CAN Driver模块成功完成状态切换后调用CanIf_ControllerModeIndication回调函数通知到上层CanIf模块。
事件触发的状态切换回调用事件触发后的回调函数通知到上层模块,例如Bus-Off后底层调用CanIf_ControllerBusOff,EcuM_CheckWakeup函数通知到CanIf和EcuM模块。
EcuM模块在初始化阶段调用CAN_Init函数完成CAN模块的初始化(所有硬件配置相关的寄存器的设置),CAN Controller状态从UNINIT状态切换到STOPPED状态。
CAN_SetBaudrate函数的调用不会切换当前状态到另一个状态,只会当前状态完成硬件寄存器配置后又回到当前状态。如果设置波特率必须重新初始化CAN Driver模块,则切换波特率的时候CAN Controller必须在STOPPED的状态,否则返回E_NOT_OK。
CAN_SetBaudrate函数在实际项目中基本不用。
上层模块调用Can_SetControllerMode函数后,Can_MainFunction_Mode周期函数回轮询CAN状态寄存器的模式标志,如果CAN Controller的模块切换成功了,Can_MainFunction_Mode函数调用CanIf_ControllerModeIndication通知到CanIf层。
Can_SetControllerMode(CAN_T_START) --> STOPPED-->STARTED:
在STOPPED状态下调用Can_SetControllerMode(CAN_T_START)函数后,设置硬件相关的寄存器,等待有限的一段时间,使的CAN Controller能够参与到CAN网络总线活动中。
在CAN Controller完全运行起来前的发送请求会丢失,在发送回调中通知到上层。上层会判断发送超时后做相应处理。
Can_SetControllerMode(CAN_T_STOP) --> STARTED-->STOPPED:
STARTED状态下调用Can_SetControllerMode(CAN_T_STOP)函数,CAN硬件会设计相关寄存器的bits,之后CAN Controller停止参与总线通信。同时未发送出去被挂起的消息会被删除。
Can_SetControllerMode(CAN_T_SLEEP) --> STOPPED-->SLEEP:
STOPPED状态下调用Can_SetControllerMode(CAN_T_SLEEP) 函数,CAN Controller进入到sleep模式。
如果CAN硬件(收发器)支持睡眠模式,Can_SetControllerMode(CAN_T_SLEEP) 函数会等待一段函数直到CAN Controller进入到SLEEP状态,同时保证CAN硬件能够被唤醒。
如果CAN硬件(收发器)不支持睡眠模式,Can_SetControllerMode(CAN_T_SLEEP) 函数会设置CAN Controller进入到逻辑sleep模式。逻辑睡眠模式将会保持直到Can_SetControllerMode(CAN_T_WAKEUP)被调用。
Can_SetControllerMode(CAN_T_WAKEUP) --> SLEEP-->STOPPD:
如果CAN硬件不支持睡眠模式,Can_SetControllerMode(CAN_T_WAKEUP) 将从逻辑sleep模式中退出,但是不会影响到CAN Controller的硬件状态(因为硬件已经在STOPPED状态了)。
如果CAN硬件支持睡眠模式,Can_SetControllerMode(CAN_T_WAKEUP)将会等待一段时间,直到CAN Controller进入到STOPPED状态。
CAN-Bus报文唤醒:
CAN-Bus事件发生后CAN Controller从SLEEP状态切换到STOPPED状态,并且调用EcuM_CheckWakeup回调函数通知到EcuM模块。在CAN-Bus总线接收报文唤醒状态切换过程中调用Can_SetControllerMode(CAN_T_WAKEUP)函数将返回CAN_NOT_OK。仅支持硬件睡眠唤醒的ECU有这个特性。
Bus-Off事件:
Bus-Off事件发生后CAN Controller从STARTED状态切换到STOPPED状态,Bus-Off中断或者MainFucntion中调用CanIf_ControllerBusOff回调函数通知到CanIf层za
EcuM模块调用Can_Init函数完成CAN硬件的初始化。
Can模块将L-PDU中的ID,DLC,和Data设置到硬件的MessageBox当中,然后触发报文发送。
Can_Write函数将会存储PduInfo参数中swPduHandle子参数直到Can模块调用CanIf_TxConfirmation(swPduHandle是CanIf_TxConfirmation的一个参数)。
L-PDU发送成功后,CAN模块调用调用CanIf_TxConfirmation通知到CanIf层。
CAN模块直接从上层模块拷贝数据,数据一致性由上层模块保证。
为了防止接收到的消息丢失,一些控制器支持从一组硬件对象构建的FIFO。还有一些控制器,可以配置具有相同属性的另一个硬件对象,该硬件对象作为影子缓冲区,并在主对象繁忙时介入。
在RX接收中断或者Can_MainFunction_Read中将接收到数据拷贝到上一层。Can模块需要保证ISR或者Can_MainFunction不被自己中断,这样在拷贝数据到上一层的时候就不会发生数据不一致的问题了。
CAN模块处理的唤醒事件是能够被CAN controller检测到的,而不是Can Transceiver。两种可能的唤醒场景:中断唤醒和轮询唤醒事件唤醒。
唤醒事件的ISR中会调用EcuM_CheckWakeup,传递唤醒源参数通知到EcuM模块。然后ECU状态管理器将设置MCU,并通过Can接口调用Can模块,从而调用Can_CheckWakeup。
当通过轮询检测到唤醒事件时,EcuM将像之前一样通过Can接口周期性地调用Can_CheckWakeup。在这两种情况下,Can_CheckWakeup将检查是否有Can控制器检测到的唤醒,并返回结果。CAN驱动程序将通过EcuM_SetWakeupEvent通知EcuM唤醒事件。
防止错误唤醒事件的唤醒验证将由EcuM和CanIf模块在事后完成,而不需要Can模块的参与。
初始化CAN模块,完成CAN模块寄存器的静态配置。
软件触发CAN Controller的状态切换。Can_SetControllerMode函数将关闭唤醒up中断,同时检查唤醒状态。Can_SetControllerMode函数将启用新状态下需要的中断。当CAN中断已经被Can_DisableControllerInterrupts功能禁用时,禁止CAN中断将不被执行。
Can_DisableControllerInterrupts函数Disable所有的CAN Controller相关的中断。
Can_EnableControllerInterrupts函数Enable所有的CAN Controller相关中断。
Check当前控制器有没有唤醒发生,如果唤醒发生后调用EcuM_SetWakeupEvent通知到EcuM模块。
参数:Can_HwHandleType Hth 用于发送消息的HRH标识
Const Can_PduType * PduInfo 指向被发送的消息结构体
CanIf模块调用Can_Write函数发送报文
Can_Write函数首先Check用于发送报文的Hardware Obejcet(在Hth中被定义,可以理解未发送邮箱)是否是空闲的。如果空闲将执行以下操作,否则返回CAN_BUSY
RH850-U2A16共有RS-CANFD单元,每个unit有8路CAN通道,总共16路CAN通道。
RH850-U2A16可选的时钟源有四个,可以根据实际使用的CAN通道数和波特率选择时钟源。
RH850-U2A16每一路CAN有错误中断,发送中断,发送/接收 FIFO完成中断。每个units有全局的错误中断和接收FIFO中断。
RH850-U2A16发送邮箱配置(Payload为64字节):
--Normal模式:每个CAN通道最多可以配置64个发送邮箱MB
--TX Queue模式:4个TX Queue,每个Queue最大64个Buffers
--RX/Tx FIFO模式:最多3个FIFO,每个FIFO深度最大为128个Buffers
RH850-U2A16接收邮箱配置(Payload为64字节):
--Normal模式:每个CAN通道最多可以配置16个接收邮箱MB
--FIFO模式:8个Receive FIFO,每个FIFO最大深度128个Buffers,接收数据如果容易丢失的话就使用FIFO模式
--RX/Tx FIFO模式:最多3个FIFO,每个FIFO深度最大为128个Buffers
本文详细介绍了AUTOSAR架构下CAN Driver的基本概念,并介绍了RH850-U2A芯片的CAN硬件资源。基于RH850-U2A芯片的MCAL配置,请关注博主的后续文章。
参考文档:
1.Specification of Communication Manager 4.3.1
2. RH850/U2A-EVA GroupUser’s Manual: Hardware
瑞萨官网