diff --git a/multi/imxrt-multi/Makefile b/multi/imxrt-multi/Makefile index f970cdc2..3f0422e5 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 rtt.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..3394290d 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 "rtt.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 + rtt_handleMsg(msg, RTT_CHANNEL_CONSOLE + id_rtt0); +#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_rtt0: + case id_rtt1: + rtt_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_rtt0, "rtt0", common.uart_port) < 0) { + return -1; + } +#endif + +#if RTT_CHANNEL1 + if (mkFile(&dir, id_rtt1, "rtt1", common.uart_port) < 0) { + return -1; + } #endif /* GPIOs */ @@ -577,6 +599,7 @@ int main(void) #endif uart_init(); + rtt_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(rtt_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..ac954cbc 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_rtt0, id_rtt1, }; /* clang-format on */ diff --git a/multi/imxrt-multi/rtt.c b/multi/imxrt-multi/rtt.c new file mode 100644 index 00000000..d93ffc4c --- /dev/null +++ b/multi/imxrt-multi/rtt.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 "rtt.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 rtt_s { + int chn; + handle_t lock; + libtty_common_t tty_common; + volatile unsigned int diag_txSkipped; /* Accessed using a debugger */ +} rtt_t; + +static struct { + char stack[1024] __attribute__((aligned(8))); + rtt_t uarts[RTT_ACTIVE_CNT]; +} rtt_common; + + +static const int rttConfig[] = { RTT_CHANNEL0, RTT_CHANNEL1 }; + + +static const int rttBlocking[] = { RTT_CHANNEL0_BLOCKING, RTT_CHANNEL1_BLOCKING }; + + +static const int rttPos[] = { RTT_CHANNEL0_POS, RTT_CHANNEL1_POS }; + + +#define RTT_CHANNEL_CNT (sizeof(rttConfig) / sizeof(rttConfig[0])) + + +static inline ssize_t rtt_txAvailMode(unsigned int chn) +{ + return (rttBlocking[chn] != 0) ? librtt_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++) { + rtt_t *uart = &rtt_common.uarts[chn_idx]; + unsigned char data; + ssize_t onRx = librtt_rxAvail(uart->chn); + ssize_t onTx = rtt_txAvailMode(uart->chn); + int txReady = libtty_txready(&uart->tty_common); + + if (rttBlocking[uart->chn] == 0) { + /* Do nothing, in this case the remaining code is unnecessary */ + } + else if (librtt_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) { + librtt_read(uart->chn, &data, 1); + libtty_putchar(&uart->tty_common, data & mask, NULL); + onRx = librtt_rxAvail(uart->chn); + } + + while (onTx > 0 && txReady) { + data = libtty_getchar(&uart->tty_common, NULL); + ssize_t written = librtt_write(uart->chn, &data, 1, 0); + if (written <= 0) { + uart->diag_txSkipped++; + } + + onTx = rtt_txAvailMode(uart->chn); + txReady = libtty_txready(&uart->tty_common); + } + + mutexUnlock(uart->lock); + } + + usleep(RTT_POLLING_RATE_MS * 1000); + } +} + + +static int rtt_initOne(rtt_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) ? librtt_initChannel(1, chn, buf, RTT_TX_BUF_SIZE) : ret; + ret = (ret == 0) ? librtt_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 rtt_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 + LIBRTT_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 = librtt_init((void *)RTT_ADDR, NULL, NULL); + if (ret != 0) { + librtt_done(); + munmap(rttBuffer, mapSize); + return ret; + } + + unsigned char *buf = rttBuffer; + for (int i = 0, chn = 0; chn < RTT_CHANNEL_CNT; ++chn) { + if (rttConfig[chn] == 0) { + continue; + } + + rtt_t *uart = &rtt_common.uarts[i++]; + int ret = rtt_initOne(uart, chn, buf); + if (ret != 0) { + librtt_done(); + munmap(rttBuffer, mapSize); + return ret; + } + + buf += RTT_RX_BUF_SIZE + RTT_TX_BUF_SIZE; + } + + beginthread(rtt_thread, IMXRT_MULTI_PRIO, rtt_common.stack, sizeof(rtt_common.stack), NULL); + return ret; +} + +void rtt_klogCblk(const char *data, size_t size) +{ +#ifdef RTT_CHANNEL_CONSOLE + libtty_write(&rtt_common.uarts[rttPos[RTT_CHANNEL_CONSOLE]].tty_common, data, size, 0); +#endif +} + + +int rtt_handleMsg(msg_t *msg, int dev) +{ + unsigned long request; + const void *in_data, *out_data = NULL; + pid_t pid; + int err; + rtt_t *uart; + + dev -= id_rtt0; + + if ((dev < 0) || (dev >= RTT_CHANNEL_CNT) || (rttConfig[dev] == 0)) { + return -EINVAL; + } + + uart = &rtt_common.uarts[rttPos[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/rtt.h b/multi/imxrt-multi/rtt.h new file mode 100644 index 00000000..488d2770 --- /dev/null +++ b/multi/imxrt-multi/rtt.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 _RTT_H_ +#define _RTT_H_ + +#include +#include + +#include + + +int rtt_init(void); + + +int rtt_handleMsg(msg_t *msg, int dev); + + +void rtt_klogCblk(const char *data, size_t size); + + +#endif /* _RTT_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 }