diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index 927e7d6460b2..9a07911f8fc6 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -56,6 +56,13 @@ extern "C" { #define PERIPH_I2C_NEED_WRITE_REGS /** @} */ +/** + * @name UART implements writing single bytes + * @{ + */ +#define PERIPH_UART_NEEDS_WRITE_BYTE (0) +/** @} */ + /** * @brief Override GPIO type * @{ diff --git a/cpu/sam0_common/periph/uart.c b/cpu/sam0_common/periph/uart.c index c7a35ab52e8e..39a7a5796d7a 100644 --- a/cpu/sam0_common/periph/uart.c +++ b/cpu/sam0_common/periph/uart.c @@ -261,34 +261,39 @@ void uart_deinit_pins(uart_t uart) #endif } -void uart_write(uart_t uart, const uint8_t *data, size_t len) +static inline void _write_byte(uart_t uart, uint8_t data) { - if (uart_config[uart].tx_pin == GPIO_UNDEF) { - return; - } - #ifdef MODULE_PERIPH_UART_NONBLOCKING - for (const void* end = data + len; data != end; ++data) { - if (irq_is_in() || __get_PRIMASK()) { - /* if ring buffer is full free up a spot */ - if (tsrb_full(&uart_tx_rb[uart])) { - while (!dev(uart)->INTFLAG.bit.DRE) {} - dev(uart)->DATA.reg = tsrb_get_one(&uart_tx_rb[uart]); - } - tsrb_add_one(&uart_tx_rb[uart], *data); - } - else { - while (tsrb_add_one(&uart_tx_rb[uart], *data) < 0) {} + if (irq_is_in() || __get_PRIMASK()) { + /* if ring buffer is full free up a spot */ + if (tsrb_full(&uart_tx_rb[uart])) { + while (!dev(uart)->INTFLAG.bit.DRE) {} + dev(uart)->DATA.reg = tsrb_get_one(&uart_tx_rb[uart]); } - dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_DRE; + tsrb_add_one(&uart_tx_rb[uart], data); } + else { + while (tsrb_add_one(&uart_tx_rb[uart], data) < 0) {} + } + dev(uart)->INTENSET.reg = SERCOM_USART_INTENSET_DRE; #else + while (!dev(uart)->INTFLAG.bit.DRE) {} + dev(uart)->DATA.reg = data; +#endif +} + +void uart_write_byte(uart_t uart, uint8_t data) +{ + _write_byte(uart, data); + while (!dev(uart)->INTFLAG.bit.TXC) {} +} + +void uart_write(uart_t uart, const uint8_t *data, size_t len) +{ for (const void* end = data + len; data != end; ++data) { - while (!dev(uart)->INTFLAG.bit.DRE) {} - dev(uart)->DATA.reg = *data; + _write_byte(uart, *data); } while (!dev(uart)->INTFLAG.bit.TXC) {} -#endif } void uart_poweron(uart_t uart) diff --git a/drivers/include/periph/uart.h b/drivers/include/periph/uart.h index d293cab2d1da..3b386200836a 100644 --- a/drivers/include/periph/uart.h +++ b/drivers/include/periph/uart.h @@ -90,6 +90,30 @@ typedef unsigned int uart_t; #define UART_DEV(x) (x) #endif +/** + * @brief Set to 1 if the CPU does not provide an implementation + * for @ref uart_write + */ +#ifndef PERIPH_UART_NEEDS_WRITE +#define PERIPH_UART_NEEDS_WRITE (0) +#endif + +/** + * @brief Set to 1 if the CPU does not provide an implementation + * for @ref uart_write_byte + */ +#ifndef PERIPH_UART_NEEDS_WRITE_BYTE +#define PERIPH_UART_NEEDS_WRITE_BYTE (1) +#endif + +/** + * @brief Set to 1 if the CPU does not provide an implementation + * for @ref uart_write_string + */ +#ifndef PERIPH_UART_NEEDS_WRITE_STRING +#define PERIPH_UART_NEEDS_WRITE_STRING (1) +#endif + /** * @brief Signature for receive interrupt callback * @@ -271,6 +295,38 @@ int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity, */ void uart_write(uart_t uart, const uint8_t *data, size_t len); +/** + * @brief Write a single byte of data to the specified UART device + * + * This function is blocking, as it will only return after @p data + * has been send. + * + * @param[in] uart UART device to use for transmission + * @param[in] data byte to write + * + */ +#if PERIPH_UART_NEEDS_WRITE_BYTE +static inline void uart_write_byte(uart_t uart, uint8_t data) +{ + uart_write(uart, &data, 1); +} +#else +void uart_write_byte(uart_t uart, uint8_t data); +#endif + +/** + * @brief Write a NULL-terminated string to the specified UART device + * + * This function is blocking, as it will only return after all characters + * of the given string have been send. The way this data is send is up to the + * implementation: active waiting, interrupt driven, DMA, etc. + * + * @param[in] uart UART device to use for transmission + * @param[in] s string to send (NULL-terminated) + * + */ +void uart_write_string(uart_t uart, const char *s); + /** * @brief Power on the given UART device * diff --git a/drivers/periph_common/uart.c b/drivers/periph_common/uart.c new file mode 100644 index 000000000000..bb863649b685 --- /dev/null +++ b/drivers/periph_common/uart.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 ML!PA Consulting GmbH + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup drivers_periph_uart + * @{ + * + * @file + * @brief common UART function fallback implementations + * + * @author Benjamin Valentin + * + * @} + */ +#include +#include + +#include "board.h" +#include "cpu.h" +#include "kernel_defines.h" +#include "periph/uart.h" + +#if PERIPH_UART_NEEDS_WRITE_STRING +void uart_write_string(uart_t uart, const char *s) +{ + if (!PERIPH_UART_NEEDS_WRITE_BYTE) { + while (*s) { + uart_write_byte(uart, (uint8_t)*s++); + } + } else { + uart_write(uart, (uint8_t*)s, strlen(s)); + } +} +#endif + +#if PERIPH_UART_NEEDS_WRITE && !PERIPH_UART_NEEDS_WRITE_BYTE +void uart_write(uart_t uart, const uint8_t *data, size_t len) +{ + for (const uint8_t *end = data + len; data != end; ++data) { + uart_write_byte(uart, *data); + } +} +#endif diff --git a/tests/periph_uart/main.c b/tests/periph_uart/main.c index 90afb22167ba..e27f9a99114c 100644 --- a/tests/periph_uart/main.c +++ b/tests/periph_uart/main.c @@ -241,7 +241,6 @@ static int cmd_mode(int argc, char **argv) static int cmd_send(int argc, char **argv) { int dev; - uint8_t endline = (uint8_t)'\n'; if (argc < 3) { printf("usage: %s \n", argv[0]); @@ -254,8 +253,8 @@ static int cmd_send(int argc, char **argv) } printf("UART_DEV(%i) TX: %s\n", dev, argv[2]); - uart_write(UART_DEV(dev), (uint8_t *)argv[2], strlen(argv[2])); - uart_write(UART_DEV(dev), &endline, 1); + uart_write_string(UART_DEV(dev), argv[2]); + uart_write_byte(UART_DEV(dev), '\n'); return 0; }