From 8fc63738f68b76286d9cd11a7661f9c2d0f463f8 Mon Sep 17 00:00:00 2001
From: Vincent Dupont <vincent@otakeys.com>
Date: Thu, 28 Sep 2017 18:03:17 +0200
Subject: [PATCH] cpu/stm32_common: adapt UART driver to use DMA

---
 cpu/stm32_common/periph/uart.c | 70 ++++++++++++++++++++++++++++------
 1 file changed, 59 insertions(+), 11 deletions(-)

diff --git a/cpu/stm32_common/periph/uart.c b/cpu/stm32_common/periph/uart.c
index 2c67d35d79..54adaea1d0 100644
--- a/cpu/stm32_common/periph/uart.c
+++ b/cpu/stm32_common/periph/uart.c
@@ -118,24 +118,21 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
     return UART_OK;
 }
 
-void uart_write(uart_t uart, const uint8_t *data, size_t len)
+static inline void send_byte(uart_t uart, uint8_t byte)
 {
-    assert(uart < UART_NUMOF);
-
-    for (size_t i = 0; i < len; i++) {
 #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) \
     || defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) \
     || defined(CPU_FAM_STM32F7)
-        while (!(dev(uart)->ISR & USART_ISR_TXE)) {}
-        dev(uart)->TDR = data[i];
+    while (!(dev(uart)->ISR & USART_ISR_TXE)) {}
+    dev(uart)->TDR = byte;
 #else
-        while (!(dev(uart)->SR & USART_SR_TXE)) {}
-        dev(uart)->DR = data[i];
+    while (!(dev(uart)->SR & USART_SR_TXE)) {}
+    dev(uart)->DR = byte;
 #endif
-    }
+}
 
-    /* make sure the function is synchronous by waiting for the transfer to
-     * finish */
+static inline void wait_for_tx_complete(uart_t uart)
+{
 #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) \
     || defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) \
     || defined(CPU_FAM_STM32F7)
@@ -145,6 +142,57 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len)
 #endif
 }
 
+void uart_write(uart_t uart, const uint8_t *data, size_t len)
+{
+    assert(uart < UART_NUMOF);
+
+#ifdef MODULE_PERIPH_DMA
+    if (!len) {
+        return;
+    }
+    if (uart_config[uart].dma != DMA_STREAM_UNDEF) {
+        if (irq_is_in()) {
+            uint16_t todo = 0;
+            if (dev(uart)->CR3 & USART_CR3_DMAT) {
+                /* DMA transfer for UART on-going */
+                todo = dma_suspend(uart_config[uart].dma);
+            }
+            if (todo) {
+                dma_stop(uart_config[uart].dma);
+                dev(uart)->CR3 &= ~USART_CR3_DMAT;
+            }
+            for (unsigned i = 0; i < len; i++) {
+                send_byte(uart, data[i]);
+            }
+            if (todo > 0) {
+                wait_for_tx_complete(uart);
+                dev(uart)->CR3 |= USART_CR3_DMAT;
+                dma_resume(uart_config[uart].dma, todo);
+            }
+        }
+        else {
+            dma_acquire(uart_config[uart].dma);
+            dev(uart)->CR3 |= USART_CR3_DMAT;
+            dma_transfer(uart_config[uart].dma, uart_config[uart].dma_chan, data,
+                         (void *)&dev(uart)->DR, len, DMA_MEM_TO_PERIPH, DMA_INC_SRC_ADDR);
+            dma_release(uart_config[uart].dma);
+
+            /* make sure the function is synchronous by waiting for the transfer to
+             * finish */
+            wait_for_tx_complete(uart);
+            dev(uart)->CR3 &= ~USART_CR3_DMAT;
+        }
+        return;
+    }
+#endif
+    for (size_t i = 0; i < len; i++) {
+        send_byte(uart, data[i]);
+    }
+    /* make sure the function is synchronous by waiting for the transfer to
+     * finish */
+    wait_for_tx_complete(uart);
+}
+
 void uart_poweron(uart_t uart)
 {
     assert(uart < UART_NUMOF);
-- 
GitLab