samv7: add RS-485 mode support to USART driver

This commit enhances SAMV7 serial driver with RS-485 mode available to
USART peripherals. The hardware automatically sets RTS pin high when
data are transfered and low then no transfer occurs. Only USART peripherals
support this mode, UART peripherals do not.

This mode can be enabled by configuration option SAMV7_USARTx_RS485MODE.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
This commit is contained in:
Michal Lenc
2022-07-14 21:41:51 +02:00
committed by Petro Karashchenko
parent a2239891e7
commit 89a2b51b96
3 changed files with 153 additions and 3 deletions
+42 -3
View File
@@ -797,27 +797,66 @@ config SAMV7_USBHOSTHS
depends on SAMV7_HAVE_USBHS
select USBHOST
config SAMV7_USART0
menuconfig SAMV7_USART0
bool "USART 0"
default n
depends on SAMV7_HAVE_USART0
select USART0_SERIALDRIVER
select ARCH_HAVE_SERIAL_TERMIOS
config SAMV7_USART1
if SAMV7_USART0
config SAMV7_USART0_RS485MODE
bool "RS-485 on USART0"
default n
---help---
Enable RS-485 interface on USART0. Please note that the pin is set
to logical 1 before the serial driver is opened. Board specific
logic is required to set the pin to logical 0 before the driver is
opened for the first time.
endif
menuconfig SAMV7_USART1
bool "USART 1"
default n
depends on SAMV7_HAVE_USART1
select USART1_SERIALDRIVER
select ARCH_HAVE_SERIAL_TERMIOS
config SAMV7_USART2
if SAMV7_USART1
config SAMV7_USART1_RS485MODE
bool "RS-485 on USART1"
default n
---help---
Enable RS-485 interface on USART1. Please note that the pin is set
to logical 1 before the serial driver is opened. Board specific
logic is required to set the pin to logical 0 before the driver is
opened for the first time.
endif
menuconfig SAMV7_USART2
bool "USART 2"
default n
depends on SAMV7_HAVE_USART2
select USART2_SERIALDRIVER
select ARCH_HAVE_SERIAL_TERMIOS
if SAMV7_USART2
config SAMV7_USART2_RS485MODE
bool "RS-485 on USART2"
default n
---help---
Enable RS-485 interface on USART2. Please note that the pin is set
to logical 1 before the serial driver is opened. Board specific
logic is required to set the pin to logical 0 before the driver is
opened for the first time.
endif
config SAMV7_WDT
bool "Watchdog Timer (WDT)"
default n
+60
View File
@@ -46,7 +46,11 @@
#include "arm_internal.h"
#include "sam_config.h"
#include "hardware/sam_uart.h"
#include "hardware/sam_pinmap.h"
#include "sam_gpio.h"
#include "sam_serial.h"
/****************************************************************************
* Pre-processor Definitions
@@ -328,6 +332,12 @@ struct sam_dev_s
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
bool flowc; /* input flow control (RTS) enabled */
#endif
bool has_rs485; /* True if RS-485 mode is enabled */
#ifdef SERIAL_HAVE_RS485
uint32_t rs485_dir_gpio; /* RS-485 RTS pin */
#endif
};
/****************************************************************************
@@ -417,6 +427,7 @@ static struct sam_dev_s g_uart0priv =
.parity = CONFIG_UART0_PARITY,
.bits = CONFIG_UART0_BITS,
.stopbits2 = CONFIG_UART0_2STOP,
.has_rs485 = false,
};
static uart_dev_t g_uart0port =
@@ -447,6 +458,7 @@ static struct sam_dev_s g_uart1priv =
.parity = CONFIG_UART1_PARITY,
.bits = CONFIG_UART1_BITS,
.stopbits2 = CONFIG_UART1_2STOP,
.has_rs485 = false,
};
static uart_dev_t g_uart1port =
@@ -477,6 +489,7 @@ static struct sam_dev_s g_uart2priv =
.parity = CONFIG_UART2_PARITY,
.bits = CONFIG_UART2_BITS,
.stopbits2 = CONFIG_UART2_2STOP,
.has_rs485 = false,
};
static uart_dev_t g_uart2port =
@@ -507,6 +520,7 @@ static struct sam_dev_s g_uart3priv =
.parity = CONFIG_UART3_PARITY,
.bits = CONFIG_UART3_BITS,
.stopbits2 = CONFIG_UART3_2STOP,
.has_rs485 = false,
};
static uart_dev_t g_uart3port =
@@ -537,6 +551,7 @@ static struct sam_dev_s g_uart4priv =
.parity = CONFIG_UART4_PARITY,
.bits = CONFIG_UART4_BITS,
.stopbits2 = CONFIG_UART4_2STOP,
.has_rs485 = false,
};
static uart_dev_t g_uart4port =
@@ -570,6 +585,12 @@ static struct sam_dev_s g_usart0priv =
#if defined(CONFIG_USART0_OFLOWCONTROL) || defined(CONFIG_USART0_IFLOWCONTROL)
.flowc = true,
#endif
#ifdef CONFIG_SAMV7_USART0_RS485MODE
.has_rs485 = true,
.rs485_dir_gpio = GPIO_USART0_RTS,
#else
.has_rs485 = false,
#endif
};
static uart_dev_t g_usart0port =
@@ -603,6 +624,12 @@ static struct sam_dev_s g_usart1priv =
#if defined(CONFIG_USART1_OFLOWCONTROL) || defined(CONFIG_USART1_IFLOWCONTROL)
.flowc = true,
#endif
#ifdef CONFIG_SAMV7_USART1_RS485MODE
.has_rs485 = true,
.rs485_dir_gpio = GPIO_USART1_RTS,
#else
.has_rs485 = false,
#endif
};
static uart_dev_t g_usart1port =
@@ -636,6 +663,12 @@ static struct sam_dev_s g_usart2priv =
#if defined(CONFIG_USART2_OFLOWCONTROL) || defined(CONFIG_USART2_IFLOWCONTROL)
.flowc = true,
#endif
#ifdef CONFIG_SAMV7_USART2_RS485MODE
.has_rs485 = true,
.rs485_dir_gpio = GPIO_USART2_RTS,
#else
.has_rs485 = false,
#endif
};
static uart_dev_t g_usart2port =
@@ -879,6 +912,17 @@ static int sam_setup(struct uart_dev_s *dev)
/* Enable receiver & transmitter */
sam_serialout(priv, SAM_UART_CR_OFFSET, (UART_CR_RXEN | UART_CR_TXEN));
#ifdef SERIAL_HAVE_RS485
if (priv->has_rs485)
{
sam_configgpio(priv->rs485_dir_gpio);
regval = sam_serialin(priv, SAM_UART_MR_OFFSET);
regval |= UART_MR_MODE_RS485;
sam_serialout(priv, SAM_UART_MR_OFFSET, regval);
}
#endif
#endif
return OK;
@@ -896,6 +940,7 @@ static int sam_setup(struct uart_dev_s *dev)
static void sam_shutdown(struct uart_dev_s *dev)
{
struct sam_dev_s *priv = (struct sam_dev_s *)dev->priv;
uint32_t regval;
/* Reset and disable receiver and transmitter */
@@ -903,6 +948,21 @@ static void sam_shutdown(struct uart_dev_s *dev)
(UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS |
UART_CR_TXDIS));
/* Set mode back to normal */
regval = sam_serialin(priv, SAM_UART_MR_OFFSET);
regval &= ~(UART_MR_MODE_MASK);
sam_serialout(priv, SAM_UART_MR_OFFSET, regval);
#ifdef SERIAL_HAVE_RS485
if (priv->has_rs485)
{
/* Force RTS pin to get low if RS-485 mode is enabled */
sam_serialout(priv, SAM_UART_CR_OFFSET, UART_CR_RTSEN);
}
#endif
/* Disable all interrupts */
sam_disableallints(priv, NULL);
+51
View File
@@ -0,0 +1,51 @@
/****************************************************************************
* arch/arm/src/samv7/sam_serial.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_ARM_SRC_SAMV7_SAM_SERIAL_H
#define __ARCH_ARM_SRC_SAMV7_SAM_SERIAL_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include "chip.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Is RS-485 used? */
#undef SERIAL_HAVE_RS485
#if defined(CONFIG_SAMV7_USART0_RS485MODE) || \
defined(CONFIG_SAMV7_USART1_RS485MODE) || \
defined(CONFIG_SAMV7_USART2_RS485MODE)
# define SERIAL_HAVE_RS485 1
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#endif /* __ARCH_ARM_SRC_SAMV7_SAM_SERIAL_H */