diff --git a/arch/arm/src/samd2l2/Kconfig b/arch/arm/src/samd2l2/Kconfig index 152475df6e0..5d6cb2a0f91 100644 --- a/arch/arm/src/samd2l2/Kconfig +++ b/arch/arm/src/samd2l2/Kconfig @@ -616,6 +616,27 @@ config SAMD2L2_SERCOM0_ISUSART endchoice +if USART0_SERIALDRIVER + +config USART0_RS485MODE + bool "RS-485 on USART0" + default n + ---help--- + Enable RS-485 interface on USART0. Your board config will have to + provide GPIO_USART0_RS485_DIR pin definition. Currently it cannot be + used with USART0_RXDMA. + +config USART0_RS485_DIR_POLARITY + int "USART0 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART0_RS485MODE + ---help--- + Polarity of DIR pin for RS-485 on USART0. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # USART0_SERIALDRIVER + choice prompt "SERCOM1 mode" default SAMD2L2_SERCOM1_ISUSART @@ -636,6 +657,27 @@ config SAMD2L2_SERCOM1_ISUSART endchoice +if USART1_SERIALDRIVER + +config USART1_RS485MODE + bool "RS-485 on USART1" + default n + ---help--- + Enable RS-485 interface on USART1. Your board config will have to + provide GPIO_USART1_RS485_DIR pin definition. Currently it cannot be + used with USART1_RXDMA. + +config USART1_RS485_DIR_POLARITY + int "USART1 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART1_RS485MODE + ---help--- + Polarity of DIR pin for RS-485 on USART1. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # USART1_SERIALDRIVER + choice prompt "SERCOM2 mode" default SAMD2L2_SERCOM2_ISUSART @@ -656,6 +698,27 @@ config SAMD2L2_SERCOM2_ISUSART endchoice +if USART2_SERIALDRIVER + +config USART2_RS485MODE + bool "RS-485 on USART2" + default n + ---help--- + Enable RS-485 interface on USART2. Your board config will have to + provide GPIO_USART2_RS485_DIR pin definition. Currently it cannot be + used with USART2_RXDMA. + +config USART2_RS485_DIR_POLARITY + int "USART2 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART2_RS485MODE + ---help--- + Polarity of DIR pin for RS-485 on USART2. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # USART2_SERIALDRIVER + choice prompt "SERCOM3 mode" default SAMD2L2_SERCOM3_ISUSART @@ -676,6 +739,27 @@ config SAMD2L2_SERCOM3_ISUSART endchoice +if USART3_SERIALDRIVER + +config USART3_RS485MODE + bool "RS-485 on USART3" + default n + ---help--- + Enable RS-485 interface on USART3. Your board config will have to + provide GPIO_USART3_RS485_DIR pin definition. Currently it cannot be + used with USART3_RXDMA. + +config USART3_RS485_DIR_POLARITY + int "USART3 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART3_RS485MODE + ---help--- + Polarity of DIR pin for RS-485 on USART3. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # USART3_SERIALDRIVER + choice prompt "SERCOM4 mode" default SAMD2L2_SERCOM4_ISUSART @@ -696,6 +780,27 @@ config SAMD2L2_SERCOM4_ISUSART endchoice +if USART4_SERIALDRIVER + +config USART4_RS485MODE + bool "RS-485 on USART4" + default n + ---help--- + Enable RS-485 interface on USART4. Your board config will have to + provide GPIO_USART4_RS485_DIR pin definition. Currently it cannot be + used with USART4_RXDMA. + +config USART4_RS485_DIR_POLARITY + int "USART4 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART4_RS485MODE + ---help--- + Polarity of DIR pin for RS-485 on USART4. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # USART4_SERIALDRIVER + choice prompt "SERCOM5 mode" default SAMD2L2_SERCOM5_ISUSART @@ -716,6 +821,27 @@ config SAMD2L2_SERCOM5_ISUSART endchoice +if USART5_SERIALDRIVER + +config USART5_RS485MODE + bool "RS-485 on USART5" + default n + ---help--- + Enable RS-485 interface on USART5. Your board config will have to + provide GPIO_USART5_RS485_DIR pin definition. Currently it cannot be + used with USART5_RXDMA. + +config USART5_RS485_DIR_POLARITY + int "USART5 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on USART5_RS485MODE + ---help--- + Polarity of DIR pin for RS-485 on USART5. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + +endif # USART5_SERIALDRIVER + config SAMD2L2_HAVE_SPI bool select SPI diff --git a/arch/arm/src/samd2l2/sam_config.h b/arch/arm/src/samd2l2/sam_config.h index 4bd9c23aa6f..96411b5accb 100644 --- a/arch/arm/src/samd2l2/sam_config.h +++ b/arch/arm/src/samd2l2/sam_config.h @@ -1,7 +1,7 @@ /************************************************************************************ * arch/arm/src/samd2l2/sam_config.h * - * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2014, 2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -135,6 +135,14 @@ # undef CONFIG_USART4_SERIAL_CONSOLE # undef CONFIG_USART5_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 +# ifdef CONFIG_USART0_RS485MODE +# define SAM_CONSOLE_RS485_DIR GPIO_USART0_RS485_DIR +# if (CONFIG_USART0_RS485_DIR_POLARITY == 0) +# define SAM_CONSOLE_RS485_DIR_POLARITY false +# else +# define SAM_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif #elif defined(CONFIG_USART1_SERIAL_CONSOLE) # undef CONFIG_USART0_SERIAL_CONSOLE # undef CONFIG_USART2_SERIAL_CONSOLE @@ -142,6 +150,14 @@ # undef CONFIG_USART4_SERIAL_CONSOLE # undef CONFIG_USART5_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 +# ifdef CONFIG_USART1_RS485MODE +# define SAM_CONSOLE_RS485_DIR GPIO_USART1_RS485_DIR +# if (CONFIG_USART1_RS485_DIR_POLARITY == 0) +# define SAM_CONSOLE_RS485_DIR_POLARITY false +# else +# define SAM_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif #elif defined(CONFIG_USART2_SERIAL_CONSOLE) # undef CONFIG_USART0_SERIAL_CONSOLE # undef CONFIG_USART1_SERIAL_CONSOLE @@ -149,6 +165,14 @@ # undef CONFIG_USART4_SERIAL_CONSOLE # undef CONFIG_USART5_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 +# ifdef CONFIG_USART2_RS485MODE +# define SAM_CONSOLE_RS485_DIR GPIO_USART2_RS485_DIR +# if (CONFIG_USART2_RS485_DIR_POLARITY == 0) +# define SAM_CONSOLE_RS485_DIR_POLARITY false +# else +# define SAM_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif #elif defined(CONFIG_USART3_SERIAL_CONSOLE) # undef CONFIG_USART0_SERIAL_CONSOLE # undef CONFIG_USART1_SERIAL_CONSOLE @@ -156,6 +180,14 @@ # undef CONFIG_USART4_SERIAL_CONSOLE # undef CONFIG_USART5_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 +# ifdef CONFIG_USART3_RS485MODE +# define SAM_CONSOLE_RS485_DIR GPIO_USART3_RS485_DIR +# if (CONFIG_USART3_RS485_DIR_POLARITY == 0) +# define SAM_CONSOLE_RS485_DIR_POLARITY false +# else +# define SAM_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif #elif defined(CONFIG_USART4_SERIAL_CONSOLE) # undef CONFIG_USART0_SERIAL_CONSOLE # undef CONFIG_USART1_SERIAL_CONSOLE @@ -163,6 +195,14 @@ # undef CONFIG_USART3_SERIAL_CONSOLE # undef CONFIG_USART5_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 +# ifdef CONFIG_USART4_RS485MODE +# define SAM_CONSOLE_RS485_DIR GPIO_USART4_RS485_DIR +# if (CONFIG_USART4_RS485_DIR_POLARITY == 0) +# define SAM_CONSOLE_RS485_DIR_POLARITY false +# else +# define SAM_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif #elif defined(CONFIG_USART5_SERIAL_CONSOLE) # undef CONFIG_USART0_SERIAL_CONSOLE # undef CONFIG_USART1_SERIAL_CONSOLE @@ -170,6 +210,14 @@ # undef CONFIG_USART3_SERIAL_CONSOLE # undef CONFIG_USART4_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 +# ifdef CONFIG_USART5_RS485MODE +# define SAM_CONSOLE_RS485_DIR GPIO_USART5_RS485_DIR +# if (CONFIG_USART5_RS485_DIR_POLARITY == 0) +# define SAM_CONSOLE_RS485_DIR_POLARITY false +# else +# define SAM_CONSOLE_RS485_DIR_POLARITY true +# endif +# endif #else # undef CONFIG_USART0_SERIAL_CONSOLE # undef CONFIG_USART1_SERIAL_CONSOLE @@ -178,6 +226,7 @@ # undef CONFIG_USART4_SERIAL_CONSOLE # undef CONFIG_USART5_SERIAL_CONSOLE # undef HAVE_SERIAL_CONSOLE +# undef SAM_CONSOLE_RS485_DIR #endif /* Are any SERCOM peripherals are configured as SPI peripherals? */ diff --git a/arch/arm/src/samd2l2/sam_lowputc.c b/arch/arm/src/samd2l2/sam_lowputc.c index 84ee5d5aaae..bfd0dcc10a3 100644 --- a/arch/arm/src/samd2l2/sam_lowputc.c +++ b/arch/arm/src/samd2l2/sam_lowputc.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/samd2l2/sam_lowputc.c * - * Copyright (C) 2014-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2014-2016, 2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * References: @@ -467,7 +467,13 @@ void sam_lowputc(uint32_t ch) /* Wait for the USART to be ready for new TX data */ - while ((getreg8(intflag) & USART_INT_DRE) == 0); + while ((getreg8(intflag) & USART_INT_DRE) == 0) + { + } + +#ifdef SAM_CONSOLE_RS485_DIR + sam_portwrite(SAM_CONSOLE_RS485_DIR, SAM_CONSOLE_RS485_DIR_POLARITY); +#endif /* Wait until synchronization is complete */ @@ -479,6 +485,12 @@ void sam_lowputc(uint32_t ch) /* Wait until data is sent */ - while ((getreg8(intflag) & USART_INT_TXC) == 0); + while ((getreg8(intflag) & USART_INT_TXC) == 0) + { + } + +#ifdef SAM_CONSOLE_RS485_DIR + sam_portwrite(SAM_CONSOLE_RS485_DIR, !SAM_CONSOLE_RS485_DIR_POLARITY); +#endif } #endif diff --git a/arch/arm/src/samd2l2/sam_serial.c b/arch/arm/src/samd2l2/sam_serial.c index 431aa82e302..f74492c8918 100644 --- a/arch/arm/src/samd2l2/sam_serial.c +++ b/arch/arm/src/samd2l2/sam_serial.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/samd2l2/sam_serial.c * - * Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2014-2015, 2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -229,6 +229,11 @@ struct sam_dev_s const struct sam_usart_config_s * const config; /* Information unique to the serial driver */ + +#ifdef HAVE_RS485 + const uint32_t rs485_dir_gpio; /* USART RS-485 DIR GPIO pin configuration */ + const bool rs485_dir_polarity; /* USART RS-485 DIR pin state for TX enabled */ +#endif }; /**************************************************************************** @@ -319,7 +324,15 @@ static char g_usart5txbuffer[CONFIG_USART5_TXBUFSIZE]; #ifdef SAMD2L2_HAVE_USART0 static struct sam_dev_s g_usart0priv = { - .config = &g_usart0config, + .config = &g_usart0config, +#ifdef CONFIG_USART0_RS485MODE + .rs485_dir_gpio = GPIO_USART0_RS485_DIR, +# if (CONFIG_USART0_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif }; static uart_dev_t g_usart0port = @@ -344,7 +357,15 @@ static uart_dev_t g_usart0port = #ifdef SAMD2L2_HAVE_USART1 static struct sam_dev_s g_usart1priv = { - .config = &g_usart1config, + .config = &g_usart1config, +#ifdef CONFIG_USART1_RS485MODE + .rs485_dir_gpio = GPIO_USART1_RS485_DIR, +# if (CONFIG_USART1_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif }; static uart_dev_t g_usart1port = @@ -369,7 +390,15 @@ static uart_dev_t g_usart1port = #ifdef SAMD2L2_HAVE_USART2 static struct sam_dev_s g_usart2priv = { - .config = &g_usart2config, + .config = &g_usart2config, +#ifdef CONFIG_USART2_RS485MODE + .rs485_dir_gpio = GPIO_USART2_RS485_DIR, +# if (CONFIG_USART2_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif }; static uart_dev_t g_usart2port = @@ -394,7 +423,15 @@ static uart_dev_t g_usart2port = #ifdef SAMD2L2_HAVE_USART3 static struct sam_dev_s g_usart3priv = { - .config = &g_usart3config, + .config = &g_usart3config, +#ifdef CONFIG_USART3_RS485MODE + .rs485_dir_gpio = GPIO_USART3_RS485_DIR, +# if (CONFIG_USART3_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif }; static uart_dev_t g_usart3port = @@ -419,7 +456,15 @@ static uart_dev_t g_usart3port = #ifdef SAMD2L2_HAVE_USART4 static struct sam_dev_s g_usart4priv = { - .config = &g_usart4config, + .config = &g_usart4config, +#ifdef CONFIG_USART4_RS485MODE + .rs485_dir_gpio = GPIO_USART4_RS485_DIR, +# if (CONFIG_USART4_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif }; static uart_dev_t g_usart4port = @@ -444,7 +489,15 @@ static uart_dev_t g_usart4port = #ifdef SAMD2L2_HAVE_USART5 static struct sam_dev_s g_usart5priv = { - .config = &g_usart5config, + .config = &g_usart5config, +#ifdef CONFIG_USART5_RS485MODE + .rs485_dir_gpio = GPIO_USART5_RS485_DIR, +# if (CONFIG_USART5_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +# else + .rs485_dir_polarity = true, +# endif +#endif }; static uart_dev_t g_usart5port = @@ -546,7 +599,21 @@ static int sam_interrupt(int irq, void *context, FAR void *arg) intflag = sam_serialin8(priv, SAM_USART_INTFLAG_OFFSET); inten = sam_serialin8(priv, SAM_USART_INTENCLR_OFFSET); - pending = intflag & inten; + pending = intflag & inten; + +#ifdef HAVE_RS485 + /* Transmission of whole buffer is over - TXC is set. + * Note - this should be first, to have the most recent TC bit value from + * SR register - sending data affects TXC, but without refresh we will not + * know that... + */ + + if ((pending & USART_INT_TXC) != 0) + { + sam_portwrite(priv->rs485_dir_gpio, !priv->rs485_dir_polarity); + sam_serialout8(priv, SAM_USART_INTENCLR_OFFSET, USART_INT_TXC); + } +#endif /* Handle an incoming, receive byte. The RXC flag is set when there is * unread data in DATA register. This flag is cleared by reading the DATA @@ -602,6 +669,14 @@ static int sam_setup(struct uart_dev_s *dev) } #endif +#ifdef HAVE_RS485 + if (priv->rs485_dir_gpio != 0) + { + (void)sam_configport(priv->rs485_dir_gpio); + sam_portwrite(priv->rs485_dir_gpio, !priv->rs485_dir_polarity); + } +#endif + return ret; } @@ -831,7 +906,7 @@ static void sam_txint(struct uart_dev_s *dev, bool enable) */ #ifndef CONFIG_SUPPRESS_SERIAL_INTS - sam_serialout8(priv, SAM_USART_INTENSET_OFFSET, USART_INT_DRE); + sam_serialout8(priv, SAM_USART_INTENSET_OFFSET, USART_TX_INTS); /* Fake a TX interrupt here by just calling uart_xmitchars() with * interrupts disabled (note this may recurse). @@ -843,7 +918,7 @@ static void sam_txint(struct uart_dev_s *dev, bool enable) } else { - /* Disable the TX interrupt */ + /* Disable the TX interrupt. Only disable DRE, TXC will disable itself! */ sam_serialout8(priv, SAM_USART_INTENCLR_OFFSET, USART_INT_DRE); } diff --git a/arch/arm/src/samd2l2/sam_usart.h b/arch/arm/src/samd2l2/sam_usart.h index 1d266af0264..71dc436d8a4 100644 --- a/arch/arm/src/samd2l2/sam_usart.h +++ b/arch/arm/src/samd2l2/sam_usart.h @@ -79,6 +79,20 @@ # undef g_consoleconfig #endif +/* Is RS-485 used? */ + +#if defined(CONFIG_USART0_RS485MODE) || defined(CONFIG_USART1_RS485MODE) || \ + defined(CONFIG_USART2_RS485MODE) || defined(CONFIG_USART3_RS485MODE) || \ + defined(CONFIG_USART4_RS485MODE) || defined(CONFIG_USART5_RS485MODE) +# define HAVE_RS485 1 +#endif + +#ifdef HAVE_RS485 +# define USART_TX_INTS (USART_INT_DRE | USART_INT_TXC) +#else +# define USART_TX_INTS (USART_INT_DRE) +#endif + /************************************************************************************ * Public Types ************************************************************************************/