diff --git a/hal/arm/Makefile b/hal/arm/Makefile index c0be07d5..0542551b 100644 --- a/hal/arm/Makefile +++ b/hal/arm/Makefile @@ -7,4 +7,4 @@ # TODO handle other common ARM stuff (e.g GIC) and # select relevant components here -OBJS += $(addprefix $(PREFIX_O)hal/arm/, nvic.o scb.o) +OBJS += $(addprefix $(PREFIX_O)hal/arm/, nvic.o scb.o rtt.o) diff --git a/hal/arm/rtt.c b/hal/arm/rtt.c new file mode 100644 index 00000000..96ed5646 --- /dev/null +++ b/hal/arm/rtt.c @@ -0,0 +1,154 @@ +/* + * Phoenix-RTOS + * + * SEGGER's Real Time Transfer - simplified driver + * + * Copyright 2023-2024 Phoenix Systems + * Author: Gerard Swiderski, Daniel Sawka + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "include/errno.h" +#include "syspage.h" +#include "hal/arm/barriers.h" + +#include +#include "rtt.h" + +#ifndef RTT_SYSPAGE_MAP_NAME +#define RTT_SYSPAGE_MAP_NAME "rtt" +#endif + +#ifndef RTT_CB_SIZE +#define RTT_CB_SIZE 256 +#endif + + +struct rtt_pipe { + const char *name; + volatile unsigned char *ptr; + unsigned int sz; + volatile unsigned int wr; + volatile unsigned int rd; + unsigned int flags; +}; + + +struct rtt_desc { + char tag[16]; + unsigned int txChannels; + unsigned int rxChannels; + struct rtt_pipe channels[]; +}; + + +static struct { + volatile struct rtt_desc *rtt; +} common; + + +static int rtt_check(unsigned int chan, rtt_dir_t dir) +{ + if ((dir == rtt_dir_up) && (chan >= common.rtt->txChannels)) { + return -ENODEV; + } + + if ((dir == rtt_dir_down) && (chan >= common.rtt->rxChannels)) { + return -ENODEV; + } + + return 0; +} + + +int _hal_rttWrite(unsigned int chan, const void *buf, unsigned int count) +{ + unsigned int sz; + unsigned int rd; + unsigned int wr; + unsigned int todo; + volatile unsigned char *dstBuf; + + if (rtt_check(chan, rtt_dir_up) < 0) { + return -ENODEV; + } + + hal_cpuDataMemoryBarrier(); + dstBuf = common.rtt->channels[chan].ptr; + sz = common.rtt->channels[chan].sz - 1; + rd = (common.rtt->channels[chan].rd + sz) & sz; + wr = common.rtt->channels[chan].wr & sz; + todo = count; + + /* TODO: Support all buffer modes (currently only trim is used, regardless of flags) */ + while ((todo != 0) && (rd != wr)) { + dstBuf[wr] = *(unsigned char *)buf++; + wr = (wr + 1) & sz; + todo--; + } + + hal_cpuDataMemoryBarrier(); + common.rtt->channels[chan].wr = wr; + + return count - todo; +} + + +int _hal_rttTxAvail(unsigned int chan) +{ + unsigned int sz; + unsigned int rd; + unsigned int wr; + + if (rtt_check(chan, rtt_dir_up) < 0) { + return -ENODEV; + } + + hal_cpuDataMemoryBarrier(); + sz = common.rtt->channels[chan].sz - 1; + rd = (common.rtt->channels[chan].rd + sz) & sz; + wr = common.rtt->channels[chan].wr & sz; + + if (wr > rd) { + return sz + 1 - (wr - rd); + } + else { + return rd - wr; + } +} + + +int _hal_rttReset(unsigned int chan, rtt_dir_t dir) +{ + if (rtt_check(chan, dir) < 0) { + return -ENODEV; + } + + hal_cpuDataMemoryBarrier(); + if (dir == rtt_dir_up) { + common.rtt->channels[chan].wr = common.rtt->channels[chan].rd; + } + else { + chan = common.rtt->txChannels + chan; + common.rtt->channels[chan].rd = common.rtt->channels[chan].wr; + } + hal_cpuDataMemoryBarrier(); + return 0; +} + + +int _hal_rttInit(void) +{ + const syspage_map_t *map = syspage_mapNameResolve(RTT_SYSPAGE_MAP_NAME); + + if (map == NULL) { + return -ENOENT; + } + + /* TODO: Place CB always at the start of the map? */ + common.rtt = (void *)(map->end - RTT_CB_SIZE); + return 0; +} diff --git a/hal/arm/rtt.h b/hal/arm/rtt.h new file mode 100644 index 00000000..fa6ffe81 --- /dev/null +++ b/hal/arm/rtt.h @@ -0,0 +1,47 @@ +/* + * Phoenix-RTOS + * + * SEGGER's Real Time Transfer - simplified driver + * + * Copyright 2023-2024 Phoenix Systems + * Author: Gerard Swiderski, Daniel Sawka + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef HAL_ARM_RTT_H_ +#define HAL_ARM_RTT_H_ + + +typedef enum { + rtt_dir_up, /* tx: target -> host */ + rtt_dir_down, /* rx: host -> target */ +} rtt_dir_t; + + +typedef enum { + rtt_mode_skip = 0, /* write if the whole message can be written at once; discard the message otherwise */ + rtt_mode_trim = 1, /* write anything if possible; discard the remaining unwritten data otherwise */ + rtt_mode_blocking = 2, /* wait until writable */ +} rtt_mode_t; + + +/* Initialize rtt internal structures */ +int _hal_rttInit(void); + + +/* Non-blocking write to channel */ +int _hal_rttWrite(unsigned int chan, const void *buf, unsigned int count); + + +/* Check for available space in tx */ +int _hal_rttTxAvail(unsigned int chan); + + +/* Reset fifo pointers */ +int _hal_rttReset(unsigned int chan, rtt_dir_t dir); + + +#endif /* end of HAL_ARM_RTT_H_ */ diff --git a/hal/armv7m/imxrt/10xx/console.c b/hal/armv7m/imxrt/10xx/console.c index 266eb129..09df6e7d 100644 --- a/hal/armv7m/imxrt/10xx/console.c +++ b/hal/armv7m/imxrt/10xx/console.c @@ -3,7 +3,7 @@ * * Operating system kernel * - * HAL console (iMXRT USART) + * HAL console (iMXRT USART + RTT) * * Copyright 2016-2017 Phoenix Systems * Author: Pawel Pisarczyk, Artur Wodejko, Aleksander Kaminski @@ -14,21 +14,35 @@ */ #include "hal/console.h" +#include "hal/arm/rtt.h" #include "include/arch/armv7m/imxrt/10xx/imxrt10xx.h" #include "imxrt10xx.h" +#include "lib/helpers.h" #include #include -#ifndef UART_CONSOLE -#define UART_CONSOLE 1 +#ifndef UART_CONSOLE_KERNEL +#ifdef UART_CONSOLE +#define UART_CONSOLE_KERNEL UART_CONSOLE +#else +#define UART_CONSOLE_KERNEL 1 +#endif +#endif + +#ifndef RTT_CONSOLE_KERNEL +#if RTT_ENABLED +#define RTT_CONSOLE_KERNEL 0 +#else +#define RTT_CONSOLE_KERNEL +#endif #endif #define CONCAT3(a, b, c) a##b##c #define CONSOLE_BAUD(n) (CONCAT3(UART, n, _BAUDRATE)) -#if CONSOLE_BAUD(UART_CONSOLE) -#define CONSOLE_BAUDRATE CONSOLE_BAUD(UART_CONSOLE) +#if !ISEMPTY(UART_CONSOLE_KERNEL) && CONSOLE_BAUD(UART_CONSOLE_KERNEL) +#define CONSOLE_BAUDRATE CONSOLE_BAUD(UART_CONSOLE_KERNEL) #else #define CONSOLE_BAUDRATE 115200 #endif @@ -63,16 +77,23 @@ void hal_consolePrint(int attr, const char *s) void hal_consolePutch(char c) { +#if RTT_ENABLED && !ISEMPTY(RTT_CONSOLE_KERNEL) + _hal_rttWrite(RTT_CONSOLE_KERNEL, &c, 1); +#endif + +#if !ISEMPTY(UART_CONSOLE_KERNEL) while (!(*(console_common.uart + uart_stat) & (1 << 23))) ; *(console_common.uart + uart_data) = c; +#endif } -void _hal_consoleInit(void) +#if !ISEMPTY(UART_CONSOLE_KERNEL) +static void _hal_uartInit(void) { - u32 t, console = UART_CONSOLE - 1; + u32 t, console = UART_CONSOLE_KERNEL - 1; static const struct { volatile u32 *base; @@ -155,3 +176,16 @@ void _hal_consoleInit(void) /* Enable TX and RX */ *(console_common.uart + uart_ctrl) |= (1 << 19) | (1 << 18); } +#endif + + +void _hal_consoleInit(void) +{ +#if RTT_ENABLED && !ISEMPTY(RTT_CONSOLE_KERNEL) + _hal_rttInit(); +#endif + +#if !ISEMPTY(UART_CONSOLE_KERNEL) + _hal_uartInit(); +#endif +} diff --git a/hal/armv7m/imxrt/117x/console.c b/hal/armv7m/imxrt/117x/console.c index 146edac8..cb021560 100644 --- a/hal/armv7m/imxrt/117x/console.c +++ b/hal/armv7m/imxrt/117x/console.c @@ -3,7 +3,7 @@ * * Operating system kernel * - * HAL console (i.MX RT1170 UART) + * HAL console (i.MX RT1170 UART + RTT) * * Copyright 2016-2017, 2019 Phoenix Systems * Author: Pawel Pisarczyk, Artur Wodejko, Aleksander Kaminski @@ -14,21 +14,35 @@ */ #include "hal/console.h" +#include "hal/arm/rtt.h" #include "include/arch/armv7m/imxrt/11xx/imxrt1170.h" #include "imxrt117x.h" +#include "lib/helpers.h" #include #include -#ifndef UART_CONSOLE -#define UART_CONSOLE 11 +#ifndef UART_CONSOLE_KERNEL +#ifdef UART_CONSOLE +#define UART_CONSOLE_KERNEL UART_CONSOLE +#else +#define UART_CONSOLE_KERNEL 11 +#endif +#endif + +#ifndef RTT_CONSOLE_KERNEL +#if RTT_ENABLED +#define RTT_CONSOLE_KERNEL 0 +#else +#define RTT_CONSOLE_KERNEL +#endif #endif #define CONCAT3(a, b, c) a##b##c #define CONSOLE_BAUD(n) (CONCAT3(UART, n, _BAUDRATE)) -#if CONSOLE_BAUD(UART_CONSOLE) -#define CONSOLE_BAUDRATE CONSOLE_BAUD(UART_CONSOLE) +#if !ISEMPTY(UART_CONSOLE_KERNEL) && CONSOLE_BAUD(UART_CONSOLE_KERNEL) +#define CONSOLE_BAUDRATE CONSOLE_BAUD(UART_CONSOLE_KERNEL) #else #define CONSOLE_BAUDRATE 115200 #endif @@ -63,16 +77,23 @@ void hal_consolePrint(int attr, const char *s) void hal_consolePutch(char c) { +#if RTT_ENABLED && !ISEMPTY(RTT_CONSOLE_KERNEL) + _hal_rttWrite(RTT_CONSOLE_KERNEL, &c, 1); +#endif + +#if !ISEMPTY(UART_CONSOLE_KERNEL) while (!(*(console_common.uart + uart_stat) & (1 << 23))) ; *(console_common.uart + uart_data) = c; +#endif } -void _hal_consoleInit(void) +#if !ISEMPTY(UART_CONSOLE_KERNEL) +static void _hal_uartInit(void) { - u32 t, console = UART_CONSOLE - 1; + u32 t, console = UART_CONSOLE_KERNEL - 1; static const struct { volatile u32 *base; @@ -156,3 +177,16 @@ void _hal_consoleInit(void) /* Enable TX and RX */ *(console_common.uart + uart_ctrl) |= (1 << 19) | (1 << 18); } +#endif + + +void _hal_consoleInit(void) +{ +#if RTT_ENABLED && !ISEMPTY(RTT_CONSOLE_KERNEL) + _hal_rttInit(); +#endif + +#if !ISEMPTY(UART_CONSOLE_KERNEL) + _hal_uartInit(); +#endif +} diff --git a/lib/helpers.h b/lib/helpers.h new file mode 100644 index 00000000..1f2c3342 --- /dev/null +++ b/lib/helpers.h @@ -0,0 +1,35 @@ +/* + * Phoenix-RTOS + * + * Generic useful macros + * + * Copyright 2024 Phoenix Systems + * Author: Daniel Sawka + * + * %LICENSE% + */ + +#ifndef _LIB_HELPERS_H_ +#define _LIB_HELPERS_H_ + +/* +These macros should only be used in `#if` and `#elif` directives, because undefined identifiers expand to 0 there. +Otherwise there will be "use of undefined identifier" errors (an exception: identifier is first checked for +existence with e.g. `#ifdef`). + +Anything that expands to a numerical expression (or to an empty value) is fine. String literals don't work. +*/ + +/* +These macros produce a logically correct result only if X is defined. You may use `#ifdef` or `defined()` +for this purpose. Unfortunately, `defined()` cannot be conveniently put inside a macro as this is undefined +behavior (see -Wexpansion-to-defined for details), so you have to use it directly on the spot, for example: +`#if defined(PERIPH1) && !ISEMPTY(PERIPH1) +// Use PERIPH1 +#endif` +*/ + +/* True if X is empty (has no value). The result in #if is valid only if defined(X) is true */ +#define ISEMPTY(X) ((0 - X - 1) == 1 && (X + 0) != -2) + +#endif