nuttx-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gn...@apache.org
Subject [incubator-nuttx] 02/02: stm32h7:Fix DMA Overrun error
Date Fri, 03 Apr 2020 16:50:37 GMT
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 fc3ab3e085ce5e904d26db674cdee4c8c5cb1068
Author: David Sidrane <David.Sidrane@NscDg.com>
AuthorDate: Thu Apr 2 12:06:58 2020 -0700

    stm32h7:Fix DMA Overrun error
---
 arch/arm/src/stm32h7/stm32_spi.c | 78 ++++++++++++++++++++++------------------
 1 file changed, 44 insertions(+), 34 deletions(-)

diff --git a/arch/arm/src/stm32h7/stm32_spi.c b/arch/arm/src/stm32h7/stm32_spi.c
index e56bde7..8c304b5 100644
--- a/arch/arm/src/stm32h7/stm32_spi.c
+++ b/arch/arm/src/stm32h7/stm32_spi.c
@@ -1451,16 +1451,6 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e
mode)
 
       spi_modifyreg(priv, STM32_SPI_CFG2_OFFSET, clrbits, setbits);
 
-#ifdef CONFIG_STM32H7_SPI_DMA
-      /* Enabling SPI causes a spurious received character indication
-       * which confuse the DMA controller so we disable DMA during that
-       * enabling; and flush the SPI RX FIFO before re-enabling DMA.
-       */
-
-      spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, SPI_CFG1_RXDMAEN |
-                          SPI_CFG1_TXDMAEN, 0);
-#endif
-
       /* Re-enable SPI */
 
       spi_enable(priv, true);
@@ -1469,19 +1459,9 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e
mode)
         {
           /* Flush SPI read FIFO */
 
-          spi_getreg(priv, STM32_SPI_TXDR_OFFSET);
+          spi_getreg(priv, STM32_SPI_RXDR_OFFSET);
         }
 
-#ifdef CONFIG_STM32H7_SPI_DMA
-
-      /* Re-enable DMA (with SPI disabled) */
-
-      spi_enable(priv, false);
-      spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_RXDMAEN |
-                          SPI_CFG1_TXDMAEN);
-      spi_enable(priv, true);
-#endif
-
       /* Save the mode so that subsequent re-configurations will be faster */
 
       priv->mode = mode;
@@ -1913,6 +1893,22 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void
*txbuffer,
       static uint8_t rxdummy[4] __attribute__((aligned(4)));
       static const uint16_t txdummy = 0xffff;
 
+      /* When starting communication using DMA, to prevent DMA channel
+       * management raising error events, these steps must be followed in
+       * order:
+       * 1. Enable DMA Rx buffer in the RXDMAEN bit in the SPI_CFG1 register,
+       *    if DMA Rx is used.
+       * 2. Enable DMA requests for Tx and Rx in DMA registers, if the DMA is
+       *    used.
+       * 3. Enable DMA Tx buffer in the TXDMAEN bit in the SPI_CFG1 register,
+       *    if DMA Tx is used.
+       * 4. Enable the SPI by setting the SPE bit.
+       */
+
+      spi_enable(priv, false);
+      spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, SPI_CFG1_TXDMAEN,
+                          SPI_CFG1_RXDMAEN);
+
       spiinfo("txbuffer=%p rxbuffer=%p nwords=%d\n",
               txbuffer, rxbuffer, nwords);
       DEBUGASSERT(priv->spibase != 0);
@@ -1920,6 +1916,9 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
       spi_dmarxsetup(priv, rxbuffer, (uint16_t *)rxdummy, nbytes);
       spi_dmatxsetup(priv, txbuffer, &txdummy, nbytes);
 
+      spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_TXDMAEN |
+                          SPI_CFG1_RXDMAEN);
+
       /* Flush cache to physical memory */
 
       if (txbuffer)
@@ -1927,19 +1926,17 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void
*txbuffer,
           up_flush_dcache((uintptr_t)txbuffer, (uintptr_t)txbuffer + nbytes);
         }
 
-      /* REVISIT: Master transfer start */
-
-      spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, 0, SPI_CR1_CSTART);
-
 #ifdef CONFIG_SPI_TRIGGER
       /* Is deferred triggering in effect? */
 
       if (!priv->defertrig)
         {
-          /* No.. Start the DMAs */
+          /* No.. Start the DMAs then the SPI */
 
           spi_dmarxstart(priv);
           spi_dmatxstart(priv);
+          spi_enable(priv, true);
+          spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, 0, SPI_CR1_CSTART);
         }
       else
         {
@@ -1948,20 +1945,32 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void
*txbuffer,
           priv->trigarmed = true;
         }
 #else
-      /* Start the DMAs */
+      /* Start the DMAs then the SPI */
 
       spi_dmarxstart(priv);
       spi_dmatxstart(priv);
+      spi_enable(priv, true);
+      spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, 0, SPI_CR1_CSTART);
 #endif
 
       /* Then wait for each to complete */
 
-      ret = spi_dmarxwait(priv);
-      if (ret >= 0)
-        {
-          ret = spi_dmatxwait(priv);
-          UNUSED(ret);
-        }
+      spi_dmarxwait(priv);
+      spi_dmatxwait(priv);
+
+      /* To close communication it is mandatory to follow these steps in
+       * order:
+       * 1. Disable DMA request for Tx and Rx in the DMA registers, if the
+       *    DMA issued.
+       * 2. Disable the SPI by following the SPI disable procedure.
+       * 3. Disable DMA Tx and Rx buffers by clearing the TXDMAEN and RXDMAEN
+       *    bits in the SPI_CFG1 register, if DMA Tx and/or DMA Rx are used.
+       */
+
+      spi_enable(priv, false);
+      spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, SPI_CFG1_TXDMAEN |
+                          SPI_CFG1_RXDMAEN, 0);
+      spi_enable(priv, true);
 
 #ifdef CONFIG_SPI_TRIGGER
       priv->trigarmed = false;
@@ -2012,7 +2021,8 @@ static int spi_trigger(FAR struct spi_dev_s *dev)
 
   spi_dmarxstart(priv);
   spi_dmatxstart(priv);
-
+  spi_enable(priv, true);
+  spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, 0, SPI_CR1_CSTART);
   return OK;
 #else
   return -ENOSYS;


Mime
View raw message