S32K3学习笔记---S32K3之CAN模块

S32K3学习笔记—S32K3之CAN模块

1.前言

​ CAN通信比较重要性,本文是基于S32K324 RTD3.0做的一个简单调试,在两个核分别注册一路CAN,会分别介绍中断和轮询两种方式,一般而言BT用轮询,APP里面一般用中断。其次也是介绍一下CANFD和CAN,主要记录整个过程。

2.原理

​ FlexCAN 模块是CAN协议的一个高完成度版本,带有CANFD协议和 CAN 2.0 B 版本协议,支持标准和拓展数据帧和长达 64 字节的数据传输,频率最大可达到 8Mbps。NXP的FLEXCAN个人感觉很复杂,要想全部了解就只能看芯片手册,下面只简单的介绍几个基本概念

image-20231126224702048

各模块功能如下:

​ 1.Bus Interface Unit (BIU):允许时钟、寻址、数据总线、中断、DMA和测试信号访问模块

​ 2.Controller Host Interface (CHI):消息缓存区仲裁和匹配算法。

​ 3.Protocol Engine (PE): 请求RAM访问、错误处理、验证接收帧、探测CAN FD帧。

一些关键功能:

​ 1.可配置长度(0,8,16,32,64 Bytes)的邮箱

​ 2.接收或者传输未使用的RAM可以用作通用的RAM

​ 3.CANFD的增强型FIFO可以储存20CANFD frames以及DMA支持

​ 4.优先级机制:最低的ID,缓存区数量最少,优先级最高

​ 5.CAN0最大96mbs, CAN1、CAN2最大64mbs

普通CAN和CANFD的区别:

image-20231202195838962

FlexCAN消息缓冲区结构

​ 1.CAN规范(版本2.0第B部分)中使用的扩展(29位标识符)和标准(11位标识符)帧都有表示。每个单独的消息缓冲 区是16、24、40或72个字节,这取决于为消息有效载荷分配的数据字节数量:分别为8、16、32或64个数据字节。

​ 2.存储区域80h–67Fh由消息缓冲器使用。启用CAN FD时,每个消息缓冲区的确切地址取决于其有效负载的大小

image-20231202203442011

​ EDL:拓展数据位。用来区分是普通 CAN 帧还是 CANFD 。当 CODE 字段为 0110 时,该位不能置1

​ BRS:位速率选择位。该位决定在 CANFD 模式下是否切换速率

​ ESI:错误状态位。该位指示发送节点是主动错误还是被动错误

​ CODE:报文缓冲区码。该字段可以被 MCU 和 FlexCAN 模块访问(读和写),作为报文缓冲区匹配与仲裁过程的一部 分

FlexCAN具有以下功能模式:

image-20231202204739974image-20231202204756918

​ 其他的像发送过程、接收过程、仲裁过程等看芯片手册

3.EB配置

​ 关于MCAL的配置,其可能依赖模块包括:Port、Platform、Mcu、Mcl、Can

​3.1 port

​ 主要是配置TX和RX,下图是将PTA6和PTA7复用为CAN0的RX和TX,其主要配置如下,具体Port和platform配置可参考之前文章 S32K3学习笔记—S32K3之Gpt、Dio、Platform

image-20231125230030259

image-20231125230639104

image-20231125230707881

3.2 paltform

​ 如果不是用的Interupt的方式,此处可以不配置, 此处主要是使能CAN的中断。

image-20231125230948945

3.3 Mcu

​ Mcu配置如下,具体的配置细节可以参考S32K3学习笔记—S32K3之MCU模块

image-20231126170602657

​ 此处配置两个用于不同硬件CAN的参考时钟就行。还有一点需要注意的,不要忘记在McuPeripheral中使能相应外设的时钟。

3.4 Mcl

​ 如果我们要用的FIFO+ DMA的形式,就需要在Mcl里面配置DMA的逻辑通道相关,此处由于自己没用过这种模式,所以暂不给出配置,如果后续有用到这种模式再回来补

注意:

​ 1.只有在使能FIFO的情况下,才能使用DMA来接收数据

​ 2.发送是不能使用DMA的

3.5 CAN

​ 首先先介绍一下polling或者Interuput的通用配置,相对比较简单。
image-20231125232722176

1.使能支持多核

2.成功接收到L-PDU后的回调函数,看需求使能

3、4.默认使能,芯片自身特定参数

5.使能修改波特率的API

image-20231125233216486

1.可以注册到两个核分区

image-20231125233247234

1.Can_MainFunction_Read或Can_MainFunction_Write的周期。单位是秒。用于polling模式

image-20231125233550714

1.在此处注册所需要的HRH和HOH

需要注意,此处一定是所有的receive之后才能注册transmit

image-20231202211938996

1.可以存储的最大L-PDU有效负载长度,CAN-8bytes,CANFD-64bytes

2.Can实现类型:basic 、full。一般诊断和网络管理报文选择basic ,其他的选择full

3.注意:对于接收邮箱的配置,如果设置成MIXED,那么程序则会将邮箱初始化成extended。

4.选择接收还是发送

5.如果前面选择的polling模式,需要使能5,选择对应的发送/接收的周期

6.增强型FIFO需要使能

接下来就是报文ID和掩码的配置,此处有两种组合

A.固定的ID报文

image-20231202213420484

​ 1.这种ID Filter+掩码的配置,只能接收0x110和0x120两条报文

B.范围ID报文

image-20231202213806308

​ 1.只有0x110 ~ 0x11f的ID报文才会被接收

​ 如下是CAN TX的object。对于发送的object配置相对简单,不需要配置CanHwFilter,只需要配置general

image-20231202213959913

​ 1.选择发送

​ 2.根据模式选择,polling需要使能该选项

接下来是CAN控制器配置

image-20231126165118856

1.使能CAN控制器

2、3、4.CAN rx tx busoff的方式,选择polling 或者 interrupt

5.是否在环回模式下运行,看需求

6.是否支持busoff自恢复

7.是否使用CANFD协议,如果只用普通CAN则不使能此选项

8.默认波特率配置参考,具体配置见后文

9.此路CAN注册到哪个核

10.CAN的时钟参考,在MCU模块配置,需要主要CAN0_2是一种时钟,CAN2_5是另外一种时钟

接下来就是CAN波特率的配置

image-20231126172307328

1.ENHANCE_CBT:提供更高的位定时分辨率,存储在ENCBT、EDCBT和EPRS寄存器中。

2.该5位字段指示从CAN总线上的CRC字段的第一位开始,Tx仲裁过程起始点可以延迟多少CAN位,默认12

3.预分频系数

4.CAN控制器的波特率 波特率 = 时钟频率(40M) / 3 /(5 + 6 + 7 + 8) 如:500K = 40M /1/(1+47+16+16)

​ 此外,采样点的公式 采样点 = 1 - 8 / (5 + 6 + 7 + 8) 如:采样点 = 1 - 16/(1+47+16+16)*100% = 0.8

5、6.同步段、传输段

7、8.相位段1 、相位段2

9.指定控制器的同步跳跃宽度

​ 如果不用CANFD,此配置可以不使能,对于CANFD 波特率和采样点的公式也是一样的,CANFD的配置如下:

image-20231126173654350

1.波特率 = 时钟 / 分频系数 / (2 + 3 + 4 + 5) 例如: 2000K = 40M / 1/ (1 + 7 + 6 + 6)

6.指定控制器的同步跳跃宽度

7.指定变送器延迟补偿偏移

8.指定传输是否应使用比特率切换

接下来就是使能FIFO

image-20231126180224835

1.Legacy FIFO是不支持CANFD的,Enhanced FIFO支持CANFD。

2.指定FIFO的过滤方案

3.使能使能DMA,此处不使能DMA,如果有需要可以使能

​ 至此,核0的CAN的配置完成了,同样,核1只需要做相同的操作就能注册一路CAN,最后只需要将EB生成的代码导入工程,进行调试就行

4.代码调试

1.polling

/*		main_c0		*/
uint8 CanIf_u8TxConfirmCnt = 0U;
boolean CanIf_bTxFlag = FALSE;
uint8 CanIf_u8RxIndicationCnt = 0U;
boolean CanIf_bRxFlag = FALSE;

void CanIf_ControllerBusOff(uint8 ControllerId)
{
    (void)ControllerId;
}

void CanIf_ControllerModeIndication(uint8 ControllerId, Can_ControllerStateType ControllerMode )
{
    (void)ControllerId;
    (void)ControllerMode;
}
void CanIf_TxConfirmation(PduIdType CanTxPduId)
{
    CanIf_u8TxConfirmCnt++;
    CanIf_bTxFlag = TRUE;
    (void)CanTxPduId;
}

void CanIf_RxIndication(const Can_HwType* Mailbox, const PduInfoType* PduInfoPtr )
{
    CanIf_u8RxIndicationCnt++;
    CanIf_bRxFlag = TRUE;
    (void)Mailbox;
    (void)PduInfoPtr;
}

void Can_DummyDelay(uint32 loops)
{
    VAR( volatile uint32, CAN_VAR) data = 0xAA55AA55;
    VAR( volatile uint32, CAN_VAR) contor1 = 0;
    VAR( volatile uint32, CAN_VAR) contor2 = loops;

    do
    {
        for (contor1 = 0; contor1 < 0x2FF; contor1++)
        {
            data ^= (1 << contor1) | (0xAAAAAA | contor2);
        }
        contor2--;
    } while( contor2 > 0);
}

Can_PduType Can_CreatePduInfo(Can_IdType id, PduIdType swPduHandle, uint8 length, uint8* sdu)
{
    Can_PduType PduInfo;
    
    PduInfo.id = id;
    PduInfo.swPduHandle = swPduHandle;
    PduInfo.length = length;
    PduInfo.sdu = sdu;
    
    return PduInfo;
}

int main_c0(void) 
{
    uint8 u8TimeOut = 100U;
    CanIf_bTxFlag = FALSE;
    CanIf_bRxFlag = FALSE;
    /* Initialize the Mcu driver */
#if (MCU_PRECOMPILE_SUPPORT == STD_ON)
    Mcu_Init(NULL_PTR);
#elif (MCU_PRECOMPILE_SUPPORT == STD_OFF)
    Mcu_Init(&Mcu_Config_VS_0);
#endif /* (MCU_PRECOMPILE_SUPPORT == STD_ON) */
    /* Initialize the clock tree and apply PLL as system clock */
    Mcu_InitClock(McuConf_McuModeSettingConf_McuModeSettingConf_0);

#if (MCU_NO_PLL == STD_OFF)
    while ( MCU_PLL_LOCKED != Mcu_GetPllStatus() )
    {
        /* Busy wait until the System PLL is locked */
    }

    Mcu_DistributePllClock();
#endif

    Mcu_SetMode(McuModeSettingConf_0);

    /* Initialize Platform driver */
    Platform_Init(NULL_PTR);  
    static Can_PduType Can_PduInfo;
    
    /* Can_CreatePduInfo(id, swPduHandle,length, sdu) */
    Can_PduInfo = Can_CreatePduInfo(0U, 0U, 8U, Can_au8Sdu8bytes);
    /* Initilize Can driver */
#if (CAN_43_FLEXCAN_PRECOMPILE_SUPPORT == STD_ON)
    Can_43_FLEXCAN_Init(NULL_PTR);
#else
    Can_43_FLEXCAN_Init(&Can_43_FLEXCAN_Config_VS_0);
#endif
    Can_43_FLEXCAN_SetControllerMode(CanController_0, CAN_CS_STARTED);
    if((Can_43_FLEXCAN_Write(CanHardwareObject_2, &Can_PduInfo) == E_OK))
    while((!CanIf_bTxFlag) && (u8TimeOut != 0U))
    {
        Can_43_FLEXCAN_MainFunction_Write();
        Can_DummyDelay(100U);
        u8TimeOut--;
    }
        
    u8TimeOut = 100U;
    while((!CanIf_bRxFlag) && (u8TimeOut != 0U))
    {
        Can_43_FLEXCAN_MainFunction_Read();
        Can_DummyDelay(100U);
        u8TimeOut--;
    }
    Can_43_FLEXCAN_SetControllerMode(CanController_0, CAN_CS_STOPPED);
    Can_43_FLEXCAN_DeInit();
    
    return (0U);
}


/*		main_c1		*/
int main_c1(void) 
{
    uint8 u8TimeOut = 100U;
    CanIf_bTxFlag = FALSE;
    CanIf_bRxFlag = FALSE;
    /* Initialize the Mcu driver */
#if (MCU_PRECOMPILE_SUPPORT == STD_ON)
    Mcu_Init(NULL_PTR);
#elif (MCU_PRECOMPILE_SUPPORT == STD_OFF)
    Mcu_Init(&Mcu_Config_VS_0);
#endif /* (MCU_PRECOMPILE_SUPPORT == STD_ON) */
    /* Initialize the clock tree and apply PLL as system clock */
    Mcu_InitClock(McuConf_McuModeSettingConf_McuModeSettingConf_0);

#if (MCU_NO_PLL == STD_OFF)
    while ( MCU_PLL_LOCKED != Mcu_GetPllStatus() )
    {
        /* Busy wait until the System PLL is locked */
    }

    Mcu_DistributePllClock();
#endif

    Mcu_SetMode(McuModeSettingConf_0);

    /* Initialize Platform driver */
    Platform_Init(NULL_PTR);  
    static Can_PduType Can_PduInfo;
    
    /* Can_CreatePduInfo(id, swPduHandle,length, sdu) */
    Can_PduInfo = Can_CreatePduInfo(0U, 0U, 8U, Can_au8Sdu8bytes);
    /* Initilize Can driver */
#if (CAN_43_FLEXCAN_PRECOMPILE_SUPPORT == STD_ON)
    Can_43_FLEXCAN_Init(NULL_PTR);
#else
    Can_43_FLEXCAN_Init(&Can_43_FLEXCAN_Config_VS_0);
#endif
    Can_43_FLEXCAN_SetControllerMode(CanController_1, CAN_CS_STARTED);
    if((Can_43_FLEXCAN_Write(CanHardwareObject_3, &Can_PduInfo) == E_OK))
    while((!CanIf_bTxFlag) && (u8TimeOut != 0U))
    {
        Can_43_FLEXCAN_MainFunction_Write();
        Can_DummyDelay(100U);
        u8TimeOut--;
    }
        
    u8TimeOut = 100U;
    while((!CanIf_bRxFlag) && (u8TimeOut != 0U))
    {
        Can_43_FLEXCAN_MainFunction_Read();
        Can_DummyDelay(100U);
        u8TimeOut--;
    }
    Can_43_FLEXCAN_SetControllerMode(CanController_1, CAN_CS_STOPPED);
    Can_43_FLEXCAN_DeInit();
    
    return (0U);
}



2.interrupt

/*		main_c0		*/
int main_co(void) 
{
    uint8 u8TimeOut = 100U;
    CanIf_bTxFlag = FALSE;
    CanIf_bRxFlag = FALSE;
    /* Initialize the Mcu driver */
#if (MCU_PRECOMPILE_SUPPORT == STD_ON)
    Mcu_Init(NULL_PTR);
#elif (MCU_PRECOMPILE_SUPPORT == STD_OFF)
    Mcu_Init(&Mcu_Config_VS_0);
#endif /* (MCU_PRECOMPILE_SUPPORT == STD_ON) */
    /* Initialize the clock tree and apply PLL as system clock */
    Mcu_InitClock(McuConf_McuModeSettingConf_McuModeSettingConf_0);

#if (MCU_NO_PLL == STD_OFF)
    while ( MCU_PLL_LOCKED != Mcu_GetPllStatus() )
    {
        /* Busy wait until the System PLL is locked */
    }

    Mcu_DistributePllClock();
#endif

    Mcu_SetMode(McuModeSettingConf_0);

    /* Initialize Platform driver */
    Platform_Init(NULL_PTR);  
    static Can_PduType Can_PduInfo;
    
    /* Can_CreatePduInfo(id, swPduHandle,length, sdu) */
    Can_PduInfo = Can_CreatePduInfo(0U, 0U, 8U, Can_au8Sdu8bytes);
    /* Initilize Can driver */
#if (CAN_43_FLEXCAN_PRECOMPILE_SUPPORT == STD_ON)
    Can_43_FLEXCAN_Init(NULL_PTR);
#else
    Can_43_FLEXCAN_Init(&Can_43_FLEXCAN_Config_VS_0);
#endif
    Can_43_FLEXCAN_SetControllerMode(CanController_0, CAN_CS_STARTED);
	
	for(;;)
	{
		
	}
    return (0U);
}

/*		main_c1		*/
int main_c1(void) 
{
    uint8 u8TimeOut = 100U;
    CanIf_bTxFlag = FALSE;
    CanIf_bRxFlag = FALSE;
    /* Initialize the Mcu driver */
#if (MCU_PRECOMPILE_SUPPORT == STD_ON)
    Mcu_Init(NULL_PTR);
#elif (MCU_PRECOMPILE_SUPPORT == STD_OFF)
    Mcu_Init(&Mcu_Config_VS_0);
#endif /* (MCU_PRECOMPILE_SUPPORT == STD_ON) */
    /* Initialize the clock tree and apply PLL as system clock */
    Mcu_InitClock(McuConf_McuModeSettingConf_McuModeSettingConf_0);

#if (MCU_NO_PLL == STD_OFF)
    while ( MCU_PLL_LOCKED != Mcu_GetPllStatus() )
    {
        /* Busy wait until the System PLL is locked */
    }

    Mcu_DistributePllClock();
#endif

    Mcu_SetMode(McuModeSettingConf_0);

    /* Initialize Platform driver */
    Platform_Init(NULL_PTR);  
    static Can_PduType Can_PduInfo;
    
    /* Can_CreatePduInfo(id, swPduHandle,length, sdu) */
    Can_PduInfo = Can_CreatePduInfo(0U, 0U, 8U, Can_au8Sdu8bytes);
    /* Initilize Can driver */
#if (CAN_43_FLEXCAN_PRECOMPILE_SUPPORT == STD_ON)
    Can_43_FLEXCAN_Init(NULL_PTR);
#else
    Can_43_FLEXCAN_Init(&Can_43_FLEXCAN_Config_VS_0);
#endif
    Can_43_FLEXCAN_SetControllerMode(CanController_1, CAN_CS_STARTED);

	for(;;)
	{
		
	}
    return (0U);
}

5.展望

​ FIFO+DMA的形式没有用过,后续有时间将这个验证一下再补上,关于原理那块比较复杂,写的很简单,如果有时间后续将原理那块丰富一下。

  • 49
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
S32K3x4EVB-Q257是一款基于ARM Cortex-M内核的汽车电子控制系统的评估板。以下是入门指南: 1. 硬件准备:首先,确保你有一块S32K3x4EVB-Q257评估板、一台电脑和必要的USB连接线。 2. 软件安装:在电脑上安装相关的开发工具和软件。这可能包括S32 Design Studio集成开发环境(IDE)、S32 SDK软件开发套件、S32K Power Software Examples等。 3. 连接电源:将评估板插入电脑上的USB接口,并连接电源线到评估板上。 4. 下载示例代码:在S32 Design Studio中创建一个新项目,并下载示例代码到评估板上。这些示例代码将帮助你了解基本的功能和操作。 5. 硬件连线:根据需要,使用连接线将评估板与其他外部设备(例如传感器、显示屏等)连接起来。评估板上的引脚和接口可以通过手册查阅获得。 6. 运行代码:编译和下载代码到评估板上,并运行它。通过调试器或串口等方式,观察代码的执行情况和输出结果。 7. 进一步学习:通过阅读相关文档、手册和参考资料,了解评估板的更多功能和特性。你可以尝试修改示例代码或编写自己的代码,以实现特定的功能。 注意事项:在使用评估板时,务必遵循相关的安全操作规程,不要超过硬件的额定电压和电流,并保持设备的正确连接和操作。 以上是关于S32K3x4EVB-Q257入门的简要指南。希望这些信息对你有所帮助!
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值