This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit a308b207238a0697597c90182fbb958f659879f0 Author: Liam Howatt <[email protected]> AuthorDate: Wed Aug 19 16:10:42 2026 -0400 arch/arm/stm32h5: Use FIFO for spi exchange. Use the SPI hardware FIFO to increase the throughput of non-DMA SPI exchanges. Signed-off-by: Liam Howatt <[email protected]> --- arch/arm/src/stm32h5/stm32_spi.c | 94 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 9 deletions(-) diff --git a/arch/arm/src/stm32h5/stm32_spi.c b/arch/arm/src/stm32h5/stm32_spi.c index 0a50f770c26..55c70df9f92 100644 --- a/arch/arm/src/stm32h5/stm32_spi.c +++ b/arch/arm/src/stm32h5/stm32_spi.c @@ -303,6 +303,7 @@ struct stm32_spidev_s uint32_t actual; /* Actual clock frequency */ int8_t nbits; /* Width of word in bits */ uint8_t mode; /* Mode 0,1,2,3 */ + uint8_t depth; /* Depth of RX/TX fifo in bytes */ #ifdef CONFIG_PM struct pm_callback_s pm_cb; /* PM callbacks */ #endif @@ -455,6 +456,7 @@ static struct stm32_spidev_s g_spi1dev = .txsem = SEM_INITIALIZER(0), #endif .lock = NXMUTEX_INITIALIZER, + .depth = 16, #ifdef CONFIG_PM .pm_cb.prepare = spi_pm_prepare, #endif @@ -527,6 +529,7 @@ static struct stm32_spidev_s g_spi2dev = .txsem = SEM_INITIALIZER(0), #endif .lock = NXMUTEX_INITIALIZER, + .depth = 16, #ifdef CONFIG_PM .pm_cb.prepare = spi_pm_prepare, #endif @@ -599,6 +602,7 @@ static struct stm32_spidev_s g_spi3dev = .txsem = SEM_INITIALIZER(0), #endif .lock = NXMUTEX_INITIALIZER, + .depth = 16, #ifdef CONFIG_PM .pm_cb.prepare = spi_pm_prepare, #endif @@ -671,6 +675,7 @@ static struct stm32_spidev_s g_spi4dev = .txsem = SEM_INITIALIZER(0), #endif .lock = NXMUTEX_INITIALIZER, + .depth = 8, #ifdef CONFIG_PM .pm_cb.prepare = spi_pm_prepare, #endif @@ -743,6 +748,7 @@ static struct stm32_spidev_s g_spi5dev = .txsem = SEM_INITIALIZER(0), #endif .lock = NXMUTEX_INITIALIZER, + .depth = 8, #ifdef CONFIG_PM .pm_cb.prepare = spi_pm_prepare, #endif @@ -816,6 +822,7 @@ static struct stm32_spidev_s g_spi6dev = .txsem = SEM_INITIALIZER(0), #endif .lock = NXMUTEX_INITIALIZER, + .depth = 8, #ifdef CONFIG_PM .pm_cb.prepare = spi_pm_prepare, #endif @@ -2012,6 +2019,17 @@ static void spi_exchange_nodma(struct spi_dev_s *dev, spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, SPI_CFG1_RXDMAEN | SPI_CFG1_TXDMAEN, 0); + /* Clear suspend flag */ + + spi_modifyreg(priv, STM32_SPI_IFCR_OFFSET, 0, SPI_IFCR_SUSPC); + + /* Master transfer start */ + + if (priv->config != SIMPLEX_RX) + { + spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, 0, SPI_CR1_CSTART); + } + /* 8- or 16-bit mode? */ if (priv->nbits > 8) @@ -2021,8 +2039,9 @@ static void spi_exchange_nodma(struct spi_dev_s *dev, const uint16_t *src = (const uint16_t *)txbuffer; uint16_t *dest = (uint16_t *)rxbuffer; uint16_t word; - - while (nwords-- > 0) + size_t n_tx_words = 0; + size_t n_rx_words = 0; + while (n_tx_words < nwords) { /* Get the next word to write. Is there a source buffer? */ @@ -2037,7 +2056,33 @@ static void spi_exchange_nodma(struct spi_dev_s *dev, /* Exchange one word */ - word = (uint16_t)spi_send(dev, (uint32_t)word); + spi_writeword(priv, (uint32_t)word); + n_tx_words++; + + /* Only read after we have preloaded the TX Fifo so we can TX/RX + * at the same time. This is important at high SPI baud rates + */ + + if (n_tx_words - n_rx_words == (priv->depth / 2)) + { + word = (uint16_t)spi_readword(priv); + n_rx_words++; + + /* Is there a buffer to receive the return value? */ + + if (dest) + { + *dest++ = word; + } + } + } + + /* Read the last of the data */ + + while (n_rx_words < nwords) + { + word = (uint16_t)spi_readword(priv); + n_rx_words++; /* Is there a buffer to receive the return value? */ @@ -2049,13 +2094,13 @@ static void spi_exchange_nodma(struct spi_dev_s *dev, } else { - /* 8-bit mode */ - const uint8_t *src = (const uint8_t *)txbuffer; - uint8_t *dest = (uint8_t *)rxbuffer; - uint8_t word; + uint8_t *dest = (uint8_t *)rxbuffer; + uint8_t word; + size_t n_tx_words = 0; + size_t n_rx_words = 0; - while (nwords-- > 0) + while (n_tx_words < nwords) { /* Get the next word to write. Is there a source buffer? */ @@ -2070,7 +2115,33 @@ static void spi_exchange_nodma(struct spi_dev_s *dev, /* Exchange one word */ - word = (uint8_t)spi_send(dev, (uint32_t)word); + spi_writebyte(priv, word); + n_tx_words++; + + /* Only read after we have preloaded the TX Fifo so we can TX/RX + * at the same time. This is important at high SPI baud rates + */ + + if (n_tx_words - n_rx_words == priv->depth) + { + word = spi_readbyte(priv); + n_rx_words++; + + /* Is there a buffer to receive the return value? */ + + if (dest) + { + *dest++ = word; + } + } + } + + /* Read the last of the data */ + + while (n_rx_words < nwords) + { + word = spi_readbyte(priv); + n_rx_words++; /* Is there a buffer to receive the return value? */ @@ -2080,6 +2151,11 @@ static void spi_exchange_nodma(struct spi_dev_s *dev, } } } + + /* Suspend */ + + spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, 0, SPI_CR1_CSUSP); + while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_SUSP) == 0); } #endif /* !CONFIG_STM32_SPI_DMA || CONFIG_STM32_DMACAPABLE ||
