Add completed but untested support for RS-485 on the LPC43xx
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4959 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
7d79c38ac6
commit
6de2e45191
@ -66,26 +66,49 @@
|
||||
# define HAVE_UART 1
|
||||
#endif
|
||||
|
||||
/* Is there a serial console? There should be at most one defined. It could be on
|
||||
* any UARTn, n=0,1,2,3
|
||||
/* Make sure all features are disabled for diabled U[S]ARTs. This simplifies
|
||||
* checking later.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_USART0_SERIAL_CONSOLE) && defined(CONFIG_LPC43_USART0)
|
||||
#ifndef CONFIG_LPC43_USART0
|
||||
# undef CONFIG_USART0_SERIAL_CONSOLE
|
||||
# undef CONFIG_USART0_RS485MODE
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_LPC43_UART1
|
||||
# undef CONFIG_UART1_SERIAL_CONSOLE
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_LPC43_USART2
|
||||
# undef CONFIG_USART2_SERIAL_CONSOLE
|
||||
# undef CONFIG_USART2_RS485MODE
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_LPC43_USART3
|
||||
# undef CONFIG_USART3_SERIAL_CONSOLE
|
||||
# undef CONFIG_USART3_RS485MODE
|
||||
#endif
|
||||
|
||||
/* Is there a serial console? There should be at most one defined. It could be on
|
||||
* any UARTn, n=0,1,2,3 - OR - there might not be any serial console at all.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_USART0_SERIAL_CONSOLE)
|
||||
# undef CONFIG_UART1_SERIAL_CONSOLE
|
||||
# undef CONFIG_USART2_SERIAL_CONSOLE
|
||||
# undef CONFIG_USART3_SERIAL_CONSOLE
|
||||
# define HAVE_CONSOLE 1
|
||||
#elif defined(CONFIG_UART1_SERIAL_CONSOLE) && defined(CONFIG_LPC43_UART1)
|
||||
#elif defined(CONFIG_UART1_SERIAL_CONSOLE)
|
||||
# undef CONFIG_USART0_SERIAL_CONSOLE
|
||||
# undef CONFIG_USART2_SERIAL_CONSOLE
|
||||
# undef CONFIG_USART3_SERIAL_CONSOLE
|
||||
# define HAVE_CONSOLE 1
|
||||
#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_LPC43_USART2)
|
||||
#elif defined(CONFIG_USART2_SERIAL_CONSOLE)
|
||||
# undef CONFIG_USART0_SERIAL_CONSOLE
|
||||
# undef CONFIG_UART1_SERIAL_CONSOLE
|
||||
# undef CONFIG_USART3_SERIAL_CONSOLE
|
||||
# define HAVE_CONSOLE 1
|
||||
#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_LPC43_USART3)
|
||||
#elif defined(CONFIG_USART3_SERIAL_CONSOLE)
|
||||
# undef CONFIG_USART0_SERIAL_CONSOLE
|
||||
# undef CONFIG_UART1_SERIAL_CONSOLE
|
||||
# undef CONFIG_USART2_SERIAL_CONSOLE
|
||||
@ -107,6 +130,14 @@
|
||||
# undef CONFIG_UART1_FLOWCONTROL
|
||||
#endif
|
||||
|
||||
/* Check for RS-485 support (USART0,2,3 only) */
|
||||
|
||||
#undef HAVE_RS485
|
||||
#if defined(CONFIG_USART0_RS485MODE) || defined(CONFIG_USART2_RS485MODE) || \
|
||||
defined(CONFIG_USART3_RS485MODE)
|
||||
# define HAVE_RS485 1
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
* Public Types
|
||||
************************************************************************************/
|
||||
|
@ -864,18 +864,137 @@ static int up_interrupt(int irq, void *context)
|
||||
* Handle LPC43xx USART0,2,3 RS485 mode set ioctl (TIOCSRS485) to enable
|
||||
* and disable RS-485 mode. This is part of the serial ioctl logic.
|
||||
*
|
||||
* Supported and un-supported LPC43 RS-485 features:
|
||||
*
|
||||
* RS-485/EIA-485 Normal Multidrop Mode (NMM) -- NOT suppored
|
||||
*
|
||||
* In this mode, an address is detected when a received byte causes the
|
||||
* USART to set the parity error and generate an interrupt. When the
|
||||
* parity error interrupt will be generated and the processor can decide
|
||||
* whether or not to disable the receiver.
|
||||
*
|
||||
* RS-485/EIA-485 Auto Address Detection (AAD) mode -- NOT supported
|
||||
*
|
||||
* In this mode, the receiver will compare any address byte received
|
||||
* (parity = ‘1’) to the 8-bit value programmed into the RS485ADRMATCH
|
||||
* register. When a matching address character is detected it will be
|
||||
* pushed onto the RXFIFO along with the parity bit, and the receiver
|
||||
* will be automatically enabled.
|
||||
*
|
||||
* When an address byte which does not match the RS485ADRMATCH value
|
||||
* is received, the receiver will be automatically disabled in hardware.
|
||||
*
|
||||
* RS-485/EIA-485 Auto Direction Control -- Supported
|
||||
*
|
||||
* Allow the transmitter to automatically control the state of the DIR
|
||||
* pin as a direction control output signal. The DIR pin will be asserted
|
||||
* (driven LOW) when the CPU writes data into the TXFIFO. The pin will be
|
||||
* de-asserted (driven HIGH) once the last bit of data has been transmitted.
|
||||
*
|
||||
* RS485/EIA-485 driver delay time -- Supported
|
||||
*
|
||||
* The driver delay time is the delay between the last stop bit leaving
|
||||
* the TXFIFO and the de-assertion of the DIR pin. This delay time can be
|
||||
* programmed in the 8-bit RS485DLY register. The delay time is in periods
|
||||
* of the baud clock.
|
||||
*
|
||||
* RS485/EIA-485 output inversion -- Supported
|
||||
*
|
||||
* The polarity of the direction control signal on the DIR pin can be
|
||||
* reversed by programming bit 5 in the RS485CTRL register.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_USART_RS485MODE
|
||||
#ifdef HAVE_RS485
|
||||
static inline int up_set_rs485_mode(struct up_dev_s *priv,
|
||||
const struct serial_rs485 *mode)
|
||||
{
|
||||
irqstate_t flags;
|
||||
uint32_t regval;
|
||||
uint64_t tmp;
|
||||
|
||||
DEBUGASSERT(priv && mode);
|
||||
flags = irqsave();
|
||||
#warning "Missing logic"
|
||||
|
||||
/* Are we enabling or disabling RS-485 support? */
|
||||
|
||||
if ((mode->flags && SER_RS485_RTS_ON_SEND) != 0)
|
||||
{
|
||||
/* Disable all RS-485 features */
|
||||
|
||||
up_serialout(priv, LPC43_UART_RS485CTRL_OFFSET, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set the RS-485/EIA-485 Control register:
|
||||
*
|
||||
* NMMEN 0 = Normal Multidrop Mode (NMM) disabled
|
||||
* RXDIS 0 = Receiver is not disabled
|
||||
* AADEN 0 = Auto Address Detect (ADD) is disabled
|
||||
* DCTRL 1 = Auto Direction Control is enabled
|
||||
* OINV ? = Value control by user mode settings
|
||||
*/
|
||||
|
||||
regval = UART_RS485CTRL_DCTRL;
|
||||
|
||||
/* Logic levels are controlled by the SER_RS485_RTS_ON_SEND and
|
||||
* SER_RS485_RTS_AFTER_SEND bits in the mode flags.
|
||||
* SER_RS485_RTS_AFTER_SEND is ignored.
|
||||
*
|
||||
* By default, DIR will go logic low on send, but this can
|
||||
* be inverted.
|
||||
*/
|
||||
|
||||
if ((mode->flags && SER_RS485_RTS_ON_SEND) != 0)
|
||||
{
|
||||
regval |= UART_RS485CTRL_OINV;
|
||||
}
|
||||
|
||||
up_serialout(priv, LPC43_UART_RS485CTRL_OFFSET, regval);
|
||||
|
||||
/* We only have control of the delay after send. Time provided
|
||||
* is in milliseconds; this must be converted to the baud clock.
|
||||
* The baud clock should be 16 times the currently selected BAUD.
|
||||
*
|
||||
* Eg. Given BAUD=115,200, then a delay of n milliseconds would be:
|
||||
*
|
||||
* 115,200 * n / 1000 = 11525 clocks.
|
||||
*
|
||||
* n=1: 115 (OK)
|
||||
* n=2: 230 (OK)
|
||||
* n>2: Out of range
|
||||
*
|
||||
* The valid range is 0 to 255 bit times.
|
||||
*
|
||||
* REVISIT: Is this time in bit time or in terms of the baud clock?
|
||||
* The text says either interchange-ably. Baud clock is 16 x BAUD
|
||||
* and a bit time is 1/BAUD. The value range of values 0-255 suggests
|
||||
* BAUD bit times, not the baud clock.
|
||||
*/
|
||||
|
||||
if (mode->delay_rts_after_send > 0)
|
||||
{
|
||||
regval = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = ((priv->baud << 4) * mode->delay_rts_after_send) / 1000;
|
||||
if (tmp > 255)
|
||||
{
|
||||
regval = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
regval = (uint32_t)tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
up_serialout(priv, LPC43_UART_RS485DLY_OFFSET, regval);
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -888,16 +1007,55 @@ static inline int up_set_rs485_mode(struct up_dev_s *priv,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_USART_RS485MODE
|
||||
#ifdef HAVE_RS485
|
||||
static inline int up_get_rs485_mode(struct up_dev_s *priv,
|
||||
struct serial_rs485 *mode)
|
||||
{
|
||||
irqstate_t flags;
|
||||
uint32_t regval;
|
||||
|
||||
DEBUGASSERT(priv && mode);
|
||||
flags = irqsave();
|
||||
#warning "Missing logic"
|
||||
|
||||
/* Assume disabled */
|
||||
|
||||
memset(mode, 0, sizeof(struct serial_rs485));
|
||||
|
||||
/* If RS-485 mode is enabled, then the DCTRL will be set in the RS485CTRL
|
||||
* register.
|
||||
*/
|
||||
|
||||
regval = up_serialin(priv, LPC43_UART_RS485CTRL_OFFSET);
|
||||
if ((regval & UART_RS485CTRL_DCTRL) != 0)
|
||||
{
|
||||
/* RS-485 mode is enabled */
|
||||
|
||||
mode->flags = SER_RS485_ENABLED;
|
||||
|
||||
/* Check if DIR is inverted */
|
||||
|
||||
if ((regval & UART_RS485CTRL_OINV) != 0)
|
||||
{
|
||||
mode->flags = (SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND);
|
||||
}
|
||||
else
|
||||
{
|
||||
mode->flags = SER_RS485_ENABLED;
|
||||
}
|
||||
|
||||
/* We only have control of the delay after send. Time must be
|
||||
* returned in milliseconds; this must be converted from the baud clock.
|
||||
* (The baud clock should be 16 times the currently selected BAUD.)
|
||||
*
|
||||
* msec = 1000 * dly / baud
|
||||
*/
|
||||
|
||||
regval = up_serialin(priv, LPC43_UART_RS485DLY_OFFSET);
|
||||
mode->delay_rts_after_send = (1000 * regval) / priv->baud;
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -950,7 +1108,7 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_USART_RS485MODE
|
||||
#ifdef HAVE_RS485
|
||||
case TIOCSRS485: /* Set RS485 mode, arg: pointer to struct serial_rs485 */
|
||||
{
|
||||
ret = up_set_rs485_mode(priv,
|
||||
@ -1016,6 +1174,7 @@ static void up_rxint(struct uart_dev_s *dev, bool enable)
|
||||
{
|
||||
priv->ier &= ~UART_IER_RBRIE;
|
||||
}
|
||||
|
||||
up_serialout(priv, LPC43_UART_IER_OFFSET, priv->ier);
|
||||
}
|
||||
|
||||
|
@ -338,11 +338,24 @@ void lpc43_usart0_setup(void)
|
||||
regval |= (BOARD_USART0_CLKSRC | BASE_USART0_CLK_AUTOBLOCK);
|
||||
putreg32(regval, LPC43_BASE_USART0_CLK);
|
||||
|
||||
/* Configure I/O pins */
|
||||
/* Configure I/O pins. NOTE that multiple pin configuration options must
|
||||
* be disambiguated by defining the pin configuration in the board.h
|
||||
* header file.
|
||||
*/
|
||||
|
||||
lpc43_pin_config(PINCONF_U0_TXD);
|
||||
lpc43_pin_config(PINCONF_U0_RXD);
|
||||
|
||||
/* If USART RS-485 mode is selected, then configure the DIR pin as well.
|
||||
* NOTE, again, that multiple pin configuration options must be
|
||||
* disambiguated by defining the pin configuration in the board.h header
|
||||
* file.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USART0_RS485MODE
|
||||
lpc43_pin_config(PINCONF_U0_DIR);
|
||||
#endif
|
||||
|
||||
irqrestore(flags);
|
||||
};
|
||||
#endif
|
||||
@ -362,8 +375,9 @@ void lpc43_uart1_setup(void)
|
||||
regval |= (BOARD_UART1_CLKSRC | BASE_UART1_CLK_AUTOBLOCK);
|
||||
putreg32(regval, LPC43_BASE_UART1_CLK);
|
||||
|
||||
/* Configure I/O pins (resolution of mulitple pins alternatvies
|
||||
* must be provided in the board.h file).
|
||||
/* Configure I/O pins. NOTE that multiple pin configuration options must
|
||||
* be disambiguated by defining the pin configuration in the board.h
|
||||
* header file.
|
||||
*/
|
||||
|
||||
lpc43_pin_config(PINCONF_U1_TXD);
|
||||
@ -398,13 +412,24 @@ void lpc43_usart2_setup(void)
|
||||
regval |= (BOARD_USART2_CLKSRC | BASE_USART2_CLK_AUTOBLOCK);
|
||||
putreg32(regval, LPC43_BASE_USART2_CLK);
|
||||
|
||||
/* Configure I/O pins (resolution of mulitple pins alternatvies
|
||||
* must be provided in the board.h file).
|
||||
/* Configure I/O pins. NOTE that multiple pin configuration options must
|
||||
* be disambiguated by defining the pin configuration in the board.h
|
||||
* header file.
|
||||
*/
|
||||
|
||||
lpc43_pin_config(PINCONF_U2_TXD);
|
||||
lpc43_pin_config(PINCONF_U2_RXD);
|
||||
|
||||
/* If USART RS-485 mode is selected, then configure the DIR pin as well.
|
||||
* NOTE, again, that multiple pin configuration options must be
|
||||
* disambiguated by defining the pin configuration in the board.h header
|
||||
* file.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USART2_RS485MODE
|
||||
lpc43_pin_config(PINCONF_U2_DIR);
|
||||
#endif
|
||||
|
||||
irqrestore(flags);
|
||||
};
|
||||
#endif
|
||||
@ -424,13 +449,24 @@ void lpc43_usart3_setup(void)
|
||||
regval |= (BOARD_USART3_CLKSRC | BASE_USART3_CLK_AUTOBLOCK);
|
||||
putreg32(regval, LPC43_BASE_USART3_CLK);
|
||||
|
||||
/* Configure I/O pins (resolution of mulitple pins alternatvies
|
||||
* must be provided in the board.h file).
|
||||
/* Configure I/O pins. NOTE that multiple pin configuration options must
|
||||
* be disambiguated by defining the pin configuration in the board.h
|
||||
* header file.
|
||||
*/
|
||||
|
||||
lpc43_pin_config(PINCONF_U3_TXD);
|
||||
lpc43_pin_config(PINCONF_U3_RXD);
|
||||
|
||||
/* If USART RS-485 mode is selected, then configure the DIR pin as well.
|
||||
* NOTE, again, that multiple pin configuration options must be
|
||||
* disambiguated by defining the pin configuration in the board.h header
|
||||
* file.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USART3_RS485MODE
|
||||
lpc43_pin_config(PINCONF_U3_DIR);
|
||||
#endif
|
||||
|
||||
irqrestore(flags);
|
||||
};
|
||||
#endif
|
||||
@ -562,4 +598,3 @@ void lpc43_setbaud(uintptr_t uartbase, uint32_t basefreq, uint32_t baud)
|
||||
putreg32((mul << UART_FDR_MULVAL_SHIFT) | (divadd << UART_FDR_DIVADDVAL_SHIFT),
|
||||
uartbase + LPC43_UART_FDR_OFFSET);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user