<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

MindSDK中FlexCAN驅動程序及樣例工程

CHANBAEK ? 來源:安德魯的設計筆記本 ? 作者:安德魯蘇 ? 2023-06-23 15:41 ? 次閱讀

引言

前文介紹了FlexCAN外設模塊,一種典型的CAN總線引擎子系統的工作機制。那么,用戶在軟件開發平臺對CAN總線引擎進行編程,需要根據硬件外設模塊的功能進行建模,將對CAN總線通信引擎的操作封裝起來,讓開發者通過軟件開發平臺的數據結構和用戶可編程應用接口(API)函數使用FlexCAN模塊?;?a target="_blank">靈動微電子微控制器的軟件開發平臺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.hhal_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驅動樣例工程清單

image.png

回環通信 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_CHBOARD_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_rxflexcan_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

    文章

    6855

    瀏覽量

    148055
  • CAN總線
    +關注

    關注

    145

    文章

    1817

    瀏覽量

    129798
  • 通信協議
    +關注

    關注

    28

    文章

    746

    瀏覽量

    39895
  • 驅動程序
    +關注

    關注

    19

    文章

    774

    瀏覽量

    47341
  • 函數
    +關注

    關注

    3

    文章

    4093

    瀏覽量

    61417
收藏 人收藏

    評論

    相關推薦

    如何在FlexCAN配置頁面設置CAN波特率500KBaud?

    我使用 S32DS 創建了一個新的 FlexCAN_Ip_Example_S32R45_M7 項目,并在驅動程序->FlexCAN_1->FlexCAN 配置頁面中將其
    發表于 03-22 07:05

    如何為IMX8啟用/驅動CAN/Flexcan?

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

    求分享IMX8MP Cortex M7 FreeRTOS FlexCAN驅動程序

    IMX8MP Cortex M7 FreeRTOS FlexCAN 驅動程序
    發表于 04-20 07:32

    求分享FlexCAN FreeRTOS驅動程序

    FlexCAN FreeRTOS 驅動程序
    發表于 04-21 06:19

    S32DS3.4在S32K312工程issue添加FlexCan RTD Driver,沒有編譯成功怎么解決?

    添加“FlexCan驅動程序 工具:S3DS3.4 RTD:PlatformSDK_S32K3_2022_07 版本:2.0.1 錯誤信息為附件圖片error.jpg。
    發表于 05-22 09:11

    CAN0_ORed_Err_Wakeup_IRQHandler() 被觸發并且FLEXCAN_GetErrorCounters返回0是為什么?

    我在 s32k116 上使用 flexcan 驅動程序。我有一個總共有 2 個節點的 CAN 網絡。我正在嘗試不同的測試用,試圖測試驅動程序和相關代碼的耐用性。有一種情況
    發表于 05-31 07:52

    WINCE驅動程序開發指南

    CE驅動程序所有驅動皆為動態鏈接庫驅動實現中可以調用所有標準的APICE驅動程序模型本機驅動程序流接口
    發表于 07-07 15:06 ?41次下載

    天語手機usb驅動程序

    天語手機usb驅動程序:天語手機usb驅動程序下載
    發表于 04-30 12:36 ?792次下載

    HC6800的USB驅動程序

    HC6800的USB驅動程序HC6800的USB驅動程序HC6800的USB驅動程序HC6800的USB驅動程序HC6800的USB驅動程序
    發表于 12-28 15:28 ?0次下載

    第9章 Linux驅動程序設計

    9.1 Linux 設備驅動程序 9.2 Linux經典Hello world驅動程序 9.3 Linux字符設備驅動程序實例
    發表于 04-11 14:56 ?3次下載

    Xilinx設備的驅動程序

    Xilinx為所有設備都提供了standalone模式的驅動程序。Xilinx SDK會根據硬件系統的配置情況,將使用的設備的驅動加入到創建的BSP工程中。Xilinx設備的驅動程序
    發表于 11-18 10:51 ?7798次閱讀

    CDM20600驅動程序,USB驅動程序和并口驅動應用程序(免費下載)

    本文檔的主要內容是CDM20600驅動程序,USB驅動程序和并口驅動應用程序(免費下載)詳細資料概述
    發表于 06-06 10:00 ?57次下載
    CDM20600<b class='flag-5'>驅動程序</b>,USB<b class='flag-5'>驅動程序</b>和并口<b class='flag-5'>驅動</b>應用<b class='flag-5'>程序</b>(免費下載)

    Linux設備驅動程序的平臺驅動程序和字符驅動程序介紹

    了解Linux設備驅動程序的基礎知識,重點介紹平臺驅動程序和字符驅動程序。 提出了簡單的平臺驅動程序實現和簡單的字符驅動程序實現。
    的頭像 發表于 11-27 06:32 ?4030次閱讀

    FX3驅動程序FX3驅動程序

    FX3驅動程序FX3驅動程序
    發表于 03-22 22:35 ?102次下載
    FX3<b class='flag-5'>驅動程序</b>FX3<b class='flag-5'>驅動程序</b>

    USB驅動程序

    USB驅動程序
    發表于 08-17 11:47 ?54次下載
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>