You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/03/17 13:42:42 UTC

[incubator-nuttx] 02/04: stm32:spi Add buffers for DMA

This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 6189b2c8bd36a6ee2a9b1e5fd58b994ecf585dc2
Author: Daniel Agar <da...@agar.ca>
AuthorDate: Sun Mar 15 21:29:11 2020 -0400

    stm32:spi Add buffers for DMA
---
 arch/arm/src/stm32/Kconfig     |  42 ++++++++++
 arch/arm/src/stm32/stm32_spi.c | 174 +++++++++++++++++++++++++++++++++--------
 2 files changed, 183 insertions(+), 33 deletions(-)

diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig
index e6851a5..0a8e8a3 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 1fea4e6..8eb87e7 100644
--- a/arch/arm/src/stm32/stm32_spi.c
+++ b/arch/arm/src/stm32/stm32_spi.c
@@ -49,6 +49,7 @@
 #include <sys/types.h>
 #include <stdint.h>
 #include <stdbool.h>
+#include <string.h>
 #include <errno.h>
 #include <debug.h>
 
@@ -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,
@@ -778,29 +881,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
  *
  * Description:
@@ -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