SylixOS裏NUC970平臺SPI總線數據傳輸

  1. 概述

    本文檔是對NUC970平臺上的SylixOS SPI總線數據傳輸的詳細分析。

     

  2. SPI總線數據傳輸流程

    NUC970平臺上SPI總線數據傳輸流程如圖 21所示。

    當一個消息準備傳輸時,第一步判斷髮送和接收緩存區是否爲空,若爲空,就沒有要接收或發送的數據,直接返回。

    第二步,判斷消息長度是否大於指定的值(可以改變,但要大於16個字節),若大於,以16字節爲單位傳輸數據,否則以單字節爲單位傳輸數據。

    21 SPI數據傳輸流程圖

  3. SPI總線的消息類型

    在SylixOS中,SPI總線的消息類型,如程序清單 21所示。

    程序清單 21 SPI總線消息類型

    /*********************************************************************************************************
      SPI 總線傳輸控制消息
    *********************************************************************************************************/
    
    typedef struct lw_spi_message {
        UINT16                   SPIMSG_usBitsPerOp;                        /*  操作單位bits數              */
        UINT16                   SPIMSG_usFlag;                             /*  傳輸控制參數                */
        
    #define LW_SPI_M_CPOL_0      0x0000                                     /*  CPOL 配置                   */
    #define LW_SPI_M_CPOL_1      0x0001
    #define LW_SPI_M_CPHA_0      0x0000                                     /*  CPHA 配置                   */
    #define LW_SPI_M_CPHA_1      0x0002
    
    #define LW_SPI_M_CPOL_EN     0x0004                                     /*  是否設置新的 CPOL 配置      */
                                                                            /*  否則 CPOL 配置與上次傳輸相同*/
    #define LW_SPI_M_CPHA_EN     0x0008                                     /*  是否設置新的 CPHA 配置      */
                                                                            /*  否則 CPHA 配置與上次傳輸相同*/
    
    #define LW_SPI_M_WRBUF_FIX   0x0010                                     /*  發送緩衝區僅發送第一個字符  */
    #define LW_SPI_M_RDBUF_FIX   0x0020                                     /*  接收緩衝區僅接收第一個字符  */
    
    #define LW_SPI_M_MSB         0x0040                                     /*  從高位到低位                */
    #define LW_SPI_M_LSB         0x0080                                     /*  從低位到高位                */
    
        UINT32                   SPIMSG_uiLen;                              /*  長度(緩衝區大小)            */
        
        UINT8                   *SPIMSG_pucWrBuffer;                        /*  發送緩衝區                  */
        UINT8                   *SPIMSG_pucRdBuffer;                        /*  接收緩衝區                  */
        
        VOIDFUNCPTR              SPIMSG_pfuncComplete;                      /*  傳輸結束後的回調函數        */
        PVOID                    SPIMSG_pvContext;                          /*  回調函數參數                */
    } LW_SPI_MESSAGE;
    typedef LW_SPI_MESSAGE      *PLW_SPI_MESSAGE;
    

  4. 技術實現

    SPI數據傳輸方式可分爲兩種:以單個字節爲單位傳輸數據和以16個字節爲單位傳輸數據。

    在SylixOS中SPI總線數據傳輸的代碼實現,如程序清單 31所示。

    程序清單 31 SPI數據傳輸函數

    /*********************************************************************************************************
    ** 函數名稱: __trySpiTransfer
    ** 功能描述: spi 傳輸函數
    ** 輸 入  : pSpiChannel     spi 通道
    **           pSpiAdapter     spi 適配器
    **           pSpiMsg         spi 傳輸消息組
    ** 輸 出  : ERROR_CODE
    *********************************************************************************************************/
    static INT  __trySpiTransfer (UINT              uiChannel,
                                  PLW_SPI_ADAPTER   pSpiadapter,
                                  PLW_SPI_MESSAGE   pSpimsg)
    {
        UINT          uiNum;
        UINT8        *pucTxBuf  = pSpimsg->SPIMSG_pucWrBuffer;              /*  發送緩存區                  */
        UINT8        *pucRxBuf  = pSpimsg->SPIMSG_pucRdBuffer;              /*  接收緩存區                  */
        UINT          uiByteLen = pSpimsg->SPIMSG_uiLen;                    /*  緩存區長度                  */
    
        if (!pucTxBuf && !pucRxBuf) {                                       /*  TxBuf和Rxbuf不能全爲空      */
            SPI_DEBUG("transfer message is invalid\n");
            return (PX_ERROR);
        }
    
        if (uiByteLen > SPI_BIG_NUM) {
            /*
             *  大於SPI_BIG_NUM字節按16字節傳輸,否則按單字節傳輸
             */
            writel(readl(REG_SPI_CNTRL(uiChannel)) & SPI_TXNUM32,           /*  設置爲32位傳輸單元          */
                   REG_SPI_CNTRL(uiChannel));
            writel(readl(REG_SPI_CNTRL(uiChannel)) | SPI_TX_FOUR,           /*  設置每次傳輸單元個數爲4     */
                   REG_SPI_CNTRL(uiChannel));
            for (uiNum = 0; (uiNum + 16) <= uiByteLen; uiNum += 16) {
                if (pucTxBuf) {
                    writel_ESwap(*(UINT*)pucTxBuf,        REG_SPI_TX0(uiChannel));
                    writel_ESwap(*(UINT*)(pucTxBuf + 4),  REG_SPI_TX1(uiChannel));
                    writel_ESwap(*(UINT*)(pucTxBuf + 8),  REG_SPI_TX2(uiChannel));
                    writel_ESwap(*(UINT*)(pucTxBuf + 12), REG_SPI_TX3(uiChannel));
                    pucTxBuf += 16;                                         /*  將TxBuf指針偏移16個字節     */
                }
                writel(readl(REG_SPI_CNTRL(uiChannel)) | SPI_CNTRL_GOBUSY,  /*  使能開始傳輸位              */
                       REG_SPI_CNTRL(usheiChannel));
                API_SemaphoreBPend(__GspiChannels[uiChannel].hSignal,       /*  掛起,等待中斷完成          */
                                   LW_OPTION_WAIT_INFINITE);
    
                if (pucRxBuf) {
                    *(UINT*)pucRxBuf        = readl_ESwap(REG_SPI_RX0(uiChannel));
                    *(UINT*)(pucRxBuf + 4)  = readl_ESwap(REG_SPI_RX1(uiChannel));
                    *(UINT*)(pucRxBuf + 8)  = readl_ESwap(REG_SPI_RX2(uiChannel));
                    *(UINT*)(pucRxBuf + 12) = readl_ESwap(REG_SPI_RX3(uiChannel));
                     pucRxBuf += 16;                                        /*  將RxBuf指針偏移16個字節     */
                }
            }
            if (uiNum < uiByteLen) {
                /*
                 *  將剩下的不足16字節的數據,按8位傳輸
                 */
                writel((readl(REG_SPI_CNTRL(uiChannel)) & SPI_TXNUM32) | SPI_TXNUM8,
                       REG_SPI_CNTRL(uiChannel));                           /*  設置8位傳輸單元             */
                writel(readl(REG_SPI_CNTRL(uiChannel)) & SPI_TX_ONE,        /*  設置每次傳輸單元個數爲1     */
                       REG_SPI_CNTRL(uiChannel));
    
                for (; uiNum < uiByteLen; uiNum++) {
                    if (pucTxBuf) {
                        writel(*(pucTxBuf++), REG_SPI_TX0(uiChannel));
                    }
                    writel(readl(REG_SPI_CNTRL(uiChannel)) | SPI_CNTRL_GOBUSY,
                           REG_SPI_CNTRL(uiChannel));                       /*  使能開始傳輸位              */
                    API_SemaphoreBPend(__GspiChannels[uiChannel].hSignal,   /*  掛起,等待中斷完成          */
                                       LW_OPTION_WAIT_INFINITE);
    
                    if (pucRxBuf) {
                        *(pucRxBuf++) = (UINT8)readl(REG_SPI_RX0(uiChannel));
                    }
                }
            }
        } else {
            /*
             *  小於16字節的數據,一直按8位傳輸
             */
            writel((readl(REG_SPI_CNTRL(uiChannel)) & SPI_TXNUM32) | SPI_TXNUM8,
                   REG_SPI_CNTRL(uiChannel));                               /*  設置8位傳輸單元             */
            writel(readl(REG_SPI_CNTRL(uiChannel)) & SPI_TX_ONE,            /*  設置每次傳輸單元個數爲1     */
                   REG_SPI_CNTRL(uiChannel));
    
            for (uiNum = 0; uiNum < uiByteLen; uiNum++) {
                if (pucTxBuf) {
                    writel(*(pucTxBuf++), REG_SPI_TX0(uiChannel));
                }
                writel(readl(REG_SPI_CNTRL(uiChannel)) | SPI_CNTRL_GOBUSY,  /*  使能開始傳輸位              */
                       REG_SPI_CNTRL(uiChannel));
                API_SemaphoreBPend(__GspiChannels[uiChannel].hSignal,       /*  掛起,等待中斷完成          */
                                   LW_OPTION_WAIT_INFINITE);
    
                if (pucRxBuf) {
                    *(pucRxBuf++) = (UINT8)readl(REG_SPI_RX0(uiChannel));
                }
            }
        }
        return  (ERROR_NONE);
    }
    


     

  5. 16字節數據傳輸流程

    在SPI總線的數據傳輸中,當緩存區長度大於指定的長度(指定的長度要大於16字節),會以16字節爲單位進行數據傳輸,傳輸流程如圖 31所示。

    31 16字節數據傳輸流程圖

  6. 單字節數據傳輸流程

    在SPI總線的數據傳輸中,當緩存區長度小於指定的長度時,會以單字節爲單位進行數據傳輸。如圖 32所示。

    32 單字節數據傳輸流程圖

     

  7. 免責聲明

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

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