You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/07/21 02:28:59 UTC

[incubator-nuttx] branch master updated (5db4d2a -> 19fddc4)

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

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


    from 5db4d2a  sched/task: Fix wrong return value from nxspawn_open()
     new 34eb918  kinetis:LPUART Add IOCTL for invert
     new 19fddc4  Kintis:LPUART add RX DMA

The 2 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/kinetis/Kconfig                       |  56 +++
 arch/arm/src/kinetis/kinetis_lpserial.c            | 553 ++++++++++++++++++++-
 .../kinetis/{kinetis_uart.h => kinetis_lpuart.h}   |  41 +-
 3 files changed, 617 insertions(+), 33 deletions(-)
 copy arch/arm/src/kinetis/{kinetis_uart.h => kinetis_lpuart.h} (69%)

[incubator-nuttx] 02/02: Kintis:LPUART add RX DMA

Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 19fddc451ca7f9d43f5a57e591f58c453cd61a0b
Author: David Sidrane <Da...@NscDg.com>
AuthorDate: Tue Jul 20 11:43:24 2021 -0700

    Kintis:LPUART add RX DMA
---
 arch/arm/src/kinetis/Kconfig            |  56 ++++
 arch/arm/src/kinetis/kinetis_lpserial.c | 509 +++++++++++++++++++++++++++++++-
 arch/arm/src/kinetis/kinetis_lpuart.h   | 101 +++++++
 3 files changed, 655 insertions(+), 11 deletions(-)

diff --git a/arch/arm/src/kinetis/Kconfig b/arch/arm/src/kinetis/Kconfig
index cbda473..03e18e2 100644
--- a/arch/arm/src/kinetis/Kconfig
+++ b/arch/arm/src/kinetis/Kconfig
@@ -1398,6 +1398,62 @@ config KINETIS_SERIAL_RXDMA_BUFFER_SIZE
 
 endmenu # Kinetis UART Configuration
 
+menu "Kinetis LPUART Configuration"
+if KINETIS_SERIALDRIVER || OTHER_SERIALDRIVER
+
+comment "LP Uart Driver Configuration"
+
+config KINETIS_LPUART0_RXDMA
+	bool "LPUART0 Rx DMA"
+	default n
+	depends on KINETIS_LPUART0 && KINETIS_EDMA
+	---help---
+		In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
+config KINETIS_LPUART1_RXDMA
+	bool "LPUART1 Rx DMA"
+	default n
+	depends on KINETIS_LPUART1 && KINETIS_EDMA
+	---help---
+		In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
+config KINETIS_LPUART2_RXDMA
+	bool "LPUART2 Rx DMA"
+	default n
+	depends on KINETIS_LPUART2 && KINETIS_EDMA
+	---help---
+		In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
+config KINETIS_LPUART3_RXDMA
+	bool "LPUART3 Rx DMA"
+	default n
+	depends on KINETIS_LPUART3 && KINETIS_EDMA
+	---help---
+		In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
+config KINETIS_LPUART4_RXDMA
+	bool "LPUART4 Rx DMA"
+	default n
+	depends on KINETIS_LPUART4 && KINETIS_EDMA
+	---help---
+		In high data rate usage, Rx DMA may eliminate Rx overrun errors
+
+config KINETIS_LPUART_RXDMA_BUFFER_SIZE
+	int "Rx DMA buffer size"
+	default 32
+	depends on KINETIS_LPUART0_RXDMA || KINETIS_LPUART1_RXDMA || KINETIS_LPUART2_RXDMA || KINETIS_LPUART3_RXDMA || KINETIS_LPUART4_RXDMA
+	---help---
+		The DMA buffer size when using RX DMA to emulate a FIFO.
+
+		When streaming data, the generic serial layer will be called
+		every time the FIFO receives half this number of bytes.
+
+		Value given here will be rounded up to next multiple of 32 bytes.
+
+endif # KINETIS_SERIALDRIVER || OTHER_SERIALDRIVER
+
+endmenu # Kinetis LPUART Configuration
+
 config KINETIS_MERGE_TTY
 	bool "Kinetis Merge TTY names for LPUARTS"
 	default n
diff --git a/arch/arm/src/kinetis/kinetis_lpserial.c b/arch/arm/src/kinetis/kinetis_lpserial.c
index 4ad9ded..be3bcf1 100644
--- a/arch/arm/src/kinetis/kinetis_lpserial.c
+++ b/arch/arm/src/kinetis/kinetis_lpserial.c
@@ -47,10 +47,14 @@
 #include "arm_arch.h"
 #include "arm_internal.h"
 
-#include "kinetis.h"
+#include "kinetis_config.h"
+#include "chip.h"
 #include "hardware/kinetis_lpuart.h"
 #include "hardware/kinetis_pinmux.h"
-
+#include "hardware/kinetis_dmamux.h"
+#include "kinetis.h"
+#include "kinetis_lpuart.h"
+#include "kinetis_edma.h"
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
@@ -69,6 +73,10 @@
 
 #if defined(HAVE_LPUART_DEVICE) && defined(USE_SERIALDRIVER)
 
+/* Assume DMA is not used on the console UART */
+
+#undef SERIAL_HAVE_CONSOLE_DMA
+
 /* Which LPUART with be tty0/console and which tty1?  The console will always
  * be ttyS0.  If there is no console then will use the lowest numbered
  * LPUART.
@@ -80,22 +88,37 @@
 #    define CONSOLE_DEV         g_lpuart0port /* LPUART0 is console */
 #    define TTYS0_DEV           g_lpuart0port /* LPUART0 is ttyS0 */
 #    define LPUART0_ASSIGNED    1
+#  if defined(CONFIG_KINETIS_LPUART0_RXDMA)
+#    define SERIAL_HAVE_CONSOLE_DMA 1
+#  endif
 #elif defined(CONFIG_LPUART1_SERIAL_CONSOLE)
 #    define CONSOLE_DEV         g_lpuart1port /* LPUART1 is console */
 #    define TTYS0_DEV           g_lpuart1port /* LPUART1 is ttyS0 */
 #    define LPUART1_ASSIGNED    1
+#  if defined(CONFIG_KINETIS_LPUART1_RXDMA)
+#    define SERIAL_HAVE_CONSOLE_DMA 1
+#  endif
 #elif defined(CONFIG_LPUART2_SERIAL_CONSOLE)
 #    define CONSOLE_DEV         g_lpuart2port /* LPUART2 is console */
 #    define TTYS0_DEV           g_lpuart2port /* LPUART2 is ttyS0 */
 #    define LPUART2_ASSIGNED    1
+#  if defined(CONFIG_KINETIS_LPUART2_RXDMA)
+#    define SERIAL_HAVE_CONSOLE_DMA 1
+#  endif
 #elif defined(CONFIG_LPUART3_SERIAL_CONSOLE)
 #    define CONSOLE_DEV         g_lpuart3port /* LPUART3 is console */
 #    define TTYS0_DEV           g_lpuart3port /* LPUART3 is ttyS0 */
 #    define LPUART3_ASSIGNED    1
+#  if defined(CONFIG_KINETIS_LPUART3_RXDMA)
+#    define SERIAL_HAVE_CONSOLE_DMA 1
+#  endif
 #elif defined(CONFIG_LPUART4_SERIAL_CONSOLE)
 #    define CONSOLE_DEV         g_lpuart4port /* LPUART4 is console */
 #    define TTYS0_DEV           g_lpuart4port /* LPUART4 is ttyS0 */
 #    define LPUART4_ASSIGNED    1
+#  if defined(CONFIG_KINETIS_LPUART4_RXDMA)
+#    define SERIAL_HAVE_CONSOLE_DMA 1
+#  endif
 #else
 #  undef CONSOLE_DEV                          /* No console */
 #  if defined(CONFIG_KINETIS_LPUART0)
@@ -182,6 +205,37 @@
 #  define LPUART4_ASSIGNED      1
 #endif
 
+#ifdef LPSERIAL_HAVE_DMA
+
+/* The DMA buffer size when using RX DMA to emulate a FIFO.
+ *
+ * When streaming data, the generic serial layer will be called every time
+ * the FIFO receives half this number of bytes.
+ *
+ * This buffer size should be an even multiple of the Cortex-M7 D-Cache line
+ * size, ARMV7M_DCACHE_LINESIZE, so that it can be individually invalidated.
+ *
+ * Should there be a Cortex-M7 without a D-Cache, ARMV7M_DCACHE_LINESIZE
+ * would be zero!
+ */
+
+#  if !defined(ARMV7M_DCACHE_LINESIZE) || ARMV7M_DCACHE_LINESIZE == 0
+#    undef ARMV7M_DCACHE_LINESIZE
+#    define ARMV7M_DCACHE_LINESIZE 32
+#  endif
+
+#  if !defined(CONFIG_KINETIS_LPUART_RXDMA_BUFFER_SIZE) || \
+      (CONFIG_KINETIS_LPUART_RXDMA_BUFFER_SIZE < ARMV7M_DCACHE_LINESIZE)
+#    undef CONFIG_KINETIS_LPUART_RXDMA_BUFFER_SIZE
+#    define CONFIG_KINETIS_LPUART_RXDMA_BUFFER_SIZE ARMV7M_DCACHE_LINESIZE
+#  endif
+
+#  define RXDMA_BUFFER_MASK   ((uint32_t)(ARMV7M_DCACHE_LINESIZE - 1))
+#  define RXDMA_BUFFER_SIZE   ((CONFIG_KINETIS_LPUART_RXDMA_BUFFER_SIZE \
+                                + RXDMA_BUFFER_MASK) & ~RXDMA_BUFFER_MASK)
+
+#endif /* LPSERIAL_HAVE_DMA */
+
 #define LPUART_CTRL_ERROR_INTS  (LPUART_CTRL_ORIE | LPUART_CTRL_FEIE | \
                                  LPUART_CTRL_NEIE | LPUART_CTRL_PEIE)
 
@@ -230,6 +284,12 @@ struct kinetis_dev_s
 #ifdef CONFIG_SERIAL_OFLOWCONTROL
   uint32_t  cts_gpio;  /* UART CTS GPIO pin configuration */
 #endif
+#ifdef LPSERIAL_HAVE_DMA
+  const uint8_t rxdma_reqsrc;
+  DMACH_HANDLE      rxdma;     /* currently-open receive DMA stream */
+  uint32_t          rxdmanext; /* Next byte in the DMA buffer to be read */
+  char      *const  rxfifo;    /* Receive DMA buffer */
+#endif
 };
 
 /****************************************************************************
@@ -242,9 +302,11 @@ static int  kinetis_attach(struct uart_dev_s *dev);
 static void kinetis_detach(struct uart_dev_s *dev);
 static int  kinetis_interrupt(int irq, void *context, void *arg);
 static int  kinetis_ioctl(struct file *filep, int cmd, unsigned long arg);
-static int  kinetis_receive(struct uart_dev_s *dev, unsigned int *status);
 static void kinetis_rxint(struct uart_dev_s *dev, bool enable);
+#if !defined(LPSERIAL_HAVE_ALL_DMA)
+static int  kinetis_receive(struct uart_dev_s *dev, unsigned int *status);
 static bool kinetis_rxavailable(struct uart_dev_s *dev);
+#endif
 #ifdef CONFIG_SERIAL_IFLOWCONTROL
 static bool kinetis_rxflowcontrol(struct uart_dev_s *dev,
                                   unsigned int nbuffered, bool upper);
@@ -253,10 +315,22 @@ static void kinetis_send(struct uart_dev_s *dev, int ch);
 static void kinetis_txint(struct uart_dev_s *dev, bool enable);
 static bool kinetis_txready(struct uart_dev_s *dev);
 
+#ifdef LPSERIAL_HAVE_DMA
+static int  kinetis_dma_nextrx(struct kinetis_dev_s *priv);
+static int  kinetis_dma_setup(struct uart_dev_s *dev);
+static void kinetis_dma_shutdown(struct uart_dev_s *dev);
+static int  kinetis_dma_receive(struct uart_dev_s *dev,
+                                unsigned int *status);
+static bool kinetis_dma_rxavailable(struct uart_dev_s *dev);
+static uint32_t get_and_clear_uart_status(struct kinetis_dev_s *priv);
+static void kinetis_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done,
+                                  int result);
+#endif
+
 /****************************************************************************
  * Private Data
  ****************************************************************************/
-
+#if !defined(LPSERIAL_HAVE_ALL_DMA)
 static const struct uart_ops_s g_lpuart_ops =
 {
   .setup          = kinetis_setup,
@@ -275,28 +349,70 @@ static const struct uart_ops_s g_lpuart_ops =
   .txready        = kinetis_txready,
   .txempty        = kinetis_txready,
 };
+#endif
+
+#ifdef LPSERIAL_HAVE_DMA
+static const struct uart_ops_s g_lpuart_dma_ops =
+{
+  .setup          = kinetis_dma_setup,
+  .shutdown       = kinetis_dma_shutdown,
+  .attach         = kinetis_attach,
+  .detach         = kinetis_detach,
+  .ioctl          = kinetis_ioctl,
+  .receive        = kinetis_dma_receive,
+  .rxint          = kinetis_rxint,
+  .rxavailable    = kinetis_dma_rxavailable,
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+  .rxflowcontrol  = kinetis_rxflowcontrol,
+#endif
+  .send           = kinetis_send,
+  .txint          = kinetis_txint,
+  .txready        = kinetis_txready,
+  .txempty        = kinetis_txready,
+};
+#endif
 
 /* I/O buffers */
 
 #ifdef CONFIG_KINETIS_LPUART0
 static char g_lpuart0rxbuffer[CONFIG_LPUART0_RXBUFSIZE];
 static char g_lpuart0txbuffer[CONFIG_LPUART0_TXBUFSIZE];
+#  ifdef CONFIG_KINETIS_LPUART0_RXDMA
+static char g_lpuart0rxfifo[RXDMA_BUFFER_SIZE]
+  __attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+#  endif
 #endif
 #ifdef CONFIG_KINETIS_LPUART1
 static char g_lpuart1rxbuffer[CONFIG_LPUART1_RXBUFSIZE];
 static char g_lpuart1txbuffer[CONFIG_LPUART1_TXBUFSIZE];
+#  ifdef CONFIG_KINETIS_LPUART1_RXDMA
+static char g_lpuart1rxfifo[RXDMA_BUFFER_SIZE]
+  __attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+#  endif
 #endif
 #ifdef CONFIG_KINETIS_LPUART2
 static char g_lpuart2rxbuffer[CONFIG_LPUART2_RXBUFSIZE];
 static char g_lpuart2txbuffer[CONFIG_LPUART2_TXBUFSIZE];
+#  ifdef CONFIG_KINETIS_LPUART2_RXDMA
+static char g_lpuart2rxfifo[RXDMA_BUFFER_SIZE]
+  __attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+#  endif
 #endif
 #ifdef CONFIG_KINETIS_LPUART3
 static char g_lpuart3rxbuffer[CONFIG_LPUART3_RXBUFSIZE];
 static char g_lpuart3txbuffer[CONFIG_LPUART3_TXBUFSIZE];
+#  ifdef CONFIG_KINETIS_LPUART3_RXDMA
+static char g_lpuart3rxfifo[RXDMA_BUFFER_SIZE]
+  __attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+#  endif
 #endif
 #ifdef CONFIG_KINETIS_LPUART4
 static char g_lpuart4rxbuffer[CONFIG_LPUART4_RXBUFSIZE];
 static char g_lpuart4txbuffer[CONFIG_LPUART4_TXBUFSIZE];
+#  ifdef CONFIG_KINETIS_LPUART4_RXDMA
+static char g_lpuart4rxfifo[RXDMA_BUFFER_SIZE]
+  __attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+#  endif
 #endif
 
 /* This describes the state of the Kinetis LPUART0 port. */
@@ -319,6 +435,10 @@ static struct kinetis_dev_s g_lpuart0priv =
   .iflow         = true,
   .rts_gpio      = PIN_LPUART0_RTS,
 #endif
+#ifdef CONFIG_KINETIS_LPUART0_RXDMA
+  .rxdma_reqsrc   = KINETIS_DMA_REQUEST_SRC_LPUART0_RX,
+  .rxfifo         = g_lpuart0rxfifo,
+#endif
 };
 
 static uart_dev_t g_lpuart0port =
@@ -333,7 +453,11 @@ static uart_dev_t g_lpuart0port =
     .size   = CONFIG_LPUART0_TXBUFSIZE,
     .buffer = g_lpuart0txbuffer,
   },
-  .ops      = &g_lpuart_ops,
+#ifdef CONFIG_KINETIS_LPUART0_RXDMA
+  .ops        = &g_lpuart_dma_ops,
+#else
+  .ops        = &g_lpuart_ops,
+#endif
   .priv     = &g_lpuart0priv,
 };
 #endif
@@ -358,6 +482,10 @@ static struct kinetis_dev_s g_lpuart1priv =
   .iflow         = true,
   .rts_gpio      = PIN_LPUART1_RTS,
 #endif
+#ifdef CONFIG_KINETIS_LPUART1_RXDMA
+  .rxdma_reqsrc   = KINETIS_DMA_REQUEST_SRC_LPUART1_RX,
+  .rxfifo         = g_lpuart1rxfifo,
+#endif
 };
 
 static uart_dev_t g_lpuart1port =
@@ -372,7 +500,11 @@ static uart_dev_t g_lpuart1port =
     .size   = CONFIG_LPUART1_TXBUFSIZE,
     .buffer = g_lpuart1txbuffer,
   },
-  .ops      = &g_lpuart_ops,
+#ifdef CONFIG_KINETIS_LPUART1_RXDMA
+  .ops        = &g_lpuart_dma_ops,
+#else
+  .ops        = &g_lpuart_ops,
+#endif
   .priv     = &g_lpuart1priv,
 };
 #endif
@@ -397,6 +529,10 @@ static struct kinetis_dev_s g_lpuart2priv =
   .iflow         = true,
   .rts_gpio      = PIN_LPUART2_RTS,
 #endif
+#ifdef CONFIG_KINETIS_LPUART2_RXDMA
+  .rxdma_reqsrc   = KINETIS_DMA_REQUEST_SRC_LPUART2_RX,
+  .rxfifo         = g_lpuart2rxfifo,
+#endif
 };
 
 static uart_dev_t g_lpuart2port =
@@ -411,7 +547,11 @@ static uart_dev_t g_lpuart2port =
     .size   = CONFIG_LPUART2_TXBUFSIZE,
     .buffer = g_lpuart2txbuffer,
   },
-  .ops      = &g_lpuart_ops,
+#ifdef CONFIG_KINETIS_LPUART2_RXDMA
+  .ops        = &g_lpuart_dma_ops,
+#else
+  .ops        = &g_lpuart_ops,
+#endif
   .priv     = &g_lpuart2priv,
 };
 #endif
@@ -436,6 +576,10 @@ static struct kinetis_dev_s g_lpuart3priv =
   .iflow         = true,
   .rts_gpio      = PIN_LPUART3_RTS,
 #endif
+#ifdef CONFIG_KINETIS_LPUART3_RXDMA
+  .rxdma_reqsrc   = KINETIS_DMA_REQUEST_SRC_LPUART3_RX,
+  .rxfifo         = g_lpuart3rxfifo,
+#endif
 };
 
 static uart_dev_t g_lpuart3port =
@@ -450,7 +594,11 @@ static uart_dev_t g_lpuart3port =
     .size   = CONFIG_LPUART3_TXBUFSIZE,
     .buffer = g_lpuart3txbuffer,
   },
-  .ops      = &g_lpuart_ops,
+#ifdef CONFIG_KINETIS_LPUART3_RXDMA
+  .ops        = &g_lpuart_dma_ops,
+#else
+  .ops        = &g_lpuart_ops,
+#endif
   .priv     = &g_lpuart3priv,
 };
 #endif
@@ -475,6 +623,10 @@ static struct kinetis_dev_s g_lpuart4priv =
   .iflow         = true,
   .rts_gpio      = PIN_LPUART4_RTS,
 #endif
+#ifdef CONFIG_KINETIS_LPUART4_RXDMA
+  .rxdma_reqsrc   = KINETIS_DMA_REQUEST_SRC_LPUART4_RX,
+  .rxfifo         = g_lpuart4rxfifo,
+#endif
 };
 
 static uart_dev_t g_lpuart4port =
@@ -489,7 +641,11 @@ static uart_dev_t g_lpuart4port =
     .size   = CONFIG_LPUART4_TXBUFSIZE,
     .buffer = g_lpuart4txbuffer,
   },
-  .ops      = &g_lpuart_ops,
+#ifdef CONFIG_KINETIS_LPUART4_RXDMA
+  .ops        = &g_lpuart_dma_ops,
+#else
+  .ops        = &g_lpuart_ops,
+#endif
   .priv     = &g_lpuart4priv,
 };
 #endif
@@ -578,6 +734,38 @@ static void kinetis_disableuartint(struct kinetis_dev_s *priv, uint32_t *ie)
 #endif
 
 /****************************************************************************
+ * Name: get_and_clear_uart_status
+ *
+ * Description:
+ *   Clears the error flags of the uart if an error occurred in s1 and
+ *   returns the status
+ *
+ * Input Parameters:
+ *   u_dev_s
+ *
+ * Returns Value:
+ *   Uart status s1
+ *
+ ****************************************************************************/
+
+#ifdef LPSERIAL_HAVE_DMA
+static uint32_t get_and_clear_uart_status(struct kinetis_dev_s *priv)
+{
+  uint32_t regval;
+
+  regval = kinetis_serialin(priv, KINETIS_LPUART_STAT_OFFSET);
+  regval &= LPUART_STAT_ERRORS;
+
+  if (regval != 0)
+    {
+      kinetis_serialout(priv, KINETIS_LPUART_STAT_OFFSET, regval);
+    }
+
+  return regval;
+}
+#endif
+
+/****************************************************************************
  * Name: kinetis_setup
  *
  * Description:
@@ -615,6 +803,83 @@ static int kinetis_setup(struct uart_dev_s *dev)
 }
 
 /****************************************************************************
+ * Name: kinetis_dma_setup
+ *
+ * Description:
+ *   Configure the UART baud, bits, parity, etc. This method is called the
+ *   first time that the serial port is opened.
+ *
+ ****************************************************************************/
+
+#ifdef LPSERIAL_HAVE_DMA
+static int kinetis_dma_setup(struct uart_dev_s *dev)
+{
+  struct kinetis_dev_s *priv = (struct kinetis_dev_s *)dev->priv;
+  int result;
+  uint32_t regval;
+  DMACH_HANDLE rxdma = NULL;
+
+  /* Do the basic UART setup first, unless we are the console */
+
+  if (!dev->isconsole)
+    {
+      result = kinetis_setup(dev);
+      if (result != OK)
+        {
+          return result;
+        }
+    }
+
+  /* Acquire the DMA channel. */
+
+  rxdma = kinetis_dmach_alloc(priv->rxdma_reqsrc | DMAMUX_CHCFG_ENBL, 0);
+  if (rxdma == NULL)
+    {
+      return -EBUSY;
+    }
+
+  /* Configure for circular DMA reception into the RX FIFO */
+
+  struct kinetis_edma_xfrconfig_s config;
+  config.saddr  = priv->uartbase + KINETIS_LPUART_DATA_OFFSET;
+  config.daddr  = (uint32_t) priv->rxfifo;
+  config.soff   = 0;
+  config.doff   = 1;
+  config.iter   = RXDMA_BUFFER_SIZE;
+  config.flags  = EDMA_CONFIG_LINKTYPE_LINKNONE | EDMA_CONFIG_LOOPDEST;
+  config.ssize  = EDMA_8BIT;
+  config.dsize  = EDMA_8BIT;
+  config.ttype  = EDMA_PERIPH2MEM;
+  config.nbytes = 1;
+#ifdef CONFIG_KINETIS_EDMA_ELINK
+  config.linkch = NULL;
+#endif
+  kinetis_dmach_xfrsetup(rxdma, &config);
+
+  /* Reset our DMA shadow pointer to match the address just programmed
+   * above.
+   */
+
+  priv->rxdmanext = 0;
+
+  /* Enable receive DMA for the UART */
+
+  regval  = kinetis_serialin(priv, KINETIS_LPUART_BAUD_OFFSET);
+  regval |= LPUART_BAUD_RDMAE;
+  kinetis_serialout(priv, KINETIS_LPUART_BAUD_OFFSET, regval);
+
+  /* Start the DMA channel, and arrange for callbacks at the half and
+   * full points in the FIFO.  This ensures that we have half a FIFO
+   * worth of time to claim bytes before they are overwritten.
+   */
+
+  kinetis_dmach_start(rxdma, kinetis_dma_rxcallback, (void *)dev);
+  priv->rxdma = rxdma;
+  return OK;
+}
+#endif
+
+/****************************************************************************
  * Name: kinetis_shutdown
  *
  * Description:
@@ -637,6 +902,37 @@ static void kinetis_shutdown(struct uart_dev_s *dev)
 }
 
 /****************************************************************************
+ * Name: kinetis_dma_shutdown
+ *
+ * Description:
+ *   Disable the UART.  This method is called when the serial
+ *   port is closed
+ *
+ ****************************************************************************/
+
+#ifdef LPSERIAL_HAVE_DMA
+static void kinetis_dma_shutdown(struct uart_dev_s *dev)
+{
+  struct kinetis_dev_s *priv = (struct kinetis_dev_s *)dev->priv;
+  DMACH_HANDLE rxdma = priv->rxdma;
+
+  /* Perform the normal UART shutdown */
+
+  kinetis_shutdown(dev);
+
+  /* Stop the DMA channel */
+
+  kinetis_dmach_stop(rxdma);
+
+  /* Release the DMA channel */
+
+  kinetis_dmach_free(rxdma);
+
+  priv->rxdma = NULL;
+}
+#endif
+
+/****************************************************************************
  * Name: kinetis_attach
  *
  * Description:
@@ -1102,7 +1398,7 @@ static int kinetis_ioctl(struct file *filep, int cmd, unsigned long arg)
  *   return 'status'.
  *
  ****************************************************************************/
-
+#if !defined(LPSERIAL_HAVE_ALL_DMA)
 static int kinetis_receive(struct uart_dev_s *dev, unsigned int *status)
 {
   struct kinetis_dev_s *priv = (struct kinetis_dev_s *)dev->priv;
@@ -1143,6 +1439,66 @@ static int kinetis_receive(struct uart_dev_s *dev, unsigned int *status)
 
   return data;
 }
+#endif
+
+/****************************************************************************
+ * Name: kinetis_dma_receive
+ *
+ * Description:
+ *   Called (usually) from the interrupt level to receive one
+ *   character from the UART.  Error bits associated with the
+ *   receipt are provided in the return 'status'.
+ *
+ ****************************************************************************/
+
+#ifdef LPSERIAL_HAVE_DMA
+static int kinetis_dma_receive(struct uart_dev_s *dev, unsigned int *status)
+{
+  struct kinetis_dev_s *priv = (struct kinetis_dev_s *)dev->priv;
+  int c = 0;
+  uint32_t stat;
+
+  /* Clear uart errors and return status information */
+
+  stat = get_and_clear_uart_status(priv);
+  if (status)
+    {
+      *status = stat;
+    }
+
+  if (kinetis_dma_nextrx(priv) != priv->rxdmanext)
+    {
+      /* Invalidate the DMA buffer */
+
+      up_invalidate_dcache((uintptr_t)priv->rxfifo,
+                           (uintptr_t)priv->rxfifo + RXDMA_BUFFER_SIZE);
+
+      /* Now read from the DMA buffer */
+
+      c = priv->rxfifo[priv->rxdmanext];
+      priv->rxdmanext++;
+      if (priv->rxdmanext == RXDMA_BUFFER_SIZE)
+        {
+          /* HACK: Skip the first byte since it is duplicate of last one. */
+
+          if (kinetis_dma_nextrx(priv) != 0)
+            {
+              priv->rxdmanext = 1;
+            }
+          else
+            {
+              /* Try to catch race conditions that will spin on the whole
+               * buffer again.
+               */
+
+              priv->rxdmanext = 0;
+            }
+        }
+    }
+
+  return c;
+}
+#endif
 
 /****************************************************************************
  * Name: kinetis_rxint
@@ -1179,13 +1535,34 @@ static void kinetis_rxint(struct uart_dev_s *dev, bool enable)
 }
 
 /****************************************************************************
- * Name: kinetis_rxavailable
+ * Name: kinetis_dma_rxavailable
  *
  * Description:
  *   Return true if the receive register is not empty
  *
  ****************************************************************************/
 
+#ifdef LPSERIAL_HAVE_DMA
+static bool kinetis_dma_rxavailable(struct uart_dev_s *dev)
+{
+  struct kinetis_dev_s *priv = (struct kinetis_dev_s *)dev->priv;
+
+  /* Compare our receive pointer to the current DMA pointer, if they
+   * do not match, then there are bytes to be received.
+   */
+
+  return (kinetis_dma_nextrx(priv) != priv->rxdmanext);
+}
+#endif
+
+/****************************************************************************
+ * Name: kinetis_rxavailable
+ *
+ * Description:
+ *   Return true if the receive register is not empty
+ *
+ ****************************************************************************/
+#if !defined(LPSERIAL_HAVE_ALL_DMA)
 static bool kinetis_rxavailable(struct uart_dev_s *dev)
 {
   struct kinetis_dev_s *priv = (struct kinetis_dev_s *)dev->priv;
@@ -1195,6 +1572,7 @@ static bool kinetis_rxavailable(struct uart_dev_s *dev)
   return (kinetis_serialin(priv, KINETIS_LPUART_STAT_OFFSET) &
           LPUART_STAT_RDRF) != 0;
 }
+#endif
 
 /****************************************************************************
  * Name: kinetis_rxflowcontrol
@@ -1270,6 +1648,26 @@ static bool kinetis_rxflowcontrol(struct uart_dev_s *dev,
 #endif
 
 /****************************************************************************
+ * Name: kinetis_dma_nextrx
+ *
+ * Description:
+ *   Returns the index into the RX FIFO where the DMA will place the next
+ *   byte that it receives.
+ *
+ ****************************************************************************/
+
+#ifdef LPSERIAL_HAVE_DMA
+static int kinetis_dma_nextrx(struct kinetis_dev_s *priv)
+{
+  size_t dmaresidual;
+
+  dmaresidual = kinetis_dmach_getcount(priv->rxdma);
+
+  return (RXDMA_BUFFER_SIZE - (int)dmaresidual) % RXDMA_BUFFER_SIZE;
+}
+#endif
+
+/****************************************************************************
  * Name: kinetis_send
  *
  * Description:
@@ -1342,6 +1740,28 @@ static bool kinetis_txready(struct uart_dev_s *dev)
 }
 
 /****************************************************************************
+ * Name: kinetis_dma_rxcallback
+ *
+ * Description:
+ *   This function checks the current DMA state and calls the generic
+ *   serial stack when bytes appear to be available.
+ *
+ ****************************************************************************/
+
+#ifdef LPSERIAL_HAVE_DMA
+static void kinetis_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done,
+                              int result)
+{
+  struct uart_dev_s *dev = (struct uart_dev_s *)arg;
+
+  if (kinetis_dma_rxavailable(dev))
+    {
+      uart_recvchars(dev);
+    }
+}
+#endif
+
+/****************************************************************************
  * Public Functions
  ****************************************************************************/
 
@@ -1410,6 +1830,11 @@ unsigned int kinetis_lpuart_serialinit(unsigned int first)
 
 #ifdef HAVE_LPUART_CONSOLE
   uart_register("/dev/console", &CONSOLE_DEV);
+#  ifdef SERIAL_HAVE_CONSOLE_DMA
+  /* If we need to re-initialise the console to enable DMA do that here. */
+
+  kinetis_dma_setup(&CONSOLE_DEV);
+#  endif
 #endif
 #if !defined(CONFIG_KINETIS_MERGE_TTY)
   /* Register all LPUARTs as LPn devices */
@@ -1454,6 +1879,68 @@ unsigned int kinetis_lpuart_serialinit(unsigned int first)
 }
 
 /****************************************************************************
+ * Name: kinetis_serial_dma_poll
+ *
+ * Description:
+ *   Checks receive DMA buffers for received bytes that have not accumulated
+ *   to the point where the DMA half/full interrupt has triggered.
+ *
+ *   This function should be called from a timer or other periodic context.
+ *
+ ****************************************************************************/
+
+#ifdef LPSERIAL_HAVE_DMA
+void kinetis_lpserial_dma_poll(void)
+{
+    irqstate_t flags;
+
+    flags = enter_critical_section();
+
+#ifdef CONFIG_KINETIS_LPUART0_RXDMA
+  if (g_lpuart0priv.rxdma != NULL)
+    {
+      kinetis_dma_rxcallback(g_lpuart0priv.rxdma, (void *)&g_lpuart0port,
+                             false, 0);
+    }
+#endif
+
+#ifdef CONFIG_KINETIS_LPUART1_RXDMA
+  if (g_lpuart1priv.rxdma != NULL)
+    {
+      kinetis_dma_rxcallback(g_lpuart1priv.rxdma, (void *)&g_lpuart1port,
+                             false, 0);
+    }
+#endif
+
+#ifdef CONFIG_KINETIS_LPUART2_RXDMA
+  if (g_lpuart2priv.rxdma != NULL)
+    {
+      kinetis_dma_rxcallback(g_lpuart2priv.rxdma, (void *)&g_lpuart2port,
+                             false, 0);
+    }
+#endif
+
+#ifdef CONFIG_KINETIS_LPUART3_RXDMA
+  if (g_lpuart3priv.rxdma != NULL)
+    {
+      kinetis_dma_rxcallback(g_lpuart3priv.rxdma, (void *)&g_lpuart3port,
+                             false, 0);
+    }
+#endif
+
+#ifdef CONFIG_KINETIS_LPUART4_RXDMA
+  if (g_lpuart4priv.rxdma != NULL)
+    {
+      kinetis_dma_rxcallback(g_lpuart4priv.rxdma, (void *)&g_lpuart4port,
+                             false, 0);
+    }
+#endif
+
+  leave_critical_section(flags);
+}
+#endif
+
+/****************************************************************************
  * Name: up_putc
  *
  * Description:
diff --git a/arch/arm/src/kinetis/kinetis_lpuart.h b/arch/arm/src/kinetis/kinetis_lpuart.h
new file mode 100644
index 0000000..6a24ca3
--- /dev/null
+++ b/arch/arm/src/kinetis/kinetis_lpuart.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+ * arch/arm/src/kinetis/kinetis_lpuart.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_KINETIS_KINETIS_LPUART_H
+#define __ARCH_ARM_SRC_KINETIS_KINETIS_LPUART_H
+
+#if defined(HAVE_UART_DEVICE) && defined(USE_SERIALDRIVER)
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Is DMA available on any (enabled) LPUART? */
+
+#undef LPSERIAL_HAVE_DMA
+#if defined(CONFIG_KINETIS_LPUART0_RXDMA) || defined(CONFIG_KINETIS_LPUART1_RXDMA) || \
+    defined(CONFIG_KINETIS_LPUART2_RXDMA) || defined(CONFIG_KINETIS_LPUART3_RXDMA) || \
+    defined(CONFIG_KINETIS_LPUART4_RXDMA)
+#  define LPSERIAL_HAVE_DMA 1
+
+/* Is DMA available on All (enabled) LPUART? */
+
+#define LPSERIAL_HAVE_ALL_DMA 1
+#  if (defined(CONFIG_KINETIS_LPUART0) && !defined(CONFIG_KINETIS_LPUART0_RXDMA)) || \
+      (defined(CONFIG_KINETIS_LPUART1) && !defined(CONFIG_KINETIS_LPUART1_RXDMA)) || \
+      (defined(CONFIG_KINETIS_LPUART2) && !defined(CONFIG_KINETIS_LPUART2_RXDMA)) || \
+      (defined(CONFIG_KINETIS_LPUART3) && !defined(CONFIG_KINETIS_LPUART3_RXDMA)) || \
+      (defined(CONFIG_KINETIS_LPUART4) && !defined(CONFIG_KINETIS_LPUART4_RXDMA))
+#    undef LPSERIAL_HAVE_ALL_DMA
+#  endif
+#endif
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Functions Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: kinetis_serial_dma_poll
+ *
+ * Description:
+ *   Must be called periodically if any Kinetis LPUART is configured for DMA.
+ *   The DMA callback is triggered for each fifo size/2 bytes, but this can
+ *   result in some bytes being transferred but not collected if the incoming
+ *   data is not a whole multiple of half the FIFO size.
+ *
+ *   May be safely called from either interrupt or thread context.
+ *
+ ****************************************************************************/
+
+#ifdef LPSERIAL_HAVE_DMA
+void kinetis_lpserial_dma_poll(void);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* HAVE_UART_DEVICE && USE_SERIALDRIVER) */
+#endif /* __ARCH_ARM_SRC_KINETIS_KINETIS_UART_H */

[incubator-nuttx] 01/02: kinetis:LPUART Add IOCTL for invert

Posted by xi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 34eb91866542e83943b540d8590d04b76caee42b
Author: David Sidrane <Da...@NscDg.com>
AuthorDate: Tue Jul 20 10:16:35 2021 -0700

    kinetis:LPUART Add IOCTL for invert
---
 arch/arm/src/kinetis/kinetis_lpserial.c | 44 ++++++++++++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)

diff --git a/arch/arm/src/kinetis/kinetis_lpserial.c b/arch/arm/src/kinetis/kinetis_lpserial.c
index 42e4cc3..4ad9ded 100644
--- a/arch/arm/src/kinetis/kinetis_lpserial.c
+++ b/arch/arm/src/kinetis/kinetis_lpserial.c
@@ -807,7 +807,7 @@ static int kinetis_ioctl(struct file *filep, int cmd, unsigned long arg)
     defined(CONFIG_KINETIS_SERIALBRK_BSDCOMPAT)
   struct inode           *inode;
   struct uart_dev_s      *dev;
-  uint8_t regval;
+  uint32_t regval;
 #endif
 #if defined(CONFIG_SERIAL_TERMIOS) || defined(CONFIG_KINETIS_SERIALBRK_BSDCOMPAT)
   struct kinetis_dev_s   *priv;
@@ -906,6 +906,8 @@ static int kinetis_ioctl(struct file *filep, int cmd, unsigned long arg)
 #  endif
           CS8;
 
+        cfsetispeed(termiosp, priv->baud);
+
         /* TODO: CCTS_IFLOW, CCTS_OFLOW */
       }
       break;
@@ -1043,6 +1045,46 @@ static int kinetis_ioctl(struct file *filep, int cmd, unsigned long arg)
       break;
 #endif /* CONFIG_KINETIS_UART_BREAKS */
 
+#ifdef CONFIG_KINETIS_UART_INVERT
+    case TIOCSINVERT:
+      {
+        uint32_t stat;
+        uint32_t ctrl;
+        irqstate_t flags;
+
+        flags = enter_critical_section();
+
+        stat = kinetis_serialin(priv, KINETIS_LPUART_STAT_OFFSET);
+        ctrl = kinetis_serialin(priv, KINETIS_LPUART_CTRL_OFFSET);
+
+        /* {R|T}XINV bit fields can written any time */
+
+        if (arg & SER_INVERT_ENABLED_RX)
+          {
+            stat |= LPUART_STAT_RXINV;
+          }
+        else
+          {
+            stat &= ~LPUART_STAT_RXINV;
+          }
+
+        if (arg & SER_INVERT_ENABLED_TX)
+          {
+            ctrl |= LPUART_CTRL_TXINV;
+          }
+        else
+          {
+            ctrl &= ~LPUART_CTRL_TXINV;
+          }
+
+        kinetis_serialout(priv, KINETIS_LPUART_STAT_OFFSET, stat);
+        kinetis_serialout(priv, KINETIS_LPUART_CTRL_OFFSET, ctrl);
+
+        leave_critical_section(flags);
+      }
+     break;
+#endif
+
     default:
       ret = -ENOTTY;
       break;