Hi community

The STM32H7 serial driver TX DMA logic is no longer working properly.

The issues started with commit 660ac63b. Subsequent attempts (f92a9068, 
6c186b60) have failed to get it working again.

I think the original idea of 660ac63b is right, it just failed to restart TX 
DMA upon TX DMA completion (if needed).

I would suggest reverting the following commits: 6c186b60 58f2a7b1 69a8b5b5. 
Then add the following patch as an amendment:

diff --git a/arch/arm/src/stm32h7/stm32_serial.c 
b/arch/arm/src/stm32h7/stm32_serial.c
index 120ea0f3b5..fc90c5d521 100644
--- a/arch/arm/src/stm32h7/stm32_serial.c
+++ b/arch/arm/src/stm32h7/stm32_serial.c
@@ -3780,11 +3780,20 @@ static void up_dma_txcallback(DMA_HANDLE handle, 
uint8_t status, void *arg)
         }
     }

-  nxsem_post(&priv->txdmasem);
-
   /* Adjust the pointers */

   uart_xmitchars_done(&priv->dev);
+
+  /* Initiate another transmit if data is ready */
+
+  if (priv->dev.xmit.tail != priv->dev.xmit.head)
+    {
+      uart_xmitchars_dma(&priv->dev);
+    }
+  else
+    {
+      nxsem_post(&priv->txdmasem);
+    }
 }
 #endif

@@ -3806,6 +3815,14 @@ static void up_dma_txavailable(struct uart_dev_s *dev)
   int rv = nxsem_trywait(&priv->txdmasem);
   if (rv == OK)
     {
+      if (dev->xmit.head == dev->xmit.tail)
+        {
+          /* No data to transfer. Release semaphore. */
+
+          nxsem_post(&priv->txdmasem);
+          return;
+        }
+
       uart_xmitchars_dma(dev);
     }
 }


However, uart_xmitchars_dma() is currently not safe to call from an interrupt 
service routine, so the following patch would also be required:

diff --git a/drivers/serial/serial_dma.c b/drivers/serial/serial_dma.c
index aa99e801ff..b2603953ad 100644
--- a/drivers/serial/serial_dma.c
+++ b/drivers/serial/serial_dma.c
@@ -97,26 +97,29 @@ void uart_xmitchars_dma(FAR uart_dev_t *dev)
 {
   FAR struct uart_dmaxfer_s *xfer = &dev->dmatx;

-  if (dev->xmit.head == dev->xmit.tail)
+  size_t head = dev->xmit.head;
+  size_t tail = dev->xmit.tail;
+
+  if (head == tail)
     {
       /* No data to transfer. */

       return;
     }

-  if (dev->xmit.tail < dev->xmit.head)
+  if (tail < head)
     {
-      xfer->buffer  = &dev->xmit.buffer[dev->xmit.tail];
-      xfer->length  = dev->xmit.head - dev->xmit.tail;
+      xfer->buffer  = &dev->xmit.buffer[tail];
+      xfer->length  = head - tail;
       xfer->nbuffer = NULL;
       xfer->nlength = 0;
     }
   else
     {
-      xfer->buffer  = &dev->xmit.buffer[dev->xmit.tail];
-      xfer->length  = dev->xmit.size - dev->xmit.tail;
+      xfer->buffer  = &dev->xmit.buffer[tail];
+      xfer->length  = dev->xmit.size - tail;
       xfer->nbuffer = dev->xmit.buffer;
-      xfer->nlength = dev->xmit.head;
+      xfer->nlength = head;
     }

   dev->tx_count += xfer->length + xfer->nlength;


Any thoughts?

Regards
Kian

Reply via email to