引言
前文介紹了FlexCAN外設(shè)模塊,一種典型的CAN總線引擎子系統(tǒng)的工作機(jī)制。那么,用戶在軟件開(kāi)發(fā)平臺(tái)對(duì)CAN總線引擎進(jìn)行編程,需要根據(jù)硬件外設(shè)模塊的功能進(jìn)行建模,將對(duì)CAN總線通信引擎的操作封裝起來(lái),讓開(kāi)發(fā)者通過(guò)軟件開(kāi)發(fā)平臺(tái)的數(shù)據(jù)結(jié)構(gòu)和用戶可編程應(yīng)用接口(API)函數(shù)使用FlexCAN模塊?;?a target="_blank">靈動(dòng)微電子微控制器的軟件開(kāi)發(fā)平臺(tái)MindSDK,包含了集成FlexCAN外設(shè)的MM32F5270和MM32F0140微控制器,其中就有FlexCAN外設(shè)模塊的驅(qū)動(dòng)程序以及樣例工程,以及對(duì)CAN總線通信協(xié)議CANopen的適配工程。本文將介紹MindSDK中FlexCAN驅(qū)動(dòng)程序及樣例工程,展現(xiàn)一種典型的CAN總線驅(qū)動(dòng)程序的實(shí)現(xiàn)及應(yīng)用場(chǎng)景。
從MindSDK獲取FlexCAN驅(qū)動(dòng)程序
通過(guò)MindSDK在線發(fā)布網(wǎng)站選擇搭載了MM32F0140微控制器的POKT-F0140
開(kāi)發(fā)板,就可以得到MM32F0140微控制器的軟件開(kāi)發(fā)包。如圖x所示。
figure-mindsdk-pokt-f0140-download-package-1
圖x 在MindSDK在線網(wǎng)站現(xiàn)在MM32F0140軟件包下載的軟件開(kāi)發(fā)包后pokt-f0140_mdk.zip
,其中就包含了FlexCAN的驅(qū)動(dòng)程序源碼,具體就是hal_flexcan.h
和hal_flexcan.c
兩個(gè)源文件。如圖x所示。
figure-mindsdk-pokt-f0140-flexcan-driver-files
圖x FlexCAN驅(qū)動(dòng)程序源碼## 數(shù)據(jù)結(jié)構(gòu)
這里列寫(xiě)FlexCAN驅(qū)動(dòng)程序中的主要數(shù)據(jù)結(jié)構(gòu)。
配置通信引擎的結(jié)構(gòu)體類(lèi)型
FLEXCAN_Init_Type
類(lèi)型的結(jié)構(gòu)體的變量,用于在初始化FlexCAN總線引擎時(shí)傳入配置參數(shù)。
/*!
* @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
類(lèi)型用于指定FlexCAN總線位時(shí)間的配置參數(shù)。關(guān)于如何配置CAN總線的位時(shí)間,后續(xù)將有專(zhuān)門(mén)文章詳解。
/*!
* @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;
訪問(wèn)MB的結(jié)構(gòu)體類(lèi)型
FLEXCAN_Mb_Type
類(lèi)型的結(jié)構(gòu)體,建立了對(duì)MB在物理存儲(chǔ)空間的映射結(jié)構(gòu),軟件使用該類(lèi)型的結(jié)構(gòu)體整體傳入或讀出硬件MB存儲(chǔ)區(qū)中的內(nèi)容。
/*!
* @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
類(lèi)型的結(jié)構(gòu)體,用于配置在MB中配置接收幀的部分屬性,這相當(dāng)于是FLEXCAN_Mb_Type
的輕量級(jí)版本,但不需要數(shù)據(jù)負(fù)載、數(shù)據(jù)長(zhǎng)度、本地優(yōu)先級(jí)等配置信息。
/*!
* @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
枚舉類(lèi)型指定了可用的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過(guò)濾器的結(jié)構(gòu)體類(lèi)型
FLEXCAN_RxMbMaskConf_Type
可以用于配置全局ID過(guò)濾器和MB專(zhuān)屬I(mǎi)D過(guò)濾器。
/*!
* @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相關(guān)的結(jié)構(gòu)體類(lèi)型
FLEXCAN_RxFifoConf_Type
類(lèi)型用于在啟用FIFO功能時(shí),配置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;
當(dāng)使用FIFO時(shí),需要使用FLEXCAN_RxFifoMaskConf_Type
結(jié)構(gòu)體類(lèi)型的變量配置ID過(guò)濾器。
/*!
* @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;
還有更多枚舉類(lèi)型和宏常量,可繼續(xù)查閱hal_flexcan.h
源文件。
API清單
FlexCAN驅(qū)動(dòng)的API相對(duì)較多,這里做了個(gè)分類(lèi),便于快速索引。更詳細(xì)的內(nèi)容可見(jiàn)源碼。
配置通信引擎的API
使用FlexCAN外設(shè)之前需要初始化驅(qū)動(dòng)引擎。
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);
訪問(wèn)MB的API
這一組API中,第二個(gè)參數(shù)channel
,對(duì)應(yīng)的是MB列表中的索引,F(xiàn)lexCAN中有16個(gè)MB,對(duì)應(yīng)channel
的取值可以是0-15。FlexCAN外設(shè)中MB的內(nèi)存區(qū)是ECC的,在使用之前必須通過(guò)FLEXCAN_ResetMb()函數(shù)復(fù)位選定的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過(guò)濾器的API
ID過(guò)濾器分為全局過(guò)濾器和MB專(zhuān)屬的過(guò)濾器,對(duì)應(yīng)有各自的過(guò)濾碼(掩碼)。
void FLEXCAN_SetGlobalMbMaskConf(FLEXCAN_Type * FLEXCANx, FLEXCAN_RxMbMaskConf_Type * conf);
void FLEXCAN_SetRxMbIndividualMaskConf(FLEXCAN_Type * FLEXCANx, uint32_t channel, FLEXCAN_RxMbMaskConf_Type * conf);
中斷和狀態(tài)的API
FlexCAN的中斷和狀態(tài)標(biāo)志位分別面向FlexCAN引擎和MB,另外還有一些屬性狀態(tài),例如計(jì)數(shù)器、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相關(guān)的API
在配置好FlexCAN引擎后,通過(guò)FLEXCAN_EnableRxFifo()函數(shù)啟用FIFO功能,之后就可以以FIFO的方式訪問(wèn)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驅(qū)動(dòng)設(shè)計(jì)了一些樣例工程,用于演示在一些典型場(chǎng)景中使用FlexCAN的方法。這些樣例工程也可以運(yùn)行在搭載MM32F0140
微控制器的POKT-F0140
開(kāi)發(fā)板上。見(jiàn)表x。
表x MindSDK中的FlexCAN驅(qū)動(dòng)樣例工程清單
回環(huán)通信 flexcan_loopback
FlexCAN外設(shè)的回環(huán)通信功能,就是將FlexCAN外設(shè)模塊的Tx信號(hào)和Rx信號(hào)在模塊內(nèi)部,由軟件配置電路連通,可用于驗(yàn)證在未接入CAN總線網(wǎng)絡(luò)時(shí),節(jié)點(diǎn)軟件本身能否正常收發(fā)通信幀。當(dāng)完成驗(yàn)證后,僅需要通過(guò)軟件關(guān)閉回環(huán)通信功能,即可用已經(jīng)驗(yàn)證過(guò)的收發(fā)過(guò)程同外部CAN總線網(wǎng)絡(luò)對(duì)接。
flexcan_loopback
樣例工程中的源碼,展示了使用FlexCAN模塊回環(huán)通信的方法。除了啟用了回環(huán)通信的功能之外,其余對(duì)CAN通信幀的發(fā)送操作和接收操作同正常對(duì)外通信無(wú)異,因此,本工程也是使用FlexCAN驅(qū)動(dòng)收發(fā)CAN通信幀的最基礎(chǔ)的用例。另外,由于使用了回環(huán)通信,不需要專(zhuān)門(mén)準(zhǔn)備發(fā)送和接收兩塊運(yùn)行不同程序的電路板,僅用一塊開(kāi)發(fā)板即可完成實(shí)驗(yàn)。
在flxcan_loopback
樣例工程的main()
函數(shù)中,除了必要的初始化微控制器的時(shí)鐘、引腳和后臺(tái)人機(jī)交互端口外,先初始化了FlexCAN模塊,然后在while(1)
循環(huán)中,先準(zhǔn)備一組數(shù)據(jù)作為CAN通信幀的數(shù)據(jù)負(fù)載發(fā)送出去,等待發(fā)送完成后,再接收一個(gè)CAN通信幀,等待接收完成后打印到終端顯示接收幀中的數(shù)據(jù)負(fù)載,周而復(fù)始。發(fā)送幀和接收幀的ID使用同一個(gè) APP_FLEXCAN_XFER_ID
,因此可以實(shí)現(xiàn)收發(fā)。
/*
* 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模塊的函數(shù) app_flexcan_init()
,初始化了FlexCAN通信引擎,包括配置CAN總線通信的位時(shí)鐘,配置好了發(fā)送MB和接收MB,分別使用兩個(gè)不同的MB索引BOARD_FLEXCAN_TX_MB_CH
和BOARD_FLEXCAN_RX_MB_CH
,并分別設(shè)定它們?yōu)橛行У姆羌せ顮顟B(tài)。最后還啟用了發(fā)送完成和接收到數(shù)據(jù)幀的中斷。雖然這里也可以使用純粹的輪詢標(biāo)志位實(shí)現(xiàn)流控制,但使用中斷方式便于向后續(xù)用例中過(guò)渡。在中斷服務(wù)程序中,當(dāng)檢測(cè)到有接收幀時(shí),從接收幀的MB中搬運(yùn)接收到的數(shù)據(jù)負(fù)載到內(nèi)存變量app_flexcan_rx_buf
中,然后清接收標(biāo)志位。有實(shí)現(xiàn)代碼如下:
/* 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;
即指定啟用了回環(huán)模式。
發(fā)送數(shù)據(jù)幀的操作被封裝成app_flexcan_tx()
函數(shù)。在該函數(shù)中,將即將發(fā)送的數(shù)據(jù)填充到MB結(jié)構(gòu)體的數(shù)據(jù)負(fù)載中,再將整個(gè)幀結(jié)構(gòu)寫(xiě)入到FlexCAN硬件的MB內(nèi)存區(qū),最后過(guò)向發(fā)送MB的內(nèi)存區(qū)寫(xiě)命令碼,啟動(dòng)發(fā)送過(guò)程。注意,這里使用預(yù)分配的幀ID(而不是作為函數(shù)傳參可配置),發(fā)送數(shù)據(jù)幀(而不是遠(yuǎn)程幀)。有源代碼如下:
/* 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);
}
接收數(shù)據(jù)幀的操作被封裝成app_flexcan_read()
函數(shù)。這里執(zhí)行的操作,僅僅是從預(yù)定的FlexCAN硬件的接收MB內(nèi)存區(qū)中把整個(gè)MB讀出來(lái),然后從MB結(jié)構(gòu)類(lèi)型中提取數(shù)據(jù)負(fù)載,作為傳參返回給函數(shù)調(diào)用者。有源代碼如下:
/* 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;
}
板對(duì)板直接通信 flexcan_b2b_tx & flexcan_b2b_rx
板對(duì)板直接通信的用例,需要兩塊開(kāi)發(fā)板,一個(gè)作為接收方,另一個(gè)作為發(fā)送方,由發(fā)送方發(fā)送CAN通信幀到接收方,從而實(shí)現(xiàn)兩塊電路板通過(guò)CAN總線傳輸數(shù)據(jù)的過(guò)程。這個(gè)實(shí)驗(yàn)的樣例工程同基本的flexcan_loopback
工程非常相近,只是收發(fā)過(guò)程拆分成兩個(gè)獨(dú)立的工程。注意,收發(fā)兩個(gè)工程中使用CAN通信幀的ID也是約定一致的。
相對(duì)于flexcan_loop
工程,獨(dú)立的flexcan_b2b_rx
和flexcan_b2b_tx
工程中對(duì)FlexCAN模塊的初始化過(guò)程,不再啟用回環(huán)模式,而是常規(guī)模式。見(jiàn)源代碼如下:
/* 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);
...
}
接收方電路板運(yùn)行flexcan_b2b_rx
工程的程序:初始化FlexCAN通信引擎后,配置接收MB,開(kāi)中斷等待接收幀完成。在后臺(tái)的FlexCAN中斷服務(wù)程序中,一旦捕獲到約定ID的通信幀,就將接收幀中的數(shù)據(jù)負(fù)載轉(zhuǎn)存到內(nèi)存中的app_flexcan_rx_buf
變量中,并且通過(guò)標(biāo)志變量app_flexcan_rx_flag
告知前臺(tái)程序,然后清除硬件標(biāo)志位。在前臺(tái)的while(1)
循環(huán)中,一旦接收到約定ID的通信幀,就在終端界面打印出接收到幀的數(shù)據(jù)內(nèi)容。
發(fā)送方電路板運(yùn)行flexcan_b2b_tx
工程的程序:初始化FlexCAN通信引擎后,配置發(fā)送MB,開(kāi)中斷等待發(fā)送幀完成。前臺(tái)的while(1)
循環(huán)中,由用戶觸發(fā)向發(fā)送MB填充數(shù)據(jù)負(fù)載,并發(fā)送預(yù)定幀數(shù)據(jù)的操作。在后臺(tái)的FlexCAN中斷服務(wù)程序中,一旦發(fā)送完成約定ID的通信幀,就通過(guò)標(biāo)志變量app_flexcan_tx_flag
告知前臺(tái)程序,然后清除硬件標(biāo)志位。
運(yùn)行實(shí)驗(yàn)時(shí),電腦同時(shí)接入發(fā)送方和接收方的兩個(gè)終端界面,先在發(fā)送方的終端界面中輸入任意字符啟動(dòng)發(fā)送幀過(guò)程,將有CAN通信幀從發(fā)送方上傳CAN總線,接收方亦會(huì)從總線上捕獲到約定同一ID的數(shù)據(jù)幀,解析出其中的數(shù)據(jù)負(fù)載再顯示到接收方的終端界面上。
板對(duì)板請(qǐng)求遠(yuǎn)程幀通信 flexcan_b2b_req & flexcan_b2b_ack
板對(duì)板請(qǐng)求遠(yuǎn)程幀通信的用例,需要兩塊開(kāi)發(fā)板,一個(gè)作為請(qǐng)求方,另一個(gè)作為響應(yīng)方,由請(qǐng)求方發(fā)送CAN通信遠(yuǎn)程幀到應(yīng)答方,應(yīng)答方收到遠(yuǎn)程幀后,準(zhǔn)備好數(shù)據(jù)幀,再將響應(yīng)的數(shù)據(jù)幀發(fā)送至CAN總線,由請(qǐng)求方捕獲,從而實(shí)現(xiàn)兩塊電路板通過(guò)CAN總線讀數(shù)據(jù)的過(guò)程。相對(duì)于板對(duì)板直接通信的寫(xiě)數(shù)據(jù)過(guò)程,板對(duì)板請(qǐng)求遠(yuǎn)程幀通信過(guò)程實(shí)現(xiàn)的是讀數(shù)據(jù)過(guò)程。這個(gè)實(shí)驗(yàn)的樣例工程同基本的flexcan_loopback
工程,以及板對(duì)板直接通信的兩個(gè)工程非常相近,只是收發(fā)過(guò)程拆分成兩個(gè)獨(dú)立的工程,并且原來(lái)的發(fā)送方先發(fā)出遠(yuǎn)程幀再接收數(shù)據(jù)幀,而原來(lái)的接收方將先等待遠(yuǎn)程幀再發(fā)送數(shù)據(jù)幀。注意,收發(fā)兩個(gè)工程中使用CAN通信幀的ID也是約定一致的。
請(qǐng)求方和響應(yīng)方的兩個(gè)工程,同flexcan_loopback
工程對(duì)FlexCAN引擎的初始化過(guò)程完全相同,并且在各自的工程中,也需要處理發(fā)送和接收過(guò)程。不同之處僅在于其中的一個(gè)通信幀從數(shù)據(jù)幀變成的遠(yuǎn)程幀。
響應(yīng)方電路板運(yùn)行flexcan_b2b_ack
工程的程序:初始化FlexCAN通信引擎后,配置接收MB,配置發(fā)送MB,開(kāi)中斷等待發(fā)送和接收幀完成。其中接收MB的幀類(lèi)型為遠(yuǎn)程幀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. */
...
}
請(qǐng)求方電路板運(yùn)行flexcan_b2b_req
工程的程序:初始化FlexCAN通信引擎后,配置接收MB,配置發(fā)送MB,開(kāi)中斷等待發(fā)送和接收幀完成。在發(fā)送請(qǐng)求幀時(shí),設(shè)定MB的幀類(lèi)型為遠(yuǎn)程幀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);
}
當(dāng)運(yùn)行通信過(guò)程時(shí):先啟動(dòng)應(yīng)答方的程序,準(zhǔn)備好響應(yīng)過(guò)程;再請(qǐng)求方的程序,發(fā)出請(qǐng)求的遠(yuǎn)程幀到CAN總線上,應(yīng)答方從CAN總線上捕獲到請(qǐng)求的遠(yuǎn)程幀后,在本機(jī)生成數(shù)據(jù)負(fù)載組,使用同遠(yuǎn)程幀相同的ID,裝成數(shù)據(jù)幀,再上傳至CAN總線;請(qǐng)求方此時(shí)可以捕獲到CAN總線上的同ID的數(shù)據(jù)幀,顯示到終端界面。周而復(fù)始。
總結(jié)
MindSDK中設(shè)計(jì)的FlexCAN驅(qū)動(dòng)程序,對(duì)FlexCAN外設(shè)進(jìn)行了建模,創(chuàng)建了一系列數(shù)據(jù)結(jié)構(gòu)和API,能夠?yàn)檐浖_(kāi)發(fā)者提供初始化FlexCAN通信引擎,通過(guò)MB的結(jié)構(gòu)類(lèi)型發(fā)送數(shù)據(jù)幀、遠(yuǎn)程幀等功能。MindSDK為FlexCAN驅(qū)動(dòng)設(shè)計(jì)的一些樣例工程,演示了在一些典型應(yīng)用場(chǎng)景中(回環(huán)通信、板對(duì)板直接通信、板對(duì)板請(qǐng)求遠(yuǎn)程幀通信)使用FlexCAN驅(qū)動(dòng)的方法。
-
微控制器
+關(guān)注
關(guān)注
48文章
7660瀏覽量
152186 -
CAN總線
+關(guān)注
關(guān)注
145文章
1956瀏覽量
131140 -
通信協(xié)議
+關(guān)注
關(guān)注
28文章
916瀏覽量
40462 -
驅(qū)動(dòng)程序
+關(guān)注
關(guān)注
19文章
849瀏覽量
48234 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4346瀏覽量
63020
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
如何為IMX8啟用/驅(qū)動(dòng)CAN/Flexcan?
求分享IMX8MP Cortex M7 FreeRTOS FlexCAN驅(qū)動(dòng)程序
WINCE驅(qū)動(dòng)程序開(kāi)發(fā)指南
RTL8139網(wǎng)卡驅(qū)動(dòng)程序分析
VxWorks下PC/104-CAN驅(qū)動(dòng)程序設(shè)計(jì)
Windows CE下GPIO驅(qū)動(dòng)程序的設(shè)計(jì)與應(yīng)用
WinCE的OLED驅(qū)動(dòng)程序設(shè)計(jì)
![WinCE的OLED<b class='flag-5'>驅(qū)動(dòng)程序</b>設(shè)計(jì)](https://file1.elecfans.com//web2/M00/A6/29/wKgZomUMPAmAa2F-AAAPu6vo7Ao739.jpg)
評(píng)論