From 585dc15f99d8a89766bb12d064fa2209909a1b6d Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 16 Jun 2020 19:53:00 +0200 Subject: [PATCH] cpu/sam0_common: UART: implement inverted RX & TX The UART TX and TX lines on SAMD5x and SAML1x can be inverted. However, the flags don't do exactly what one would expect. See errata 2.18.5: SERCOM-UART: TXINV and RXINV Bits Reference: > The TXINV and RXINV bits in the CTRLA register have inverted functionality. > > Workaround: > In software interpret the TXINV bit as a functionality of RXINV, and conversely, > interpret the RXINV bit as a functionality of TXINV. --- cpu/sam0_common/include/periph_cpu_common.h | 2 ++ cpu/sam0_common/periph/uart.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index 495a031399..2dd5839aad 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -168,6 +168,8 @@ typedef enum { UART_FLAG_NONE = 0x0, /**< No flags set */ UART_FLAG_RUN_STANDBY = 0x1, /**< run SERCOM in standby mode */ UART_FLAG_WAKEUP = 0x2, /**< wake from sleep on receive */ + UART_FLAG_RXINV = 0x4, /**< invert RX signal */ + UART_FLAG_TXINV = 0x8, /**< invert TX signal */ } uart_flag_t; #ifndef DOXYGEN diff --git a/cpu/sam0_common/periph/uart.c b/cpu/sam0_common/periph/uart.c index 41ebccec1d..366edbae9e 100644 --- a/cpu/sam0_common/periph/uart.c +++ b/cpu/sam0_common/periph/uart.c @@ -114,6 +114,18 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) if (uart_config[uart].flags & UART_FLAG_RUN_STANDBY) { dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_RUNSTDBY; } +#ifdef SERCOM_USART_CTRLA_RXINV + /* COM100-61: The TXINV and RXINV bits in the CTRLA register have inverted functionality. */ + if (uart_config[uart].flags & UART_FLAG_TXINV) { + dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_RXINV; + } +#endif +#ifdef SERCOM_USART_CTRLA_TXINV + /* COM100-61: The TXINV and RXINV bits in the CTRLA register have inverted functionality. */ + if (uart_config[uart].flags & UART_FLAG_RXINV) { + dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_TXINV; + } +#endif /* calculate and set baudrate */ uint32_t baud = (((sam0_gclk_freq(uart_config[uart].gclk_src) * 8) / baudrate) / 16);