基于S32K SDK FLEXCAN的通信

基于S32K SDK FLEXCAN的通信

  • 1 前言
  • 2 基本流程
  • 3 实例
    • 3.1硬件资源
    • 3.2 实现功能
    • 3.3 实现
      • 3.3.1 MCU配置
      • 3.3.2 定义CAN通信配置及邮箱
      • 3.3.3 初始化CAN实例及缓冲区
      • 3.3.4 定义回调函数及处理内容
    • 3.4 运行结果
  • 后记

1 前言

在NXP S32K SDK中FLEXCAN提供了CAN和CAN FD的驱动。本文讲解基本CAN通信的程序方法。

2 基本流程

第一步:基本硬件配置
这一步主要配置S32Kxxx MCU的硬件资源。如时钟,引脚,CAN物理层。这一步利用Processor Expert完成。
第二步:定义CAN通信配置及邮箱。
第三步:初始化CAN实例及缓冲区。
第四部:定义回调函数及处理内容。

3 实例

3.1硬件资源

MCU: S32K118
使用引脚:
PTC1:按键
PTA10:LED输出
PTB1:CAN Tx
PTB0:CAN Rx

3.2 实现功能

a. 按下按键后以500Kbps波特率发送ID=1,长度为8,内容为0x01 02 03 04 05 06 07 08的数据。
b. 当接收到500Kbps波特率 ID=2的帧时,点亮LED灯。当接收到ID=4的帧时,关闭LED灯。

3.3 实现

3.3.1 MCU配置

在Processor Expert中:
a. GPIO配置
按使用引脚将PTA10, PTC1分别设置为输出和输入如下:
GPIO设置
设置CAN通信所用引脚:
CAN引脚设置
b. 设置CAN硬件参数
CAN配置
这部分设置在SDK生成代码后对应:canCom1.c的如下内容:

const flexcan_user_config_t canCom1_InitConfig0 = {
/*CAN通信配置结构体名:canCom1_InitConfig0*/
    .fd_enable = false, /*不使用CAN FD*/
    .pe_clock = FLEXCAN_CLK_SOURCE_PERIPH,  /*CAN通信使用外设时钟源*/
    .max_num_mb = 10,/*邮箱数量为10*/
    .num_id_filters = FLEXCAN_RX_FIFO_ID_FILTERS_8, /*CAN帧ID过滤器数量为8*/
    .is_rx_fifo_needed = false,   /*不使用FIFO*/
    .flexcanMode = FLEXCAN_NORMAL_MODE,    /*正常模式*/
    .payload = FLEXCAN_PAYLOAD_SIZE_8,     
    .bitrate = {  /*仲裁场位时间设置*/
        .propSeg = 7,
        .phaseSeg1 = 4,
        .phaseSeg2 = 1,
        .preDivider = 5,
        .rJumpwidth = 1
    },
    .bitrate_cbt = {/*数据场位时间设置*/
        .propSeg = 7,
        .phaseSeg1 = 4,
        .phaseSeg2 = 1,
        .preDivider = 5,
        .rJumpwidth = 1
    },
    .transfer_type = FLEXCAN_RXFIFO_USING_INTERRUPTS,/*中断方式*/
    .rxFifoDMAChannel = 0U
};

3.3.2 定义CAN通信配置及邮箱

a ,配置CAN通信格式
在主程序设置配置结构体及接收数据缓冲区,例如接收部分如下:

flexcan_data_info_t Rx_dataInfo =
  {
          .data_length = 8U,
          .msg_id_type = FLEXCAN_MSG_ID_STD, /*使用11位标准ID格式*/
          .enable_brs  = false,  /*因为不使用CAN FD所以关闭*/
          .fd_enable   = false,  /*因为不使用CAN FD所以关闭*/
          .fd_padding  = 0U      /*因为不使用CAN FD所以关闭*/
  };
flexcan_msgbuff_t recvBuff; //接收数据缓冲区

在SDK中定义的数据缓冲区格式如下,后文将按这个结构体进行CAN报文的设置。

typedef struct {
    uint32_t cs;                        /*!< Code and Status*/
    uint32_t msgId;                     /*!< Message Buffer ID*/
    uint8_t data[64];                   /*!< Data bytes of the FlexCAN message*/
    uint8_t dataLen;                    /*!< Length of data in bytes */
} flexcan_msgbuff_t;

b. 定义通信邮箱

//定义发送邮箱,最后数字为CAN ID值
#define Tx_MB_01 (1UL)
// 定义接收邮箱,最后的数字为CAN ID值
#define Rx_MB_02 (2UL)
#define Rx_MB_04 (4UL)

3.3.3 初始化CAN实例及缓冲区

a. 配置CAN通信格式
在主程序中按前面Process Expert中指定的CAN实例及配置结构体名进行CAN口的初始化。

FLEXCAN_DRV_Init(INST_CANCOM1, &canCom1_State, &canCom1_InitConfig0);

b.初始化收发缓冲区

   /*配置发送缓冲区*/
    FLEXCAN_DRV_ConfigTxMb(INST_CANCOM1, Tx_MB_01, &sendBuff, 1);//ID=1

    /*配置接收缓冲区*/
    FLEXCAN_DRV_ConfigRxMb(INST_CANCOM1, Rx_MB_02, &recvBuff, 2);  // ID=2
    FLEXCAN_DRV_ConfigRxMb(INST_CANCOM1, Rx_MB_04, &recvBuff, 4);  // ID=4

3.3.4 定义回调函数及处理内容

a. 定义回调函数
此处回调函数在SDK中的格式为:

typedef void(* flexcan_callback_t) (uint8_t instance, flexcan_event_type_t eventType, uint32_t
buffIdx, flexcan_state_t *flexcanState)

本例中只用回调函数进行CAN的接收处理。
主程序中安装回调函数如下:

   FLEXCAN_DRV_InstallEventCallback(INST_CANCOM1,CAN_CallBack,NULL);

   FLEXCAN_DRV_Receive(INST_CANCOM1, Rx_MB_02, &recvBuff);
   FLEXCAN_DRV_Receive(INST_CANCOM1, Rx_MB_04, &recvBuff);

程序中定义的回调函数为:CAN_CallBack()
由于基本的CAN收发函数除非使用阻塞型函数外,函数之后后直接退出。CAN的操作结束时会触发回调函数。因此在安装回调函数后,马上使用CAN的接收API函数FLEXCAN_DRV_Receive()进行读操作。若有数据被接收到了,则自动进入回调函数中。

b.回调函数

void CAN_CallBack(uint8_t instance, flexcan_event_type_t eventType, uint32_t buffIdx, flexcan_state_t *flexcanState)
{

	(void) buffIdx;
	(void) flexcanState;
	if(eventType == FLEXCAN_EVENT_RX_COMPLETE)
	{/*CAN读完成事件触发时执行*/

		if(recvBuff.msgId==2)
		{  /*ID=2的帧点灯*/
			PINS_DRV_SetPins(GPIO2_PORT, (1 << LED2));
			FLEXCAN_DRV_Receive(INST_CANCOM1,Rx_MB_02, &recvBuff);
		}
		if(recvBuff.msgId==4)
		{/*ID=4的帧关灯*/
			PINS_DRV_ClearPins(GPIO2_PORT, (1 << LED2));
			FLEXCAN_DRV_Receive(INST_CANCOM1,Rx_MB_04, &recvBuff);
		}

	}
}

其中“eventType”是事件类型,FLEXCAN_EVENT_RX_COMPLETE为读CAN完成事件。而后的程序按帧ID进行不同的开关灯操作。

c.CAN的发送处理
在按键处理程序中,当判断到有按键按下时,执行:

sendBuff.msgId=0x1;
           sendBuff.dataLen=8;
           for (int i=0;i<9;i++)
           {
        	   sendBuff.data[i]=i+1;
           }
            /* Send the information via CAN */
            SendCANData(Tx_MB_01, sendBuff.msgId, sendBuff.data, 8UL);
           

SendCANData()

void SendCANData(uint32_t mailbox, uint32_t messageId, uint8_t * data, uint32_t len)
{

    FLEXCAN_DRV_Send(INST_CANCOM1, mailbox, &Tx_dataInfo, messageId, data);
}

3.4 运行结果

上位机CAN报文
其中第一帧为硬件向上位机发送的CAN报文。第二,三帧为上位机发给硬件的开关灯报文。硬件开关灯正常,CAN通信收发成功。

后记

  本文于2024.1.21日首发于“车灯电子扫地僧”。 如果你喜欢我的文章,也可以“车灯电子扫地僧”搜索微信订阅号。更多文章等待您的发掘。