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:40 UTC

[incubator-nuttx] branch master updated (a5e643b -> 4e475cb)

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

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


    from a5e643b  Fix typos in comments and documentation.
     new 6f32a6a  stm32f7:spi Add buffers for DMA
     new 6189b2c  stm32:spi Add buffers for DMA
     new da854cc  stm32:spi nxstyle
     new 4e475cb  stm32f7:spi nxstyle

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 arch/arm/src/stm32/Kconfig       |  42 ++++++++
 arch/arm/src/stm32/stm32_spi.c   | 184 +++++++++++++++++++++++++-------
 arch/arm/src/stm32f7/Kconfig     |  42 ++++++++
 arch/arm/src/stm32f7/stm32_spi.c | 223 +++++++++++++++++++++++++++++----------
 4 files changed, 399 insertions(+), 92 deletions(-)


[incubator-nuttx] 01/04: stm32f7:spi Add buffers for DMA

Posted by gn...@apache.org.
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 6f32a6ad8fe9b207f20b7fc23734ea84a9e6038c
Author: David Sidrane <Da...@NscDg.com>
AuthorDate: Fri Mar 13 14:22:20 2020 -0700

    stm32f7:spi Add buffers for DMA
---
 arch/arm/src/stm32f7/Kconfig     |  42 ++++++++
 arch/arm/src/stm32f7/stm32_spi.c | 213 ++++++++++++++++++++++++++++++---------
 2 files changed, 206 insertions(+), 49 deletions(-)

diff --git a/arch/arm/src/stm32f7/Kconfig b/arch/arm/src/stm32f7/Kconfig
index a4b4b0b..d6395cb 100644
--- a/arch/arm/src/stm32f7/Kconfig
+++ b/arch/arm/src/stm32f7/Kconfig
@@ -2297,6 +2297,13 @@ config STM32F7_SPI1_DMA
 	---help---
 		Use DMA to improve SPI1 transfer performance.
 
+config STM32F7_SPI1_DMA_BUFFER
+	int "SPI1 DMA buffer size"
+	default 0
+	depends on STM32F7_SPI1_DMA
+	---help---
+		Add a properly aligned DMA buffer for RX and TX DMA for SPI1.
+
 config STM32F7_SPI2_DMA
 	bool "SPI2 DMA"
 	default n
@@ -2304,6 +2311,13 @@ config STM32F7_SPI2_DMA
 	---help---
 		Use DMA to improve SPI2 transfer performance.
 
+config STM32F7_SPI2_DMA_BUFFER
+	int "SPI2 DMA buffer size"
+	default 0
+	depends on STM32F7_SPI2_DMA
+	---help---
+		Add a properly aligned DMA buffer for RX and TX DMA for SPI2.
+
 config STM32F7_SPI3_DMA
 	bool "SPI3 DMA"
 	default n
@@ -2311,6 +2325,13 @@ config STM32F7_SPI3_DMA
 	---help---
 		Use DMA to improve SPI3 transfer performance.
 
+config STM32F7_SPI3_DMA_BUFFER
+	int "SPI3 DMA buffer size"
+	default 0
+	depends on STM32F7_SPI3_DMA
+	---help---
+		Add a properly aligned DMA buffer for RX and TX DMA for SPI3.
+
 config STM32F7_SPI4_DMA
 	bool "SPI4 DMA"
 	default n
@@ -2318,6 +2339,13 @@ config STM32F7_SPI4_DMA
 	---help---
 		Use DMA to improve SPI4 transfer performance.
 
+config STM32F7_SPI4_DMA_BUFFER
+	int "SPI4 DMA buffer size"
+	default 0
+	depends on STM32F7_SPI4_DMA
+	---help---
+		Add a properly aligned DMA buffer for RX and TX DMA for SPI4.
+
 config STM32F7_SPI5_DMA
 	bool "SPI5 DMA"
 	default n
@@ -2325,6 +2353,13 @@ config STM32F7_SPI5_DMA
 	---help---
 		Use DMA to improve SPI5 transfer performance.
 
+config STM32F7_SPI5_DMA_BUFFER
+	int "SPI5 DMA buffer size"
+	default 0
+	depends on STM32F7_SPI5_DMA
+	---help---
+		Add a properly aligned DMA buffer for RX and TX DMA for SPI5.
+
 config STM32F7_SPI6_DMA
 	bool "SPI6 DMA"
 	default n
@@ -2332,6 +2367,13 @@ config STM32F7_SPI6_DMA
 	---help---
 		Use DMA to improve SPI6 transfer performance.
 
+config STM32F7_SPI6_DMA_BUFFER
+	int "SPI6 DMA buffer size"
+	default 0
+	depends on STM32F7_SPI6_DMA
+	---help---
+		Add a properly aligned DMA buffer for RX and TX DMA for SPI6.
+
 endmenu # "SPI Configuration"
 
 menu "I2C Configuration"
diff --git a/arch/arm/src/stm32f7/stm32_spi.c b/arch/arm/src/stm32f7/stm32_spi.c
index 6c17b0f..b15f34b 100644
--- a/arch/arm/src/stm32f7/stm32_spi.c
+++ b/arch/arm/src/stm32f7/stm32_spi.c
@@ -51,6 +51,7 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <stddef.h>
+#include <string.h>
 #include <errno.h>
 #include <debug.h>
 
@@ -104,9 +105,9 @@
 #    error "Unknown STM32 DMA"
 #  endif
 
-#if (SPI_DMA_PRIO & ~DMA_SCR_PL_MASK) != 0
+#  if (SPI_DMA_PRIO & ~DMA_SCR_PL_MASK) != 0
 #    error "Illegal value for CONFIG_SPI_DMAPRIO"
-#endif
+#  endif
 
 /* DMA channel configuration */
 
@@ -118,6 +119,56 @@
 #  define SPI_TXDMA8_CONFIG         (SPI_DMA_PRIO|DMA_SCR_MSIZE_8BITS |DMA_SCR_PSIZE_8BITS |DMA_SCR_MINC|DMA_SCR_DIR_M2P)
 #  define SPI_TXDMA16NULL_CONFIG    (SPI_DMA_PRIO|DMA_SCR_MSIZE_8BITS |DMA_SCR_PSIZE_16BITS             |DMA_SCR_DIR_M2P)
 #  define SPI_TXDMA8NULL_CONFIG     (SPI_DMA_PRIO|DMA_SCR_MSIZE_8BITS |DMA_SCR_PSIZE_8BITS              |DMA_SCR_DIR_M2P)
+
+/* If built with CONFIG_ARMV7M_DCACHE Buffers need to be aligned and
+ * multiples of ARMV7M_DCACHE_LINESIZE
+ */
+
+#  if defined(CONFIG_ARMV7M_DCACHE)
+#    define SPIDMA_BUFFER_MASK   (ARMV7M_DCACHE_LINESIZE - 1)
+#    define SPIDMA_SIZE(b) (((b) + SPIDMA_BUFFER_MASK) & ~SPIDMA_BUFFER_MASK)
+#    define SPIDMA_BUF_ALIGN   aligned_data(ARMV7M_DCACHE_LINESIZE)
+#  else
+#    define SPIDMA_SIZE(b)  (b)
+#    define SPIDMA_BUF_ALIGN
+#  endif
+
+#  if defined(CONFIG_STM32F7_SPI1_DMA_BUFFER) && \
+            CONFIG_STM32F7_SPI1_DMA_BUFFER > 0
+#    define SPI1_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_STM32F7_SPI1_DMA_BUFFER)
+#    define SPI1_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN
+#  endif
+
+#  if defined(CONFIG_STM32F7_SPI2_DMA_BUFFER) && \
+            CONFIG_STM32F7_SPI2_DMA_BUFFER > 0
+#    define SPI2_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_STM32F7_SPI2_DMA_BUFFER)
+#    define SPI2_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN
+#  endif
+
+#  if defined(CONFIG_STM32F7_SPI3_DMA_BUFFER) && \
+            CONFIG_STM32F7_SPI3_DMA_BUFFER > 0
+#    define SPI3_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_STM32F7_SPI3_DMA_BUFFER)
+#    define SPI3_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN
+#  endif
+
+#  if defined(CONFIG_STM32F7_SPI4_DMA_BUFFER) && \
+            CONFIG_STM32F7_SPI4_DMA_BUFFER > 0
+#    define SPI4_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_STM32F7_SPI4_DMA_BUFFER)
+#    define SPI4_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN
+#  endif
+
+#  if defined(CONFIG_STM32F7_SPI5_DMA_BUFFER) && \
+            CONFIG_STM32F7_SPI5_DMA_BUFFER > 0
+#    define SPI5_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_STM32F7_SPI5_DMA_BUFFER)
+#    define SPI5_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN
+#  endif
+
+#if defined(CONFIG_STM32F7_SPI6_DMA_BUFFER) && \
+            CONFIG_STM32F7_SPI6_DMA_BUFFER > 0
+#    define SPI6_DMABUFSIZE_ADJUSTED SPIDMA_SIZE(CONFIG_STM32F7_SPI6_DMA_BUFFER)
+#    define SPI6_DMABUFSIZE_ALGN SPIDMA_BUF_ALIGN
+#  endif
+
 #endif
 
 /****************************************************************************
@@ -141,6 +192,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 */
@@ -172,7 +226,6 @@ static inline void spi_putreg(FAR struct stm32_spidev_s *priv,
 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_9to16bitmode(FAR struct stm32_spidev_s *priv);
 
 /* DMA support */
 
@@ -268,6 +321,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   =
@@ -283,6 +341,11 @@ static struct stm32_spidev_s g_spi1dev =
 #  ifdef CONFIG_STM32F7_SPI1_DMA
   .rxch     = DMAMAP_SPI1_RX,
   .txch     = DMAMAP_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,
@@ -326,6 +389,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   =
@@ -341,6 +409,11 @@ static struct stm32_spidev_s g_spi2dev =
 #  ifdef CONFIG_STM32F7_SPI2_DMA
   .rxch     = DMAMAP_SPI2_RX,
   .txch     = DMAMAP_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,
@@ -384,6 +457,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   =
@@ -399,6 +477,11 @@ static struct stm32_spidev_s g_spi3dev =
 #  ifdef CONFIG_STM32F7_SPI3_DMA
   .rxch     = DMAMAP_SPI3_RX,
   .txch     = DMAMAP_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,
@@ -442,6 +525,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   =
@@ -457,6 +545,11 @@ static struct stm32_spidev_s g_spi4dev =
 #  ifdef CONFIG_STM32F7_SPI4_DMA
   .rxch     = DMAMAP_SPI4_RX,
   .txch     = DMAMAP_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,
@@ -500,6 +593,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   =
@@ -515,6 +613,11 @@ static struct stm32_spidev_s g_spi5dev =
 #  ifdef CONFIG_STM32F7_SPI5_DMA
   .rxch     = DMAMAP_SPI5_RX,
   .txch     = DMAMAP_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,
@@ -558,6 +661,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   =
@@ -573,6 +681,11 @@ static struct stm32_spidev_s g_spi6dev =
 #  ifdef CONFIG_STM32F7_SPI6_DMA
   .rxch     = DMAMAP_SPI6_RX,
   .txch     = DMAMAP_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,
@@ -776,26 +889,6 @@ static inline void spi_writebyte(FAR struct stm32_spidev_s *priv,
 }
 
 /****************************************************************************
- * Name: spi_9to16bitmode
- *
- * Description:
- *   Check if the SPI is operating in more then 8 bit mode
- *
- * Input Parameters:
- *   priv     - Device-specific state data
- *
- * Returned Value:
- *   true: >8 bit mode-bit mode, false: <= 8-bit mode
- *
- ****************************************************************************/
-
-static inline bool spi_9to16bitmode(FAR struct stm32_spidev_s *priv)
-{
-  return ((spi_getreg(priv, STM32_SPI_CR2_OFFSET) & SPI_CR2_DS_9BIT) ==
-          SPI_CR2_DS_9BIT);
-}
-
-/****************************************************************************
  * Name: spi_dmarxwait
  *
  * Description:
@@ -926,7 +1019,7 @@ static void spi_dmarxsetup(FAR struct stm32_spidev_s *priv,
 {
   /* 8- or 16-bit mode? */
 
-  if (spi_9to16bitmode(priv))
+  if (priv->nbits > 8)
     {
       /* 16-bit mode -- is there a buffer to receive data in? */
 
@@ -977,7 +1070,7 @@ static void spi_dmatxsetup(FAR struct stm32_spidev_s *priv,
 {
   /* 8- or 16-bit mode? */
 
-  if (spi_9to16bitmode(priv))
+  if (priv->nbits > 8)
     {
       /* 16-bit mode -- is there a buffer to transfer data from? */
 
@@ -1505,7 +1598,7 @@ static uint32_t spi_send(FAR struct spi_dev_s *dev, uint32_t wd)
    * frames, two bytes are received by a 16-bit read of the data register!
    */
 
-  if (spi_9to16bitmode(priv))
+  if (priv->nbits > 8)
     {
       spi_writeword(priv, (uint16_t)(wd & 0xffff));
       ret = (uint32_t)spi_readword(priv);
@@ -1522,7 +1615,7 @@ static uint32_t spi_send(FAR struct spi_dev_s *dev, uint32_t wd)
 
   regval = spi_getreg(priv, STM32_SPI_SR_OFFSET);
 
-  if (spi_9to16bitmode(priv))
+  if (priv->nbits > 8)
     {
       spiinfo("Sent: %04x Return: %04x Status: %02x\n", wd, ret, regval);
     }
@@ -1574,7 +1667,7 @@ static void spi_exchange_nodma(FAR struct spi_dev_s *dev,
 
   /* 8- or 16-bit mode? */
 
-  if (spi_9to16bitmode(priv))
+  if (priv->nbits > 8)
     {
       /* 16-bit mode */
 
@@ -1672,14 +1765,15 @@ 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_STM32F7_SPI_DMATHRESHOLD
   /* Convert the number of word to a number of bytes */
 
   size_t nbytes = (priv->nbits > 8) ? nwords << 1 : nwords;
 
+#ifdef CONFIG_STM32F7_SPI_DMATHRESHOLD
+
   /* If this is a small SPI transfer, then let spi_exchange_nodma() do the work. */
 
   if (nbytes <= CONFIG_STM32F7_SPI_DMATHRESHOLD)
@@ -1701,27 +1795,26 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
     }
 
 #ifdef CONFIG_STM32F7_DMACAPABLE
-  if ((txbuffer &&
+  /* If this bus uses a in driver DMA aligned buffers we can skip the test */
+
+  if ((txbuffer && priv->txbuf == 0 &&
       !stm32_dmacapable((uint32_t)txbuffer, nwords, priv->txccr)) ||
-      (rxbuffer &&
-      !stm32_dmacapable((uint32_t)rxbuffer, nwords, priv->rxccr)))
+      (rxbuffer && priv->rxbuf == 0 &&
+       !stm32_dmacapable((uint32_t)rxbuffer, nwords, priv->rxccr)))
     {
-      /* Unsupported memory region fall back to non-DMA method. */
+      /* Unsupported memory region or not in driver buffers
+       * fall back to non-DMA method.
+       */
 
       spi_exchange_nodma(dev, txbuffer, rxbuffer, nwords);
     }
   else
 #endif
     {
-      static uint8_t rxdummy[ARMV7M_DCACHE_LINESIZE]
-        __attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
-      static const uint16_t txdummy = 0xffff;
-      size_t buflen = nwords;
+      /* The dummy buffer is used to DMA with out increment into  */
 
-      if (spi_9to16bitmode(priv))
-        {
-          buflen = nwords * sizeof(uint16_t);
-        }
+      static uint8_t rxdummy[4] __attribute__((aligned(4)));
+      static const uint16_t txdummy = 0xffff;
 
       spiinfo("txbuffer=%p rxbuffer=%p nwords=%d\n",
               txbuffer, rxbuffer, nwords);
@@ -1729,6 +1822,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, (uint16_t *)rxdummy, nwords);
       spi_dmatxsetup(priv, txbuffer, &txdummy, nwords);
 
@@ -1736,7 +1850,7 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
 
       if (txbuffer)
         {
-          up_flush_dcache((uintptr_t)txbuffer, (uintptr_t)txbuffer + buflen);
+          up_flush_dcache((uintptr_t)txbuffer, (uintptr_t)txbuffer + nbytes);
         }
 
 #ifdef CONFIG_SPI_TRIGGER
@@ -1776,12 +1890,12 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
       if (rxbuffer)
         {
           up_invalidate_dcache((uintptr_t)rxbuffer,
-                               (uintptr_t)rxbuffer + buflen);
-        }
-      else
-        {
-          up_invalidate_dcache((uintptr_t)rxdummy,
-                               (uintptr_t)rxdummy + sizeof(rxdummy));
+                               (uintptr_t)rxbuffer + nbytes);
+
+          if (priv->rxbuf)
+            {
+              memcpy(xbuffer, priv->rxbuf, nbytes);
+            }
         }
     }
 }
@@ -2244,6 +2358,7 @@ FAR struct spi_dev_s *stm32_spibus_initialize(int bus)
 #endif
     {
       spierr("ERROR: Unsupported SPI bus: %d\n", bus);
+      return NULL;
     }
 
   leave_critical_section(flags);


[incubator-nuttx] 03/04: stm32:spi nxstyle

Posted by gn...@apache.org.
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 da854ccb997bee4ed740c95352931196cc6a4894
Author: David Sidrane <Da...@NscDg.com>
AuthorDate: Mon Mar 16 14:38:22 2020 -0700

    stm32:spi nxstyle
---
 arch/arm/src/stm32/stm32_spi.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/arm/src/stm32/stm32_spi.c b/arch/arm/src/stm32/stm32_spi.c
index 8eb87e7..160e277 100644
--- a/arch/arm/src/stm32/stm32_spi.c
+++ b/arch/arm/src/stm32/stm32_spi.c
@@ -389,7 +389,7 @@ static const struct spi_ops_s g_sp2iops =
 #ifdef CONFIG_SPI_CALLBACK
   .registercallback  = stm32_spi2register,  /* provided externally */
 #else
-  .registercallback  = 0,  /* not implemented */
+  .registercallback  = 0,                   /* not implemented */
 #endif
 };
 
@@ -454,7 +454,7 @@ static const struct spi_ops_s g_sp3iops =
 #ifdef CONFIG_SPI_CALLBACK
   .registercallback  = stm32_spi3register,  /* provided externally */
 #else
-  .registercallback  = 0,  /* not implemented */
+  .registercallback  = 0,                   /* not implemented */
 #endif
 };
 
@@ -519,7 +519,7 @@ static const struct spi_ops_s g_sp4iops =
 #ifdef CONFIG_SPI_CALLBACK
   .registercallback  = stm32_spi4register,  /* provided externally */
 #else
-  .registercallback  = 0,  /* not implemented */
+  .registercallback  = 0,                   /* not implemented */
 #endif
 };
 
@@ -584,7 +584,7 @@ static const struct spi_ops_s g_sp5iops =
 #ifdef CONFIG_SPI_CALLBACK
   .registercallback  = stm32_spi5register,  /* provided externally */
 #else
-  .registercallback  = 0,  /* not implemented */
+  .registercallback  = 0,                   /* not implemented */
 #endif
 };
 
@@ -649,7 +649,7 @@ static const struct spi_ops_s g_sp6iops =
 #ifdef CONFIG_SPI_CALLBACK
   .registercallback  = stm32_spi6register,  /* provided externally */
 #else
-  .registercallback  = 0,  /* not implemented */
+  .registercallback  = 0,                   /* not implemented */
 #endif
 };
 


[incubator-nuttx] 04/04: stm32f7:spi nxstyle

Posted by gn...@apache.org.
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 4e475cb630b0938cc6f4c28c8919a91d77e58818
Author: David Sidrane <Da...@NscDg.com>
AuthorDate: Mon Mar 16 14:38:36 2020 -0700

    stm32f7:spi nxstyle
---
 arch/arm/src/stm32f7/stm32_spi.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/arm/src/stm32f7/stm32_spi.c b/arch/arm/src/stm32f7/stm32_spi.c
index b15f34b..9d82b48 100644
--- a/arch/arm/src/stm32f7/stm32_spi.c
+++ b/arch/arm/src/stm32f7/stm32_spi.c
@@ -385,7 +385,7 @@ static const struct spi_ops_s g_sp2iops =
 #ifdef CONFIG_SPI_CALLBACK
   .registercallback  = stm32_spi2register,  /* provided externally */
 #else
-  .registercallback  = 0,  /* not implemented */
+  .registercallback  = 0,                   /* not implemented */
 #endif
 };
 
@@ -453,7 +453,7 @@ static const struct spi_ops_s g_sp3iops =
 #ifdef CONFIG_SPI_CALLBACK
   .registercallback  = stm32_spi3register,  /* provided externally */
 #else
-  .registercallback  = 0,  /* not implemented */
+  .registercallback  = 0,                   /* not implemented */
 #endif
 };
 
@@ -521,7 +521,7 @@ static const struct spi_ops_s g_sp4iops =
 #ifdef CONFIG_SPI_CALLBACK
   .registercallback  = stm32_spi4register,  /* provided externally */
 #else
-  .registercallback  = 0,  /* not implemented */
+  .registercallback  = 0,                   /* not implemented */
 #endif
 };
 
@@ -589,7 +589,7 @@ static const struct spi_ops_s g_sp5iops =
 #ifdef CONFIG_SPI_CALLBACK
   .registercallback  = stm32_spi5register,  /* provided externally */
 #else
-  .registercallback  = 0,  /* not implemented */
+  .registercallback  = 0,                   /* not implemented */
 #endif
 };
 
@@ -657,7 +657,7 @@ static const struct spi_ops_s g_sp6iops =
 #ifdef CONFIG_SPI_CALLBACK
   .registercallback  = stm32_spi6register,  /* provided externally */
 #else
-  .registercallback  = 0,  /* not implemented */
+  .registercallback  = 0,                   /* not implemented */
 #endif
 };
 


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

Posted by gn...@apache.org.
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