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:
patacongo 2012-07-20 18:32:16 +00:00
parent 7d79c38ac6
commit 6de2e45191
3 changed files with 244 additions and 19 deletions

View File

@ -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
************************************************************************************/

View File

@ -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);
}

View File

@ -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);
}