From 9dcc4ef5af597e580f5cd30581c1ef16d5eb055d Mon Sep 17 00:00:00 2001 From: Jacek Maksymowicz Date: Thu, 12 Sep 2024 16:10:13 +0200 Subject: [PATCH] imxrt-multi: add support for console over RTT JIRA: RTOS-754 --- librtt/rtt.c | 9 +- multi/imxrt-multi/Makefile | 4 +- multi/imxrt-multi/config.h | 50 +++++- multi/imxrt-multi/imxrt-multi.c | 27 ++++ multi/imxrt-multi/imxrt-multi.h | 3 +- multi/imxrt-multi/rttuart.c | 265 ++++++++++++++++++++++++++++++++ multi/imxrt-multi/rttuart.h | 32 ++++ multi/imxrt-multi/uart.c | 4 +- 8 files changed, 387 insertions(+), 7 deletions(-) create mode 100644 multi/imxrt-multi/rttuart.c create mode 100644 multi/imxrt-multi/rttuart.h diff --git a/librtt/rtt.c b/librtt/rtt.c index 751d2adb..eee45e34 100644 --- a/librtt/rtt.c +++ b/librtt/rtt.c @@ -357,12 +357,17 @@ int rtt_initChannel(int isTx, unsigned int ch, unsigned char *buf, size_t sz) } } - ch += (isTx != 0) ? 0 : rtt->txChannels; + if (isTx != 0) { + librtt_common.lastRd[ch] = 0; + } + else { + ch += rtt->txChannels; + } + rtt->channel[ch].name = name; rtt->channel[ch].ptr = buf; rtt->channel[ch].sz = sz; rtt->channel[ch].rd = 0; - librtt_common.lastRd[ch] = 0; rtt->channel[ch].wr = 0; return 0; } diff --git a/multi/imxrt-multi/Makefile b/multi/imxrt-multi/Makefile index f970cdc2..1534495e 100644 --- a/multi/imxrt-multi/Makefile +++ b/multi/imxrt-multi/Makefile @@ -8,13 +8,13 @@ NAME := imxrt-multi LOCAL_PATH := $(call my-dir) -LOCAL_SRCS = imxrt-multi.c common.c uart.c gpio.c spi.c i2c.c fs.c posixsrv.c pct2075.c +LOCAL_SRCS = imxrt-multi.c common.c uart.c gpio.c spi.c i2c.c fs.c posixsrv.c pct2075.c rttuart.c ifneq ($(TARGET_SUBFAMILY), imxrt117x) LOCAL_SRCS += trng.c else LOCAL_SRCS += cm4.c endif -DEP_LIBS := libtty libklog libpseudodev i2c-common +DEP_LIBS := libtty libklog libpseudodev i2c-common librtt LIBS := libdummyfs libklog libpseudodev libposixsrv LOCAL_HEADERS := imxrt-multi.h diff --git a/multi/imxrt-multi/config.h b/multi/imxrt-multi/config.h index 26b06c6e..5f1c7f68 100644 --- a/multi/imxrt-multi/config.h +++ b/multi/imxrt-multi/config.h @@ -754,7 +754,7 @@ /* clang-format on */ -#ifndef UART_CONSOLE +#if !defined(UART_CONSOLE) && !defined(RTT_CHANNEL_CONSOLE) #if defined(__CPU_IMXRT105X) #define UART_CONSOLE 1 #elif defined(__CPU_IMXRT106X) @@ -766,6 +766,54 @@ #endif #endif +#if defined(UART_CONSOLE) +#if ISEMPTY(UART_CONSOLE) +#error "UART_CONSOLE must not be empty" +#elif UART_CONSOLE <= 0 +#error "Invalid value for UART_CONSOLE" +#endif +#endif + + +/* RTT */ + +#ifndef RTT_CHANNEL0 +#define RTT_CHANNEL0 0 +#elif !ISBOOLEAN(RTT_CHANNEL0) +#error "RTT_CHANNEL0 must have a value of 0, 1, or be undefined" +#endif + +#ifndef RTT_CHANNEL1 +#define RTT_CHANNEL1 0 +#elif !ISBOOLEAN(RTT_CHANNEL1) +#error "RTT_CHANNEL1 must have a value of 0, 1, or be undefined" +#endif + +#ifndef RTT_CHANNEL0_BLOCKING +#define RTT_CHANNEL0_BLOCKING 0 +#elif !ISBOOLEAN(RTT_CHANNEL0_BLOCKING) +#error "RTT_CHANNEL0_BLOCKING must have a value of 0, 1, or be undefined" +#endif + +#ifndef RTT_CHANNEL1_BLOCKING +#define RTT_CHANNEL1_BLOCKING 0 +#elif !ISBOOLEAN(RTT_CHANNEL1_BLOCKING) +#error "RTT_CHANNEL1_BLOCKING must have a value of 0, 1, or be undefined" +#endif + + +#if defined(UART_CONSOLE) && defined(RTT_CHANNEL_CONSOLE) +#error "Console on UART and RTT not supported" +#elif defined(RTT_CHANNEL_CONSOLE) +#if ISEMPTY(RTT_CHANNEL_CONSOLE) +#error "RTT_CHANNEL_CONSOLE must not be empty" +#elif RTT_CHANNEL_CONSOLE < 0 +#error "Invalid value for RTT_CHANNEL_CONSOLE" +#endif + +#define ONLY_RTT_CONSOLE +#endif + /* SPI */ diff --git a/multi/imxrt-multi/imxrt-multi.c b/multi/imxrt-multi/imxrt-multi.c index d3691cef..3ff37df7 100644 --- a/multi/imxrt-multi/imxrt-multi.c +++ b/multi/imxrt-multi/imxrt-multi.c @@ -33,6 +33,7 @@ #include "common.h" #include "uart.h" +#include "rttuart.h" #include "gpio.h" #include "spi.h" #include "i2c.h" @@ -168,7 +169,11 @@ static void uart_dispatchMsg(msg_t *msg) switch (id) { case id_console: +#ifdef ONLY_RTT_CONSOLE + rttuart_handleMsg(msg, RTT_CHANNEL_CONSOLE + id_rttuart0); +#else uart_handleMsg(msg, UART_CONSOLE - 1 + id_uart1); +#endif break; case id_uart1: @@ -191,6 +196,11 @@ static void uart_dispatchMsg(msg_t *msg) break; #endif + case id_rttuart0: + case id_rttuart1: + rttuart_handleMsg(msg, id); + break; + default: msg->o.err = -ENODEV; break; @@ -335,6 +345,18 @@ static int createDevFiles(void) } #endif +#endif + +#if RTT_CHANNEL0 + if (mkFile(&dir, id_rttuart0, "rttuart0", common.uart_port) < 0) { + return -1; + } +#endif + +#if RTT_CHANNEL1 + if (mkFile(&dir, id_rttuart1, "rttuart1", common.uart_port) < 0) { + return -1; + } #endif /* GPIOs */ @@ -577,6 +599,7 @@ int main(void) #endif uart_init(); + rttuart_init(); gpio_init(); spi_init(); i2c_init(); @@ -585,7 +608,11 @@ int main(void) oid.id = id_console; create_dev(&oid, _PATH_CONSOLE); +#ifdef ONLY_RTT_CONSOLE + libklog_init(rttuart_klogCblk); +#else libklog_init(uart_klogCblk); +#endif oid_t kmsgctrl = { .port = common.uart_port, .id = id_kmsgctrl }; libklog_ctrlRegister(&kmsgctrl); diff --git a/multi/imxrt-multi/imxrt-multi.h b/multi/imxrt-multi/imxrt-multi.h index 13f768d2..5283a5f4 100644 --- a/multi/imxrt-multi/imxrt-multi.h +++ b/multi/imxrt-multi/imxrt-multi.h @@ -31,7 +31,8 @@ enum { id_console = 0, id_uart1, id_uart2, id_uart3, id_uart4, id_uart5, id_uart id_i2c5, id_i2c6, id_cm4_0, id_cm4_1, id_cm4_2, id_cm4_3, #endif - id_trng, id_pseudoNull, id_pseudoZero, id_pseudoFull, id_pseudoRandom, id_kmsgctrl, id_temp1 + id_trng, id_pseudoNull, id_pseudoZero, id_pseudoFull, id_pseudoRandom, id_kmsgctrl, id_temp1, + id_rttuart0, id_rttuart1, }; /* clang-format on */ diff --git a/multi/imxrt-multi/rttuart.c b/multi/imxrt-multi/rttuart.c new file mode 100644 index 00000000..2e1a4151 --- /dev/null +++ b/multi/imxrt-multi/rttuart.c @@ -0,0 +1,265 @@ +/* + * Phoenix-RTOS + * + * iMX RT RTT communication driver + * + * Copyright 2017-2024 Phoenix Systems + * Author: Kamil Amanowicz, Marek Bialowas, Aleksander Kaminski, Jacek Maksymowicz + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "rttuart.h" + + +#ifndef RTT_ADDR +/* RTT descriptors location, last 256 bytes of DTCM */ +#define RTT_ADDR (0x20040000 - 0x100) +#endif + +#define RTT_TX_BUF_SIZE 1024 +#define RTT_RX_BUF_SIZE 256 +#define RTT_POLLING_RATE_MS 20 +#define RTT_NO_PICKUP_TIMEOUT_MS (2 * RTT_POLLING_RATE_MS) +#define RTT_RETRIES (RTT_NO_PICKUP_TIMEOUT_MS / RTT_POLLING_RATE_MS) + +/* Doesn't need to be large, data will mostly be stored in RTT buffers */ +#define TTY_BUF_SIZE 64 + +#define RTT_CHANNEL0_POS 0 +#define RTT_CHANNEL1_POS (RTT_CHANNEL0_POS + RTT_CHANNEL0) +#define RTT_ACTIVE_CNT (RTT_CHANNEL0 + RTT_CHANNEL1) + +typedef struct rttuart_s { + int chn; + handle_t lock; + libtty_common_t tty_common; + volatile unsigned int diag_txSkipped; /* Accessed using a debugger */ +} rttuart_t; + +static struct { + char stack[1024] __attribute__((aligned(8))); + rttuart_t uarts[RTT_ACTIVE_CNT]; +} rttuart_common; + + +static const int rttuartConfig[] = { RTT_CHANNEL0, RTT_CHANNEL1 }; + + +static const int rttuartBlocking[] = { RTT_CHANNEL0_BLOCKING, RTT_CHANNEL1_BLOCKING }; + + +static const int rttuartPos[] = { RTT_CHANNEL0_POS, RTT_CHANNEL1_POS }; + + +#define RTT_CHANNEL_CNT (sizeof(rttuartConfig) / sizeof(rttuartConfig[0])) + + +static inline ssize_t rttuart_txAvailMode(unsigned int chn) +{ + return (rttuartBlocking[chn] != 0) ? rtt_txAvail(chn) : 1; +} + + +static void rtt_thread(void *arg) +{ + unsigned retries[RTT_ACTIVE_CNT]; + memset(retries, 0, sizeof(retries)); + + for (;;) { + for (int chn_idx = 0; chn_idx < RTT_ACTIVE_CNT; chn_idx++) { + rttuart_t *uart = &rttuart_common.uarts[chn_idx]; + unsigned char data; + ssize_t onRx = rtt_rxAvail(uart->chn); + ssize_t onTx = rttuart_txAvailMode(uart->chn); + int txReady = libtty_txready(&uart->tty_common); + + if (rttuartBlocking[uart->chn] == 0) { + /* Do nothing, in this case the remaining code is unnecessary */ + } + else if (rtt_txCheckReaderAttached(uart->chn) != 0) { + retries[chn_idx] = RTT_RETRIES; + } + else if (onTx == 0) { + if (retries[chn_idx] == 0) { + onTx = 1; + } + else { + retries[chn_idx]--; + } + } + + + if ((onRx == 0) && ((txReady == 0) || (onTx == 0))) { + continue; + } + + mutexLock(uart->lock); + const unsigned char mask = ((uart->tty_common.term.c_cflag & CSIZE) == CS7) ? 0x7f : 0xff; + while (onRx > 0) { + rtt_read(uart->chn, &data, 1); + libtty_putchar(&uart->tty_common, data & mask, NULL); + onRx = rtt_rxAvail(uart->chn); + } + + while (onTx > 0 && txReady) { + data = libtty_getchar(&uart->tty_common, NULL); + ssize_t written = rtt_write(uart->chn, &data, 1, 0); + if (written <= 0) { + uart->diag_txSkipped++; + } + + onTx = rttuart_txAvailMode(uart->chn); + txReady = libtty_txready(&uart->tty_common); + } + + mutexUnlock(uart->lock); + } + + usleep(RTT_POLLING_RATE_MS * 1000); + } +} + + +static int rttuart_initOne(rttuart_t *uart, int chn, unsigned char *buf) +{ + libtty_callbacks_t callbacks; + callbacks.arg = uart; + callbacks.set_baudrate = NULL; + callbacks.set_cflag = NULL; + callbacks.signal_txready = NULL; + + uart->chn = chn; + + int ret = 0; + ret = (ret == 0) ? rtt_initChannel(1, chn, buf, RTT_TX_BUF_SIZE) : ret; + ret = (ret == 0) ? rtt_initChannel(0, chn, buf + RTT_TX_BUF_SIZE, RTT_RX_BUF_SIZE) : ret; + ret = (ret == 0) ? mutexCreate(&uart->lock) : ret; + /* TODO: calculate approx. baud rate based on buffer size and polling rate */ + ret = (ret == 0) ? libtty_init(&uart->tty_common, &callbacks, TTY_BUF_SIZE, libtty_int_to_baudrate(115200)) : ret; + + return ret; +} + + +int rttuart_init(void) +{ + if (RTT_ACTIVE_CNT == 0) { + return EOK; + } + + /* Reserve memory for the descriptor and buffers */ + intptr_t startAddr = (RTT_ADDR - (RTT_ACTIVE_CNT * (RTT_TX_BUF_SIZE + RTT_RX_BUF_SIZE))) & ~(_PAGE_SIZE - 1); + size_t mapSize = RTT_ADDR + RTT_DESC_SIZE - startAddr; + unsigned char *rttBuffer = mmap( + NULL, + mapSize, + PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_UNCACHED | MAP_PHYSMEM, + -1, + startAddr); + + if (rttBuffer == MAP_FAILED) { + return -ENOMEM; + } + + int ret = rtt_init((void *)RTT_ADDR, NULL, NULL); + if (ret != 0) { + rtt_done(); + munmap(rttBuffer, mapSize); + return ret; + } + + unsigned char *buf = rttBuffer; + for (int i = 0, chn = 0; chn < RTT_CHANNEL_CNT; ++chn) { + if (rttuartConfig[chn] == 0) { + continue; + } + + rttuart_t *uart = &rttuart_common.uarts[i++]; + int ret = rttuart_initOne(uart, chn, buf); + if (ret != 0) { + rtt_done(); + munmap(rttBuffer, mapSize); + return ret; + } + + buf += RTT_RX_BUF_SIZE + RTT_TX_BUF_SIZE; + } + + beginthread(rtt_thread, IMXRT_MULTI_PRIO, rttuart_common.stack, sizeof(rttuart_common.stack), NULL); + return ret; +} + +void rttuart_klogCblk(const char *data, size_t size) +{ +#ifdef RTT_CHANNEL_CONSOLE + libtty_write(&rttuart_common.uarts[rttuartPos[RTT_CHANNEL_CONSOLE]].tty_common, data, size, 0); +#endif +} + + +int rttuart_handleMsg(msg_t *msg, int dev) +{ + unsigned long request; + const void *in_data, *out_data = NULL; + pid_t pid; + int err; + rttuart_t *uart; + + dev -= id_rttuart0; + + if ((dev < 0) || (dev >= RTT_CHANNEL_CNT) || (rttuartConfig[dev] == 0)) { + return -EINVAL; + } + + uart = &rttuart_common.uarts[rttuartPos[dev]]; + + switch (msg->type) { + case mtWrite: + msg->o.err = libtty_write(&uart->tty_common, msg->i.data, msg->i.size, msg->i.io.mode); + break; + + case mtRead: + msg->o.err = libtty_read(&uart->tty_common, msg->o.data, msg->o.size, msg->i.io.mode); + break; + + case mtGetAttr: + if (msg->i.attr.type != atPollStatus) { + msg->o.err = -ENOSYS; + break; + } + + msg->o.attr.val = libtty_poll_status(&uart->tty_common); + msg->o.err = EOK; + break; + + case mtDevCtl: + in_data = ioctl_unpack(msg, &request, NULL); + pid = ioctl_getSenderPid(msg); + err = libtty_ioctl(&uart->tty_common, pid, request, in_data, &out_data); + ioctl_setResponse(msg, request, err, out_data); + break; + + default: + msg->o.err = -ENOSYS; + break; + } + + return EOK; +} diff --git a/multi/imxrt-multi/rttuart.h b/multi/imxrt-multi/rttuart.h new file mode 100644 index 00000000..3aabb3f4 --- /dev/null +++ b/multi/imxrt-multi/rttuart.h @@ -0,0 +1,32 @@ +/* + * Phoenix-RTOS + * + * iMX RT RTT communication driver + * + * Copyright 2024 Phoenix Systems + * Author: Jacek Maksymowicz + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _RTTUART_H_ +#define _RTTUART_H_ + +#include +#include + +#include + + +int rttuart_init(void); + + +int rttuart_handleMsg(msg_t *msg, int dev); + + +void rttuart_klogCblk(const char *data, size_t size); + + +#endif /* _RTTUART_H_ */ diff --git a/multi/imxrt-multi/uart.c b/multi/imxrt-multi/uart.c index 2eead088..c27b78f0 100644 --- a/multi/imxrt-multi/uart.c +++ b/multi/imxrt-multi/uart.c @@ -772,7 +772,9 @@ static void uart_initPins(void) void uart_klogCblk(const char *data, size_t size) { - libtty_write(&uart_common.uarts[uartPos[UART_CONSOLE - id_uart1]].tty_common, data, size, 0); +#ifdef UART_CONSOLE + libtty_write(&uart_common.uarts[uartPos[UART_CONSOLE - 1]].tty_common, data, size, 0); +#endif }