【Autosar】MCAL - CAN(NXP - S32K14x)

MCAL - CAN(NXP - S32K14x)

MCAL - 汇总

  • 配置工具:EB Tresos Studio
  • 芯片类型:S32K146

1. 概述

在这里插入图片描述

S32K146内部FlexCan模块结构如上图所示,各模块功能介绍如下:

  • Bus Interface Unit:总线接口,建立与其他模块之间的访问(DMA/中断/时钟…)

  • Controller Host Interface:

    • Tx Arbitration:发送仲裁
    • Rx Matching:接收匹配
  • Message Buffers:数据缓存区

  • Protocol Engine:

    • CAN FD监测
    • 错误处理
    • 接收验证
    • 请求RAM访问以接收和发送数据帧

1.1 邮箱

1.1.1 邮箱资源

在这里插入图片描述

S32K14x系列FlexCan资源如上图所示,S32K146有三个FlexCAN模块且有2个支持CAN FD功能,其中FlexCAN0和FlexCAN1拥有32个邮箱,FlexCAN2拥有16个邮箱,以上邮箱个数是基于数据长度为8Byte时的邮箱个数,长度为16/32/64Byte时邮箱个数如下图所示:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

1.1.2 邮箱构成

在这里插入图片描述

邮箱结构如上图所示,前8个字节包含了报文的基本信息,后面是报文的数据,最多可以存放64个字节,各字段功能如下:

  • EDL:CAN / CAN FD
  • BRS:CAN FD帧格式的速率切换
  • ESI:标识发送节点是错误主动还是错误被动
  • CODE:邮箱当前状态(具体请参考 S32K-RM:Table 55-11)
  • SRR:保证数据帧格式优先于扩展帧(因此设置为扩展帧时此位置1)
  • IDE:标准帧 / 扩展帧
  • RTR:数据帧 / 远程帧
  • DLC:数据长度
  • TIME STAMP:时间戳(任何帧的标识符的第二位出现在总线上时,Free Running Timer (TIMER)值被捕获,当传输/接收结束时该值被写入TIME STAMP)
  • PRIO:优先级用于邮箱的发送仲裁
  • ID:报文ID

DLC长度对照表:

在这里插入图片描述

1.2 发送流程

在这里插入图片描述

用户将数据填充至发送邮箱,注意:CODE字段最后写入,当写入CODE字段后会激活邮箱并加入仲裁机制,仲裁胜出的邮箱内容将被拷贝到隐藏邮箱(SMB),SMB中的数据将被protocol engine遵循can协议规则发送至can总线。

1.2.1 发送仲裁
  • 编号越小优先级越高:LUBF寄存器置1
    在这里插入图片描述
  • 比特序列仲裁:CAN总线仲裁机制
    在这里插入图片描述
  • 优先级仲裁:邮箱中设置的优先级将被增加到仲裁机制当中,PRIO值越低优先级越高
    在这里插入图片描述

1.3 接收流程

在这里插入图片描述

protocol engine从can总线接收到报文后存入隐藏邮箱(SMB),recive process(接收进程)将SMB中的ID与接收邮箱中的ID进行匹配,匹配成功后将数据存入邮箱。

1.4 波特率计算方式

1.4.1 位时序概述

位时序参考文档

CAN通信的每一位数据位是由4个段组成,如下图所示:
在这里插入图片描述

  • SYNC_SEG:同步段
  • PROP_SEG:传播时间段
  • PHASE_SEG1:相位缓冲段 1
  • PHASE_SEG2:相位缓冲段 2
  • SJW:重新同步跳跃宽度(用于采样点容差)

这些段的作用是为了同步节点之间的数据传输,保证采样点的一致性,在同一个CAN网络中,所有节点根据MCU频率、采样点都会指定位时序的参数,例如我是零部件供应商,那么我会根据主机厂给定的CAN开发协议来设定这些值。

采样点计算公式:SP = (SYNC_SEG + PROP_SEG + PHASE_SEG1)/ (SYNC_SEG + PROP_SEG + PHASE_SEG1 + PHASE_SEG2)

SJW:重同步,用于延长或缩短PTS1和PTS2以补偿采样点的偏差。(1-4TQ,并且不能超过PHASE_SEG1和PHASE_SEG2)。例如SJW=1TQ,总TQ数为20,那么容差就是1 / 20 = 5%。如果采样点设置的是80%,那么容差就是75% - 80%。
在这里插入图片描述

第二采样点计算公式:SSP = OFFSET * DIV / Bit Time + 5%
注意:
1. OFFSET * DIV :取决于芯片类型,有些要求使用分频前的时钟进行计算,有些需要使用分频后的时钟进行计算
2. 5%:偏差值,需要根据不同芯片实际测量值所得

TDCO = Propagation Delay+Transceiver Delay+Node Processing Delay

1.4.2 波特率计算公式

在这里插入图片描述

PE Clock:CAN模块的报文发送与接收都是由PE Engine控制,它的时钟频率决定波特率。

如下图所示,PE Clock的时钟源有两个选择,外设时钟频率和晶振时钟频率,如果对于通信时序公差比较严格,则建议使用晶振时钟频率(防抖效果更好)。
在这里插入图片描述
CAN通讯中,一个数据位由4各段组成,每个段由多个Tq组成,一个数据位则由多个Tq组成,最终波特率计算公式如下所示:

① Tq = (PRESDIV + 1) / fcanclk
② CAN Bit Time = (Number of Time Quanta in 1 bit time) * Tq
③ Bit Rate = 1 / CAN Bit Time

例:CAN波特率为500kHz,输入时钟选择外设时钟(SYS_CLK:80MHz):

① CAN Bit Time = 1 / Bit Rate = 1 / 500kHz = 0.000002s

② 0.000002 = Num * (PresDiv + 1)/ 80MHz

③ Num * (PresDiv + 1)= 160

Num:8 ~ 25

PresDiv:0 ~ 255

因此我们可以配置PresDiv:7,Num:20

④ Num分配的依照产品开发的CAN协议手册规约,每个产品开发的时候都有严格的约束。

2. API

函数描述
Can_InitCAN模块初始化
Can_ChangeBaudrate修改波特率
Can_CheckBaudrate检查波特率
Can_SetControllerMode设置CAN控制器模式
Can_DisableControllerInterrupts禁用CAN中断
Can_EnableControllerInterrupts使能CAN中断
Can_WriteCAN信号发送
Can_MainFunction_Write发送确认(轮询函数)
Can_MainFunction_Read接收确认(轮询函数)
Can_MainFunction_BusOffBussOff确认(轮询函数)
Can_MainFunction_Mode模式确认(轮询函数)

3. 配置介绍

3.1 General

在这里插入图片描述

Can Main Function Busoff Period:Can_MainFunction_BusOff函数的调用周期(CAN驱动中不使用,应在上层SchM模块使用)

Can Main Function Mode Period:Can_MainFunction_Mode函数的调用周期(CAN驱动中不使用,应在上层SchM模块使用)

Can Multiplexed Transmission:多路传输,启用后,如果目标MB处于Busy状态,则寻找其他空闲的且Object ID相同的邮箱进行发送

Can Maximum Message Buffers:最大邮箱个数

CanLPduReceiveCalloutFunction:LPDU(Id/Data/Length)接收回调函数

Can define loop as cycle:不使用OS的情况下勾选,不勾选则会引入"Os.h"

Can Timeout Duration (in Number of loops) :超时时间,各个循环中的超时计数

Can Extended ID Support:ID数据类型(true:uint32 false:uint16)

Can MB Count Extension Support:邮箱数据类型(true:uint16 false:uint8),如果定义的邮箱个数超过255,则必须开启

Message buffer data size:数据域大小(在控制器的波特率界面开启CAN FD后生效)

3.2 CanController

3.2.1 General

在这里插入图片描述

Can Hardware Channel:CAN硬件通道选择

Can Controller Activation:勾选后此通道的配置信息才会生效,否则生成的配置信息都是空的

Can Rx Processing Type:中断/轮询确认接收数据

Can Tx Processing Type:中断/轮询确认发送数据

Can BusOff Processing Type:中断/轮询确认BussOff

以上三者相同,选择触发事件后是通过轮询的方式还是中断的方式获取通知信息

Can Listen Only Mode:只收不发模式

Can Loop Back Mode:自发自收模式

Can Lowest Buffer Transmit First:仲裁机制(邮箱编号越低优先级越高)

Can Local Priority Enable:仲裁机制(本地优先级 - 参考仲裁机制部分)

Can Clock from Bus:PE时钟选择(true:系统时钟 false:外设时钟)

Can Controller Default Baudrate:波特率

Can CPU Reference Clock:参考时钟

3.2.1 CanControllerBaudrateConfig
3.2.1.1 General

在这里插入图片描述

Can Time Segments Checking:位序列检查

Can Tx ArbitrationStart Delay:仲裁启动延迟

Can Controller Prescaller:时钟分频(生成的配置自动-1)

Can Controller BaudRate:波特率

Can Propagation Segment:传播时间段(生成的配置自动-1,范围1~8)

Can Phase Segment 1:相位缓冲段1(生成的配置自动-1,范围1~8)

Can Phase Segment 2:相位缓冲段2(生成的配置自动-1,范围2~8)

Can Resynch Jump Width:跳转宽度(范围1~4)

3.2.1.2 CanControllerFdBaudrateConfig

在这里插入图片描述

Can FD Controller BaudRate (dynamic range):波特率

Can FD Propagation Segment:传播时间段

Can FD Phase Segment 1:相位缓冲段1

Can FD Phase Segment 2:相位缓冲段2

Can FD Resynch Jump Width:相位缓冲段2

CanControllerTxBitRateSwitch:速率切换

CanControllerFdIsoCANFD:使能CAN FD

CanControllerFdPrExcEn:

CanControllerFdEdgeFilterDis:

3.3 CanHardwareObject

在这里插入图片描述

FD padding value:CAN FD填充数据(使能CAN FD后开启)

Can Implementation Type:Basic / Full

Can ID Message Type:报文类型(标准 / 扩展 / Mixed)

Can ID Bits Local Priority:本地优先级,用于发送时邮箱仲裁机制(范围:0~7)

Can Object ID:HOH句柄

Can MB Type:邮箱类型(发送 / 接收)

CanTriggerTransmitEnable:

Can Controller Reference:控制器选择

Can MainFunction RW Period Reference:读写轮询周期选择

Can Hw Filter Code:匹配码

Can Hw Filter Mask:掩码

3.4 CanMainFunctionRWPeriods

在这里插入图片描述

生成如下宏定义供上层使用,CAN驱动自己不使用:

#define CAN_MAINFUNCTION_PERIOD         (0.001F)
#define CAN_MAINFUNCTION_PERIOD_READ    (0.001F)
#define CAN_MAINFUNCTION_PERIOD_WRITE   (0.001F)

4. 配置介绍扩展

4.1 HwFilterCode / HwFilterMask

  • Can Hw Filter Code:匹配码的作用是用于和接收到的报文做比较
  • Can Hw Filter Mask:掩码的作用是决定比较ID的哪几个Bit

如下图所示,掩码置1的位置,报文ID和匹配码必须一致,否则将被过滤,掩码置0的位置忽略比较。

在这里插入图片描述
掩码计算方式如下所示:

static void MaskCalcTest()
{
    uint code = 0x15F;
    uint mask = 0x7FF;

    uint[] id = { 0x188, 0x198, 0x257};

    foreach (var item in id)
    {
        mask &= ~(code ^ item);
    }

    Console.WriteLine(mask);
}

4.2 Basic / Full

  • Basic:该邮箱允许接收一组报文

    现象:接收由Can Hw Filter CodeCan Hw Filter Mask划定范围的报文。

    原理:Can Hw Filter Code被设置到邮箱的ID字段,Can Hw Filter Mask被设置到该邮箱对应的RXIMR寄存器。

  • Full:该邮箱只接收一个报文

    现象:只接收与Can Hw Filter Code一致的报文。

    原理:Can Hw Filter Code被设置到邮箱的ID字段,RXIMR寄存器设置为0xFFFFFFFF(所有位都匹配)。

4.3 Can ID Message Type(Mixed)

  • 接收配置成Mixed相当于配置成扩展帧
  • 发送的时候不关心此配置,根据报文ID的IDE位判断是否是扩展帧
#if (CAN_EXTENDEDID == STD_ON)
if ( (u32MbMessageId & FLEXCAN_MBC_ID_IDE_U32) != (uint32)0U)
{
    /* Set the IDE bit in the MBCS register of the MB */
    u32MbConfig |= FLEXCAN_MBCS_IDE_U32;
    /* Clear the MSB bit of the id - this is used for sending embedded information by CanIf to Can to say if it is an extended or standard message type. */
    u32MbMessageId &= (~FLEXCAN_MBC_ID_IDE_U32);
}
else
{
    #endif /* (CAN_EXTENDEDID == STD_ON) */
    /* Standard ID - need to shift left 18 bits. */
    u32MbMessageId <<= FLEXCAN_STANDARD_ID_SHIFT_U32;
    #if (CAN_EXTENDEDID == STD_ON)
}
#endif /* (CAN_EXTENDEDID == STD_ON) */

参考资料:

S32K-RM.pdf - NXP

AUTOSAR_MCAL_CAN_UM[1].pdf - NXP

使用MegalocanMCAL)库来操作CAN总线,首先需要配置CAN接收器以便捕获CAN报文。一旦接收到CAN消息,你可以将其保存在内存中,然后将这些信息封装成适合通过以太网传输的结构。以太网通信通常涉及到使用TCP/IP协议栈,可以使用标准的套接字API或者更高级的库(如Python的socket模块)来建立连接并发送数据。 以下是简化步骤: 1. **初始化CAN接收**: - 初始化MCAL CAN驱动,设置接收滤波器以指定兴趣的ID范围。 - 开始接收循环,当有新报文到来时,读取并处理它。 ```python from mcal import CAN can = CAN() can.init() # 初始化CAN设备 can.set_filter(...) # 设置接收过滤条件 can.start_receiving() ``` 2. **接收和保存CAN报文**: -CAN接收到报文时,获取其ID和数据,并存入数据结构(如字典或列表)供后续处理。 ```python while True: message = can.receive() if message is not None: received_candata = { 'id': message.id, 'data': bytes(message.data), ... } ``` 3. **以太网发送**: - 创建一个以太网数据包,将CAN报文数据插入适当的位置(比如在UDP/TCP数据部分)。 - 使用socket库发送数据。 ```python import socket eth_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) eth_socket.sendto(encoded_can_data, ('ethernet_host', port)) ``` 4. **以太网接收**: - 对于以太网,你可以监听来自特定主机的报文,或者使用轮询/事件驱动的方式接收数据。 - 接收以太网数据后,解析数据,找到其中包含的CAN报文信息,并通过CAN发送。 ```python while True: data, addr = eth_socket.recvfrom(BufferSize) decoded_data = decode_ethernet_data(data) if should_send_can(decoded_data): send_can_message(decoded_data) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值