CAN总线开发一本全(4) - FlexCAN的驱动程序
CAN总线开发一本全(4) - FlexCAN的驱动程序
苏勇,2023年2月
文章目录
- CAN总线开发一本全(4) - FlexCAN的驱动程序
- 引言
- 从MindSDK获取FlexCAN驱动程序
- 数据结构
- 配置通信引擎的结构体类型
- 访问MB的结构体类型
- 配置ID过滤器的结构体类型
- FIFO相关的结构体类型
- API清单
- 配置通信引擎的API
- 访问MB的API
- 配置ID过滤器的API
- 中断和状态的API
- FIFO相关的API
- 样例工程
- 回环通信 flexcan_loopback
- 板对板直接通信 flexcan_b2b_tx & flexcan_b2b_rx
- 板对板请求远程帧通信 flexcan_b2b_req & flexcan_b2b_ack
- 总结
- 参考文献
引言
前文介绍了FlexCAN外设模块,一种典型的CAN总线引擎子系统的工作机制。那么,用户在软件开发平台对CAN总线引擎进行编程,需要根据硬件外设模块的功能进行建模,将对CAN总线通信引擎的操作封装起来,让开发者通过软件开发平台的数据结构和用户可编程应用接口(API)函数使用FlexCAN模块。基于灵动微电子微控制器的软件开发平台MindSDK,包含了集成FlexCAN外设的MM32F5270和MM32F0140微控制器,其中就有FlexCAN外设模块的驱动程序以及样例工程,以及对CAN总线通信协议CANopen的适配工程。本文将介绍MindSDK中FlexCAN驱动程序及样例工程,展现一种典型的CAN总线驱动程序的实现及应用场景。
从MindSDK获取FlexCAN驱动程序
通过MindSDK在线发布网站 https://mindsdk.mindmotion.com.cn 选择搭载了MM32F0140微控制器的POKT-F0140开发板,就可以得到MM32F0140微控制器的软件开发包。如图x所示。

下载的软件开发包后pokt-f0140_mdk.zip,其中就包含了FlexCAN的驱动程序源码,具体就是hal_flexcan.h和hal_flexcan.c两个源文件。如图x所示。

数据结构
这里列写FlexCAN驱动程序中的主要数据结构。
配置通信引擎的结构体类型
FLEXCAN_Init_Type类型的结构体的变量,用于在初始化FlexCAN总线引擎时传入配置参数。
/*!* @brief This type of structure instance is used to keep the settings when calling the @ref FLEXCAN_Init() to initialize the general setting of FLEXCAN.*/
typedef struct
{uint8_t MaxXferNum; /*!< Max number of message buffer to be used. */uint32_t BitRate; /*!< Data bit per second when using FLEXCAN for transmision and reception. */uint32_t ClockFreqHz; /*!< Clock source frequency. */FLEXCAN_ClockSource_Type ClockSource; /*!< Clock source selection. */FLEXCAN_SelfWakeUp_Type SelfWakeUp; /*!< Stop mode self wake up source. */FLEXCAN_WorkMode_Type WorkMode; /*!< FLEXCAN function mode. */FLEXCAN_Mask_Type Mask; /*!< Filter work range for filtering the received frames. */FLEXCAN_TimConf_Type * TimConf; /*!< FLEXCAN timer and time synchronization setup. */bool EnableSelfReception; /*!< Whether to receive frames sent by FLEXCAN itself. */bool EnableTimerSync; /*!< Refresh the timer every frame reception. */
} FLEXCAN_Init_Type;
其中,FLEXCAN_TimConf_Type类型用于指定FlexCAN总线位时间的配置参数。关于如何配置CAN总线的位时间,后续将有专门文章详解。
/*!* @brief This type of structure instance is used to keep the settings when calling the @ref FLEXCAN_SetTimingConf() to initialize the time configuration.*/
typedef struct
{bool EnableExtendedTime; /*!< If enable, the setting time range can be broader. */uint32_t PhaSegLen1; /*!< Phase segment 1. */uint32_t PhaSegLen2; /*!< Phase segment 2. */uint32_t PropSegLen; /*!< Propagation segment. Compensate for signal delays across the network.*/uint32_t JumpWidth; /*!< Resynchronize jump width. */uint32_t PreDiv; /*!< The divider for FLEXCAN clock source. */
} FLEXCAN_TimConf_Type;
访问MB的结构体类型
FLEXCAN_Mb_Type类型的结构体,建立了对MB在物理存储空间的映射结构,软件使用该类型的结构体整体传入或读出硬件MB存储区中的内容。
/*!* @brief This type of structure instance is used to keep the settings when calling the @ref FLEXCAN_WriteTxMb() to set the mask for buffer.*/
typedef struct
{struct{uint32_t TIMESTAMP : 16; /*!< Free-running counter time stamp. */uint32_t LENGTH : 4; /*!< Length of Data in Bytes. */uint32_t TYPE : 1; /*!< Frame data type or remote type. */uint32_t FORMAT : 1; /*!< Frame extended format or standard format. */uint32_t RESERVED_0 : 1; /*!< Reservation. */uint32_t IDHIT : 9; /*!< Id filter number hit by fifo. */};struct{uint32_t ID :29; /*!< Frame Identifier. */uint32_t PRIORITY: 3; /*!< Local priority. */};union{struct{uint32_t WORD0; /*!< CAN Frame payload word0. */uint32_t WORD1; /*!< CAN Frame payload word1. */};struct{/* The sequence refers to the little-endian-storage and big-endian transfer. */uint8_t BYTE3; /*!< CAN Frame payload byte3. */uint8_t BYTE2; /*!< CAN Frame payload byte2. */uint8_t BYTE1; /*!< CAN Frame payload byte1. */uint8_t BYTE0; /*!< CAN Frame payload byte0. */uint8_t BYTE7; /*!< CAN Frame payload byte7. */uint8_t BYTE6; /*!< CAN Frame payload byte6. */uint8_t BYTE5; /*!< CAN Frame payload byte5. */uint8_t BYTE4; /*!< CAN Frame payload byte4. */};};
} FLEXCAN_Mb_Type;
FLEXCAN_RxMbConf_Type类型的结构体,用于配置在MB中配置接收帧的部分属性,这相当于是FLEXCAN_Mb_Type的轻量级版本,但不需要数据负载、数据长度、本地优先级等配置信息。
/*!* @brief This type of structure instance is used to keep the settings when calling the @ref FLEXCAN_SetRxMb() to set the mask for buffer.*/
typedef struct
{FLEXCAN_MbType_Type MbType; /*!< Data frame or Remote frame switcher. */FLEXCAN_MbFormat_Type MbFormat; /*!< Extended or standard id switcher. */uint32_t Id; /*!< Id value. */
} FLEXCAN_RxMbConf_Type;
FLEXCAN_MbCode_Type枚举类型指定了可用的CODE命令。
/*!* @brief FLEXCAN Xfer MB frame code switcher.*/
typedef enum
{/* rx. */FLEXCAN_MbCode_RxInactive = 0u, /*!< Code for MB being not active. */FLEXCAN_MbCode_RxFull = 2u, /*!< Code for MB being full. */FLEXCAN_MbCode_RxEmpty = 4u, /*!< Code for MB being active and empty. */FLEXCAN_MbCode_RxOverrun = 6u, /*!< Code for MB being over written without accessing the received frame. */FLEXCAN_MbCode_RxRanswer = 10u, /*!< Code for Rx waiting for remote frame. */FLEXCAN_MbCode_RxBusy = 15u, /*!< Code for Rx updating MB. *//* rx. */FLEXCAN_MbCode_TxInactive = 8u, /*!< Code for data response for Tx inactive. */FLEXCAN_MbCode_TxAbort = 9u, /*!< Code for Tx abort after transmission. */FLEXCAN_MbCode_TxDataOrRemote = 12u, /*!< Code for data frame or remote frame transmission. */FLEXCAN_MbCode_TxTanswer = 14u, /*!< Code for data response for remote frame. */
} FLEXCAN_MbCode_Type;
配置ID过滤器的结构体类型
FLEXCAN_RxMbMaskConf_Type可以用于配置全局ID过滤器和MB专属ID过滤器。
/*!* @brief This type of structure instance is used to keep the settings when calling the @ref FLEXCAN_SetGlobalMbMaskConf() to set the mask for buffer.*/
typedef struct
{FLEXCAN_MbType_Type MbType; /*!< Data frame or Remote frame switcher. */FLEXCAN_MbFormat_Type MbFormat; /*!< Extended or standard id switcher. */uint32_t IdMask; /*!< Id mask. */
} FLEXCAN_RxMbMaskConf_Type;
FIFO相关的结构体类型
FLEXCAN_RxFifoConf_Type类型用于在启用FIFO功能时,配置FIFO的属性。
/*!* @brief This type of structure instance is used to keep the settings when calling the @ref FLEXCAN_EnableRxFifo() to initialize the fifo setting.*/
typedef struct
{FLEXCAN_FifoIdFilterFormat_Type FilterFormat; /*!< fifo filter format which will decide how to filter the fifo reception. */uint32_t IdFilterNum; /*!< The fifo filter element num. */uint32_t * IdFilterTable; /*!< Filter array to be set for Rx fifo. */FLEXCAN_FifoPriority_Type priority; /*!< Enable matching process start with fifo. */
} FLEXCAN_RxFifoConf_Type;
当使用FIFO时,需要使用FLEXCAN_RxFifoMaskConf_Type结构体类型的变量配置ID过滤器。
/*!* @brief This type of structure instance is used to keep the settings when calling the @ref FLEXCAN_SetRxFifoGlobalMaskConf() to set the conf for fifo mask filter.*/
typedef struct
{FLEXCAN_MbType_Type MbType; /*!< Data frame or Remote frame switcher. */FLEXCAN_MbFormat_Type MbFormat; /*!< Extended or standard id switcher. */FLEXCAN_FifoIdFilterFormat_Type FilterFormat; /*!< fifo filter format. */union{uint32_t RxIdA; /*!< The fifo Id setting for filter format A. */uint16_t RxIdB[2]; /*!< The fifo Id setting for filter format B. */uint8_t RxIdC[4]; /*!< The fifo Id setting for filter format C. */};
} FLEXCAN_RxFifoMaskConf_Type;
还有更多枚举类型和宏常量,可继续查阅hal_flexcan.h源文件。
API清单
FlexCAN驱动的API相对较多,这里做了个分类,便于快速索引。更详细的内容可见源码。
配置通信引擎的API
使用FlexCAN外设之前需要初始化驱动引擎。
void FLEXCAN_Enable(FLEXCAN_Type * FLEXCANx, bool enable);
void FLEXCAN_DoSoftReset(FLEXCAN_Type * FLEXCANx);
bool FLEXCAN_Init(FLEXCAN_Type * FLEXCANx, FLEXCAN_Init_Type * init);
void FLEXCAN_SetTimingConf(FLEXCAN_Type * FLEXCANx, FLEXCAN_TimConf_Type * conf);
void FLEXCAN_EnableFreezeMode(FLEXCAN_Type * FLEXCANx, bool enable);
访问MB的API
这一组API中,第二个参数channel,对应的是MB列表中的索引,FlexCAN中有16个MB,对应channel的取值可以是0-15。FlexCAN外设中MB的内存区是ECC的,在使用之前必须通过FLEXCAN_ResetMb()函数复位选定的MB。
void FLEXCAN_ResetMb(FLEXCAN_Type * FLEXCANx, uint32_t channel);
void FLEXCAN_SetMbCode(FLEXCAN_Type * FLEXCANx, uint32_t channel, FLEXCAN_MbCode_Type code);
void FLEXCAN_SetRxMb(FLEXCAN_Type * FLEXCANx, uint32_t channel, FLEXCAN_RxMbConf_Type * conf);
bool FLEXCAN_WriteTxMb(FLEXCAN_Type * FLEXCANx, uint32_t channel, FLEXCAN_Mb_Type * mb);
bool FLEXCAN_ReadRxMb(FLEXCAN_Type * FLEXCANx, uint32_t channel, FLEXCAN_Mb_Type * mb);
配置ID过滤器的API
ID过滤器分为全局过滤器和MB专属的过滤器,对应有各自的过滤码(掩码)。
void FLEXCAN_SetGlobalMbMaskConf(FLEXCAN_Type * FLEXCANx, FLEXCAN_RxMbMaskConf_Type * conf);
void FLEXCAN_SetRxMbIndividualMaskConf(FLEXCAN_Type * FLEXCANx, uint32_t channel, FLEXCAN_RxMbMaskConf_Type * conf);
中断和状态的API
FlexCAN的中断和状态标志位分别面向FlexCAN引擎和MB,另外还有一些属性状态,例如计数器、CRC值等。
void FLEXCAN_EnableInterrupts(FLEXCAN_Type * FLEXCANx, uint32_t interrupts, bool enable);
uint32_t FLEXCAN_GetStatus(FLEXCAN_Type * FLEXCANx);
void FLEXCAN_ClearStatus(FLEXCAN_Type * FLEXCANx, uint32_t flags);
void FLEXCAN_EnableMbInterrupts(FLEXCAN_Type * FLEXCANx, uint32_t interrupts, bool enable);
uint32_t FLEXCAN_GetMbStatus(FLEXCAN_Type * FLEXCANx);
void FLEXCAN_ClearMbStatus(FLEXCAN_Type * FLEXCANx, uint32_t mbs);
uint32_t FLEXCAN_GetTxError(FLEXCAN_Type * FLEXCANx);
uint32_t FLEXCAN_GetRxError(FLEXCAN_Type * FLEXCANx);
uint32_t FLEXCAN_GetMatchCrcValue(FLEXCAN_Type * FLEXCANx, uint32_t * channel);
FIFO相关的API
在配置好FlexCAN引擎后,通过FLEXCAN_EnableRxFifo()函数启用FIFO功能,之后就可以以FIFO的方式访问MB。
bool FLEXCAN_EnableRxFifo(FLEXCAN_Type * FLEXCANx, FLEXCAN_RxFifoConf_Type * conf);
void FLEXCAN_SetRxFifoGlobalMaskConf(FLEXCAN_Type * FLEXCANx, FLEXCAN_RxFifoMaskConf_Type * conf);
bool FLEXCAN_ReadRxFifo(FLEXCAN_Type * FLEXCANx, FLEXCAN_Mb_Type * mb);
void FLEXCAN_EnableFifoDMA(FLEXCAN_Type * FLEXCANx, bool enable);
uint32_t FLEXCAN_GetFifoAddr(FLEXCAN_Type * FLEXCANx);
样例工程
MindSDK为FlexCAN驱动设计了一些样例工程,用于演示在一些典型场景中使用FlexCAN的方法。这些样例工程也可以运行在搭载MM32F0140微控制器的POKT-F0140开发板上。见表x。
| 工程 | 说明 |
|---|---|
| driver_examples\flexcan\flexcan_loopback | 回环通信实验 |
| driver_examples\flexcan\flexcan_b2b_tx | 板对板直接通信,发送方,发送数据帧 |
| driver_examples\flexcan\flexcan_b2b_rx | 板对板直接通信,接收方,接收数据帧 |
| driver_examples\flexcan\flexcan_b2b_req | 板对板请求远程帧通信,请求方,发送远程帧,捕获数据帧 |
| driver_examples\flexcan\flexcan_b2b_ack | 板对板请求远程帧通信,响应方,捕获远程帧,发送数据帧 |
| driver_examples\flexcan\flexcan_b2b_tx_self | 板对板直接通信,发送方,发送数据帧,但同时监听自己发送的数据帧 |
回环通信 flexcan_loopback
FlexCAN外设的回环通信功能,就是将FlexCAN外设模块的Tx信号和Rx信号在模块内部,由软件配置电路连通,可用于验证在未接入CAN总线网络时,节点软件本身能否正常收发通信帧。当完成验证后,仅需要通过软件关闭回环通信功能,即可用已经验证过的收发过程同外部CAN总线网络对接。
flexcan_loopback样例工程中的源码,展示了使用FlexCAN模块回环通信的方法。除了启用了回环通信的功能之外,其余对CAN通信帧的发送操作和接收操作同正常对外通信无异,因此,本工程也是使用FlexCAN驱动收发CAN通信帧的最基础的用例。另外,由于使用了回环通信,不需要专门准备发送和接收两块运行不同程序的电路板,仅用一块开发板即可完成实验。
在flxcan_loopback样例工程的main()函数中,除了必要的初始化微控制器的时钟、引脚和后台人机交互端口外,先初始化了FlexCAN模块,然后在while(1)循环中,先准备一组数据作为CAN通信帧的数据负载发送出去,等待发送完成后,再接收一个CAN通信帧,等待接收完成后打印到终端显示接收帧中的数据负载,周而复始。发送帧和接收帧的ID使用同一个 APP_FLEXCAN_XFER_ID,因此可以实现收发。
/** Variables.*/
volatile bool app_flexcan_rx_flag = false; /* Flag the message buffer reception state. */
FLEXCAN_Mb_Type app_flexcan_rx_mb; /* For message buffer rx frame storage. */
uint8_t app_flexcan_tx_buf[APP_FLEXCAN_XFER_BUF_LEN]; /* The flexcan tx buffer for tx mb frame preparation. */
uint8_t app_flexcan_rx_buf[APP_FLEXCAN_XFER_BUF_LEN]; /* The flexcan rx buffer for rx mb frame storage. *//** Declerations.*/
void app_flexcan_init(void); /* Setup flexcan. */
void app_flexcan_tx(uint8_t *tx_buf); /* Send frame. */
void app_flexcan_read(uint8_t *rx_buf); /* Receive frame. *//** Functions.*/
int main(void)
{BOARD_Init();printf("\r\nflexcan_loopback example.\r\n");/* Setup the flexcan module.*/app_flexcan_init();printf("press any key to send loop back frame with id 0x%x.\r\n", (unsigned)APP_FLEXCAN_XFER_ID);while (1){getchar();/* Send a message through flexcan. */for (uint8_t i = 0u; i < APP_FLEXCAN_XFER_BUF_LEN; i++){app_flexcan_tx_buf[i] = ( app_flexcan_tx_buf[i] + i) % 256u;}app_flexcan_tx(app_flexcan_tx_buf);printf("app_flexcan_tx() done.\r\n");/* Wait for reception. */while (!app_flexcan_rx_flag) /* This flag will be on when the Rx interrupt is asserted. */{}app_flexcan_rx_flag = false;printf("app_flexcan_read(): ");for (uint8_t i = 0u; i < APP_FLEXCAN_XFER_BUF_LEN; i++){printf("%u ", (unsigned)app_flexcan_rx_buf[i]);}printf("\r\n\r\n");}
}
其中,初始化FlexCAN模块的函数 app_flexcan_init(),初始化了FlexCAN通信引擎,包括配置CAN总线通信的位时钟,配置好了发送MB和接收MB,分别使用两个不同的MB索引BOARD_FLEXCAN_TX_MB_CH和BOARD_FLEXCAN_RX_MB_CH,并分别设定它们为有效的非激活状态。最后还启用了发送完成和接收到数据帧的中断。虽然这里也可以使用纯粹的轮询标志位实现流控制,但使用中断方式便于向后续用例中过渡。在中断服务程序中,当检测到有接收帧时,从接收帧的MB中搬运接收到的数据负载到内存变量app_flexcan_rx_buf中,然后清接收标志位。有实现代码如下:
/* Setup the flexcan module. */
void app_flexcan_init(void)
{/* Set bit timing. */FLEXCAN_TimConf_Type flexcan_tim_conf;flexcan_tim_conf.EnableExtendedTime = true;flexcan_tim_conf.PhaSegLen1 = 5u;flexcan_tim_conf.PhaSegLen2 = 1u;flexcan_tim_conf.PropSegLen = 2u;flexcan_tim_conf.JumpWidth = 1u;/* Setup flexcan. */FLEXCAN_Init_Type flexcan_init;flexcan_init.MaxXferNum = APP_FLEXCAN_XFER_MaxNum; /* The max mb number to be used. */flexcan_init.ClockSource = FLEXCAN_ClockSource_Periph; /* Use peripheral clock. */flexcan_init.BitRate = APP_FLEXCAN_XFER_BITRATE; /* Set bitrate. */flexcan_init.ClockFreqHz = BOARD_FLEXCAN_CLOCK_FREQ; /* Set clock frequency. */flexcan_init.SelfWakeUp = FLEXCAN_SelfWakeUp_BypassFilter; /* Use unfiltered signal to wake up flexcan. */flexcan_init.WorkMode = FLEXCAN_WorkMode_LoopBack; /* Normal workmode, can receive and transport. */flexcan_init.Mask = FLEXCAN_Mask_Global; /* Use global mask for filtering. */flexcan_init.EnableSelfReception = true; /* Must receive mb frame sent by self. */flexcan_init.EnableTimerSync = true; /* Every tx or rx done, refresh the timer to start from zero. */flexcan_init.TimConf = &flexcan_tim_conf; /* Set timing sychronization. */FLEXCAN_Init(BOARD_FLEXCAN_PORT, &flexcan_init);/* Set tx mb. */FLEXCAN_ResetMb(BOARD_FLEXCAN_PORT, BOARD_FLEXCAN_TX_MB_CH);FLEXCAN_SetMbCode(BOARD_FLEXCAN_PORT, BOARD_FLEXCAN_TX_MB_CH, FLEXCAN_MbCode_TxInactive);/* Set rx mb. */FLEXCAN_RxMbConf_Type flexcan_mb_conf;flexcan_mb_conf.Id = APP_FLEXCAN_XFER_ID; /* Id for filtering with mask and receiving. */flexcan_mb_conf.MbType = FLEXCAN_MbType_Data; /* Only receive standard data frame. */flexcan_mb_conf.MbFormat = FLEXCAN_MbFormat_Standard;FLEXCAN_SetRxMb(BOARD_FLEXCAN_PORT, BOARD_FLEXCAN_RX_MB_CH, &flexcan_mb_conf);FLEXCAN_SetMbCode(BOARD_FLEXCAN_PORT, BOARD_FLEXCAN_RX_MB_CH, FLEXCAN_MbCode_RxEmpty); /* Set for receiving. *//* Enable intterupts for rx mb. */FLEXCAN_EnableMbInterrupts(BOARD_FLEXCAN_PORT, BOARD_FLEXCAN_RX_MB_INT, true);NVIC_EnableIRQ(BOARD_FLEXCAN_IRQn);
}/* Interrupt request handler. */
void BOARD_FLEXCAN_IRQHandler(void)
{if (0u!= (FLEXCAN_GetMbStatus(BOARD_FLEXCAN_PORT) & BOARD_FLEXCAN_RX_MB_STATUS) ){/* Read the message. */app_flexcan_read(app_flexcan_rx_buf);/* Clear flexcan mb interrupt flag. */FLEXCAN_ClearMbStatus(BOARD_FLEXCAN_PORT, BOARD_FLEXCAN_RX_MB_STATUS);/* Update the flag. */app_flexcan_rx_flag = true;}
}
其中,flexcan_init.WorkMode = FLEXCAN_WorkMode_LoopBack;即指定启用了回环模式。
发送数据帧的操作被封装成app_flexcan_tx() 函数。在该函数中,将即将发送的数据填充到MB结构体的数据负载中,再将整个帧结构写入到FlexCAN硬件的MB内存区,最后过向发送MB的内存区写命令码,启动发送过程。注意,这里使用预分配的帧ID(而不是作为函数传参可配置),发送数据帧(而不是远程帧)。有源代码如下:
/* Send a message frame. */
void app_flexcan_tx(uint8_t * tx_buf)
{/* Prepare the mb to be sent. */FLEXCAN_Mb_Type mb;mb.ID = APP_FLEXCAN_XFER_ID; /* Indicated ID number. */mb.TYPE = FLEXCAN_MbType_Data; /* Data frame type. */mb.FORMAT = FLEXCAN_MbFormat_Standard; /* STD frame format. */mb.PRIORITY = APP_FLEXCAN_XFER_PRIORITY; /* The priority of the frame mb. */mb.BYTE0 = tx_buf[0]; /* Set the data payload. */mb.BYTE1 = tx_buf[1];mb.BYTE2 = tx_buf[2];mb.BYTE3 = tx_buf[3];mb.BYTE4 = tx_buf[4];mb.BYTE5 = tx_buf[5];mb.BYTE6 = tx_buf[6];mb.BYTE7 = tx_buf[7];mb.LENGTH = APP_FLEXCAN_XFER_BUF_LEN; /* Set the size of data payload. */FLEXCAN_WriteTxMb(BOARD_FLEXCAN_PORT, BOARD_FLEXCAN_TX_MB_CH, &mb);/* Write code to send. */FLEXCAN_SetMbCode(BOARD_FLEXCAN_PORT, BOARD_FLEXCAN_TX_MB_CH, FLEXCAN_MbCode_TxDataOrRemote);
}
接收数据帧的操作被封装成app_flexcan_read()函数。这里执行的操作,仅仅是从预定的FlexCAN硬件的接收MB内存区中把整个MB读出来,然后从MB结构类型中提取数据负载,作为传参返回给函数调用者。有源代码如下:
/* Receive a message frame. */
void app_flexcan_read(uint8_t *rx_buf)
{/* Read the info from mb and reconstruct for understanding. */FLEXCAN_ReadRxMb(BOARD_FLEXCAN_PORT, BOARD_FLEXCAN_RX_MB_CH, &app_flexcan_rx_mb);rx_buf[0] = app_flexcan_rx_mb.BYTE0;rx_buf[1] = app_flexcan_rx_mb.BYTE1;rx_buf[2] = app_flexcan_rx_mb.BYTE2;rx_buf[3] = app_flexcan_rx_mb.BYTE3;rx_buf[4] = app_flexcan_rx_mb.BYTE4;rx_buf[5] = app_flexcan_rx_mb.BYTE5;rx_buf[6] = app_flexcan_rx_mb.BYTE6;rx_buf[7] = app_flexcan_rx_mb.BYTE7;
}
板对板直接通信 flexcan_b2b_tx & flexcan_b2b_rx
板对板直接通信的用例,需要两块开发板,一个作为接收方,另一个作为发送方,由发送方发送CAN通信帧到接收方,从而实现两块电路板通过CAN总线传输数据的过程。这个实验的样例工程同基本的flexcan_loopback工程非常相近,只是收发过程拆分成两个独立的工程。注意,收发两个工程中使用CAN通信帧的ID也是约定一致的。
相对于flexcan_loop工程,独立的flexcan_b2b_rx和flexcan_b2b_tx工程中对FlexCAN模块的初始化过程,不再启用回环模式,而是常规模式。见源代码如下:
/* Set up the flexCAN module. */
void app_flexcan_init(void)
{.../* Setup FlexCAN. */FLEXCAN_Init_Type flexcan_init;...flexcan_init.WorkMode = FLEXCAN_WorkMode_Normal; /* Normal workmode, can receive and transport. */...FLEXCAN_Init(BOARD_FLEXCAN_PORT, &flexcan_init);...
}
接收方电路板运行flexcan_b2b_rx工程的程序:初始化FlexCAN通信引擎后,配置接收MB,开中断等待接收帧完成。在后台的FlexCAN中断服务程序中,一旦捕获到约定ID的通信帧,就将接收帧中的数据负载转存到内存中的app_flexcan_rx_buf变量中,并且通过标志变量app_flexcan_rx_flag告知前台程序,然后清除硬件标志位。在前台的while(1)循环中,一旦接收到约定ID的通信帧,就在终端界面打印出接收到帧的数据内容。
发送方电路板运行flexcan_b2b_tx工程的程序:初始化FlexCAN通信引擎后,配置发送MB,开中断等待发送帧完成。前台的while(1)循环中,由用户触发向发送MB填充数据负载,并发送预定帧数据的操作。在后台的FlexCAN中断服务程序中,一旦发送完成约定ID的通信帧,就通过标志变量app_flexcan_tx_flag告知前台程序,然后清除硬件标志位。
运行实验时,电脑同时接入发送方和接收方的两个终端界面,先在发送方的终端界面中输入任意字符启动发送帧过程,将有CAN通信帧从发送方上传CAN总线,接收方亦会从总线上捕获到约定同一ID的数据帧,解析出其中的数据负载再显示到接收方的终端界面上。
板对板请求远程帧通信 flexcan_b2b_req & flexcan_b2b_ack
板对板请求远程帧通信的用例,需要两块开发板,一个作为请求方,另一个作为响应方,由请求方发送CAN通信远程帧到应答方,应答方收到远程帧后,准备好数据帧,再将响应的数据帧发送至CAN总线,由请求方捕获,从而实现两块电路板通过CAN总线读数据的过程。相对于板对板直接通信的写数据过程,板对板请求远程帧通信过程实现的是读数据过程。这个实验的样例工程同基本的flexcan_loopback工程,以及板对板直接通信的两个工程非常相近,只是收发过程拆分成两个独立的工程,并且原来的发送方先发出远程帧再接收数据帧,而原来的接收方将先等待远程帧再发送数据帧。注意,收发两个工程中使用CAN通信帧的ID也是约定一致的。
请求方和响应方的两个工程,同flexcan_loopback工程对FlexCAN引擎的初始化过程完全相同,并且在各自的工程中,也需要处理发送和接收过程。不同之处仅在于其中的一个通信帧从数据帧变成的远程帧。
响应方电路板运行flexcan_b2b_ack工程的程序:初始化FlexCAN通信引擎后,配置接收MB,配置发送MB,开中断等待发送和接收帧完成。其中接收MB的帧类型为远程帧FLEXCAN_MbType_Remote。
void app_flexcan_init(void)
{.../* Set rx mb. */FLEXCAN_RxMbConf_Type flexcan_mb_conf;flexcan_mb_conf.Id = APP_FLEXCAN_XFER_ID; /* Id for filtering with mask and receiving. */flexcan_mb_conf.MbType = FLEXCAN_MbType_Remote; /* Only receive remote data frame. */flexcan_mb_conf.MbFormat = FLEXCAN_MbFormat_Standard;FLEXCAN_SetRxMb(BOARD_FLEXCAN_PORT, BOARD_FLEXCAN_RX_MB_CH, &flexcan_mb_conf);FLEXCAN_SetMbCode(BOARD_FLEXCAN_PORT, BOARD_FLEXCAN_RX_MB_CH, FLEXCAN_MbCode_RxEmpty); /* Set for receiving. */...
}
请求方电路板运行flexcan_b2b_req工程的程序:初始化FlexCAN通信引擎后,配置接收MB,配置发送MB,开中断等待发送和接收帧完成。在发送请求帧时,设定MB的帧类型为远程帧FLEXCAN_MbType_Remote。
/* Send a message frame. */
void app_flexcan_req()
{FLEXCAN_Mb_Type mb;mb.ID = APP_FLEXCAN_XFER_ID; /* Indicated ID number. */mb.TYPE = FLEXCAN_MbType_Remote; /* Setup remote frame. */mb.FORMAT = FLEXCAN_MbFormat_Standard; /* STD frame format. */mb.PRIORITY = APP_FLEXCAN_XFER_PRIORITY; /* The priority of the frame mb. */mb.LENGTH = APP_FLEXCAN_REQ_BUF_LEN; /* Set the workload size. */FLEXCAN_WriteTxMb(BOARD_FLEXCAN_PORT, BOARD_FLEXCAN_TX_MB_CH, &mb); /* Send. *//* Write code to send. */FLEXCAN_SetMbCode(BOARD_FLEXCAN_PORT, BOARD_FLEXCAN_TX_MB_CH, FLEXCAN_MbCode_TxDataOrRemote);
}
当运行通信过程时:先启动应答方的程序,准备好响应过程;再请求方的程序,发出请求的远程帧到CAN总线上,应答方从CAN总线上捕获到请求的远程帧后,在本机生成数据负载组,使用同远程帧相同的ID,装成数据帧,再上传至CAN总线;请求方此时可以捕获到CAN总线上的同ID的数据帧,显示到终端界面。周而复始。
总结
MindSDK中设计的FlexCAN驱动程序,对FlexCAN外设进行了建模,创建了一系列数据结构和API,能够为软件开发者提供初始化FlexCAN通信引擎,通过MB的结构类型发送数据帧、远程帧等功能。MindSDK为FlexCAN驱动设计的一些样例工程,演示了在一些典型应用场景中(回环通信、板对板直接通信、板对板请求远程帧通信)使用FlexCAN驱动的方法。
参考文献
- MindSDK在线发布网站,https://mindsdk.mindmotion.com.cn
本文中使用的MindSDK样例工程,可以从MindSDK在线网站上获取最新版,亦可从从此处下载当前版本的软件包: https://download.csdn.net/download/suyong_yq/87501465
相关文章:
CAN总线开发一本全(4) - FlexCAN的驱动程序
CAN总线开发一本全(4) - FlexCAN的驱动程序 苏勇,2023年2月 文章目录CAN总线开发一本全(4) - FlexCAN的驱动程序引言从MindSDK获取FlexCAN驱动程序数据结构配置通信引擎的结构体类型访问MB的结构体类型配置ID过滤器的…...
如何分析linux tcp/ip 丢包问题
引用手把手教你用Dropwatch诊断问题通过dropwatch定位系统内核丢包Finding out if/why a server is dropping packetsgithub source coed: pavel-odintsov/drop_watchHow to drop a packet in Linux in more ways than one试试Linux下的ip命令,ifconfig已经过时了Ho…...
旅游规划(树型dp)
W 市的交通规划出现了重大问题,市政府下定决心在全市各大交通路口安排疏导员来疏导密集的车流。 但由于人员不足,W 市市长决定只在最需要安排人员的路口安排人员。 具体来说,W 市的交通网络十分简单,由 n 个交叉路口和 n−1 条街道…...
【C++】string类的模拟实现
当你将放弃作为一种习惯,你一辈子也不会有出息… 文章目录一、Default member functions1.Constructor2.Copy constructor(代码重构:传统写法和现代写法)3.operator(代码重构:传统写法和现代写法ÿ…...
笔记(一)——STL容器
容器分类:序列式容器:每个元素都有固定位置,取决于插入的时机和地点,和元素无关,如vector、deque、list、stack、queue。关联式容器:元素位置取决于特定的排序准则,和插入顺序无关,如…...
红黑树
红黑树是一个相对的平衡,减少了旋转的消耗 一个节点不是红的就是黑的根节点是黑的一个节点是红的,孩子是黑的(没有连续的红色节点)对于每个节点,从该节点到后代节点的简单路径,都包含相同的黑色࿰…...
RIP路由协议的更新(电子科技大学TCP/IP第二次实验)
一.实验目的 1、掌握 RIP 协议在路由更新时的发送信息和发送方式 2、掌握 RIP 协议的路由更新算法 二.预备知识 1、静态路由选择和动态路由选择 2、内部网关协议和外部网关协议 3、距离向量路由选择 三.实验原理 RIP 协议(…...
基于JWT实现用户身份认证
常见场景 账号/密码登录、手机号验证码登录、微信扫码登录 解决方案 基于Session认证方案 什么是session认证方案 服务端生成httpsession认证(内存-sessionId)sessionId写到浏览器cookie浏览器请求的header中自动带sessionId到服务端服务端校验sessionId是否合法 优点 .…...
SaltStack 远程命令执行漏洞(CVE-2020-16846)
目录 (一)漏洞描述 (二)漏洞复现 1、在vulhub上启动docker 2、访问docker靶机 https /ip:8000...
SAP 详细解析成本收集器
成本收集器作为成本对象,主要应用于按期间进行成本核算的情况,在这种情况下会把产品创建为成本收集器,实际成本的收集和差异的结算全部按照成本收集器进行处理,财务的成本分析也针对成本收集器进行。 成本收集器是按期间核算&am…...
Vision Transformer学习了什么-WHAT DO VISION TRANSFORMERS LEARN? A VISUAL EXPLORATION
WHAT DO VISION TRANSFORMERS LEARN? A VISUAL EXPLORATION 文章地址 代码地址 摘要 视觉转换器( Vision Transformers,ViTs )正在迅速成为计算机视觉的事实上的架构,但我们对它们为什么工作和学习什么知之甚少。虽然现有研究对卷积神经网络的机制进…...
一种全新的图像滤波理论的实验(三)
一、前言 2023年02月22日,我发布了滤波后,为针对异常的白色和黑色像素进行处理的实验,本次发布基于上下文处理的方案的实验,目的是通过基于加权概率模型滤波后,在逆滤波时直接修复大量的白色和黑色的异常像素…...
CV——day79 读论文:基于小目标检测的扩展特征金字塔网络
Extended Feature Pyramid Network for Small Object DetectionI. INTRODUCTIONII. RELATED WORKA. 深层物体探测器B. 跨尺度特征C. 目标检测中的超分辨率III. OUR APPROACHA. 扩展特征金字塔网络B. 特征纹理传输C. 交叉分辨蒸馏IV. EXPERIMENTSA. Experimental Settings1&…...
智能家居项目(五)测试串口功能
目录 一、写一个单独测试串口的demo 二、直接运行上一篇智能家居的代码 一、写一个单独测试串口的demo 1、TTL串口与树莓派的连接方式 (1)TTL的RXD和TXD针脚连接到树莓的TXD和RXD上(T–>R R–>T),交叉连&…...
2023年全国最新道路运输从业人员精选真题及答案7
百分百题库提供道路运输安全员考试试题、道路运输从业人员考试预测题、道路安全员考试真题、道路运输从业人员证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 71.根据《中华人民共和国安全生产法》,生产经营单位…...
python的所有知识点(含讲解),不看就亏死了
目录 简介 特点 搭建开发环境 版本 hello world 注释 文件类型 变量 常量 数据类型 运算符和表达式 控制语句 数组相关 函数相关 字符串相关 文件处理 对象和类,注:不是那个对象!!!!&…...
【Servlet篇】Response对象详细解读
文章目录Response 继承体系Response 设置响应数据设置响应行数据设置响应头数据设置响应体数据Response 重定向Response 响应字符数据Response 响应字节数据Response 继承体系 前面说到,我们使用 Request 对象来获取请求数据,使用 Response 对象来设置响…...
SAP FICO期初开账存货导入尾差
一、问题 1.AFS物料网格级别库存导入先除再乘有尾差: 旧系统数据迁移自两个系统:一个管理数量账(网格级别),一个管理金额账(物料级别) 2.MB52分工厂与MB5L分工厂统计差异: M…...
微信商城小程序怎么做_分享实体店做微信商城小程序制作步骤
各行各业都在用微商城小程序开店,不管是餐饮店还是便利店,还是五金店。都是可以利用微信小程序开一个线上店铺。实现线上跟线下店铺更加全面的结合。维护好自己的老客户。让您的客户给您拉新,带来新客户。小程序经过这几年的快速发展和不断升…...
【moment.js】时间格式化插件
Moment.js 用于在JavaScript中解析,验证,操作和显示日期和时间。是一款在项目中使用频率极高的时间格式化工具,Ant Design Vue 组件中就是使用它来处理时间的。 安装 npm install moment --save # npm yarn add moment # Ya…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...
从实验室到产业:IndexTTS 在六大核心场景的落地实践
一、内容创作:重构数字内容生产范式 在短视频创作领域,IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色,生成的 “各位吴彦祖们大家好” 语音相似度达 97%,单条视频播放量突破百万…...
