0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

MindSDK中FlexCAN驅(qū)動程序及樣例工程

CHANBAEK ? 來源:安德魯?shù)脑O(shè)計筆記本 ? 作者:安德魯蘇 ? 2023-06-23 15:41 ? 次閱讀

引言

前文介紹了FlexCAN外設(shè)模塊,一種典型的CAN總線引擎子系統(tǒng)的工作機制。那么,用戶在軟件開發(fā)平臺對CAN總線引擎進行編程,需要根據(jù)硬件外設(shè)模塊的功能進行建模,將對CAN總線通信引擎的操作封裝起來,讓開發(fā)者通過軟件開發(fā)平臺的數(shù)據(jù)結(jié)構(gòu)和用戶可編程應(yīng)用接口(API)函數(shù)使用FlexCAN模塊?;?a target="_blank">靈動微電子微控制器的軟件開發(fā)平臺MindSDK,包含了集成FlexCAN外設(shè)的MM32F5270和MM32F0140微控制器,其中就有FlexCAN外設(shè)模塊的驅(qū)動程序以及樣例工程,以及對CAN總線通信協(xié)議CANopen的適配工程。本文將介紹MindSDK中FlexCAN驅(qū)動程序及樣例工程,展現(xiàn)一種典型的CAN總線驅(qū)動程序的實現(xiàn)及應(yīng)用場景。

從MindSDK獲取FlexCAN驅(qū)動程序

通過MindSDK在線發(fā)布網(wǎng)站選擇搭載了MM32F0140微控制器的POKT-F0140開發(fā)板,就可以得到MM32F0140微控制器的軟件開發(fā)包。如圖x所示。

圖片

figure-mindsdk-pokt-f0140-download-package-1

圖x 在MindSDK在線網(wǎng)站現(xiàn)在MM32F0140軟件包下載的軟件開發(fā)包后pokt-f0140_mdk.zip,其中就包含了FlexCAN的驅(qū)動程序源碼,具體就是hal_flexcan.hhal_flexcan.c兩個源文件。如圖x所示。

圖片

figure-mindsdk-pokt-f0140-flexcan-driver-files

圖x FlexCAN驅(qū)動程序源碼## 數(shù)據(jù)結(jié)構(gòu)

這里列寫FlexCAN驅(qū)動程序中的主要數(shù)據(jù)結(jié)構(gòu)。

配置通信引擎的結(jié)構(gòu)體類型

FLEXCAN_Init_Type類型的結(jié)構(gòu)體的變量,用于在初始化FlexCAN總線引擎時傳入配置參數(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類型用于指定FlexCAN總線位時間的配置參數(shù)。關(guān)于如何配置CAN總線的位時間,后續(xù)將有專門文章詳解。

/*!
 * @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的結(jié)構(gòu)體類型

FLEXCAN_Mb_Type類型的結(jié)構(gòu)體,建立了對MB在物理存儲空間的映射結(jié)構(gòu),軟件使用該類型的結(jié)構(gòu)體整體傳入或讀出硬件MB存儲區(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類型的結(jié)構(gòu)體,用于配置在MB中配置接收幀的部分屬性,這相當(dāng)于是FLEXCAN_Mb_Type的輕量級版本,但不需要數(shù)據(jù)負(fù)載、數(shù)據(jù)長度、本地優(yōu)先級等配置信息

/*!
 * @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過濾器的結(jié)構(gòu)體類型

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相關(guān)的結(jié)構(gòu)體類型

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;

當(dāng)使用FIFO時,需要使用FLEXCAN_RxFifoMaskConf_Type結(jié)構(gòu)體類型的變量配置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;

還有更多枚舉類型和宏常量,可繼續(xù)查閱hal_flexcan.h源文件。

API清單

FlexCAN驅(qū)動的API相對較多,這里做了個分類,便于快速索引。更詳細(xì)的內(nèi)容可見源碼。

配置通信引擎的API

使用FlexCAN外設(shè)之前需要初始化驅(qū)動引擎。

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中,第二個參數(shù)channel,對應(yīng)的是MB列表中的索引,F(xiàn)lexCAN中有16個MB,對應(yīng)channel的取值可以是0-15。FlexCAN外設(shè)中MB的內(nèi)存區(qū)是ECC的,在使用之前必須通過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過濾器的API

ID過濾器分為全局過濾器和MB專屬的過濾器,對應(yīng)有各自的過濾碼(掩碼)。

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),例如計數(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引擎后,通過FLEXCAN_EnableRxFifo()函數(shù)啟用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驅(qū)動設(shè)計了一些樣例工程,用于演示在一些典型場景中使用FlexCAN的方法。這些樣例工程也可以運行在搭載MM32F0140微控制器的POKT-F0140開發(fā)板上。見表x。

表x MindSDK中的FlexCAN驅(qū)動樣例工程清單

image.png

回環(huán)通信 flexcan_loopback

FlexCAN外設(shè)的回環(huán)通信功能,就是將FlexCAN外設(shè)模塊的Tx信號和Rx信號在模塊內(nèi)部,由軟件配置電路連通,可用于驗證在未接入CAN總線網(wǎng)絡(luò)時,節(jié)點軟件本身能否正常收發(fā)通信幀。當(dāng)完成驗證后,僅需要通過軟件關(guān)閉回環(huán)通信功能,即可用已經(jīng)驗證過的收發(fā)過程同外部CAN總線網(wǎng)絡(luò)對接。

flexcan_loopback樣例工程中的源碼,展示了使用FlexCAN模塊回環(huán)通信的方法。除了啟用了回環(huán)通信的功能之外,其余對CAN通信幀的發(fā)送操作和接收操作同正常對外通信無異,因此,本工程也是使用FlexCAN驅(qū)動收發(fā)CAN通信幀的最基礎(chǔ)的用例。另外,由于使用了回環(huán)通信,不需要專門準(zhǔn)備發(fā)送和接收兩塊運行不同程序的電路板,僅用一塊開發(fā)板即可完成實驗。

flxcan_loopback樣例工程的main()函數(shù)中,除了必要的初始化微控制器的時鐘、引腳和后臺人機交互端口外,先初始化了FlexCAN模塊,然后在while(1)循環(huán)中,先準(zhǔn)備一組數(shù)據(jù)作為CAN通信幀的數(shù)據(jù)負(fù)載發(fā)送出去,等待發(fā)送完成后,再接收一個CAN通信幀,等待接收完成后打印到終端顯示接收幀中的數(shù)據(jù)負(fù)載,周而復(fù)始。發(fā)送幀和接收幀的ID使用同一個 APP_FLEXCAN_XFER_ID,因此可以實現(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總線通信的位時鐘,配置好了發(fā)送MB和接收MB,分別使用兩個不同的MB索引BOARD_FLEXCAN_TX_MB_CHBOARD_FLEXCAN_RX_MB_CH,并分別設(shè)定它們?yōu)橛行У姆羌せ顮顟B(tài)。最后還啟用了發(fā)送完成和接收到數(shù)據(jù)幀的中斷。雖然這里也可以使用純粹的輪詢標(biāo)志位實現(xiàn)流控制,但使用中斷方式便于向后續(xù)用例中過渡。在中斷服務(wù)程序中,當(dāng)檢測到有接收幀時,從接收幀的MB中搬運接收到的數(shù)據(jù)負(fù)載到內(nèi)存變量app_flexcan_rx_buf中,然后清接收標(biāo)志位。有實現(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ù)載中,再將整個幀結(jié)構(gòu)寫入到FlexCAN硬件的MB內(nèi)存區(qū),最后過向發(fā)送MB的內(nèi)存區(qū)寫命令碼,啟動發(fā)送過程。注意,這里使用預(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ū)中把整個MB讀出來,然后從MB結(jié)構(gòu)類型中提取數(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;
}

板對板直接通信 flexcan_b2b_tx & flexcan_b2b_rx

板對板直接通信的用例,需要兩塊開發(fā)板,一個作為接收方,另一個作為發(fā)送方,由發(fā)送方發(fā)送CAN通信幀到接收方,從而實現(xiàn)兩塊電路板通過CAN總線傳輸數(shù)據(jù)的過程。這個實驗的樣例工程同基本的flexcan_loopback工程非常相近,只是收發(fā)過程拆分成兩個獨立的工程。注意,收發(fā)兩個工程中使用CAN通信幀的ID也是約定一致的。

相對于flexcan_loop工程,獨立的flexcan_b2b_rxflexcan_b2b_tx工程中對FlexCAN模塊的初始化過程,不再啟用回環(huán)模式,而是常規(guī)模式。見源代碼如下:

/* 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中斷服務(wù)程序中,一旦捕獲到約定ID的通信幀,就將接收幀中的數(shù)據(jù)負(fù)載轉(zhuǎn)存到內(nèi)存中的app_flexcan_rx_buf變量中,并且通過標(biāo)志變量app_flexcan_rx_flag告知前臺程序,然后清除硬件標(biāo)志位。在前臺的while(1)循環(huán)中,一旦接收到約定ID的通信幀,就在終端界面打印出接收到幀的數(shù)據(jù)內(nèi)容。

發(fā)送方電路板運行flexcan_b2b_tx工程的程序:初始化FlexCAN通信引擎后,配置發(fā)送MB,開中斷等待發(fā)送幀完成。前臺的while(1)循環(huán)中,由用戶觸發(fā)向發(fā)送MB填充數(shù)據(jù)負(fù)載,并發(fā)送預(yù)定幀數(shù)據(jù)的操作。在后臺的FlexCAN中斷服務(wù)程序中,一旦發(fā)送完成約定ID的通信幀,就通過標(biāo)志變量app_flexcan_tx_flag告知前臺程序,然后清除硬件標(biāo)志位。

運行實驗時,電腦同時接入發(fā)送方和接收方的兩個終端界面,先在發(fā)送方的終端界面中輸入任意字符啟動發(fā)送幀過程,將有CAN通信幀從發(fā)送方上傳CAN總線,接收方亦會從總線上捕獲到約定同一ID的數(shù)據(jù)幀,解析出其中的數(shù)據(jù)負(fù)載再顯示到接收方的終端界面上。

板對板請求遠(yuǎn)程幀通信 flexcan_b2b_req & flexcan_b2b_ack

板對板請求遠(yuǎn)程幀通信的用例,需要兩塊開發(fā)板,一個作為請求方,另一個作為響應(yīng)方,由請求方發(fā)送CAN通信遠(yuǎn)程幀到應(yīng)答方,應(yīng)答方收到遠(yuǎn)程幀后,準(zhǔn)備好數(shù)據(jù)幀,再將響應(yīng)的數(shù)據(jù)幀發(fā)送至CAN總線,由請求方捕獲,從而實現(xiàn)兩塊電路板通過CAN總線讀數(shù)據(jù)的過程。相對于板對板直接通信的寫數(shù)據(jù)過程,板對板請求遠(yuǎn)程幀通信過程實現(xiàn)的是讀數(shù)據(jù)過程。這個實驗的樣例工程同基本的flexcan_loopback工程,以及板對板直接通信的兩個工程非常相近,只是收發(fā)過程拆分成兩個獨立的工程,并且原來的發(fā)送方先發(fā)出遠(yuǎn)程幀再接收數(shù)據(jù)幀,而原來的接收方將先等待遠(yuǎn)程幀再發(fā)送數(shù)據(jù)幀。注意,收發(fā)兩個工程中使用CAN通信幀的ID也是約定一致的。

請求方和響應(yīng)方的兩個工程,同flexcan_loopback工程對FlexCAN引擎的初始化過程完全相同,并且在各自的工程中,也需要處理發(fā)送和接收過程。不同之處僅在于其中的一個通信幀從數(shù)據(jù)幀變成的遠(yuǎn)程幀。

響應(yīng)方電路板運行flexcan_b2b_ack工程的程序:初始化FlexCAN通信引擎后,配置接收MB,配置發(fā)送MB,開中斷等待發(fā)送和接收幀完成。其中接收MB的幀類型為遠(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. */
    ...
}

請求方電路板運行flexcan_b2b_req工程的程序:初始化FlexCAN通信引擎后,配置接收MB,配置發(fā)送MB,開中斷等待發(fā)送和接收幀完成。在發(fā)送請求幀時,設(shè)定MB的幀類型為遠(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īng)答方的程序,準(zhǔn)備好響應(yīng)過程;再請求方的程序,發(fā)出請求的遠(yuǎn)程幀到CAN總線上,應(yīng)答方從CAN總線上捕獲到請求的遠(yuǎn)程幀后,在本機生成數(shù)據(jù)負(fù)載組,使用同遠(yuǎn)程幀相同的ID,裝成數(shù)據(jù)幀,再上傳至CAN總線;請求方此時可以捕獲到CAN總線上的同ID的數(shù)據(jù)幀,顯示到終端界面。周而復(fù)始。

總結(jié)

MindSDK中設(shè)計的FlexCAN驅(qū)動程序,對FlexCAN外設(shè)進行了建模,創(chuàng)建了一系列數(shù)據(jù)結(jié)構(gòu)和API,能夠為軟件開發(fā)者提供初始化FlexCAN通信引擎,通過MB的結(jié)構(gòu)類型發(fā)送數(shù)據(jù)幀、遠(yuǎn)程幀等功能。MindSDK為FlexCAN驅(qū)動設(shè)計的一些樣例工程,演示了在一些典型應(yīng)用場景中(回環(huán)通信、板對板直接通信、板對板請求遠(yuǎn)程幀通信)使用FlexCAN驅(qū)動的方法。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 微控制器
    +關(guān)注

    關(guān)注

    48

    文章

    7399

    瀏覽量

    150681
  • CAN總線
    +關(guān)注

    關(guān)注

    145

    文章

    1908

    瀏覽量

    130516
  • 通信協(xié)議
    +關(guān)注

    關(guān)注

    28

    文章

    826

    瀏覽量

    40198
  • 驅(qū)動程序
    +關(guān)注

    關(guān)注

    19

    文章

    814

    瀏覽量

    47872
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4264

    瀏覽量

    62254
收藏 人收藏

    評論

    相關(guān)推薦

    如何為IMX8啟用/驅(qū)動CAN/Flexcan?

    我們剛開始使用 IMX8,我們正在尋找 IMx8dx/qxp 的 CAN/Flexcan 驅(qū)動程序。我們在 DTS 文件啟用了 Flexcan,但在內(nèi)核
    發(fā)表于 04-17 08:50

    求分享IMX8MP Cortex M7 FreeRTOS FlexCAN驅(qū)動程序

    IMX8MP Cortex M7 FreeRTOS FlexCAN 驅(qū)動程序
    發(fā)表于 04-20 07:32

    求分享FlexCAN FreeRTOS驅(qū)動程序

    FlexCAN FreeRTOS 驅(qū)動程序
    發(fā)表于 04-21 06:19

    WINCE驅(qū)動程序開發(fā)指南

    CE驅(qū)動程序所有驅(qū)動皆為動態(tài)鏈接庫驅(qū)動實現(xiàn)可以調(diào)用所有標(biāo)準(zhǔn)的APICE驅(qū)動程序模型本機驅(qū)動程序
    發(fā)表于 07-07 15:06 ?41次下載

    RTL8139網(wǎng)卡驅(qū)動程序分析

    對多數(shù)驅(qū)動程序開發(fā)的學(xué)習(xí)者來說,總是感覺很難⼊門,不能從整體上把握驅(qū)動程序是如何驅(qū)動硬件設(shè)備⼯作的。本文以Linux內(nèi)核8139網(wǎng)卡
    發(fā)表于 10-19 15:04 ?39次下載

    VxWorks下PC/104-CAN驅(qū)動程序設(shè)計

    詳細(xì)介紹實時多任務(wù)操作系統(tǒng)VxWorks環(huán)境下驅(qū)動程序的設(shè)計原理;針對驅(qū)動程序實現(xiàn)的困難,給出VxWorks 下實現(xiàn)驅(qū)動程序工程步驟。文章以PC/104-CAN 適配卡為
    發(fā)表于 04-16 09:40 ?12次下載

    Windows CE下GPIO驅(qū)動程序的設(shè)計與應(yīng)用

    Windows CE 流接口設(shè)備驅(qū)動程序是一種基本的設(shè)備驅(qū)動程序。本文以S3C2410 開發(fā)板的GPIO 流接口驅(qū)動,說明了
    發(fā)表于 01-06 16:02 ?48次下載

    WinCE的OLED驅(qū)動程序設(shè)計

    以維信諾VGG13264C 132×64 OLED 顯示模塊的WindowsCE 驅(qū)動程序設(shè)計為, 詳細(xì)闡述了嵌入式Windows CE 驅(qū)動程序的開發(fā)過程,并對設(shè)計實現(xiàn)的驅(qū)動程序
    發(fā)表于 03-26 16:10 ?2083次閱讀
    WinCE的OLED<b class='flag-5'>驅(qū)動程序</b>設(shè)計

    Xilinx設(shè)備的驅(qū)動程序

    Xilinx為所有設(shè)備都提供了standalone模式的驅(qū)動程序。Xilinx SDK會根據(jù)硬件系統(tǒng)的配置情況,將使用的設(shè)備的驅(qū)動加入到創(chuàng)建的BSP工程。Xilinx設(shè)備的
    發(fā)表于 11-18 10:51 ?8066次閱讀

    Linux設(shè)備驅(qū)動程序的平臺驅(qū)動程序和字符驅(qū)動程序介紹

    了解Linux設(shè)備驅(qū)動程序的基礎(chǔ)知識,重點介紹平臺驅(qū)動程序和字符驅(qū)動程序。 提出了簡單的平臺驅(qū)動程序實現(xiàn)和簡單的字符驅(qū)動程序實現(xiàn)。
    的頭像 發(fā)表于 11-27 06:32 ?4228次閱讀

    MindSDK應(yīng)用基礎(chǔ)—TIM模塊

    MindSDK為MM32使用星辰處理器內(nèi)核的系列微控制器,實現(xiàn)了一組TIM工程MindSDK
    的頭像 發(fā)表于 06-29 17:16 ?792次閱讀

    MindSDK為MM32實現(xiàn)了一組TIM工程

    MindSDK為MM32使用星辰處理器內(nèi)核的系列微控制器,實現(xiàn)了一組TIM工程,MindSDK
    的頭像 發(fā)表于 06-30 17:32 ?838次閱讀

    MindSDK應(yīng)用基礎(chǔ)—SPI模塊簡介

    MindSDK為MM32主流的微控制器,實現(xiàn)了一系列SPI驅(qū)動工程。本文通過講解 SPI 模塊的
    的頭像 發(fā)表于 08-10 17:14 ?1011次閱讀

    MindSDK應(yīng)用基礎(chǔ)—ADC模塊

    MindSDK為MM32主流的微控制器,實現(xiàn)了一組ADC工程。本文通過講解ADC模塊的
    的頭像 發(fā)表于 08-17 17:16 ?871次閱讀

    MindSDK應(yīng)用基礎(chǔ)——TIM模塊

    MindSDK應(yīng)用基礎(chǔ)——TIM模塊
    的頭像 發(fā)表于 10-25 16:25 ?505次閱讀