关于SPI TX优化的做法: 1. 可以对发送作如下的优化: 检测SPI_STATUS的TX_SPACE bit,是否能够继续想TX FIFO中填充数据。最后检测TX_DONE中断 for (i = 0; i < byteCount; i += wordLen) { /* Copy data to be written into local variable. * The padding required is to nearest byte. * Do fallthrough switch instead of a loop. */ temp = 0; switch (wordLen) { case 4: temp = (data[i + 3] << 24); case 3: temp |= (data[i + 2] << 16); case 2: temp |= (data[i + 1] << 8); case 1: temp |= data; default: break; } /* Wait for the tx_space bit in status register */ while (!(SPI->lpp_spi_status & CY_U3P_LPP_SPI_TX_SPACE)) { if (timeout-- == 0) { status = CY_U3P_ERROR_TIMEOUT; break; } } if (status != CY_U3P_SUCCESS) { break; } SPI->lpp_spi_egress_data = temp; } 数据发送分完成在检测SPI_INTR寄存器的TX_DONE bit,等待数据发送完成。 while (!(SPI->lpp_spi_intr & CY_U3P_LPP_SPI_TX_DONE)) { if (timeout-- == 0) { status = CY_U3P_ERROR_TIMEOUT; break; } } 如下是改动后的源代码。 /* * Transmits data word by word over * the SPI interface. */ CyU3PReturnStatus_t CyU3PSpiTransmitWords ( uint8_t *data, uint32_t byteCount) { uint8_t wordLen; uint32_t intrMask, i; uint32_t temp, timeout; CyU3PReturnStatus_t status; if (!glIsSpiConfigured) { return CY_U3P_ERROR_NOT_CONFIGURED; } if (byteCount == 0) { return CY_U3P_SUCCESS; } if (data == NULL) { return CY_U3P_ERROR_NULL_POINTER; } status = CyU3PSpiGetLock (); if (status != CY_U3P_SUCCESS) { return status; } /* Get the wordLen from the config register and convert it to byte length. */ temp = SPI->lpp_spi_config; wordLen = ((temp & CY_U3P_LPP_SPI_WL_MASK) >> CY_U3P_LPP_SPI_WL_POS); if ((wordLen & 0x07) != 0) { wordLen = (wordLen >> 3) + 1; } else { wordLen = (wordLen >> 3); } if ((byteCount % wordLen) != 0) { status = CY_U3P_ERROR_BAD_ARGUMENT; } /* Check if the DMA mode is running. */ if ((temp & (CY_U3P_LPP_SPI_DMA_MODE | CY_U3P_LPP_SPI_ENABLE)) == (CY_U3P_LPP_SPI_DMA_MODE| CY_U3P_LPP_SPI_ENABLE)) { status = CY_U3P_ERROR_ALREADY_STARTED; } if (status != CY_U3P_SUCCESS) { CyU3PSpiReleaseLock(); return status; } CyU3PSpiResetFifo (CyTrue, CyFalse); /* Disable interrupts. */ intrMask = SPI->lpp_spi_intr_mask; SPI->lpp_spi_intr_mask = 0; /* Enable the TX. */ SPI->lpp_spi_config |= CY_U3P_LPP_SPI_TX_ENABLE; /* Re-enable SPI block. */ SPI->lpp_spi_config |= CY_U3P_LPP_SPI_ENABLE; timeout = glSpiWriteTimeout; for (i = 0; i < byteCount; i += wordLen) { /* Copy data to be written into local variable. * The padding required is to nearest byte. * Do fallthrough switch instead of a loop. */ temp = 0; switch (wordLen) { case 4: temp = (data[i + 3] << 24); case 3: temp |= (data[i + 2] << 16); case 2: temp |= (data[i + 1] << 8); case 1: temp |= data; default: break; } /* Wait for the tx_space bit in status register */ while (!(SPI->lpp_spi_status & CY_U3P_LPP_SPI_TX_SPACE)) { if (timeout-- == 0) { status = CY_U3P_ERROR_TIMEOUT; break; } } if (status != CY_U3P_SUCCESS) { break; } SPI->lpp_spi_egress_data = temp; } /* Wait for the TX_DONE interrupt */ while (!(SPI->lpp_spi_intr & CY_U3P_LPP_SPI_TX_DONE)) { if (timeout-- == 0) { status = CY_U3P_ERROR_TIMEOUT; break; } } /* Clear the TX_DONE interrupt. */ SPI->lpp_spi_intr = CY_U3P_LPP_SPI_TX_DONE; /* Disable the TX. */ SPI->lpp_spi_config &= ~CY_U3P_LPP_SPI_TX_ENABLE; /* Clear all interrupts and restore interrupt mask. */ SPI->lpp_spi_intr |= CY_U3P_LPP_SPI_TX_DONE; SPI->lpp_spi_intr_mask = intrMask; /* Wait until the SPI block is no longer busy and disable. */ while ((SPI->lpp_spi_status & CY_U3P_LPP_SPI_BUSY) != 0); SPI->lpp_spi_config &= ~CY_U3P_LPP_SPI_ENABLE; CyU3PSpiReleaseLock(); return status; }
|