CAN总线协议 (附带S32K系列的CAN报文接收驱动)

本文档意在记录笔者开发CAN时的心得与体会,纯属为了加深自己印象

CAN的基本知识:

① CAN的概念

        CAN是一种多主方式的串行通讯总线,1993年,CAN 已形成国际标准 ISO11898(高速应用)ISO11519-2(低速应用)

② CAN的总线结构:

       1.  ISO 11898

        ISO 11898标准的CAN总线网络,是闭环结构总线两端各连接一个120欧的电阻,两根信号线形成回路。是高速短距离的CAN网络,通信速率为125kbit/s~1Mkbit/s。在1Mbit/s通讯速率时,总线长度最长可达到40m

        2.  ISO 11519-2

        ISO 11519-2标准的CAN总线网络,是开环结构,两根信号线独立各自串联一个2.2k欧的电阻。是低速远距离的CAN网络,通信速率最高可达125kbit/s。在40kbit/s速率时,总线长度可达到1000m

3.  ISO11898ISO11519-2对比图

4.  CAN总线是异步通信

        CAN总线由两根信号线组成,CAN_HCAN_LCAN没有时钟信号,没有时间同步,是一种异步通信方式,注意的是,SPI、I2C是同步通信方式,他们有时钟线。

5.  CAN总线的差分信号

        CAN总线的两根信号线通常采用双绞线,传输的是差分信号,通过CAN_H与CAN_L的电压差来表示总线电平

        差分信号的优点:抗干扰能力强,能有效抑制外部电磁干扰

        同样使用差分信号来表示总线电平的还有RS485

6.  CAN总线的显性与隐性

        CAN总线逻辑1为隐性,总线逻辑0为显性(反着来,我是这样记的)

        CAN的总线逻辑1与逻辑0,对于开环结构和闭环结构是不一样的,因为开环结构与闭环结构形成的CAN网络中的CAN_H、CAN_L电压值不同,隐性电平和显性电平的电压值不同。

        大体判断:

                CAN_H与CAN_L的电压差大(开口)---->显性---->逻辑0

                CAN_H与CAN_L的电压差小(闭合)---->隐性---->逻辑1

        

        6.1  ISO 11898的显性与隐性(高速,闭环,短)

                显性---->总线逻辑0---->CAN_H与CAN_L开口---->电压差为2V左右

                隐性---->总线逻辑1---->CAN_H与CAN_L闭口---->电压差为0V左右

        6.2  ISO 11519-2的显性与隐性(低速,开环,长)

                显性---->总线逻辑0---->CAN_H与CAN_L开口---->电压差大于2V

                隐性---->总线逻辑1---->CAN_H与CAN_L闭口---->电压差小于0V

7.  CAN节点

        CAN网络中,没有主机、从机的概念,各个终端设备都称为节点,一个CAN节点的硬件部分,一般由CAN控制器+CAN收发器组成。

        CAN控制器:负责CAN总线的逻辑控制,实现CAN传输协议

        CAN收发器:负责MCU逻辑电平与CAN总线电平之间的转换

       CAN收发器:TXD与RXD是由MCU中接出来的引脚,比如MCU要发送一个逻辑1,只需要传给TXD一个逻辑1,经过CAN收发器,会将逻辑1转为差分信号,例如ISO 11898中,会将CAN_H与CAN_L线上的电压设置为2.5V,传到总线上为CAN_H - CAN_L ≈ 0V 隐性电平,逻辑1。

        同理,当CAN_H与CAN_L读到CAN总线电平分别为3.5V和1.5V,经过收发器转换,MCU可从RXD上读到逻辑0(CAN_H - CAN_L ≈ 2V 显性电平 逻辑0)

        

        注意:

                CAN控制器一般是MCU的片上外设CAN控制器一般是外接的单独的芯片

                在总线上显性电平具有优先权

③ CAN的波特率和位时序

        CAN总线协议的每一帧,可以看作一串连续的电平信号,

         波特率:一个CAN网络,需要规定一个统一的通信波特率,各节点都以相同的波特率进行数据通信。

        位时序:指一个节点,采集CAN总线上的一个位数据的时序。

        一位又分为4段:同步段(SS)、传播时间段(PTS)、相位缓冲段1(PBS1)、相位缓冲段2(PBS2)

        一位可以当做一条水平的时间轴,不同的段在整个时间轴的占比不一样,每一段由若干个最小时间单元Time Quantum(Tq)组成。

        位由多少个Tq构成、位里的每个段由多少个Tq构成等,都可以任意设定,这些组成了位时序

        通过设置位时序多个单元可同时采样,也可以任意设定采样点。

        通过位时序的控制,CAN总线可以进行位同步,以消除各个节点时钟的差异所产生的波特率误差问题,确保接收数据的准确性。

        有些地方也会将这样分

       在s32ds中的设置为

在stm32中的配置为

CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1=CAN_BS1_9tq;
CAN_InitStructure.CAN_BS2=CAN_BS2_6tq;
CAN_InitStructure.CAN_Prescaler=5;

SS 段(SYNC SEG):同步段

        在这个段内,总线上应该发送一次位信号的跳变。如果节点在同步段检测到总线上的一个跳变沿,就表示节点与总线是同步的。同步段的长度固定为1个Tq

PTS 段(PROP SEG):传播时间段

        这个时间段是用于补偿网络的物理延时时间,包括:发送单元的输出延迟、总线上信号的传播延迟、接收单元的输入延迟,一般大小为1~8Tq

PBS1 段(PHASE SEG1):相位缓冲段

        主要是用来补偿边沿阶段的误差,它的时间长度在重新同步时可以加长。PBS1段的初始大小可以为1~8Tq

PBS2 段(PHASE SEG2):另一个相位缓冲段

        也是用来补偿边沿阶段误差的,它的时间长度在重新同步时可以缩短。PBS2段的初始大小可以为2~8Tq

        对于PBS段而言,当信号边沿不能被包含于SS段中时,可以在此段进行补偿,吸收时钟误差

SJW (reSynchronization Jump Width):重新同步补偿宽度

        在重新同步时,PBS1和PBS2段的允许加长或缩短的时间长度,SJW加大后允许误差加大,但通信速度下降。SJW为补偿此误差的最大值,每一次误差补偿都不能超过这个值,1~4Tq

        CAN的同步

        1.  硬同步:在帧起始信号时,同步总线上所有器件的位时序,无法确保后续一连串的位时序都是同步的。

        2.  重新同步:在检测到总线上的时序与节点使用的时序有相位差时(即总线上的跳变沿不在节点时序的SS段范围),通过延长PBS1段或PBS2段来获得同步。

        同步过程:

                硬同步:硬同步阶段,当节点检测到本身SS段并不在总线电平下降沿跳变处,节点则会把自己的位时序中的SS段平移至总线出现下降沿的部分,后面部分的段,也会跟着后移,依次获得同步。即:节点在检测到帧起始信号(SOF)时,才开始"设置段"

        重新同步:重新同步阶段,利用普通数据位的高至低电平的跳变沿来同步(帧起始信号是特殊的跳变沿)。重新同步与硬同步相似的地方:它们都使用SS段来进行检测,同步的目的都是使节点内的SS段把跳变沿包含起来

第一种情况:相位超前,PBS段太短,PBS2后的SS段在跳变沿前,此时要延长PBS1

第二种情况:相位滞后,PBS段太长,PBS2后的SS段在跳变沿后,此时要缩短PBS2

       采样点

        读取总线电平的时刻,并将读到的电平作为位值的点。一般在PBS1结束处。在使用CAN工具的时候一般都需要设置采样点。

        延长/缩短PBS段来达到同步:

                PTS+PBS1小而PBS2加大,此时采样点前移

                PTS+PBS1大而PBS2减小,此时采样点后移

        

波特率的计算

        位时间长度NBT(一位的时间) = (SS段大小 + PTS段大小 + PBS1段大小 + PBS2段大小) x Tq

        注意:别忘记了,SS+PTS+PBS1+PBS2 是等于1个位,Tq的时间单位为s

        波特率 = 1/位时间长度NBT  (一秒能有多少位)

④ CAN的帧类型

        跳出位时序的框框,我们从大一点的角度看CAN信号

        CAN网络通信是通过5种类型的帧进行的:数据帧、遥控帧、错误帧、过载帧、帧间空间

        数据帧和遥控帧标准格式和扩展格式两种格式。标准格式有11个位的标识符(11个位的ID),扩展格式有29个位的标识符(29个位的ID)

        

帧类型帧用途
数据帧节点发送的包含ID和数据的帧,用于发送单元向接收单元传送数据的帧
遥控帧节点向网络上的其他节点发出的某个ID的数据请求,发送节点收到遥控帧后就可以发送相应ID的数据帧
错误帧节点检测出错误时,向其他节点发送的通知错误的帧
过载帧接收单元未做好接收数据的准备时发送的帧,发送节点收到过载帧后可以暂缓发送数据帧
帧间空间用于将数据帧、遥控帧与前后的帧分隔开的帧

数据帧:

        发送节点接收节点发送数据的帧

        数据帧由7个段组成:

                1. 帧起始:表示数据帧开始的段。

                2. 仲裁段:表示该帧优先级的段。

                3. 控制段:表示数据的字节数及保留位的段。

                4. 数据段:数据的内容,可发送0~8个字节的数据。

                5. CRC段:检查帧的传输错误的段。

                6. ACK段:表示确认正确接收的段。

                7. 帧结束:表示数据帧结束的段。

        帧起始:

                1个位的显性电平,表示帧开始

        仲裁段:

                表示数据优先级的段,标准格式和扩展格式在此的结构有所不同,通讯网络矩阵中的帧ID,也就是这里的数据。

        控制段:

                控制段由6个位构成,表示数据段的字节数。标准格式和扩展格式有所不同。

        数据段:

                0~8个字节,CANFD就是0~64字节,从MSB开始输出

        CRC段:

                检查帧传输错误的帧。

        ACK段:

                用来确认是否正常接收。

        帧结束:

                表示该帧的结束。由7个隐性电平位构成。

遥控帧(远程帧):

        用于接收节点发送节点请求发送数据所用的帧。

错误帧:

        当检测出错误时向其它单元通知错误的帧

过载帧:

        接收节点通知其未做好接收准备的帧

帧间空间:

        用于将数据帧及遥控帧与前面的帧分离的帧

CAN报文详解(S32K1系列)

        CAN报文的组成:帧ID + 帧数据

        帧ID分为:标准帧(11位ID)和扩展帧(29位ID)

在NXP S32K144的CAN模块(FlexCAN)中,CAN_Receive()函数的主要作用是从接收FIFO或邮箱中获取CAN帧数据。CAN_Receive函数会取出这些东西:

CAN_Receive()流程:

        1.  检查当前是否可以接收数据

        2.  读取ID段,判断该报文是否匹配所设置的接收过滤规则

        3.  读取DLC,确定数据长度

        4.  读取数据段,存储到用户提供的缓冲区中

        5.  清除中断标志,准备下一次接收

ID(仲裁段)

                对于标准帧(11位ID)

                对于扩展帧(29位ID)

DLC(数据长度)

        数据段的长度(CAN 0~8字节,CAN FD 0~64字节)

CRC(循环冗余校验)

        硬件自动处理,不会暴露给用户代码

ACK、EOF(结束帧)、帧间隔等

        这些字段在CAN硬件通信过程中自动处理,CAN_Receive()不会直接涉及这些字段

当有CAN报文来时,会进入注册的CAN中断中,在CAN中断中,创建一个结构体can_message_t *msg = NULL;  之后使用CAN_Receive()接收数据,并映射到这个结构体上,然后通过结构体,去获取帧ID与数据,将帧ID与数据,保存至我们自己创建的缓冲区中,然后轮询缓冲区是否有东西,这样去处理CAN报文

//首先,CAN模块初始化时,就需要注册CAN中断
CAN_InstallEventCallback(&can_pal1_instance, AnyName_Callback, NULL);


//具体的中断函数
void AnyName_Callback(uint32_t instance, can_event_t eventType, uint32_t objIdx, void *driverState)
{
    if(CAN_EVENT_TX_COMPLETE == eventType)
    {
        //判断中断事件,这里是发送完成中断
    }
    
    if(CAN_EVENT_RX_COMPLETE == eventType)
    {
        //判断中断事件,这里是接收完成中断
        can_message_t *msg = NULL;//创建一个结构体,待会好取数据
        
        if(objIdx == RX_MB0)//判断是哪一个邮箱的数据
        {
            CAN_Receive(&can_pal1_instance, RX_MB0, &CAN_RX0_Message_Buffer[0]); 
             //CAN_RX0_Message_Buffer[0]是自己创建的
            msg = &CAN_RX0_Message_Buffer[0];//映射过来,待会好取东西
        else if(objIdx == RX_MB1)
        {
            CAN_Receive(&can_pal1_instance, RX_MB1, &CAN_RX1_Message_Buffer[0]); 
             //CAN_RX0_Message_Buffer[0]是自己创建的
            msg = &CAN_RX1_Message_Buffer[0];//映射过来,待会好取东西
        }
        else if(objIdx == RX_MB2)
        {
            CAN_Receive(&can_pal1_instance, RX_MB2, &CAN_RX2_Message_Buffer[0]); 
             //CAN_RX0_Message_Buffer[0]是自己创建的
            msg = &CAN_RX2_Message_Buffer[0];//映射过来,待会好取东西
        }
    }

    if(msg != NULL)
    {
        //获取CAN数据
        msg -> id
        msg -> data
        msg -> length  //这个是代表数据的长度
        根据需要自己取
    }

}

解析CAN中断函数

void xxxxx(uint32_t instance, can_event_t eventType, uint32_t objIdx, void *driverState)

        instance:CAN实例编号,作用为识别哪个CAN模块触发了该回调函数。

        eventType:事件类型,作用为此次回调函数对应的事件类型,包括:

1.CAN_TX_COMPLETE(发送完成): 表示一条消息已经从指定邮箱成功发送出去。

2.CAN_RX_COMPLETE(接收完成): 表示一条消息已经成功接收到,通常需要进一步读取数据。

3.CAN_ERROR(错误事件): 表示在传输或接收过程中检测到了错误,如仲裁错误、总线错误等。

4.其它具体事件类型,根据 SDK 定义可能还会有其他细分事件

        objIdx:对象索引,作用为标识触发该事件的邮箱或FIFO索引。对于Rx事件,它代表了哪个接收缓冲区中有新数据到来了

        driverState:驱动状态指针,作用为,用户可以访问或修改驱动的运行状态、统计信息等

status_t CAN_Receive(const can_instance_t * const instance,
                     uint32_t buffIdx,
                     can_message_t *message);

instance:

        说明:指向can_instance_t结构体的指针,该结构体包含了CAN控制器的配置、寄存器地址及驱动状态信息。

        作用:用于标识和访问当前使用的CAN模块。在多CAN实例的应用中,此参数用于区分不同的硬件实例。

buffIdx:

        说明:一个无符号 32 位整数,表示接收缓冲区或邮箱的索引。

        作用:用于指定从哪个接收邮箱或 FIFO 缓冲区中读取数据。在配置接收滤波器或者循环使用接收邮箱的场景中,buffIdx 帮助驱动准确定位到目标消息存储区域。

message:

        说明:指向 can_message_t 结构体的指针,该结构体用于存储接收到的 CAN 消息。自己定义好。

        作用:函数将解析出的 CAN 数据帧(包括 ID、数据长度、数据内容等)填入这个结构体,供上层应用进行后续处理。

### S32K3 Microcontroller CAN FIFO Configuration and Usage In the context of configuring and using the CAN FIFO on an S32K3 microcontroller, several key aspects must be considered to ensure efficient message handling. The CAN FIFO feature allows for a more streamlined software design by managing received messages through buffers organized as queues[^1]. The setup process involves initializing specific registers that control how incoming frames are handled within these buffer structures. For instance, setting up masks plays a crucial role when aiming to receive all possible IDs without limitation. To achieve reception of any ID regardless of its value: - All mask bits should be set to `0`, which means every bit position will not affect whether or not a frame is accepted into one of the available slots. For practical implementation purposes, consider this C code snippet demonstrating initialization steps tailored towards enabling such functionality: ```c // Initialize CAN module with desired parameters (e.g., baud rate) CAN_Init(CAN_MODULE_BASEADDR); // Configure filter mode to accept all IDs by disabling filtering via masking uint8_t canFilterConfig[] = {0x00}; // Mask register initialized to zero CAN_SetRxMask(CAN_MODULE_BASEADDR, &canFilterConfig); ``` This approach ensures flexibility during development phases where testing various types of communication scenarios becomes necessary. Moreover, it simplifies debugging efforts since there's no need to worry about predefining acceptable identifiers beforehand. Additionally, leveraging FIFO capabilities enhances performance especially under high-load conditions due to reduced CPU intervention required for processing each individual event compared to traditional interrupt-driven methods[^2]. #### Important Considerations When working with CAN FIFOs in applications requiring robustness against data loss, monitoring queue status regularly helps prevent overflow situations leading to dropped packets. Implementing proper error-checking mechanisms also contributes significantly toward maintaining reliable operation over time.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值