溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

SylixOS SylixOS CAN總線驅(qū)動之三

發(fā)布時間:2020-07-23 02:25:09 來源:網(wǎng)絡(luò) 閱讀:527 作者:Best_CC 欄目:網(wǎng)絡(luò)安全


  1. SylixOS CAN報文傳送流程

  2. CAN報文傳送流程框圖

    在SylixOS中CAN報文的傳輸框圖如圖 11所示。

    SylixOS SylixOS CAN總線驅(qū)動之三

    圖 11 SylixOS CAN報文傳輸框圖

    (注:此文檔承接之前的文檔編寫,之前文檔中詳細介紹過的報文,傳輸結(jié)構(gòu)體在此文檔中不做詳細介紹。)

     

  3. SylixOS CAN報文緩存機制

    在SylixOS中CAN報文的傳輸不是底層和上層應(yīng)用的直接傳輸。而是在底層和應(yīng)用層中間加了一層系統(tǒng)緩存隊列。所有收發(fā)的CAN報文都要先經(jīng)過一個系統(tǒng)緩存機制傳輸?shù)秸嬲{(diào)用到它的地方。

  4. 系統(tǒng)CAN發(fā)送報文緩存

    SylixOS中CAN報文是以消息隊列的方式進行緩存的,程序清單 21是向消息隊列中寫入一幀CAN報文的具體實現(xiàn)。

    程序清單 21從緩存中讀取一幀CAN報文

    /*********************************************************************************************************
    ** 函數(shù)名稱: __canITx
    ** 功能描述: 從發(fā)送緩沖區(qū)中讀出一個數(shù)據(jù)
    ** 輸 入  :
    **           pcanDev           CAN 設(shè)備
    **           pcanframe         指向待讀出的數(shù)據(jù)
    ** 輸 出  : ERROR_NONE or PX_ERROR
    ** 全局變量:
    ** 調(diào)用模塊:
    *********************************************************************************************************/
    static INT  __canITx (__CAN_DEV  *pcanDev, PCAN_FRAME  pcanframe)
    {
        INTREG  iregInterLevel;
        INT     iTemp = 0;
    
        if (!pcanDev || !pcanframe) {
            return (PX_ERROR);
        }
    
        iTemp = __canReadQueue(pcanDev,
                               pcanDev->CAN_pcanqSendQueue,
                               pcanframe, 1);                               /*  從發(fā)送隊列中讀取一幀數(shù)據(jù)    */
    
        LW_SPIN_LOCK_QUICK(&pcanDev->CAN_slLock, &iregInterLevel);
        if (iTemp <=  0) {
            pcanDev->CAN_canstatWriteState.CANSTAT_bBufEmpty = LW_TRUE;     /*  發(fā)送隊列空                  */
        }
        LW_SPIN_UNLOCK_QUICK(&pcanDev->CAN_slLock, iregInterLevel);
    
        API_SemaphoreBPost(pcanDev->CAN_ulSendSemB);                        /*  釋放信號量                  */
        SEL_WAKE_UP_ALL(&pcanDev->CAN_selwulList, SELWRITE);                /*  釋放所有等待寫的線程        */
    
        return ((iTemp) ? (ERROR_NONE) : (PX_ERROR));
    }



     

  5. 系統(tǒng)CAN接收報文緩存

    上層應(yīng)用向底層傳輸一幀CAN報文的時候也是通過系統(tǒng)緩存,向系統(tǒng)緩存中寫入一幀CAN報文的具體實現(xiàn)如程序清單 22所示。

    程序清單 22向緩存中寫入一幀CAN報文


    /*********************************************************************************************************
    ** 函數(shù)名稱: __canIRx
    ** 功能描述: 向接收緩沖區(qū)中寫入一個數(shù)據(jù)
    ** 輸 入  :
    **           pcanDev            CAN 設(shè)備
    **           pcanframe          指向待寫入的數(shù)據(jù)
    ** 輸 出  : ERROR_NONE or PX_ERROR
    ** 全局變量:
    ** 調(diào)用模塊:
    *********************************************************************************************************/
    static INT  __canIRx (__CAN_DEV  *pcanDev, PCAN_FRAME   pcanframe)
    {
        INT     iTemp = 0;
    
        if (!pcanDev || !pcanframe) {
            return (PX_ERROR);
        }
    
        iTemp = __canWriteQueue(pcanDev,
                                pcanDev->CAN_pcanqRecvQueue,
                                pcanframe, 1);                              /*  往接收隊列中寫入一幀數(shù)據(jù)    */
    
        API_SemaphoreBPost(pcanDev->CAN_ulRcvSemB);                         /*  釋放信號量                  */
        SEL_WAKE_UP_ALL(&pcanDev->CAN_selwulList, SELREAD);                 /*  select() 激活               */
    
        return ((iTemp) ? (ERROR_NONE) : (PX_ERROR));
    }


     


  6. 具體調(diào)用實現(xiàn)

  7. 應(yīng)用層傳輸?shù)津?qū)動層具體實現(xiàn)

    第一步:如程序清單 31所示,在應(yīng)用層創(chuàng)建一個線程,打開一個CAN設(shè)備。

     

    程序清單 31打開CAN設(shè)備


        iFd = open(devname, O_RDWR, 0666);
        if (iFd < 0) {
            printf("failed to open %s!\n", devname);
            return  (LW_NULL);
        }


     


    第二步:如程序清單 32所示,填充一個CAN報文結(jié)構(gòu)體。

    程序清單 32填充CAN報文

     CAN_FRAME canframe;
    canframe.CAN_bExtId = LW_FALSE;
    canframe.CAN_bRtr = LW_FALSE;
    canframe.CAN_ucLen = CAN_MAX_DATA;
    lib_memcpy((CHAR *)canframe.CAN_ucData, "01234567", CAN_MAX_DATA);
    canframe.CAN_uiId = 0;




     

    第三步:如程序清單 33所示,調(diào)用write函數(shù)向系統(tǒng)TX緩存隊列中寫入一幀CAN報文,再調(diào)用ioctl函數(shù)實現(xiàn)底層傳輸。

    程序清單 33填充發(fā)送緩存

    stLen = write(iFd, &canframe, sizeof(CAN_FRAME));
    ioctl(iFd, CAN_DEV_STARTUP, 0);
    case CAN_DEV_STARTUP:
         __flexcanStartup(pCanchan);
         break;


    第四步:如程序清單 34所示,最終調(diào)用到底層傳輸函數(shù)。從系統(tǒng)隊列中讀取一幀CAN報文后對設(shè)備寄存器進行相關(guān)操作將消息傳輸?shù)娇偩€上。

    程序清單 34底層starup函數(shù)


    /*********************************************************************************************************
    ** 函數(shù)名稱: __flexcanStartup
    ** 功能描述: 啟動數(shù)據(jù)發(fā)送
    ** 輸  入  : pCanchan    通道對象
    ** 輸  出  : NONE
    ** 全局變量:
    ** 調(diào)用模塊:
    *********************************************************************************************************/
    static INT __flexcanStartup (CAN_CHAN  *pCanchan)
    {
        FLEXCAN_CHAN   *pChannel = container_of(pCanchan, FLEXCAN_CHAN, CANCH_canchan);
        CAN_FRAME       canFrame;
        INT             iCount;
    
        if (!pChannel->CANCH_pcbGetTx) {
            return  (PX_ERROR);
        }
    
        while (pChannel->CANCH_pcbGetTx(pChannel->CANCH_pvGetTxArg,         /* 從發(fā)送緩沖區(qū)中讀取數(shù)據(jù)發(fā)送   */
                                       &canFrame) == ERROR_NONE) {
            __flexcanSend(pChannel, &canFrame);
    
        }
    
        return  (ERROR_NONE);
    }


    注:如果想要發(fā)送多幀CAN報文,在寫入操作結(jié)束后需要加等待,以確保所有的CAN報文都成功寫入系統(tǒng)緩存隊列中。


     

  8. 驅(qū)動層傳輸?shù)綉?yīng)用層

    第一步:底層如果接收到CAN報文以后,會觸發(fā)一次中斷,在中斷服務(wù)函數(shù)中所做的事就是判斷狀態(tài)標(biāo)志位置,如果是接收中斷,就把接收到的CAN報文通過回調(diào)函數(shù)寫入,系統(tǒng)緩存隊列中,具體實現(xiàn)如程序清單 35所示。

    程序清單 35 CAN底層中斷服務(wù)函數(shù)

     

    /*********************************************************************************************************
    ** 函數(shù)名稱: __flexcanIrq
    ** 功能描述: can 中斷服務(wù)程序
    ** 輸  入  : pChannel         通道對象
    **           ulVector         中斷向量號
    ** 輸  出  : ERROR CODE
    ** 全局變量:
    ** 調(diào)用模塊:
    *********************************************************************************************************/
    static irqreturn_t __flexcanIrq (PVOID pvArg, ULONG ulVector)
    {
        FLEXCAN_CHAN  *pChannel;
        UINT32         uiIflag1, uiEsr, uiValue;
        CAN_FRAME      canframe;
    
        can_debug("[CAN]irq\r\n");
    
        pChannel = (FLEXCAN_CHAN *)pvArg;
        uiIflag1 = CAN_READ(FLEXCAN_IFLAG1);
        uiEsr    = CAN_READ(FLEXCAN_ESR1);
    
        uiValue = CAN_READ(FLEXCAN_CTRL1);
        uiValue &= ~(FLEXCAN_CTRL1_ERR_ALL);
        CAN_WRITE(FLEXCAN_CTRL1, uiValue);
        CAN_WRITE(FLEXCAN_IMASK1, 0);
    
        if (uiEsr & FLEXCAN_ESR1_ERR_ALL) {
            can_debug("There is something wrong!\n");
            CAN_READ(FLEXCAN_ESR1);
            CAN_WRITE(FLEXCAN_ESR1, FLEXCAN_ESR1_ERR_ALL);
        }
    
        if (uiEsr & FLEXCAN_ESR1_RX) {
            if (uiIflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) {
                CAN_WRITE(FLEXCAN_IMASK1, FLEXCAN_IFLAG_DEFAULT & ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE);
                memset(&canframe, 0, sizeof(CAN_FRAME));
                __flexcanRecv(pChannel, &canframe);
                if (pChannel->CANCH_pcbPutRcv(pChannel->CANCH_pvPutRcvArg, &canframe) != ERROR_NONE) {
                    pChannel->CANCH_pcbSetBusState(pChannel->CANCH_pvSetBusStateArg,
                                                   CAN_DEV_BUS_RXBUFF_OVERRUN);
                }
            }
        }
    
        if (uiIflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
            can_debug("FIFO overflow\n");
            CAN_WRITE(FLEXCAN_IFLAG1, FLEXCAN_IFLAG_RX_FIFO_OVERFLOW);
        }
    
        CAN_WRITE(FLEXCAN_IMASK1, FLEXCAN_IFLAG_DEFAULT);
        return  (LW_IRQ_HANDLED);
    }



    第二步:在應(yīng)用程序中創(chuàng)建一個線程,在線程中所做的事情就是不間斷得讀取系統(tǒng)緩存的消息隊列。如果緩存不為空,就讀取里面的CAN報文,并打印,具體操作如程序清單 36所示。

    程序清單 36 CAN應(yīng)用層讀取緩存


        while (1) {
            stLen = read(iFd, &canframe, sizeof(STR_CANMSG_T));
            stFrameNum = stLen / sizeof(STR_CANMSG_T);
    
            if (stFrameNum != 1) {
                printf("failed to recv can frame, abort recving!\n");
                break;
            } else {
                sprintf(cFramInfo, "id=%d, len=%d, data=%02x %02x %02x %02x %02x %02x %02x %02x\n",
                        canframe.Id, (INT)canframe.DLC,
                        canframe.Data[0],
                        canframe.Data[1],
                        canframe.Data[2],
                        canframe.Data[3],
                        canframe.Data[4],
                        canframe.Data[5],
                        canframe.Data[6],
                        canframe.Data[7]);
                printf(cFramInfo);
            }
        }


    CAN報文傳輸流程,到此結(jié)束。


     

  9. 免責(zé)聲明

    內(nèi)部交流文檔,若發(fā)現(xiàn)相關(guān)錯誤或者建議,請及時聯(lián)系文檔創(chuàng)建者進行修訂和更新。


向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI