diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index e6851a5911d..0a8e8a346a3 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -8820,6 +8820,13 @@ config STM32_SPI1_DMA ---help--- Use DMA to improve SPI1 transfer performance. +config STM32_SPI1_DMA_BUFFER + int "SPI1 DMA buffer size" + default 0 + depends on STM32_SPI1_DMA + ---help--- + Add a properly aligned DMA buffer for RX and TX DMA for SPI1. + config STM32_SPI_DMATHRESHOLD int "SPI DMA threshold" default 4 @@ -8836,6 +8843,13 @@ config STM32_SPI2_DMA ---help--- Use DMA to improve SPI2 transfer performance. +config STM32_SPI2_DMA_BUFFER + int "SPI2 DMA buffer size" + default 0 + depends on STM32_SPI2_DMA + ---help--- + Add a properly aligned DMA buffer for RX and TX DMA for SPI2. + config STM32_SPI3_DMA bool "SPI3 DMA" default n @@ -8843,6 +8857,13 @@ config STM32_SPI3_DMA ---help--- Use DMA to improve SPI3 transfer performance. +config STM32_SPI3_DMA_BUFFER + int "SPI3 DMA buffer size" + default 0 + depends on STM32_SPI3_DMA + ---help--- + Add a properly aligned DMA buffer for RX and TX DMA for SPI3. + config STM32_SPI4_DMA bool "SPI4 DMA" default n @@ -8850,6 +8871,13 @@ config STM32_SPI4_DMA ---help--- Use DMA to improve SPI4 transfer performance. +config STM32_SPI4_DMA_BUFFER + int "SPI4 DMA buffer size" + default 0 + depends on STM32_SPI4_DMA + ---help--- + Add a properly aligned DMA buffer for RX and TX DMA for SPI4. + config STM32_SPI5_DMA bool "SPI5 DMA" default n @@ -8857,6 +8885,13 @@ config STM32_SPI5_DMA ---help--- Use DMA to improve SPI5 transfer performance. +config STM32_SPI5_DMA_BUFFER + int "SPI5 DMA buffer size" + default 0 + depends on STM32_SPI5_DMA + ---help--- + Add a properly aligned DMA buffer for RX and TX DMA for SPI5. + config STM32_SPI6_DMA bool "SPI6 DMA" default n @@ -8864,6 +8899,13 @@ config STM32_SPI6_DMA ---help--- Use DMA to improve SPI6 transfer performance. +config STM32_SPI5_DMA_BUFFER + int "SPI5 DMA buffer size" + default 0 + depends on STM32_SPI5_DMA + ---help--- + Add a properly aligned DMA buffer for RX and TX DMA for SPI6. + endmenu # SPI Configuration menu "I2S Configuration" diff --git a/arch/arm/src/stm32/stm32_spi.c b/arch/arm/src/stm32/stm32_spi.c index 1fea4e6ba03..8eb87e722be 100644 --- a/arch/arm/src/stm32/stm32_spi.c +++ b/arch/arm/src/stm32/stm32_spi.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -118,8 +119,6 @@ # error "Unknown STM32 DMA" # endif -#endif - /* DMA channel configuration */ #if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32L15XX) || \ @@ -145,6 +144,48 @@ # error "Unknown STM32 DMA" #endif +# define SPIDMA_BUFFER_MASK (4 - 1) +# define SPIDMA_SIZE(b) (((b) + SPIDMA_BUFFER_MASK) & ~SPIDMA_BUFFER_MASK) +# define SPIDMA_BUF_ALIGN aligned_data(4) + +# if defined(CONFIG_STM32_SPI1_DMA_BUFFER) && \ + CONFIG_STM32_SPI1_DMA_BUFFER > 0 +# define SPI1_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_STM32_SPI1_DMA_BUFFER) +# define SPI1_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN +# endif + +# if defined(CONFIG_STM32_SPI2_DMA_BUFFER) && \ + CONFIG_STM32_SPI2_DMA_BUFFER > 0 +# define SPI2_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_STM32_SPI2_DMA_BUFFER) +# define SPI2_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN +# endif + +# if defined(CONFIG_STM32_SPI3_DMA_BUFFER) && \ + CONFIG_STM32_SPI3_DMA_BUFFER > 0 +# define SPI3_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_STM32_SPI3_DMA_BUFFER) +# define SPI3_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN +# endif + +# if defined(CONFIG_STM32_SPI4_DMA_BUFFER) && \ + CONFIG_STM32_SPI4_DMA_BUFFER > 0 +# define SPI4_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_STM32_SPI4_DMA_BUFFER) +# define SPI4_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN +# endif + +# if defined(CONFIG_STM32_SPI5_DMA_BUFFER) && \ + CONFIG_STM32_SPI5_DMA_BUFFER > 0 +# define SPI5_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_STM32_SPI5_DMA_BUFFER) +# define SPI5_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN +# endif + +# if defined(CONFIG_STM32_SPI6_DMA_BUFFER) && \ + CONFIG_STM32_SPI6_DMA_BUFFER > 0 +# define SPI6_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_STM32_SPI6_DMA_BUFFER) +# define SPI6_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN +# endif + +#endif + /************************************************************************************ * Private Types ************************************************************************************/ @@ -166,6 +207,9 @@ struct stm32_spidev_s #endif uint8_t rxch; /* The RX DMA channel number */ uint8_t txch; /* The TX DMA channel number */ + uint8_t *rxbuf; /* The RX DMA buffer */ + uint8_t *txbuf; /* The TX DMA buffer */ + size_t buflen; /* The DMA buffer length */ DMA_HANDLE rxdma; /* DMA channel handle for RX transfers */ DMA_HANDLE txdma; /* DMA channel handle for TX transfers */ sem_t rxsem; /* Wait for RX DMA to complete */ @@ -199,7 +243,6 @@ static inline void spi_putreg8(FAR struct stm32_spidev_s *priv, uint8_t offset, #endif static inline uint16_t spi_readword(FAR struct stm32_spidev_s *priv); static inline void spi_writeword(FAR struct stm32_spidev_s *priv, uint16_t byte); -static inline bool spi_16bitmode(FAR struct stm32_spidev_s *priv); /* DMA support */ @@ -285,6 +328,11 @@ static const struct spi_ops_s g_sp1iops = #endif }; +#if defined(SPI1_DMABUFSIZE_ADJUSTED) +static uint8_t g_spi1_txbuf[SPI1_DMABUFSIZE_ADJUSTED] SPI1_DMABUFSIZE_ALGN; +static uint8_t g_spi1_rxbuf[SPI1_DMABUFSIZE_ADJUSTED] SPI1_DMABUFSIZE_ALGN; +#endif + static struct stm32_spidev_s g_spi1dev = { .spidev = @@ -300,6 +348,11 @@ static struct stm32_spidev_s g_spi1dev = # ifdef CONFIG_STM32_SPI1_DMA .rxch = DMACHAN_SPI1_RX, .txch = DMACHAN_SPI1_TX, +#if defined(SPI1_DMABUFSIZE_ADJUSTED) + .rxbuf = g_spi1_rxbuf, + .txbuf = g_spi1_txbuf, + .buflen = SPI1_DMABUFSIZE_ADJUSTED, +# endif # else .rxch = 0, .txch = 0, @@ -340,6 +393,11 @@ static const struct spi_ops_s g_sp2iops = #endif }; +#if defined(SPI2_DMABUFSIZE_ADJUSTED) +static uint8_t g_spi2_txbuf[SPI2_DMABUFSIZE_ADJUSTED] SPI2_DMABUFSIZE_ALGN; +static uint8_t g_spi2_rxbuf[SPI2_DMABUFSIZE_ADJUSTED] SPI2_DMABUFSIZE_ALGN; +#endif + static struct stm32_spidev_s g_spi2dev = { .spidev = @@ -355,6 +413,11 @@ static struct stm32_spidev_s g_spi2dev = # ifdef CONFIG_STM32_SPI2_DMA .rxch = DMACHAN_SPI2_RX, .txch = DMACHAN_SPI2_TX, +#if defined(SPI2_DMABUFSIZE_ADJUSTED) + .rxbuf = g_spi2_rxbuf, + .txbuf = g_spi2_txbuf, + .buflen = SPI2_DMABUFSIZE_ADJUSTED, +# endif # else .rxch = 0, .txch = 0, @@ -395,6 +458,11 @@ static const struct spi_ops_s g_sp3iops = #endif }; +#if defined(SPI3_DMABUFSIZE_ADJUSTED) +static uint8_t g_spi3_txbuf[SPI3_DMABUFSIZE_ADJUSTED] SPI3_DMABUFSIZE_ALGN; +static uint8_t g_spi3_rxbuf[SPI3_DMABUFSIZE_ADJUSTED] SPI3_DMABUFSIZE_ALGN; +#endif + static struct stm32_spidev_s g_spi3dev = { .spidev = @@ -410,6 +478,11 @@ static struct stm32_spidev_s g_spi3dev = # ifdef CONFIG_STM32_SPI3_DMA .rxch = DMACHAN_SPI3_RX, .txch = DMACHAN_SPI3_TX, +#if defined(SPI3_DMABUFSIZE_ADJUSTED) + .rxbuf = g_spi3_rxbuf, + .txbuf = g_spi3_txbuf, + .buflen = SPI3_DMABUFSIZE_ADJUSTED, +# endif # else .rxch = 0, .txch = 0, @@ -450,6 +523,11 @@ static const struct spi_ops_s g_sp4iops = #endif }; +#if defined(SPI4_DMABUFSIZE_ADJUSTED) +static uint8_t g_spi4_txbuf[SPI4_DMABUFSIZE_ADJUSTED] SPI4_DMABUFSIZE_ALGN; +static uint8_t g_spi4_rxbuf[SPI4_DMABUFSIZE_ADJUSTED] SPI4_DMABUFSIZE_ALGN; +#endif + static struct stm32_spidev_s g_spi4dev = { .spidev = @@ -465,6 +543,11 @@ static struct stm32_spidev_s g_spi4dev = # ifdef CONFIG_STM32_SPI4_DMA .rxch = DMACHAN_SPI4_RX, .txch = DMACHAN_SPI4_TX, +#if defined(SPI4_DMABUFSIZE_ADJUSTED) + .rxbuf = g_spi4_rxbuf, + .txbuf = g_spi4_txbuf, + .buflen = SPI4_DMABUFSIZE_ADJUSTED, +# endif # else .rxch = 0, .txch = 0, @@ -505,6 +588,11 @@ static const struct spi_ops_s g_sp5iops = #endif }; +#if defined(SPI5_DMABUFSIZE_ADJUSTED) +static uint8_t g_spi5_txbuf[SPI5_DMABUFSIZE_ADJUSTED] SPI5_DMABUFSIZE_ALGN; +static uint8_t g_spi5_rxbuf[SPI5_DMABUFSIZE_ADJUSTED] SPI5_DMABUFSIZE_ALGN; +#endif + static struct stm32_spidev_s g_spi5dev = { .spidev = @@ -520,6 +608,11 @@ static struct stm32_spidev_s g_spi5dev = # ifdef CONFIG_STM32_SPI5_DMA .rxch = DMACHAN_SPI5_RX, .txch = DMACHAN_SPI5_TX, +#if defined(SPI5_DMABUFSIZE_ADJUSTED) + .rxbuf = g_spi5_rxbuf, + .txbuf = g_spi5_txbuf, + .buflen = SPI5_DMABUFSIZE_ADJUSTED, +# endif # else .rxch = 0, .txch = 0, @@ -560,6 +653,11 @@ static const struct spi_ops_s g_sp6iops = #endif }; +#if defined(SPI6_DMABUFSIZE_ADJUSTED) +static uint8_t g_spi6_txbuf[SPI6_DMABUFSIZE_ADJUSTED] SPI6_DMABUFSIZE_ALGN; +static uint8_t g_spi6_rxbuf[SPI6_DMABUFSIZE_ADJUSTED] SPI6_DMABUFSIZE_ALGN; +#endif + static struct stm32_spidev_s g_spi6dev = { .spidev = @@ -575,6 +673,11 @@ static struct stm32_spidev_s g_spi6dev = # ifdef CONFIG_STM32_SPI6_DMA .rxch = DMACHAN_SPI6_RX, .txch = DMACHAN_SPI6_TX, +#if defined(SPI6_DMABUFSIZE_ADJUSTED) + .rxbuf = g_spi6_rxbuf, + .txbuf = g_spi6_txbuf, + .buflen = SPI6_DMABUFSIZE_ADJUSTED, +# endif # else .rxch = 0, .txch = 0, @@ -777,29 +880,6 @@ static inline void spi_writeword(FAR struct stm32_spidev_s *priv, uint16_t word) } } -/************************************************************************************ - * Name: spi_16bitmode - * - * Description: - * Check if the SPI is operating in 16-bit mode - * - * Input Parameters: - * priv - Device-specific state data - * - * Returned Value: - * true: 16-bit mode, false: 8-bit mode - * - ************************************************************************************/ - -static inline bool spi_16bitmode(FAR struct stm32_spidev_s *priv) -{ -#if defined(CONFIG_STM32_STM32F30XX) || defined(CONFIG_STM32_STM32F37XX) - return (priv->nbits > 8); -#else - return ((spi_getreg(priv, STM32_SPI_CR1_OFFSET) & SPI_CR1_DFF) != 0); -#endif -} - /************************************************************************************ * Name: spi_dmarxwait * @@ -930,7 +1010,7 @@ static void spi_dmarxsetup(FAR struct stm32_spidev_s *priv, FAR void *rxbuffer, { /* 8- or 16-bit mode? */ - if (spi_16bitmode(priv)) + if (priv->nbits > 8) { /* 16-bit mode -- is there a buffer to receive data in? */ @@ -980,7 +1060,7 @@ static void spi_dmatxsetup(FAR struct stm32_spidev_s *priv, FAR const void *txbu { /* 8- or 16-bit mode? */ - if (spi_16bitmode(priv)) + if (priv->nbits > 8) { /* 16-bit mode -- is there a buffer to transfer data from? */ @@ -1570,7 +1650,7 @@ static void spi_exchange_nodma(FAR struct spi_dev_s *dev, FAR const void *txbuff /* 8- or 16-bit mode? */ - if (spi_16bitmode(priv)) + if (priv->nbits > 8) { /* 16-bit mode */ @@ -1665,14 +1745,14 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, FAR void *rxbuffer, size_t nwords) { FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev; - + FAR void * xbuffer = rxbuffer; DEBUGASSERT(priv != NULL); -#ifdef CONFIG_STM32_SPI_DMATHRESHOLD /* Convert the number of word to a number of bytes */ size_t nbytes = (priv->nbits > 8) ? nwords << 1 : nwords; +#ifdef CONFIG_STM32_SPI_DMATHRESHOLD /* If this is a small SPI transfer, then let spi_exchange_nodma() do the work. */ if (nbytes <= CONFIG_STM32_SPI_DMATHRESHOLD) @@ -1694,8 +1774,10 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, } #ifdef CONFIG_STM32_DMACAPABLE - if ((txbuffer && !stm32_dmacapable((uint32_t)txbuffer, nwords, priv->txccr)) || - (rxbuffer && !stm32_dmacapable((uint32_t)rxbuffer, nwords, priv->rxccr))) + if ((txbuffer && priv->txbuf == 0 && + !stm32_dmacapable((uint32_t)txbuffer, nwords, priv->txccr)) || + (rxbuffer && priv->rxbuf == 0 && + !stm32_dmacapable((uint32_t)rxbuffer, nwords, priv->rxccr))) { /* Unsupported memory region fall back to non-DMA method. */ @@ -1712,6 +1794,27 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, /* Setup DMAs */ + /* If this bus uses a in driver buffers we will incur 2 copies, + * The copy cost is << less the non DMA transfer time and having + * the buffer in the driver ensures DMA can be used. This is bacause + * the API does not support passing the buffer extent so the only + * extent is buffer + the transfer size. These can sizes be less than + * the cache line size, and not aligned and tyicaly greater then 4 + * bytes, which is about the break even point for the DMA IO overhead. + */ + + if (txbuffer && priv->txbuf) + { + if (nbytes > priv->buflen) + { + nbytes = priv->buflen; + } + + memcpy(priv->txbuf, txbuffer, nbytes); + txbuffer = priv->txbuf; + rxbuffer = rxbuffer ? priv->rxbuf : rxbuffer; + } + spi_dmarxsetup(priv, rxbuffer, &rxdummy, nwords); spi_dmatxsetup(priv, txbuffer, &txdummy, nwords); @@ -1743,6 +1846,11 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, spi_dmarxwait(priv); spi_dmatxwait(priv); + if (rxbuffer && priv->rxbuf) + { + memcpy(xbuffer, priv->rxbuf, nbytes); + } + #ifdef CONFIG_SPI_TRIGGER priv->trigarmed = false; #endif