summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-10-21 09:21:03 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-10-21 09:21:03 -0600
commitd1e88b1eec781a4f66f796d443acef0e41253bca (patch)
treefdbf878afa156f77d234cda894aeee69aba7f115
parentd99b0b9e153ad159f1fe1a9f114bc2b55fd09c00 (diff)
downloadnuttx-d1e88b1eec781a4f66f796d443acef0e41253bca.tar.gz
nuttx-d1e88b1eec781a4f66f796d443acef0e41253bca.tar.bz2
nuttx-d1e88b1eec781a4f66f796d443acef0e41253bca.zip
EFM32: Add a LEUART-based serial driver (untestee)
-rw-r--r--nuttx/arch/arm/src/efm32/Make.defs14
-rw-r--r--nuttx/arch/arm/src/efm32/efm32_leserial.c889
-rw-r--r--nuttx/arch/arm/src/efm32/efm32_serial.c45
3 files changed, 924 insertions, 24 deletions
diff --git a/nuttx/arch/arm/src/efm32/Make.defs b/nuttx/arch/arm/src/efm32/Make.defs
index 1016eb7e7..27ecfeafd 100644
--- a/nuttx/arch/arm/src/efm32/Make.defs
+++ b/nuttx/arch/arm/src/efm32/Make.defs
@@ -95,12 +95,24 @@ CHIP_ASRCS += efm32_vectors.S
endif
CHIP_CSRCS = efm32_start.c efm32_clockconfig.c efm32_irq.c efm32_timerisr.c
-CHIP_CSRCS += efm32_gpio.c efm32_lowputc.c efm32_serial.c
+CHIP_CSRCS += efm32_gpio.c efm32_lowputc.c
ifneq ($(CONFIG_ARCH_IDLE_CUSTOM),y)
CHIP_CSRCS += efm32_idle.c
endif
+ifeq ($(CONFIG_EFM32_USART),y)
+CHIP_CSRCS += efm32_serial.c
+else
+ifeq ($(CONFIG_EFM32_UART),y)
+CHIP_CSRCS += efm32_serial.c
+endif
+endif
+
+ifeq ($(CONFIG_EFM32_LEART),y)
+CHIP_CSRCS += efm32_leserial.c
+endif
+
ifeq ($(CONFIG_EFM32_GPIO_IRQ),y)
CHIP_CSRCS += efm32_gpioirq.c
endif
diff --git a/nuttx/arch/arm/src/efm32/efm32_leserial.c b/nuttx/arch/arm/src/efm32/efm32_leserial.c
new file mode 100644
index 000000000..0a8f19802
--- /dev/null
+++ b/nuttx/arch/arm/src/efm32/efm32_leserial.c
@@ -0,0 +1,889 @@
+/****************************************************************************
+ * arch/arm/src/efm32/efm32_leserial.c
+ *
+ * Copyright (C) 2024 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <semaphore.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/serial/serial.h>
+
+#include <arch/board/board.h>
+
+#include "up_arch.h"
+#include "up_internal.h"
+
+#include "chip/efm32_leart.h"
+#include "efm32_config.h"
+#include "efm32_lowputc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* Some sanity checks *******************************************************/
+/* Is there at least one UART enabled and configured as a RS-232 device? */
+
+#ifndef HAVE_LEUART_DEVICE
+# warning "No LEUARTs enabled"
+#endif
+
+/* If we are not using the serial driver for the console, then we still must
+ * provide some minimal implementation of up_putc.
+ */
+
+#ifdef USE_SERIALDRIVER
+
+/* Which LEUART with be ttyLE0/console and which ttyLE1? The console will always
+ * be ttyLE0. If there is no console then will use the lowest numbered LEUART.
+ */
+
+/* First pick the console and ttys0. This could be either LEUART0-1 */
+
+#if defined(CONFIG_LEUART0_SERIAL_CONSOLE)
+# define CONSOLE_DEV g_leuart0port /* LEUART0 is console */
+# define TTYLE0_DEV g_leuart0port /* LEUART0 is ttyLE0 */
+# define LEUART0_ASSIGNED 1
+#elif defined(CONFIG_LEUART1_SERIAL_CONSOLE)
+# define CONSOLE_DEV g_leuart1port /* LEUART1 is console */
+# define TTYLE0_DEV g_leuart1port /* LEUART1 is ttyLE0 */
+# define LEUART1_ASSIGNED 1
+#else
+# undef CONSOLE_DEV /* No console */
+# if defined(CONFIG_EFM32_LEUART0)
+# define TTYLE0_DEV g_leuart0port /* LEUART0 is ttyLE0 */
+# define LEUART0_ASSIGNED 1
+# elif defined(CONFIG_EFM32_LEUART1)
+# define TTYLE0_DEV g_leuart1port /* LEUART1 is ttyLE0 */
+# define LEUART1_ASSIGNED 1
+# endif
+#endif
+
+/* Pick ttyLE1. This could be any of LEUART0-1, excluding the and the
+ * LEUART already selected for ttyLE0
+ */
+
+#if defined(CONFIG_EFM32_LEUART0) && !defined(LEUART0_ASSIGNED)
+# define TTYLE1_DEV g_leuart0port /* LEUART0 is ttyLE1 */
+# define LEUART0_ASSIGNED 1
+#elif defined(CONFIG_EFM32_LEUART1) && !defined(LEUART1_ASSIGNED)
+# define TTYLE1_DEV g_leuart1port /* LEUART1 is ttyLE1 */
+# define LEUART1_ASSIGNED 1
+#endif
+
+/* TX/RX interrupts */
+
+#define EFM32_TXERR_INTS (LEUART_IEN_TXOF)
+#define EFM32_RXERR_INTS (LEUART_IEN_RXOF | LEUART_IEN_PERR | \
+ LEUART_IEN_FERR)
+#ifdef CONFIG_DEBUG
+# define EFM32_TX_INTS (LEUART_IEN_TXBL | EFM32_TXERR_INTS)
+# define EFM32_RX_INTS (LEUART_IEN_RXDATAV | EFM32_RXERR_INTS)
+#else
+# define EFM32_TX_INTS LEUART_IEN_TXBL
+# define EFM32_RX_INTS LEUART_IEN_RXDATAV
+#endif
+
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct efm32_config_s
+{
+ uintptr_t uartbase; /* Base address of UART registers */
+ xcpt_t handler; /* Interrupt handler */
+ uint32_t baud; /* Configured baud */
+ uint8_t irq; /* IRQ associated with this LEUART (for enable) */
+ uint8_t parity; /* 0=none, 1=odd, 2=even */
+ uint8_t bits; /* Number of bits (8 or 9) */
+ bool stop2; /* True: 2 stop bits */
+};
+
+struct efm32_leuart_s
+{
+ const struct efm32_config_s *config;
+ uint16_t ien; /* Interrupts enabled */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static inline uint32_t efm32_serialin(struct efm32_leuart_s *priv, int offset);
+static inline void efm32_serialout(struct efm32_leuart_s *priv, int offset,
+ uint32_t value);
+static inline void efm32_setuartint(struct efm32_leuart_s *priv);
+
+static void efm32_restoreuartint(struct efm32_leuart_s *priv, uint32_t ien);
+static void efm32_disableuartint(struct efm32_leuart_s *priv, uint32_t *ien);
+static int efm32_setup(struct uart_dev_s *dev);
+static void efm32_shutdown(struct uart_dev_s *dev);
+static int efm32_attach(struct uart_dev_s *dev);
+static void efm32_detach(struct uart_dev_s *dev);
+static int efm32_interrupt(struct uart_dev_s *dev);
+#if defined(CONFIG_EFM32_LEUART0)
+static int efm32_leuart0_interrupt(int irq, void *context);
+#endif
+#if defined(CONFIG_EFM32_LEUART1)
+static int efm32_leuart1_interrupt(int irq, void *context);
+#endif
+static int efm32_ioctl(struct file *filep, int cmd, unsigned long arg);
+static int efm32_receive(struct uart_dev_s *dev, uint32_t *status);
+static void efm32_rxint(struct uart_dev_s *dev, bool enable);
+static bool efm32_rxavailable(struct uart_dev_s *dev);
+static void efm32_send(struct uart_dev_s *dev, int ch);
+static void efm32_txint(struct uart_dev_s *dev, bool enable);
+static bool efm32_txready(struct uart_dev_s *dev);
+static bool efm32_txempty(struct uart_dev_s *dev);
+
+/****************************************************************************
+ * Private Variables
+ ****************************************************************************/
+
+static const struct uart_ops_s g_leuart_ops =
+{
+ .setup = efm32_setup,
+ .shutdown = efm32_shutdown,
+ .attach = efm32_attach,
+ .detach = efm32_detach,
+ .ioctl = efm32_ioctl,
+ .receive = efm32_receive,
+ .rxint = efm32_rxint,
+ .rxavailable = efm32_rxavailable,
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+ .rxflowcontrol = NULL,
+#endif
+ .send = efm32_send,
+ .txint = efm32_txint,
+ .txready = efm32_txready,
+ .txempty = efm32_txempty,
+};
+
+/* I/O buffers */
+
+#ifdef CONFIG_EFM32_LEUART0
+static char g_leuart0rxbuffer[CONFIG_LEUART0_RXBUFSIZE];
+static char g_leuart0txbuffer[CONFIG_LEUART0_TXBUFSIZE];
+#endif
+#ifdef CONFIG_EFM32_LEUART1
+static char g_leuart1rxbuffer[CONFIG_LEUART1_RXBUFSIZE];
+static char g_leuart1txbuffer[CONFIG_LEUART1_TXBUFSIZE];
+#endif
+
+/* This describes the state of the EFM32 LEUART0 port. */
+
+#ifdef CONFIG_EFM32_LEUART0
+static const struct efm32_leuart_s g_leuart0config =
+{
+ .uartbase = EFM32_LEUART0_BASE,
+ .handler = efm32_leuart0_interrupt,
+ .baud = CONFIG_LEUART0_BAUD,
+ .irq = EFM32_IRQ_LEUART0,
+ .parity = CONFIG_LEUART0_PARITY,
+ .bits = CONFIG_LEUART0_BITS,
+ .stop2 = CONFIG_LEUART0_2STOP,
+};
+
+static struct efm32_leuart_s g_leuart0priv =
+{
+ .config = &g_leuart0config,
+};
+
+static struct uart_dev_s g_leuart0port =
+{
+ .recv =
+ {
+ .size = CONFIG_LEUART0_RXBUFSIZE,
+ .buffer = g_leuart0rxbuffer,
+ },
+ .xmit =
+ {
+ .size = CONFIG_LEUART0_TXBUFSIZE,
+ .buffer = g_leuart0txbuffer,
+ },
+ .ops = &g_leuart_ops,
+ .priv = &g_leuart0priv,
+};
+#endif
+
+/* This describes the state of the EFM32 LEUART1 port. */
+
+#ifdef CONFIG_EFM32_LEUART1
+static struct efm32_config_s g_leuart1config =
+{
+ .uartbase = EFM32_LEUART1_BASE,
+ .handler = efm32_leuart1_interrupt,
+ .baud = CONFIG_LEUART1_BAUD,
+ .irq = EFM32_IRQ_LEUART1,
+ .parity = CONFIG_LEUART1_PARITY,
+ .bits = CONFIG_LEUART1_BITS,
+ .stop2 = CONFIG_LEUART1_2STOP,
+};
+
+static struct efm32_leuart_s g_leuart1priv =
+{
+ .config = &g_leuart1config,
+};
+
+static struct uart_dev_s g_leuart1port =
+{
+ .recv =
+ {
+ .size = CONFIG_LEUART1_RXBUFSIZE,
+ .buffer = g_leuart1rxbuffer,
+ },
+ .xmit =
+ {
+ .size = CONFIG_LEUART1_TXBUFSIZE,
+ .buffer = g_leuart1txbuffer,
+ },
+ .ops = &g_leuart_ops,
+ .priv = &g_leuart1priv,
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: efm32_serialin
+ ****************************************************************************/
+
+static inline uint32_t efm32_serialin(struct efm32_leuart_s *priv, int offset)
+{
+ return getreg32(priv->config->uartbase + offset);
+}
+
+/****************************************************************************
+ * Name: efm32_serialout
+ ****************************************************************************/
+
+static inline void efm32_serialout(struct efm32_leuart_s *priv, int offset,
+ uint32_t value)
+{
+ putreg32(value, priv->config->uartbase + offset);
+}
+
+/****************************************************************************
+ * Name: efm32_setuartint
+ ****************************************************************************/
+
+static inline void efm32_setuartint(struct efm32_leuart_s *priv)
+{
+ efm32_serialout(priv, EFM32_LEUART_IEN_OFFSET, priv->ien);
+}
+
+/****************************************************************************
+ * Name: efm32_restoreuartint
+ ****************************************************************************/
+
+static void efm32_restoreuartint(struct efm32_leuart_s *priv, uint32_t ien)
+{
+ irqstate_t flags;
+
+ /* Re-enable/re-disable interrupts corresponding to the state of bits in ien */
+
+ flags = irqsave();
+ priv->ien = ien;
+ efm32_setuartint(priv);
+ irqrestore(flags);
+}
+
+/****************************************************************************
+ * Name: efm32_disableuartint
+ ****************************************************************************/
+
+static void efm32_disableuartint(struct efm32_leuart_s *priv, uint32_t *ien)
+{
+ irqstate_t flags;
+
+ flags = irqsave();
+ if (ien)
+ {
+ *ien = priv->ien;
+ }
+
+ efm32_restoreuartint(priv, 0);
+ irqrestore(flags);
+}
+
+/****************************************************************************
+ * Name: efm32_setup
+ *
+ * Description:
+ * Configure the UART baud, bits, parity, etc. This method is called the
+ * first time that the serial port is opened.
+ *
+ ****************************************************************************/
+
+static int efm32_setup(struct uart_dev_s *dev)
+{
+ struct efm32_leuart_s *priv = (struct efm32_leuart_s*)dev->priv;
+ uint32_t regval;
+
+#ifndef CONFIG_SUPPRESS_LEUART_CONFIG
+ const struct efm32_config_s *config = priv->config;
+
+ /* Configure the UART as an RS-232 UART */
+
+ efm32_leuartconfigure(config->uartbase, config->baud, config->parity,
+ config->bits, config->stop2);
+#endif
+
+ /* Make sure that all interrupts are disabled */
+
+ efm32_restoreuartint(priv, 0);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: efm32_shutdown
+ *
+ * Description:
+ * Disable the UART. This method is called when the serial
+ * port is closed
+ *
+ ****************************************************************************/
+
+static void efm32_shutdown(struct uart_dev_s *dev)
+{
+ struct efm32_leuart_s *priv = (struct efm32_leuart_s*)dev->priv;
+
+ /* Disable interrupts */
+
+ efm32_restoreuartint(priv, 0);
+
+ /* Reset the LEUART/UART by disabling it and restoring all of the registers
+ * to the initial, reset value. Only the ROUTE data set by efm32_lowsetup
+ * is preserved.
+ */
+
+ efm32_leuart_reset(priv->config->uartbase);
+}
+
+/****************************************************************************
+ * Name: efm32_attach
+ *
+ * Description:
+ * Configure the UART to operation in interrupt driven mode. This method is
+ * called when the serial port is opened. Normally, this is just after the
+ * the setup() method is called, however, the serial console may operate in
+ * a non-interrupt driven mode during the boot phase.
+ *
+ * RX and TX interrupts are not enabled when by the attach method (unless the
+ * hardware supports multiple levels of interrupt enabling). The RX and TX
+ * interrupts are not enabled until the txint() and rxint() methods are called.
+ *
+ ****************************************************************************/
+
+static int efm32_attach(struct uart_dev_s *dev)
+{
+ struct efm32_leuart_s *priv = (struct efm32_leuart_s*)dev->priv;
+ const struct efm32_config_s *config = priv->config;
+ int ret;
+
+ /* Attach and enable the IRQ(s). The interrupts are (probably) still
+ * disabled in the C2 register.
+ */
+
+ ret = irq_attach(config->irq, config->handler);
+ if (ret >= 0)
+ {
+ up_enable_irq(config->irq);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: efm32_detach
+ *
+ * Description:
+ * Detach UART interrupts. This method is called when the serial port is
+ * closed normally just before the shutdown method is called. The exception
+ * is the serial console which is never shutdown.
+ *
+ ****************************************************************************/
+
+static void efm32_detach(struct uart_dev_s *dev)
+{
+ struct efm32_leuart_s *priv = (struct efm32_leuart_s*)dev->priv;
+ const struct efm32_config_s *config = priv->config;
+
+ /* Disable interrupts */
+
+ efm32_restoreuartint(priv, 0);
+ up_disable_irq(config->irq);
+
+ /* Detach from the interrupt(s) */
+
+ irq_detach(config->irq);
+}
+
+/****************************************************************************
+ * Name: efm32_interrupt
+ *
+ * Description:
+ * This is the common UART RX interrupt handler.
+ *
+ ****************************************************************************/
+
+static int efm32_interrupt(struct uart_dev_s *dev)
+{
+ struct efm32_leuart_s *priv = (struct efm32_leuart_s*)dev->priv;
+ uint32_t intflags;
+
+ DEBUGASSERT(priv);
+
+ /* Read the interrupt flags register */
+
+ intflags = efm32_serialin(priv, EFM32_LEUART_IF_OFFSET);
+
+ /* Clear pending interrupts by writing to the interrupt flag clear
+ * register.
+ */
+
+ efm32_serialout(priv, EFM32_LEUART_IFC_OFFSET, intflags);
+
+ /* Check if the receive data is available is full (RXDATAV). */
+
+ if ((intflags & LEUART_IEN_RXDATAV) != 0)
+ {
+ /* Process incoming bytes */
+
+ uart_recvchars(dev);
+ }
+
+ /* Check if the transmit data buffer became empty */
+
+ if ((intflags & LEUART_IEN_TXBL) != 0)
+ {
+ /* Process outgoing bytes */
+
+ uart_xmitchars(dev);
+ }
+
+#ifdef CONFIG_DEBUG
+ /* Check for receive errors */
+
+ if ((intflags & EFM32_RXERR_INTS) != 0)
+ {
+ /* RXOF - RX Overflow Interrupt Enable
+ * RXUF - RX Underflow Interrupt Enable
+ * TXUF - TX Underflow Interrupt Enable
+ * PERR - Parity Error Interrupt Enable
+ * FERR - Framing Error Interrupt Enable
+ */
+
+ lldbg("RX ERROR: %08x\n", intflags);
+ }
+
+ /* Check for transmit errors */
+
+ if ((intflags & EFM32_TXERR_INTS) != 0)
+ {
+ /* TXOF - TX Overflow Interrupt Enable */
+
+ lldbg("RX ERROR: %08x\n", intflags);
+ }
+#endif
+
+ return OK;
+}
+
+#if defined(CONFIG_EFM32_LEUART0)
+static int efm32_leuart0_interrupt(int irq, void *context)
+{
+ return efm32_interrupt(&g_leuart0port);
+}
+#endif
+
+#if defined(CONFIG_EFM32_LEUART1)
+static int efm32_leuart1_interrupt(int irq, void *context)
+{
+ return efm32_interrupt(&g_leuart1port);
+}
+#endif
+
+/****************************************************************************
+ * Name: efm32_ioctl
+ *
+ * Description:
+ * All ioctl calls will be routed through this method
+ *
+ ****************************************************************************/
+
+static int efm32_ioctl(struct file *filep, int cmd, unsigned long arg)
+{
+#if 0 /* Reserved for future growth */
+ struct inode *inode;
+ struct uart_dev_s *dev;
+ struct efm32_leuart_s *priv;
+ int ret = OK;
+
+ DEBUGASSERT(filep, filep->f_inode);
+ inode = filep->f_inode;
+ dev = inode->i_private;
+
+ DEBUGASSERT(dev, dev->priv)
+ priv = (struct efm32_leuart_s*)dev->priv;
+
+ switch (cmd)
+ {
+ case xxx: /* Add commands here */
+ break;
+
+ default:
+ ret = -ENOTTY;
+ break;
+ }
+
+ return ret;
+#else
+ return -ENOTTY;
+#endif
+}
+
+/****************************************************************************
+ * Name: efm32_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'.
+ *
+ ****************************************************************************/
+
+static int efm32_receive(struct uart_dev_s *dev, uint32_t *status)
+{
+ struct efm32_leuart_s *priv = (struct efm32_leuart_s*)dev->priv;
+ uint32_t rxdatax;
+
+ /* Get error status information:
+ *
+ * FERR Data Framing Error
+ * PERR Data Parity Error
+ */
+
+ rxdatax = efm32_serialin(priv, EFM32_LEUART_RXDATAX_OFFSET);
+
+ /* Return status information */
+
+ if (status)
+ {
+ *status = rxdatax;
+ }
+
+ /* Then return the actual received byte. */
+
+ return (int)(rxdatax & _LEUART_RXDATAX_RXDATA_MASK);
+}
+
+/****************************************************************************
+ * Name: efm32_rxint
+ *
+ * Description:
+ * Call to enable or disable RX interrupts
+ *
+ ****************************************************************************/
+
+static void efm32_rxint(struct uart_dev_s *dev, bool enable)
+{
+ struct efm32_leuart_s *priv = (struct efm32_leuart_s*)dev->priv;
+ irqstate_t flags;
+
+ flags = irqsave();
+ if (enable)
+ {
+ /* Receive an interrupt when their is anything in the Rx data register (or an Rx
+ * timeout occurs).
+ */
+
+#ifndef CONFIG_SUPPRESS_SERIAL_INTS
+ priv->ien |= EFM32_RX_INTS;
+ efm32_setuartint(priv);
+#endif
+ }
+ else
+ {
+ priv->ien &= ~EFM32_RX_INTS;
+ efm32_setuartint(priv);
+ }
+
+ irqrestore(flags);
+}
+
+/****************************************************************************
+ * Name: efm32_rxavailable
+ *
+ * Description:
+ * Return true if the receive register is not empty
+ *
+ ****************************************************************************/
+
+static bool efm32_rxavailable(struct uart_dev_s *dev)
+{
+ struct efm32_leuart_s *priv = (struct efm32_leuart_s*)dev->priv;
+
+ /* Return true if the receive data is available (RXDATAV). */
+
+ return (efm32_serialin(priv, EFM32_LEUART_STATUS_OFFSET) & LEUART_STATUS_RXDATAV) != 0;
+}
+
+/****************************************************************************
+ * Name: efm32_send
+ *
+ * Description:
+ * This method will send one byte on the UART.
+ *
+ ****************************************************************************/
+
+static void efm32_send(struct uart_dev_s *dev, int ch)
+{
+ struct efm32_leuart_s *priv = (struct efm32_leuart_s*)dev->priv;
+ efm32_serialout(priv, EFM32_LEUART_TXDATA_OFFSET, (uint32_t)ch);
+}
+
+/****************************************************************************
+ * Name: efm32_txint
+ *
+ * Description:
+ * Call to enable or disable TX interrupts
+ *
+ ****************************************************************************/
+
+static void efm32_txint(struct uart_dev_s *dev, bool enable)
+{
+ struct efm32_leuart_s *priv = (struct efm32_leuart_s*)dev->priv;
+ irqstate_t flags;
+
+ flags = irqsave();
+ if (enable)
+ {
+ /* Enable the TX interrupt */
+
+#ifndef CONFIG_SUPPRESS_SERIAL_INTS
+ priv->ien |= EFM32_TX_INTS;
+ efm32_setuartint(priv);
+
+ /* Fake a TX interrupt here by just calling uart_xmitchars() with
+ * interrupts disabled (note this may recurse).
+ */
+
+ uart_xmitchars(dev);
+#endif
+ }
+ else
+ {
+ /* Disable the TX interrupt */
+
+ priv->ien &= ~EFM32_TX_INTS;
+ efm32_setuartint(priv);
+ }
+
+ irqrestore(flags);
+}
+
+/****************************************************************************
+ * Name: efm32_txready
+ *
+ * Description:
+ * Return true if the transmit data register is not full
+ *
+ ****************************************************************************/
+
+static bool efm32_txready(struct uart_dev_s *dev)
+{
+ struct efm32_leuart_s *priv = (struct efm32_leuart_s*)dev->priv;
+
+ /* The TX Buffer Level (TXBL) status bit indicates the level of the
+ * transmit buffer. Set when the transmit buffer is empty, and cleared
+ * when it is full.
+ */
+
+ return (efm32_serialin(priv, EFM32_LEUART_STATUS_OFFSET) & LEUART_STATUS_TXBL) != 0;
+}
+
+/****************************************************************************
+ * Name: efm32_txempty
+ *
+ * Description:
+ * Return true if the transmit data register is empty
+ *
+ ****************************************************************************/
+
+static bool efm32_txempty(struct uart_dev_s *dev)
+{
+ struct efm32_leuart_s *priv = (struct efm32_leuart_s*)dev->priv;
+
+ /* TX Complete (TXC) is set when a transmission has completed and no more
+ * data is available in the transmit buffer.
+ */
+
+ return (efm32_serialin(priv, EFM32_LEUART_STATUS_OFFSET) & LEUART_STATUS_TXC) != 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_earlyserialinit
+ *
+ * Description:
+ * Performs the low level UART initialization early in debug so that the
+ * serial console will be available during bootup. This must be called
+ * before up_serialinit. NOTE: This function depends on GPIO pin
+ * configuration performed in efm32_consoleinit() and main clock iniialization
+ * performed in efm32_clkinitialize().
+ *
+ ****************************************************************************/
+
+void up_earlyserialinit(void)
+{
+ /* Disable interrupts from all UARTS. The console is enabled in
+ * pic32mx_consoleinit()
+ */
+
+ efm32_restoreuartint(TTYLE0_DEV.priv, 0);
+#ifdef TTYLE1_DEV
+ efm32_restoreuartint(TTYLE1_DEV.priv, 0);
+#endif
+
+ /* Configuration whichever one is the console */
+
+#ifdef CONSOLE_DEV
+ CONSOLE_DEV.isconsole = true;
+ efm32_setup(&CONSOLE_DEV);
+#endif
+}
+
+/****************************************************************************
+ * Name: up_serialinit
+ *
+ * Description:
+ * Register serial console and serial ports. This assumes that
+ * up_earlyserialinit was called previously.
+ *
+ ****************************************************************************/
+
+void up_serialinit(void)
+{
+ /* Register the console */
+
+#ifdef CONSOLE_DEV
+ (void)uart_register("/dev/console", &CONSOLE_DEV);
+#endif
+
+ /* Register all UARTs */
+
+ (void)uart_register("/dev/ttyLE0", &TTYLE0_DEV);
+#ifdef TTYLE1_DEV
+ (void)uart_register("/dev/ttyLE1", &TTYLE1_DEV);
+#endif
+}
+
+/****************************************************************************
+ * Name: up_putc
+ *
+ * Description:
+ * Provide priority, low-level access to support OS debug writes
+ *
+ ****************************************************************************/
+
+#ifdef HAVE_LEUART_CONSOLE
+int up_putc(int ch)
+{
+ struct efm32_leuart_s *priv = (struct efm32_leuart_s*)CONSOLE_DEV.priv;
+ uint32_t ien;
+
+ efm32_disableuartint(priv, &ien);
+
+ /* Check for LF */
+
+ if (ch == '\n')
+ {
+ /* Add CR */
+
+ efm32_lowputc('\r');
+ }
+
+ efm32_lowputc(ch);
+ efm32_restoreuartint(priv, ien);
+ return ch;
+}
+#endif
+
+#else /* USE_SERIALDRIVER */
+
+/****************************************************************************
+ * Name: up_putc
+ *
+ * Description:
+ * Provide priority, low-level access to support OS debug writes
+ *
+ ****************************************************************************/
+
+#ifdef HAVE_LEUART_CONSOLE
+int up_putc(int ch)
+{
+ /* Check for LF */
+
+ if (ch == '\n')
+ {
+ /* Add CR */
+
+ efm32_lowputc('\r');
+ }
+
+ efm32_lowputc(ch);
+ return ch;
+}
+#endif
+
+#endif /* USE_SERIALDRIVER */
diff --git a/nuttx/arch/arm/src/efm32/efm32_serial.c b/nuttx/arch/arm/src/efm32/efm32_serial.c
index 616acff9c..4fda1f47f 100644
--- a/nuttx/arch/arm/src/efm32/efm32_serial.c
+++ b/nuttx/arch/arm/src/efm32/efm32_serial.c
@@ -77,7 +77,7 @@
#ifdef USE_SERIALDRIVER
-/* Which UART with be tty0/console and which tty1-4? The console will always
+/* Which UART with be ttyS0/console and which tty1-4? The console will always
* be ttyS0. If there is no console then will use the lowest numbered UART.
*/
@@ -740,6 +740,12 @@ static int efm32_rxinterrupt(struct uart_dev_s *dev)
intflags = efm32_serialin(priv, EFM32_USART_IF_OFFSET);
+ /* Clear pending interrupts by writing to the interrupt flag clear
+ * register.
+ */
+
+ efm32_serialout(priv, EFM32_USART_IFC_OFFSET, intflags & EFM32_RX_INTS);
+
/* Check if the receive data is available is full (RXDATAV). */
if ((intflags & USART_IEN_RXDATAV) != 0)
@@ -765,11 +771,6 @@ static int efm32_rxinterrupt(struct uart_dev_s *dev)
}
#endif
- /* Clear pending interrupts by writing to the interrupt flag clear
- * register.
- */
-
- efm32_serialout(priv, EFM32_USART_IFC_OFFSET, intflags & EFM32_RX_INTS);
return OK;
}
@@ -827,6 +828,12 @@ static int efm32_txinterrupt(struct uart_dev_s *dev)
intflags = efm32_serialin(priv, EFM32_USART_IF_OFFSET);
+ /* Clear pending interrupts by writing to the interrupt flag clear
+ * register. We won't clear RX errors until they have been reported.
+ */
+
+ efm32_serialout(priv, EFM32_USART_IFC_OFFSET, intflags & EFM32_TX_INTS);
+
/* Check if the transmit data buffer became half full */
if ((intflags & USART_IEN_TXBL) != 0)
@@ -847,11 +854,6 @@ static int efm32_txinterrupt(struct uart_dev_s *dev)
}
#endif
- /* Clear pending interrupts by writing to the interrupt flag clear
- * register. We won't clear RX errors until they have been reported.
- */
-
- efm32_serialout(priv, EFM32_USART_IFC_OFFSET, intflags & EFM32_TX_INTS);
return OK;
}
@@ -946,12 +948,8 @@ static int efm32_receive(struct uart_dev_s *dev, uint32_t *status)
/* Get error status information:
*
- * FE: Framing error. To clear FE, read S1 with FE set and then read
- * read UART data register (D).
- * NF: Noise flag. To clear NF, read S1 and then read the UART data
- * register (D).
- * PF: Parity error flag. To clear PF, read S1 and then read the UART
- * data register (D).
+ * FERR Data Framing Error
+ * PERR Data Parity Error
*/
rxdatax = efm32_serialin(priv, EFM32_USART_RXDATAX_OFFSET);
@@ -963,9 +961,7 @@ static int efm32_receive(struct uart_dev_s *dev, uint32_t *status)
*status = rxdatax;
}
- /* Then return the actual received byte. Reading S1 then D clears all
- * RX errors.
- */
+ /* Then return the actual received byte. */
return (int)(rxdatax & _USART_RXDATAX_RXDATA_MASK);
}
@@ -1016,7 +1012,7 @@ static bool efm32_rxavailable(struct uart_dev_s *dev)
{
struct efm32_usart_s *priv = (struct efm32_usart_s*)dev->priv;
- /* Return true if the receive data is available is full (RXDATAV). */
+ /* Return true if the receive data is available (RXDATAV). */
return (efm32_serialin(priv, EFM32_USART_STATUS_OFFSET) & USART_STATUS_RXDATAV) != 0;
}
@@ -1108,8 +1104,7 @@ static bool efm32_txempty(struct uart_dev_s *dev)
struct efm32_usart_s *priv = (struct efm32_usart_s*)dev->priv;
/* TX Complete (TXC) is set when a transmission has completed and no more
- * data is available in the transmit buffer. Cleared when data is written
- * to the transmit buffer
+ * data is available in the transmit buffer.
*/
return (efm32_serialin(priv, EFM32_USART_STATUS_OFFSET) & USART_STATUS_TXC) != 0;
@@ -1201,6 +1196,7 @@ void up_serialinit(void)
*
****************************************************************************/
+#ifndef HAVE_LEUART_CONSOLE
int up_putc(int ch)
{
#ifdef HAVE_UART_CONSOLE
@@ -1223,6 +1219,7 @@ int up_putc(int ch)
#endif
return ch;
}
+#endif
#else /* USE_SERIALDRIVER */
@@ -1234,6 +1231,7 @@ int up_putc(int ch)
*
****************************************************************************/
+#ifndef HAVE_LEUART_CONSOLE
int up_putc(int ch)
{
#ifdef HAVE_UART_CONSOLE
@@ -1250,5 +1248,6 @@ int up_putc(int ch)
#endif
return ch;
}
+#endif
#endif /* USE_SERIALDRIVER */