我们知道CanDrive是通信协议栈中的最底层,之前的文章已经讲了在autosar架构中的Com服务层系列文章 Com通信系列介绍
我们废话不多说,直接进入今天的主题
为了与文档描述保持一致,下文将使用CAN模块来表示CAN Driver。简单地说,CAN模块属于一部分的最底层内容,其作用是执行硬件访问和为上层提供独立的硬件接口(这里能访问CAN模块的上层只有Can Interface模块)。说到访问硬件,先了解几个概念,如下图所示:
首先给出我们结论:如果我们想接受或者发生我们的消息,要保证两个状态机的状态 1.我们的Can Drive驱动状态机 2.对应Can Controller 控制器的状态机。
首先我们说一下Can Drive驱动状态机
CAN模块驱动状态机有两个状态,在上电或重置后,CAN模块进入CAN_UNINIT状态(未初始化状态),初始化后,CAN模块进入CAN_READY状态,这时可执行一些与读、写、总线关闭、唤醒和控制器状态设置相关的功能。也就是说CAN接收和发送必须在驱动状态机处于CAN_READY才能执行。
在驱动状态机处于CAN_READY状态前提下,还需要考虑CAN控制器状态。因为在硬件层面,CAN控制器会执行很复杂的状态机,去实现不同的硬件行为。有时是需要在相应的状态才会去实现某些功能,比如初始化,波特率设置等;有时是外部事件(总线关闭,唤醒事件)会触发状态变化,导致是否能执行某些功能。
出于简化目的,这里将CAN控制器的状态分为4个。
CAN控制器未初始化- UNINIT 属于CAN模块的所有寄存器都处于复位状态,不使能CAN中断。 CAN控制器不参与CAN总线。
CAN控制器状态已停止- STOPPED 在这种状态下,CAN控制器已初始化,但不参与总线。另外也不得发送错误帧和确认。
CAN控制器状态已启动- STARTED 控制器处于正常运行模式,具有完整的功能,这意味着它已加入网络。
对于许多控制器而言,离开“初始化”模式会使控制器启动。CAN控制器状态为睡眠- SLEEP 与STOPPED仅有的不同是:CAN的硬件设置支持睡眠模式(由CAN硬件支持唤醒的CAN总线直接唤醒)
通过上述定义可知:CAN接收和发送必须在控制器状态机处于STARTED状态才能执行。怎么能让CAN控制器处于STARTED状态呢,通过上述状态机不难发现,得先进入STOPPED状态才行。一般有以下几种方法来触发CAN控制器的状态转移到STOPPED:
文档对这4个状态和控制器模式设置函数Can_SetControllerMode都做明确的定义
上述两个状态一般都是先通过初始化函数设置,即在使用Can模块的任何其他功能之前,ECU状态管理器模块在启动阶段调用CAN模块的初始化函数(Can_Init)进行初始化,其内容有:
初始化后,CAN驱动状态为CAN_READY,CAN控制器状态为STOPPED。
当CAN模块满足条件,可以访问寄存器了,那么CAN模块怎么去实现CAN发送或接收所需的操作呢?以及需要做哪些操作呢??
在回答这两个问题前,为了发送或接收涉及的数据格式,需再介绍下PDU的概念,PDU包括协议控制信息(Protocol Control Information,PCI)和服务数据单元(Service Data Unit, SDU)。
其中SDU是指从上层模块传过来,要求发送的数据;或下层模块接收的,已提取好的数据,需要传给上层。
PCI是指需要将SDU从特定协议层的一个实例传递到另一实例。 例如。 它包含源和目标信息。PCI在发送方的协议层添加,再在接收方被删除。
通俗地理解就是:PDU不仅仅是数据(SDU),还携带了来自哪要去哪的信息(PCI);每到哪都会删掉之前的信息,添加这是哪要去哪的信息(不同层的PCI更新),如下图所示。
对于CanDrive来说,发送信号的要做两件事:一是先访问硬件,将数据写入寄存器;二是发送成功后,向上层CAN Interface模块确认。
针对写数据操作,CAN Interface模块调用Can_Write函数,其定义如下:
这里首先要说明下Hth的定义。每一个硬件对象都由ID,DLC和 SDU三部分组成,如下图15。用来存储写入数据的硬件对象就叫Hth,用来存储接收数据的硬件对象就叫Hrh
所以不难理解,Can_Write的输入参数Hth其实就是硬件对象的编号(id),而且实际上是已经定义好了硬件对象的编号与CAN ID的映射关系,比如下图16所示,如果想发送CAN ID 为0x001的数据,那么调用Can_Write函数的输入参数Hth应该为4。
然后引用文档内容说明下Can_Write函数要执行主要动作,如下所示:
这样我们就知道写数据的过程,最后再了解下发送确认过程,从前面文章可知,BSW调度器会周期性调用Can_MainFunction_Write函数,其定义如下:
注意这个函数调用的条件是CAN发送处理方式为POLLING(轮询)。这里说明下CAN发送处理方式,有3种:
(1)轮询模式(polling mode)
轮询模式下Can模块的发送确认被调度模块(BSW Scheduler)触发,执行随后的处理。比如设定CAN发送为轮询模式,那么Can_MainFunction_Write就会在预定义的时间间隔被周期性地调用(比如每几ms调用一次),然后Can_MainFunction_Write中再去调用上层的CAN Interface模块的CanIf_TxConfirmation模块,向上确认。
(2)中断模式(interrupt mode)
中断模式下Can模块的发送确认由CAN控制器的中断触发,执行随后的处理,比如设定CAN发送为中断模式,那么中断触发后,调用Can模块的发送确认处理函数,在该函数中去调用Can Interface模块的CanIf_TxConfirmation函数,向上确认。
(3)混合模式(mixed mode)
即(1)(2)的混合使用,看具体设定,是使用轮询模式还是使用中断模式的处理方式。
所以这里我选择的是轮询方式进行介绍。根据CanIf_TxConfirmation函数的输入参数可知,向上确认的是哪个CAN ID发送成功。(这里不对CanIf的函数介绍,下篇文章再介绍)
从前面文章可知,CAN接收时,对于CAN模块同样有两个操作:一是先访问硬件,从寄存器提取数据;二是通知上层CAN Interface模块,传递数据。
针对读数据操作,首先BSW调度器周期性调用Can模块的Can_MainFunction_Read函数,其定义如下。同样地CAN接收处理方式有轮询,中断和混合模式 。这里选择的是轮询模式。
最后,数据成功提取后,Can_MainFunction_Read函数将通过调用CanIf_RxIndication函数通知CAN Interface模块,向上传递数据。(这里不对CanIf的函数介绍,下篇文章再介绍)
我们用思维导图的形式去总结我们今天发送与接收操作的整个过程
预告:下一篇我们讲学习下Canif层的知识