This commit implements RS485 RX/TX switching and RTS/CTS flow control for the IMXRT family. It has been tested on 1020 but I don't see any reason for issues on any other family member.

This commit is contained in:
Dave Marples
2019-05-30 13:44:08 -06:00
committed by Gregory Nutt
parent 64feadfc21
commit 173897afb9
6 changed files with 430 additions and 101 deletions
+22 -18
View File
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/imxrt/imxrt_lowputc.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Copyright (C) 2018, 2019 Gregory Nutt. All rights reserved.
* Author: Ivan Ucherdzhiev <ivanucherdjiev@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
@@ -118,7 +118,8 @@
#endif
/* Clocking *****************************************************************/
/* the UART module receives two clocks, a peripheral_clock (ipg_clk) and the
/* The UART module receives two clocks, a peripheral_clock (ipg_clk) and the
* module_clock (ipg_perclk). The peripheral_clock is used as write clock
* of the TxFIFO, read clock of the RxFIFO and synchronization of the modem
* control input pins. It must always be running when UART is enabled.
@@ -458,12 +459,12 @@ int imxrt_lpuart_configure(uint32_t base,
if (baud_diff > ((config->baud / 100) * 3))
{
/* Unacceptable baud rate difference of more than 3%*/
/* Unacceptable baud rate difference of more than 3% */
return ERROR;
}
/* Enable lpuart clock*/
/* Enable lpuart clock */
imxrt_lpuart_clock_enable(base);
@@ -471,10 +472,10 @@ int imxrt_lpuart_configure(uint32_t base,
regval = getreg32(base + IMXRT_LPUART_GLOBAL_OFFSET);
regval |= LPUART_GLOBAL_RST;
putreg32(regval,base + IMXRT_LPUART_GLOBAL_OFFSET);
putreg32(regval, base + IMXRT_LPUART_GLOBAL_OFFSET);
regval &= ~LPUART_GLOBAL_RST;
putreg32(regval,base + IMXRT_LPUART_GLOBAL_OFFSET);
putreg32(regval, base + IMXRT_LPUART_GLOBAL_OFFSET);
regval = 0;
@@ -524,20 +525,21 @@ int imxrt_lpuart_configure(uint32_t base,
}
#endif /* HAVE_LPUART_DEVICE */
/************************************************************************************
/****************************************************************************
* Name: imxrt_lowputc
*
* Description:
* Output a byte with as few system dependencies as possible. This will even work
* BEFORE the console is initialized if we are booting from U-Boot (and the same
* UART is used for the console, of course.)
* Output a byte with as few system dependencies as possible. This will
* even work BEFORE the console is initialized if we are booting from U-
* Boot (and the same UART is used for the console, of course.)
*
************************************************************************************/
****************************************************************************/
#if defined(HAVE_LPUART_DEVICE) && defined(CONFIG_DEBUG_FEATURES)
void imxrt_lowputc(int ch)
{
while ((getreg32(IMXRT_CONSOLE_BASE + IMXRT_LPUART_STAT_OFFSET) & LPUART_STAT_TDRE) == 0)
while ((getreg32(IMXRT_CONSOLE_BASE + IMXRT_LPUART_STAT_OFFSET) &
LPUART_STAT_TDRE) == 0)
{
}
@@ -549,11 +551,12 @@ void imxrt_lowputc(int ch)
putreg32((uint32_t)'\r', IMXRT_CONSOLE_BASE + IMXRT_LPUART_DATA_OFFSET);
/* Wait for the transmit register to be emptied. When the TXFE bit is non-zero,
* the TX Buffer FIFO is empty.
/* Wait for the transmit register to be emptied. When the TXFE bit is
* non-zero, the TX Buffer FIFO is empty.
*/
while ((getreg32(IMXRT_CONSOLE_BASE + IMXRT_LPUART_STAT_OFFSET) & LPUART_STAT_TDRE) == 0)
while ((getreg32(IMXRT_CONSOLE_BASE + IMXRT_LPUART_STAT_OFFSET) &
LPUART_STAT_TDRE) == 0)
{
}
}
@@ -562,11 +565,12 @@ void imxrt_lowputc(int ch)
putreg32((uint32_t)ch, IMXRT_CONSOLE_BASE + IMXRT_LPUART_DATA_OFFSET);
/* Wait for the transmit register to be emptied. When the TXFE bit is non-zero,
* the TX Buffer FIFO is empty.
/* Wait for the transmit register to be emptied. When the TXFE bit is
* non-zero, the TX Buffer FIFO is empty.
*/
while ((getreg32(IMXRT_CONSOLE_BASE + IMXRT_LPUART_STAT_OFFSET) & LPUART_STAT_TDRE) == 0)
while ((getreg32(IMXRT_CONSOLE_BASE + IMXRT_LPUART_STAT_OFFSET) &
LPUART_STAT_TDRE) == 0)
{
}
}
+14 -9
View File
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/imxrt/imxrt_lowputc.h
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Copyright (C) 2018, 2019 Gregory Nutt. All rights reserved.
* Author: Ivan Ucherdzhiev <ivanucherdjiev@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
@@ -64,6 +64,10 @@ struct uart_config_s
uint8_t parity; /* 0=none, 1=odd, 2=even */
uint8_t bits; /* Number of bits (5-9) */
bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */
bool userts; /* True: Assert RTS when there are data to be sent */
bool invrts; /* True: Invert sense of RTS pin (true=active high) */
bool usects; /* True: Condition transmission on CTS asserted */
bool users485; /* True: Assert RTS while transmission progresses */
};
#endif
@@ -84,27 +88,28 @@ struct uart_config_s
void imxrt_lowsetup(void);
/************************************************************************************
/****************************************************************************
* Name: imxrt_lpuart_configure
*
* Description:
* Configure a UART for non-interrupt driven operation
*
************************************************************************************/
****************************************************************************/
#ifdef HAVE_LPUART_DEVICE
int imxrt_lpuart_configure(uint32_t base, FAR const struct uart_config_s *config);
int imxrt_lpuart_configure(uint32_t base,
FAR const struct uart_config_s *config);
#endif
/************************************************************************************
/****************************************************************************
* Name: imxrt_lowputc
*
* Description:
* Output a byte with as few system dependencies as possible. This will even work
* BEFORE the console is initialized if we are booting from U-Boot (and the same
* UART is used for the console, of course.)
* Output a byte with as few system dependencies as possible. This will
* even work BEFORE the console is initialized if we are booting from U-
* Boot (and the same UART is used for the console, of course.)
*
************************************************************************************/
****************************************************************************/
#if defined(HAVE_LPUART_DEVICE) && defined(CONFIG_DEBUG_FEATURES)
void imxrt_lowputc(int ch);
+112 -16
View File
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/imxrt/imxrt_serial.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Copyright (C) 2018, 2019 Gregory Nutt. All rights reserved.
* Author: Ivan Ucherdzhiev <ivanucherdjiev@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
@@ -315,18 +315,6 @@
# define PM_IDLE_DOMAIN 0 /* Revisit */
#endif
#ifdef CONFIG_SERIAL_IFLOWCONTROL
# define IFLOW 1
#else
# define IFLOW 0
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
# define OFLOW 1
#else
# define OFLOW 0
#endif
/****************************************************************************
* Private Types
****************************************************************************/
@@ -339,7 +327,8 @@ struct imxrt_uart_s
uint8_t irq; /* IRQ associated with this UART */
uint8_t parity; /* 0=none, 1=odd, 2=even */
uint8_t bits; /* Number of bits (7 or 8) */
#ifdef CONFIG_SERIAL_IFLOWCONTROL
#if defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)
uint8_t inviflow:1; /* Invert RTS sense */
const uint32_t rts_gpio; /* U[S]ART RTS GPIO pin configuration */
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
@@ -353,7 +342,9 @@ struct imxrt_uart_s
#ifdef CONFIG_SERIAL_OFLOWCONTROL
uint8_t oflow:1; /* output flow control (CTS) enabled */
#endif
uint8_t reserved:(7 - IFLOW + OFLOW);
#ifdef CONFIG_SERIAL_RS485CONTROL
uint8_t rs485mode:1; /* We are in RS485 (RTS on TX) mode */
#endif
};
/****************************************************************************
@@ -474,8 +465,20 @@ static struct imxrt_uart_s g_uart1priv =
#endif
#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL)
.iflow = 1,
#endif
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)) \
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL)))
.rts_gpio = GPIO_LPUART1_RTS,
#endif
#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \
&& defined(CONFIG_LPUART1_INVERTIFLOWCONTROL))
.inviflow = 1,
#endif
#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)
.rs485mode = 1,
#endif
};
static struct uart_dev_s g_uart1port =
@@ -512,8 +515,19 @@ static struct imxrt_uart_s g_uart2priv =
#endif
#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL)
.iflow = 1,
#endif
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)) \
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL)))
.rts_gpio = GPIO_LPUART2_RTS,
#endif
#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \
&& defined(CONFIG_LPUART2_INVERTIFLOWCONTROL))
.inviflow = 1,
#endif
#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)
.rs485mode = 1,
#endif
};
static struct uart_dev_s g_uart2port =
@@ -548,8 +562,19 @@ static struct imxrt_uart_s g_uart3priv =
#endif
#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL)
.iflow = 1,
#endif
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL)) \
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL)))
.rts_gpio = GPIO_LPUART3_RTS,
#endif
#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \
&& defined(CONFIG_LPUART3_INVERTIFLOWCONTROL))
.inviflow = 1,
#endif
#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL)
.rs485mode = 1,
#endif
};
static struct uart_dev_s g_uart3port =
@@ -584,8 +609,19 @@ static struct imxrt_uart_s g_uart4priv =
#endif
#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL)
.iflow = 1,
#endif
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL)) \
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL)))
.rts_gpio = GPIO_LPUART4_RTS,
#endif
#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \
&& defined(CONFIG_LPUART4_INVERTIFLOWCONTROL))
.inviflow = 1,
#endif
#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL)
.rs485mode = 1,
#endif
};
static struct uart_dev_s g_uart4port =
@@ -620,8 +656,19 @@ static struct imxrt_uart_s g_uart5priv =
#endif
#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL)
.iflow = 1,
#endif
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL)) \
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL)))
.rts_gpio = GPIO_LPUART5_RTS,
#endif
#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \
&& defined(CONFIG_LPUART5_INVERTIFLOWCONTROL))
.inviflow = 1,
#endif
#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL)
.rs485mode = 1,
#endif
};
static struct uart_dev_s g_uart5port =
@@ -656,8 +703,19 @@ static struct imxrt_uart_s g_uart6priv =
#endif
#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL)
.iflow = 1,
#endif
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL)) \
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL)))
.rts_gpio = GPIO_LPUART6_RTS,
#endif
#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \
&& defined(CONFIG_LPUART6_INVERTIFLOWCONTROL))
.inviflow = 1,
#endif
#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL)
.rs485mode = 1,
#endif
};
static struct uart_dev_s g_uart6port =
@@ -692,8 +750,19 @@ static struct imxrt_uart_s g_uart7priv =
#endif
#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL)
.iflow = 1,
#endif
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL)) \
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL)))
.rts_gpio = GPIO_LPUART7_RTS,
#endif
#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \
&& defined(CONFIG_LPUART7_INVERTIFLOWCONTROL))
.inviflow = 1,
#endif
#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL)
.rs485mode = 1,
#endif
};
static struct uart_dev_s g_uart7port =
@@ -728,8 +797,19 @@ static struct imxrt_uart_s g_uart8priv =
#endif
#if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART8_IFLOWCONTROL)
.iflow = 1,
#endif
# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL)) \
|| (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART8_IFLOWCONTROL)))
.rts_gpio = GPIO_LPUART8_RTS,
#endif
#if (((defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL))) \
&& defined(CONFIG_LPUART8_INVERTIFLOWCONTROL))
.inviflow = 1,
#endif
#if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL)
.rs485mode = 1,
#endif
};
static struct uart_dev_s g_uart8port =
@@ -842,7 +922,10 @@ static int imxrt_setup(struct uart_dev_s *dev)
{
struct imxrt_uart_s *priv = (struct imxrt_uart_s *)dev->priv;
#ifndef CONFIG_SUPPRESS_LPUART_CONFIG
struct uart_config_s config;
struct uart_config_s config =
{
0
};
int ret;
/* Configure the UART */
@@ -851,6 +934,18 @@ static int imxrt_setup(struct uart_dev_s *dev)
config.parity = priv->parity; /* 0=none, 1=odd, 2=even */
config.bits = priv->bits; /* Number of bits (5-9) */
config.stopbits2 = priv->stopbits2; /* true: Configure with 2 stop bits instead of 1 */
#ifdef CONFIG_SERIAL_IFLOWCONTROL
config.usects = priv->iflow; /* Flow control on inbound side */
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
config.userts = priv->oflow; /* Flow control on outbound side */
#endif
#ifdef CONFIG_SERIAL_RS485CONTROL
config.users485 = priv->rs485mode; /* Switch into RS485 mode */
#endif
#if defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)
config.invrts = priv->inviflow; /* Inversion of outbound flow control */
#endif
ret = imxrt_lpuart_configure(priv->uartbase, &config);
@@ -1436,6 +1531,7 @@ static void up_pm_notify(struct pm_callback_s *cb, int domain,
default:
/* Should not get here */
break;
}
}
+2 -2
View File
@@ -163,10 +163,10 @@ Status
configuration, you will see a crash due to memory corruption consistently,
specially in the nested signal test (apps/examples/ostest/signest.c).
2018-06-20: There is a problem with the Interrupt Stack for SMP in
2018-06-20: There was a problem with the Interrupt Stack for SMP in
arch/arm/src/armv7-a/arm_vectors.S: There is only one interrupt stack for
all CPUs! A fix for this was put in place on 2018-06-21. Big Improvement!
Bit this does not completely eliminate instabilities which seem to be
But this does not completely eliminate instabilities which seem to be
related to memory corruption -- mm_mallinfo() asserts.
Platform Features
+6
View File
@@ -81,6 +81,12 @@ config SERIAL_IFLOWCONTROL
bool
default n
config SERIAL_RS485CONTROL
bool
default n
---help---
Use RTS pin to control RS485 direction (Asserted while transmitting).
config SERIAL_OFLOWCONTROL
bool
default n
File diff suppressed because it is too large Load Diff