-
概述
本文档是对NUC970平台上的SylixOS SPI总线数据传输的详细分析。
-
SPI总线数据传输流程
NUC970平台上SPI总线数据传输流程如图 21所示。
当一个消息准备传输时,第一步判断发送和接收缓存区是否为空,若为空,就没有要接收或发送的数据,直接返回。
第二步,判断消息长度是否大于指定的值(可以改变,但要大于16个字节),若大于,以16字节为单位传输数据,否则以单字节为单位传输数据。
图21 SPI数据传输流程图
-
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个字节为单位传输数据。
在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); }
-
16字节数据传输流程
在SPI总线的数据传输中,当缓存区长度大于指定的长度(指定的长度要大于16字节),会以16字节为单位进行数据传输,传输流程如图 31所示。
图 31 16字节数据传输流程图
-
单字节数据传输流程
在SPI总线的数据传输中,当缓存区长度小于指定的长度时,会以单字节为单位进行数据传输。如图 32所示。
图 32单字节数据传输流程图
-
免责声明
内部交流文档,仅针对NUC970相关平台,若发现相关错误或者建议,请及时联系文章档创建者进行修订和更新。
时间: 2024-10-26 21:17:12