本文檔是對NUC970平臺上的SylixOS SPI總線數據傳輸的詳細分析。緩存
NUC970平臺上SPI總線數據傳輸流程如圖 21所示。函數
當一個消息準備傳輸時,第一步判斷髮送和接收緩存區是否爲空,若爲空,就沒有要接收或發送的數據,直接返回。ui
第二步,判斷消息長度是否大於指定的值(能夠改變,但要大於16個字節),若大於,以16字節爲單位傳輸數據,不然以單字節爲單位傳輸數據。spa
圖21 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;
SPI數據傳輸方式可分爲兩種:以單個字節爲單位傳輸數據和以16個字節爲單位傳輸數據。it
在SylixOS中SPI總線數據傳輸的代碼實現,如程序清單 31所示。配置
程序清單 31 SPI數據傳輸函數map
/********************************************************************************************************* ** 函數名稱: __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); }
在SPI總線的數據傳輸中,當緩存區長度大於指定的長度(指定的長度要大於16字節),會以16字節爲單位進行數據傳輸,傳輸流程如圖 31所示。
圖 31 16字節數據傳輸流程圖
在SPI總線的數據傳輸中,當緩存區長度小於指定的長度時,會以單字節爲單位進行數據傳輸。如圖 32所示。
圖 32單字節數據傳輸流程圖
內部交流文檔,僅針對NUC970相關平臺,若發現相關錯誤或者建議,請及時聯繫文章檔建立者進行修訂和更新。