diff --git a/drivers/drivers_initialize.c b/drivers/drivers_initialize.c index 050a2ace37..7b41e6339e 100644 --- a/drivers/drivers_initialize.c +++ b/drivers/drivers_initialize.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,10 @@ void drivers_initialize(void) syslog_initialize(); +#ifdef CONFIG_SERIAL_RTT + serial_rtt_initialize(); +#endif + #if defined(CONFIG_DEV_NULL) devnull_register(); /* Standard /dev/null */ #endif diff --git a/drivers/segger/Kconfig b/drivers/segger/Kconfig index a9bc5ee3a6..95c0bf8af3 100644 --- a/drivers/segger/Kconfig +++ b/drivers/segger/Kconfig @@ -63,6 +63,34 @@ config SEGGER_RTT_BUFFER_SIZE_DOWN ---help--- Size of the buffer for terminal input to target from host (Usually keyboard input) +config SEGGER_RTT1_BUFFER_SIZE_UP + int "Segger RTT Channel 1 UP Buffer Size" + depends on SEGGER_RTT_MAX_NUM_UP_BUFFERS >= 2 + default SEGGER_RTT_BUFFER_SIZE_UP + ---help--- + Size of the buffer for channel 1 output of target, up to host + +config SEGGER_RTT1_BUFFER_SIZE_DOWN + int "Segger RTT Channel 1 DOWN Buffer Size" + depends on SEGGER_RTT_MAX_NUM_DOWN_BUFFERS >= 2 + default SEGGER_RTT_BUFFER_SIZE_DOWN + ---help--- + Size of the buffer for channel 1 input to target from host + +config SEGGER_RTT2_BUFFER_SIZE_UP + int "Segger RTT Channel 2 UP Buffer Size" + depends on SEGGER_RTT_MAX_NUM_UP_BUFFERS >= 3 + default SEGGER_RTT_BUFFER_SIZE_UP + ---help--- + Size of the buffer for channel 2 output of target, up to host + +config SEGGER_RTT2_BUFFER_SIZE_DOWN + int "Segger RTT Channel 2 Down Buffer Size" + depends on SEGGER_RTT_MAX_NUM_DOWN_BUFFERS >= 3 + default SEGGER_RTT_BUFFER_SIZE_DOWN + ---help--- + Size of the buffer for channel 2 input to target from host + choice prompt "SEGGER_RTT_MODE" default SEGGER_RTT_MODE_NO_BLOCK_SKIP @@ -94,6 +122,57 @@ config SYSLOG_RTT ---help--- Use Segger J-Link RTT as a SYSLOG output device. +config SERIAL_RTT + bool "Segger RTT serial driver" + select SEGGER_RTT + select SERIAL_RXDMA + select SERIAL_TXDMA + depends on SERIAL + default n + ---help--- + This option is used to enable RTT serial device + In Segger RTT serial driver, RTT channel buffer and serial DMA buffer are shared, + So you cannot use RTT stream to operate it + +if SERIAL_RTT + +config SERIAL_RTT_POLLING_INTERVAL + int "Segger RTT serial pilling interval (us)" + default USEC_PER_TICK + ---help--- + This option is used to configure the RTT serial polling interval + +config SERIAL_RTT0 + bool "Segger RTT serial for channel 0" + default n + ---help--- + This option is used to enable the serial driver of channel 0 + +config SERIAL_RTT1 + bool "Segger RTT serial for channel 1" + default n + depends on SEGGER_RTT_MAX_NUM_DOWN_BUFFERS >= 2 + ---help--- + This option is used to enable the serial driver of channel 1 + +config SERIAL_RTT2 + bool "Segger RTT serial for channel 2" + default n + depends on SEGGER_RTT_MAX_NUM_DOWN_BUFFERS >= 3 + ---help--- + This option is used to enable the serial driver of channel 2 + +config SERIAL_RTT_CONSOLE + int "Segger RTT console channel" + default 0 if SERIAL_RTT0 + default -1 + ---help--- + Select RTT console channel, using RTT channel 0 by default. + The buffer size of RTT channel 0 is configured by SEGGER_RTT_BUFFER_SIZE_UP/DOWN + You need to turn off other console devices before using Segger RTT console + +endif # SERIAL_RTT + if DRIVERS_NOTE config SEGGER_SYSVIEW bool "Note SEGGER SystemView driver" diff --git a/drivers/segger/Make.defs b/drivers/segger/Make.defs index 8db4b5d307..02306b97c7 100644 --- a/drivers/segger/Make.defs +++ b/drivers/segger/Make.defs @@ -65,6 +65,10 @@ ifeq ($(CONFIG_SYSLOG_RTT),y) CSRCS += segger/syslog_rtt.c endif +ifeq ($(CONFIG_SERIAL_RTT),y) + CSRCS += segger/serial_rtt.c +endif + ifeq ($(CONFIG_SEGGER_SYSVIEW),y) CSRCS += segger/note_sysview.c CSRCS += segger/SystemView/SYSVIEW/SEGGER_SYSVIEW.c diff --git a/drivers/segger/serial_rtt.c b/drivers/segger/serial_rtt.c new file mode 100644 index 0000000000..895d232d09 --- /dev/null +++ b/drivers/segger/serial_rtt.c @@ -0,0 +1,459 @@ +/**************************************************************************** + * drivers/segger/serial_rtt.c + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef SEGGER_RTT_BUFFER_SECTION +# define SERIAL_RTT_BUFFER_SECTION locate_data(SEGGER_RTT_BUFFER_SECTION) +#else +# define SERIAL_RTT_BUFFER_SECTION +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct serial_rtt_s +{ + struct uart_dev_s uart; + struct wdog_s wdog; + int channel; + FAR char *up_buffer; + FAR char *down_buffer; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int serial_rtt_setup(FAR struct uart_dev_s *dev); +static void serial_rtt_shutdown(FAR struct uart_dev_s *dev); +static int serial_rtt_attach(FAR struct uart_dev_s *dev); +static void serial_rtt_detach(FAR struct uart_dev_s *dev); +static int serial_rtt_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); +static int serial_rtt_receive(FAR struct uart_dev_s *dev, + FAR unsigned int *status); +static void serial_rtt_rxint(FAR struct uart_dev_s *dev, bool enable); +static bool serial_rtt_rxavailable(FAR struct uart_dev_s *dev); +static void serial_rtt_dmasend(FAR struct uart_dev_s *dev); +static void serial_rtt_dmareceive(FAR struct uart_dev_s *dev); +static void serial_rtt_dmarxfree(FAR struct uart_dev_s *dev); +static void serial_rtt_dmatxavail(FAR struct uart_dev_s *dev); +static void serial_rtt_send(FAR struct uart_dev_s *dev, int ch); +static void serial_rtt_txint(FAR struct uart_dev_s *dev, bool enable); +static bool serial_rtt_txready(FAR struct uart_dev_s *dev); +static bool serial_rtt_txempty(FAR struct uart_dev_s *dev); + +static void serial_rtt_timeout(wdparm_t arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct uart_ops_s g_serial_rtt_ops = +{ + serial_rtt_setup, + serial_rtt_shutdown, + serial_rtt_attach, + serial_rtt_detach, + serial_rtt_ioctl, + serial_rtt_receive, + serial_rtt_rxint, + serial_rtt_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + NULL, +#endif + serial_rtt_dmasend, + serial_rtt_dmareceive, + serial_rtt_dmarxfree, + serial_rtt_dmatxavail, + serial_rtt_send, + serial_rtt_txint, + serial_rtt_txready, + serial_rtt_txempty, +}; + +#ifdef CONFIG_SERIAL_RTT0 +static char g_rtt0_xmit_buffer[CONFIG_SEGGER_RTT_BUFFER_SIZE_UP]; +static char g_rtt0_recv_buffer[CONFIG_SEGGER_RTT_BUFFER_SIZE_DOWN]; + +static struct serial_rtt_s g_serial_rtt0 = +{ + .uart = + { + .isconsole = CONFIG_SERIAL_RTT_CONSOLE == 0, + .recv = + { + .buffer = g_rtt0_recv_buffer, + .size = CONFIG_SEGGER_RTT_BUFFER_SIZE_DOWN, + }, + .xmit = + { + .buffer = g_rtt0_xmit_buffer, + .size = CONFIG_SEGGER_RTT_BUFFER_SIZE_UP, + }, + .ops = &g_serial_rtt_ops, + .priv = &g_serial_rtt0, + }, + .channel = 0, + .up_buffer = NULL, + .down_buffer = NULL, +}; +#endif + +#ifdef CONFIG_SERIAL_RTT1 +static char g_rtt1_xmit_buffer[CONFIG_SEGGER_RTT1_BUFFER_SIZE_UP]; +static char g_rtt1_recv_buffer[CONFIG_SEGGER_RTT1_BUFFER_SIZE_DOWN]; + +static char SERIAL_RTT_BUFFER_SECTION +g_rtt1_up_buffer[CONFIG_SEGGER_RTT1_BUFFER_SIZE_UP]; +static char SERIAL_RTT_BUFFER_SECTION +g_rtt1_down_buffer[CONFIG_SEGGER_RTT1_BUFFER_SIZE_DOWN]; + +static struct serial_rtt_s g_serial_rtt1 = +{ + .uart = + { + .isconsole = CONFIG_SERIAL_RTT_CONSOLE == 1, + .recv = + { + .buffer = g_rtt1_recv_buffer, + .size = CONFIG_SEGGER_RTT1_BUFFER_SIZE_DOWN, + }, + .xmit = + { + .buffer = g_rtt1_xmit_buffer, + .size = CONFIG_SEGGER_RTT1_BUFFER_SIZE_UP, + }, + .ops = &g_serial_rtt_ops, + .priv = &g_serial_rtt1, + }, + .channel = 1, + .up_buffer = g_rtt1_up_buffer, + .down_buffer = g_rtt1_down_buffer, +}; +#endif + +#ifdef CONFIG_SERIAL_RTT2 +static char g_rtt2_xmit_buffer[CONFIG_SEGGER_RTT2_BUFFER_SIZE_UP]; +static char g_rtt2_recv_buffer[CONFIG_SEGGER_RTT2_BUFFER_SIZE_DOWN]; + +static char SERIAL_RTT_BUFFER_SECTION +g_rtt2_up_buffer[CONFIG_SEGGER_RTT2_BUFFER_SIZE_UP]; +static char SERIAL_RTT_BUFFER_SECTION +g_rtt2_down_buffer[CONFIG_SEGGER_RTT2_BUFFER_SIZE_DOWN]; + +static struct serial_rtt_s g_serial_rtt2 = +{ + .uart = + { + .isconsole = CONFIG_SERIAL_RTT_CONSOLE == 2, + .recv = + { + .buffer = g_rtt2_recv_buffer, + .size = CONFIG_SEGGER_RTT2_BUFFER_SIZE_DOWN, + }, + .xmit = + { + .buffer = g_rtt2_xmit_buffer, + .size = CONFIG_SEGGER_RTT2_BUFFER_SIZE_UP, + }, + .ops = &g_serial_rtt_ops, + .priv = &g_serial_rtt2, + }, + .channel = 2, + .up_buffer = g_rtt2_up_buffer, + .down_buffer = g_rtt2_down_buffer, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: serial_rtt_setup + ****************************************************************************/ + +static int serial_rtt_setup(FAR struct uart_dev_s *dev) +{ + return OK; +} + +/**************************************************************************** + * Name: serial_rtt_shutdown + ****************************************************************************/ + +static void serial_rtt_shutdown(FAR struct uart_dev_s *dev) +{ +} + +/**************************************************************************** + * Name: serial_rtt_attach + ****************************************************************************/ + +static int serial_rtt_attach(FAR struct uart_dev_s *dev) +{ + FAR struct serial_rtt_s *rtt = dev->priv; + wd_start(&rtt->wdog, USEC2TICK(CONFIG_SERIAL_RTT_POLLING_INTERVAL), + serial_rtt_timeout, (wdparm_t)dev); + return OK; +} + +/**************************************************************************** + * Name: serial_rtt_detach + ****************************************************************************/ + +static void serial_rtt_detach(FAR struct uart_dev_s *dev) +{ + FAR struct serial_rtt_s *rtt = dev->priv; + wd_cancel(&rtt->wdog); +} + +/**************************************************************************** + * Name: serial_rtt_ioctl + ****************************************************************************/ + +static int serial_rtt_ioctl(FAR struct file *filep, int cmd, + unsigned long arg) +{ + return -ENOTTY; +} + +/**************************************************************************** + * Name: serial_rtt_receive + ****************************************************************************/ + +static int serial_rtt_receive(FAR struct uart_dev_s *dev, + FAR unsigned int *status) +{ + FAR struct serial_rtt_s *rtt = dev->priv; + int ret; + int ch; + + ret = SEGGER_RTT_ReadNoLock(rtt->channel, &ch, 1); + *status = ret == 1 ? 0 : -EAGAIN; + return ch; +} + +/**************************************************************************** + * Name: serial_rtt_rxint + ****************************************************************************/ + +static void serial_rtt_rxint(FAR struct uart_dev_s *dev, bool enable) +{ +} + +/**************************************************************************** + * Name: serial_rtt_rxavailable + ****************************************************************************/ + +static bool serial_rtt_rxavailable(FAR struct uart_dev_s *dev) +{ + FAR struct serial_rtt_s *rtt = dev->priv; + return SEGGER_RTT_HasData(rtt->channel) != 0; +} + +/**************************************************************************** + * Name: serial_rtt_dmasend + ****************************************************************************/ + +static void serial_rtt_dmasend(FAR struct uart_dev_s *dev) +{ + FAR struct serial_rtt_s *rtt = dev->priv; + FAR struct uart_dmaxfer_s *xfer = &dev->dmatx; + size_t len; + + SEGGER_RTT_BLOCK_IF_FIFO_FULL(rtt->channel); + len = SEGGER_RTT_WriteNoLock(rtt->channel, xfer->buffer, xfer->length); + if (len == xfer->length && xfer->nlength) + { + len += SEGGER_RTT_WriteNoLock(rtt->channel, xfer->nbuffer, + xfer->nlength); + } + + xfer->nbytes = len; + uart_xmitchars_done(dev); +} + +/**************************************************************************** + * Name: serial_rtt_dmareceive + ****************************************************************************/ + +static void serial_rtt_dmareceive(FAR struct uart_dev_s *dev) +{ + FAR struct serial_rtt_s *rtt = dev->priv; + FAR struct uart_dmaxfer_s *xfer = &dev->dmarx; + size_t len; + + len = SEGGER_RTT_ReadNoLock(rtt->channel, xfer->buffer, xfer->length); + if (len == xfer->length && xfer->nbuffer && + SEGGER_RTT_HasData(rtt->channel)) + { + len += SEGGER_RTT_ReadNoLock(rtt->channel, xfer->nbuffer, + xfer->nlength); + } + + xfer->nbytes = len; + uart_recvchars_done(dev); +} + +/**************************************************************************** + * Name: serial_rtt_dmarxfree + ****************************************************************************/ + +static void serial_rtt_dmarxfree(FAR struct uart_dev_s *dev) +{ + /* When the DMA buffer is empty, check whether there is data to read */ + + if (serial_rtt_rxavailable(dev)) + { + uart_recvchars_dma(dev); + } +} + +/**************************************************************************** + * Name: serial_rtt_dmatxavail + ****************************************************************************/ + +static void serial_rtt_dmatxavail(FAR struct uart_dev_s *dev) +{ + if (serial_rtt_txready(dev)) + { + uart_xmitchars_dma(dev); + } +} + +/**************************************************************************** + * Name: serial_rtt_send + ****************************************************************************/ + +static void serial_rtt_send(FAR struct uart_dev_s *dev, int ch) +{ + FAR struct serial_rtt_s *rtt = dev->priv; + + SEGGER_RTT_BLOCK_IF_FIFO_FULL(rtt->channel); + SEGGER_RTT_PutChar(rtt->channel, ch); +} + +/**************************************************************************** + * Name: serial_rtt_txint + ****************************************************************************/ + +static void serial_rtt_txint(FAR struct uart_dev_s *dev, bool enable) +{ +} + +/**************************************************************************** + * Name: serial_rtt_txready + ****************************************************************************/ + +static bool serial_rtt_txready(FAR struct uart_dev_s *dev) +{ + FAR struct serial_rtt_s *rtt = dev->priv; + return SEGGER_RTT_GetAvailWriteSpace(rtt->channel) != 0; +} + +/**************************************************************************** + * Name: serial_rtt_txempty + ****************************************************************************/ + +static bool serial_rtt_txempty(FAR struct uart_dev_s *dev) +{ + FAR struct serial_rtt_s *rtt = dev->priv; + return SEGGER_RTT_GetBytesInBuffer(rtt->channel) == 0; +} + +/**************************************************************************** + * Name: serial_rtt_timeout + ****************************************************************************/ + +static void serial_rtt_timeout(wdparm_t arg) +{ + FAR struct serial_rtt_s *rtt = (FAR struct serial_rtt_s *)arg; + + serial_rtt_dmarxfree(&rtt->uart); + serial_rtt_dmatxavail(&rtt->uart); + wd_start(&rtt->wdog, USEC2TICK(CONFIG_SERIAL_RTT_POLLING_INTERVAL), + serial_rtt_timeout, arg); +} + +/**************************************************************************** + * Name: serial_rtt_register + ****************************************************************************/ + +static void serial_rtt_register(FAR const char *name, + FAR struct serial_rtt_s *rtt) +{ + SEGGER_RTT_ConfigUpBuffer(rtt->channel, name, rtt->up_buffer, + rtt->uart.xmit.size, + SEGGER_RTT_MODE_NO_BLOCK_TRIM); + SEGGER_RTT_ConfigDownBuffer(rtt->channel, name, rtt->down_buffer, + rtt->uart.recv.size, + SEGGER_RTT_MODE_NO_BLOCK_TRIM); + + if (rtt->uart.isconsole) + { + uart_register("/dev/console", &rtt->uart); + } + + uart_register(name, &rtt->uart); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * serial_rtt_initialize + ****************************************************************************/ + +void serial_rtt_initialize(void) +{ +#ifdef CONFIG_SERIAL_RTT0 + serial_rtt_register("/dev/rtt0", &g_serial_rtt0); +#endif + +#ifdef CONFIG_SERIAL_RTT1 + serial_rtt_register("/dev/rtt1", &g_serial_rtt1); +#endif + +#ifdef CONFIG_SERIAL_RTT2 + serial_rtt_register("/dev/rtt2", &g_serial_rtt2); +#endif +} diff --git a/include/nuttx/segger/rtt.h b/include/nuttx/segger/rtt.h index aa4dc41024..0b18528030 100644 --- a/include/nuttx/segger/rtt.h +++ b/include/nuttx/segger/rtt.h @@ -98,6 +98,14 @@ ssize_t syslog_rtt_write(FAR struct syslog_channel_s *channel, FAR const char *buffer, size_t buflen); #endif +/**************************************************************************** +* Name: serial_rtt_initialize +*****************************************************************************/ + +#ifdef CONFIG_SERIAL_RTT +void serial_rtt_initialize(void); +#endif + #ifdef __cplusplus } #endif