drivers/segger: add RTT serial support

usage:
  1. Connect Jlink, start JLinkGDBServer
     JLinkGDBServer -if SWD -device stm32h743zi -speed 16000
  2. Listen to the RTT port data and forward it to the virtual serial port
     sudo socat -d -d PTY,link=/dev/ttyRTT0,raw,ignoreeof TCP:127.0.0.1:19021,reuseaddr
  3. Read serial data
     minicom -D /dev/ttyRTT0

Performance:(STM32H743, 400MHZ)
time "dd if=/dev/zero of=/dev/console bs=512 count=2048"
6.67 sec  157KB/s

Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
This commit is contained in:
yinshengkai 2023-07-06 22:09:05 +08:00 committed by Xiang Xiao
parent e1553e8407
commit 9c6f48e57b
5 changed files with 555 additions and 0 deletions

View File

@ -38,6 +38,7 @@
#include <nuttx/note/note_driver.h>
#include <nuttx/power/pm.h>
#include <nuttx/power/regulator.h>
#include <nuttx/segger/rtt.h>
#include <nuttx/sensors/sensor.h>
#include <nuttx/serial/pty.h>
#include <nuttx/syslog/syslog.h>
@ -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

View File

@ -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"

View File

@ -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

459
drivers/segger/serial_rtt.c Normal file
View File

@ -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 <assert.h>
#include <sys/types.h>
#include <syslog.h>
#include <nuttx/kmalloc.h>
#include <nuttx/segger/rtt.h>
#include <nuttx/serial/serial.h>
#include <nuttx/wdog.h>
#include <SEGGER_RTT.h>
/****************************************************************************
* 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
}

View File

@ -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