From b7db90da43544ca0fbf4ad165bd4b66a9a255fe0 Mon Sep 17 00:00:00 2001 From: Pavel Kral Date: Mon, 15 Jul 2019 18:47:43 +0200 Subject: [PATCH] drivers: serial: uart_rtt: Virtual UARTs over RTT channels Add support for virtual UART device that uses Segger RTT channels for data transfers. Due to the RTT principle, this driver supports only polling API. Signed-off-by: Pavel Kral --- CODEOWNERS | 2 + drivers/serial/CMakeLists.txt | 1 + drivers/serial/Kconfig | 2 + drivers/serial/Kconfig.rtt | 105 +++++++++++++++++++++++++++++ drivers/serial/uart_rtt.c | 120 ++++++++++++++++++++++++++++++++++ 5 files changed, 230 insertions(+) create mode 100644 drivers/serial/Kconfig.rtt create mode 100644 drivers/serial/uart_rtt.c diff --git a/CODEOWNERS b/CODEOWNERS index 576326c014b..03b912c2156 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -151,6 +151,8 @@ /drivers/serial/*ns16550* @gnuless /drivers/serial/Kconfig.litex @mateusz-holenko @kgugala @pgielda /drivers/serial/uart_liteuart.c @mateusz-holenko @kgugala @pgielda +/drivers/serial/Kconfig.rtt @carlescufi @pkral78 +/drivers/serial/uart_rtt.c @carlescufi @pkral78 /drivers/net/ @jukkar @tbursztyka /drivers/ptp_clock/ @jukkar /drivers/spi/ @tbursztyka diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 7473c519b3a..6f38414ec7e 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -29,6 +29,7 @@ zephyr_library_sources_if_kconfig(uart_psoc6.c) zephyr_library_sources_if_kconfig(uart_pl011.c) zephyr_library_sources_if_kconfig(uart_rv32m1_lpuart.c) zephyr_library_sources_if_kconfig(uart_liteuart.c) +zephyr_library_sources_ifdef(CONFIG_UART_RTT_DRIVER uart_rtt.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index bb530621cf6..a93fcd98c16 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -125,4 +125,6 @@ source "drivers/serial/Kconfig.rv32m1_lpuart" source "drivers/serial/Kconfig.litex" +source "drivers/serial/Kconfig.rtt" + endif # SERIAL diff --git a/drivers/serial/Kconfig.rtt b/drivers/serial/Kconfig.rtt new file mode 100644 index 00000000000..182d8094d05 --- /dev/null +++ b/drivers/serial/Kconfig.rtt @@ -0,0 +1,105 @@ +# Kconfig - Virtual UART RTT driver option +# +# Copyright (c) 2019 omSquare s.r.o. +# +# SPDX-License-Identifier: Apache-2.0 + +menuconfig UART_RTT + bool "Enable UART RTT driver" + depends on USE_SEGGER_RTT + help + This option enables access RTT channel as UART device. + +if UART_RTT + +config UART_RTT_0 + bool "Enable UART on RTT channel 0" + depends on SEGGER_RTT_MAX_NUM_UP_BUFFERS >= 1 && SEGGER_RTT_MAX_NUM_DOWN_BUFFERS >= 1 + depends on SEGGER_RTT_MODE_NO_BLOCK_SKIP + select SERIAL_HAS_DRIVER + select UART_RTT_DRIVER + help + Enable UART on (default) RTT channel 0. Default channel has to be configured in non-blocking skip mode. + +config UART_RTT_1 + bool "Enable UART on RTT channel 1" + depends on SEGGER_RTT_MAX_NUM_UP_BUFFERS >= 2 && SEGGER_RTT_MAX_NUM_DOWN_BUFFERS >= 2 + select SERIAL_HAS_DRIVER + select UART_RTT_DRIVER + help + Enable UART on RTT channel 1 + +if UART_RTT_1 + +config UART_RTT_1_TX_BUFFER_SIZE + int "Size of RTT_1 TX buffer (up to host)" + range 1 65535 + default 1024 + help + Size of the RTT up buffer for UART 1 transmission. + +config UART_RTT_1_RX_BUFFER_SIZE + int "Size of RTT_1 RX buffer (down from host)" + range 1 65535 + default 16 + help + Size of the RTT down buffer for UART 1 reception. + +endif + +config UART_RTT_2 + bool "Enable UART on RTT channel 2" + depends on SEGGER_RTT_MAX_NUM_UP_BUFFERS >= 3 && SEGGER_RTT_MAX_NUM_DOWN_BUFFERS >= 3 + select SERIAL_HAS_DRIVER + select UART_RTT_DRIVER + help + Enable UART on RTT channel 2 + +if UART_RTT_2 + +config UART_RTT_2_TX_BUFFER_SIZE + int "Size of RTT_2 TX buffer (up to host)" + range 1 65535 + default 1024 + help + Size of the RTT up buffer for UART 2 transmission. + +config UART_RTT_2_RX_BUFFER_SIZE + int "Size of RTT_2 RX buffer (down from host)" + range 1 65535 + default 16 + help + Size of the RTT down buffer for UART 2 reception. + +endif + +config UART_RTT_3 + bool "Enable UART on RTT channel 3" + depends on SEGGER_RTT_MAX_NUM_UP_BUFFERS >= 4 && SEGGER_RTT_MAX_NUM_DOWN_BUFFERS >= 4 + select SERIAL_HAS_DRIVER + select UART_RTT_DRIVER + help + Enable UART on RTT channel 3 + +if UART_RTT_3 + +config UART_RTT_3_TX_BUFFER_SIZE + int "Size of RTT_3 TX buffer (up to host)" + range 1 65535 + default 1024 + help + Size of the RTT up buffer for UART 3 transmission. + +config UART_RTT_3_RX_BUFFER_SIZE + int "Size of RTT_3 RX buffer (down from host)" + range 1 65535 + default 16 + help + Size of the RTT down buffer for UART 3 reception. + +endif + +config UART_RTT_DRIVER + bool + +endif diff --git a/drivers/serial/uart_rtt.c b/drivers/serial/uart_rtt.c new file mode 100644 index 00000000000..de628295f08 --- /dev/null +++ b/drivers/serial/uart_rtt.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2019 omSquare s.r.o. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +struct uart_rtt_config { + void *up_buffer; + size_t up_size; + void *down_buffer; + size_t down_size; + u8_t channel; +}; + +static inline const struct uart_rtt_config *get_dev_config(struct device *dev) +{ + return dev->config->config_info; +} + +static int uart_rtt_init(struct device *dev) +{ + /* + * Channel 0 is initialized at compile-time, Kconfig ensures that + * it is configured in correct, non-blocking mode. Other channels + * need to be configured at run-time. + */ + if (get_dev_config(dev)) { + const struct uart_rtt_config *cfg = get_dev_config(dev); + + SEGGER_RTT_ConfigUpBuffer(cfg->channel, dev->config->name, + cfg->up_buffer, cfg->up_size, + SEGGER_RTT_MODE_NO_BLOCK_SKIP); + SEGGER_RTT_ConfigDownBuffer(cfg->channel, dev->config->name, + cfg->down_buffer, cfg->down_size, + SEGGER_RTT_MODE_NO_BLOCK_SKIP); + } + return 0; +} + +/** + * @brief Poll the device for input. + * + * @param dev UART device struct + * @param c Pointer to character + * + * @return 0 if a character arrived, -1 if the input buffer if empty. + */ + +static int uart_rtt_poll_in(struct device *dev, unsigned char *c) +{ + unsigned int ch = + get_dev_config(dev) ? get_dev_config(dev)->channel : 0; + unsigned int ret = SEGGER_RTT_Read(ch, c, 1); + + return ret ? 0 : -1; +} + +/** + * @brief Output a character in polled mode. + * + * @param dev UART device struct + * @param c Character to send + */ +static void uart_rtt_poll_out(struct device *dev, unsigned char c) +{ + unsigned int ch = + get_dev_config(dev) ? get_dev_config(dev)->channel : 0; + + SEGGER_RTT_Write(ch, &c, 1); +} + +static const struct uart_driver_api uart_rtt_driver_api = { + .poll_in = uart_rtt_poll_in, + .poll_out = uart_rtt_poll_out, +}; + +#if CONFIG_UART_RTT_0 + +DEVICE_DEFINE(uart_rtt0, "RTT_0", uart_rtt_init, NULL, NULL, NULL, + /* Initialize UART device after RTT init. */ + PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &uart_rtt_driver_api); + +#endif + +#define UART_RTT_CHANNEL(n) \ + static u8_t \ + uart_rtt##n##_tx_buffer[CONFIG_UART_RTT_##n##_TX_BUFFER_SIZE]; \ + static u8_t \ + uart_rtt##n##_rx_buffer[CONFIG_UART_RTT_##n##_RX_BUFFER_SIZE]; \ + \ + static const char uart_rtt##n##_name[] = "RTT_" #n "\0"; \ + \ + static const struct uart_rtt_config uart_rtt##n##_config = { \ + .channel = n, \ + .up_buffer = uart_rtt##n##_tx_buffer, \ + .up_size = sizeof(uart_rtt##n##_tx_buffer), \ + .down_buffer = uart_rtt##n##_rx_buffer, \ + .down_size = sizeof(uart_rtt##n##_rx_buffer), \ + }; \ + \ + DEVICE_DEFINE(uart_rtt##n, uart_rtt##n##_name, uart_rtt_init, NULL, \ + NULL, &uart_rtt##n##_config, PRE_KERNEL_2, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &uart_rtt_driver_api) + +#if CONFIG_UART_RTT_1 +UART_RTT_CHANNEL(1); +#endif + +#if CONFIG_UART_RTT_2 +UART_RTT_CHANNEL(2); +#endif + +#if CONFIG_UART_RTT_3 +UART_RTT_CHANNEL(3); +#endif