引言
前文介紹了FlexCAN外設模塊,一種典型的CAN總線引擎子系統的工作機制。那么,用戶在軟件開發平臺對CAN總線引擎進行編程,需要根據硬件外設模塊的功能進行建模,將對CAN總線通信引擎的操作封裝起來,讓開發者通過軟件開發平臺的數據結構和用戶可編程應用接口(API)函數使用FlexCAN模塊。基于靈動微電子微控制器的軟件開發平臺MindSDK,包含了集成FlexCAN外設的MM32F5270和MM32F0140微控制器,其中就有FlexCAN外設模塊的驅動程序以及樣例工程,以及對CAN總線通信協議CANopen的適配工程。本文將介紹MindSDK中FlexCAN驅動程序及樣例工程,展現一種典型的CAN總線驅動程序的實現及應用場景。
從MindSDK獲取FlexCAN驅動程序
通過MindSDK在線發布網站選擇搭載了MM32F0140微控制器的POKT-F0140
開發板,就可以得到MM32F0140微控制器的軟件開發包。如圖x所示。
figure-mindsdk-pokt-f0140-download-package-1
圖x 在MindSDK在線網站現在MM32F0140軟件包下載的軟件開發包后pokt-f0140_mdk.zip
,其中就包含了FlexCAN的驅動程序源碼,具體就是hal_flexcan.h
和hal_flexcan.c
兩個源文件。如圖x所示。
figure-mindsdk-pokt-f0140-flexcan-driver-files
圖x FlexCAN驅動程序源碼## 數據結構
這里列寫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。
表x MindSDK中的FlexCAN驅動樣例工程清單
回環通信 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驅動的方法。
-
微控制器
+關注
關注
48文章
7564瀏覽量
151558 -
CAN總線
+關注
關注
145文章
1952瀏覽量
130831 -
通信協議
+關注
關注
28文章
887瀏覽量
40326 -
驅動程序
+關注
關注
19文章
837瀏覽量
48079 -
函數
+關注
關注
3文章
4333瀏覽量
62709
發布評論請先 登錄
相關推薦
評論