SylixOS 基於AT91SAM9X25的CAN總線傳輸流程解析

  1. 概述

    本文檔是在AT91SAM9X25平臺上進行SylixOS CAN總線驅動開發時,對CAN總線底層傳輸流程的解析。

    適用於正在學習CAN總線驅動的技術工程師。

     

  2. 技術實現

    CAN總線的傳輸流程可以分成兩個部分:

    一部分是CAN總線的發送流程,主要工作是將準備發送的數據填充到對應的寄存器,並使能開始傳輸位和郵箱中斷位;另一部分是CAN總線的中斷處理流程,主要工作是對觸發中斷的中斷源進行判斷,並對不同的中斷進行相關處理。

  3. CAN總線的發送流程

    AT91SAM9X25平臺上,CAN總線發送流程如圖 21所示。在填寫數據的幀ID時,必須要將郵箱設置爲禁用模式。正常情況下,當我們將數據填充完成,開始發送數據時,就可以在總線上測到我們發送的數據。這裏使能的郵箱中斷是傳輸完成中斷。

    21 CAN總線的發送流程圖

    具體的代碼實現如程序清單 21所示。

    程序清單 21 CAN總線的傳輸函數

    /*********************************************************************************************************
    ** 函數名稱: __canTransmit
    ** 功能描述: CAN的傳輸
    ** 輸    入: pChannel     通道對象
    **           pcanFrame    can幀結構體指針
    ** 輸    出:
    ** 返    回: LW_FALSE     傳輸出錯
    **           LW_TRUE      傳輸成功
    *********************************************************************************************************/
    static INT  __canTransmit (__PCAN_CHANNEL  pChannel,
                               CAN_FRAME      *pcanFrame)
    {
        UINT uiRegMid;
        UINT uiRegMcr;
    
        if (pcanFrame->CAN_bExtId) {                                        /*  如果是擴展幀                */
            uiRegMid = (pcanFrame->CAN_uiId & CAN_EFF_MASK) | CAN_MID_MIDE;
        } else {                                                            /*  如果是標準幀                */
            uiRegMid = (pcanFrame->CAN_uiId & CAN_SFF_MASK) << CAN_MID_MIDVA_SHIFT;
        }
        uiRegMcr = (pcanFrame->CAN_bRtr & 1 ? CAN_MCR_MRTR : 0)  |
                    (pcanFrame->CAN_ucLen << CAN_MSR_MDLC_SHIFT) |
                    CAN_MCR_MTCR;
    
        writel((MB_MODE_DISABLED) | SET_PRIO_IS_0,                          /*  寫ID時,將郵箱設爲禁用模式  */
               REG_CAN_MMR(CHANNEL, MB_TX));
        writel(uiRegMid, REG_CAN_MID(CHANNEL, MB_TX));                      /*  將ID寫到對應寄存器          */
        writel((MB_MODE_TX) | SET_PRIO_IS_0,                                /*  設置爲TX模式                */
               REG_CAN_MMR(CHANNEL, MB_TX));
    
        if (!(readl(REG_CAN_MSR(CHANNEL, MB_TX)) & CAN_MSR_MRDY)) {
            printk("TX Mailbox is busy!\n");
            return (LW_FALSE);
        }
    
        if (pcanFrame->CAN_ucLen > 0) {                                     /*  如果有數據                  */
            UINT uiDataL;
            uiDataL  = pcanFrame->CAN_ucData[0] << 0;
            uiDataL += pcanFrame->CAN_ucData[1] << 8;
            uiDataL += pcanFrame->CAN_ucData[2] << 16;
            uiDataL += pcanFrame->CAN_ucData[3] << 24;
            writel(uiDataL, REG_CAN_MDL(CHANNEL, MB_TX));                   /*  填充數據寄存器              */
        }
        if (pcanFrame->CAN_ucLen > 3) {                                     /*  超過4個字節數據             */
            UINT uiDataH;
            uiDataH  = pcanFrame->CAN_ucData[4] << 0;
            uiDataH += pcanFrame->CAN_ucData[5] << 8;
            uiDataH += pcanFrame->CAN_ucData[6] << 16;
            uiDataH += pcanFrame->CAN_ucData[7] << 24;
            writel(uiDataH, REG_CAN_MDH(CHANNEL, MB_TX));                   /*  填充數據寄存器              */
        }
    
        writel(uiRegMcr, REG_CAN_MCR(CHANNEL, MB_TX));                      /*  觸發傳輸                    */
        writel((1 << MB_TX), REG_CAN_IER(CHANNEL));                         /*  使能發送郵箱中斷            */
    
        return (LW_TRUE);
    }

    
    
     

  4. CAN總線的中斷處理流程

    CAN總線的中斷處理流程如圖 22所示。在AT91SAM9X25平臺上,讀狀態寄存器(REG_CAN_SR)就可以清除中斷標誌位。通過對狀態寄存器和中斷屏蔽寄存器的比較,可以判斷出是哪一種中斷,並進行相應的處理。

    22 CAN總線的中斷處理流程圖

    具體代碼實現如程序清單 22所示。

     

    程序清單 22 CAN總線的中斷處理函數

    /*********************************************************************************************************
    ** 函數名稱: __canIrq
    ** 功能描述: 中斷服務函數
    ** 輸  入  : pCanchan         通道對象
    **           ulVector         中斷向量號
    ** 輸  出  : LW_IRQ_HANDLED   系統中斷返回值
    **           LW_IRQ_NONE      系統中斷返回值
    *********************************************************************************************************/
    static irqreturn_t __canIrq (__PCAN_CHANNEL  pChannel, ULONG  ulVector)
    {
        UINT  uiRegSr;
        UINT  uiRegImr;
        UINT  uiRxOrErr;
    
        uiRegSr  = readl(REG_CAN_SR(CHANNEL));                              /*  清除中斷標誌位              */
        uiRegImr = readl(REG_CAN_IMR(CHANNEL));
        uiRegSr &= uiRegImr;
        if (!uiRegSr) {
            goto exit;
        }
    
        /*
         *  Rx和錯誤中斷
         */
        uiRxOrErr = ((1 << MB_RX)                                           /*  RX和錯誤中斷的中斷位        */
                     | AT91_IRQ_ERR_FRAME);
        if (uiRegSr & uiRxOrErr) {
            if (uiRegSr & (1 << MB_RX)) {
                __canReadMsg(pChannel);
            } else {
                _DebugFormat(__PRINTMESSAGE_LEVEL, "__canIrq: Frame error!\r\n");
                readl(REG_CAN_SR(CHANNEL));                                 /*  清除錯誤中斷標誌位          */
                return (LW_IRQ_NONE);
            }
        }
    
        /*
         *  Tx中斷
         */
        if (uiRegSr & (AT91_MB_MASK(MAILBOXES_NUM) & (~AT91_MB_MASK(MB_TX)))) {
            writel(1 << MB_TX, REG_CAN_IDR(CHANNEL));                       /*  禁用發送郵箱的中斷          */
        }
    
    exit:
        return (LW_IRQ_HANDLED);
    }
    

     

  5. 免責聲明

    內部交流文檔,僅針對AT91SAM9X25相關平臺,若發現相關錯誤或者建議,請及時聯繫文檔創建者進行修訂和更新。

發佈了27 篇原創文章 · 獲贊 50 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章