From 612f5efbd7b7150d807412eb91e4e432d7e6b56c Mon Sep 17 00:00:00 2001 From: Damian Loewnau Date: Sun, 16 Oct 2022 13:02:59 +0200 Subject: [PATCH] add nrf91 multi driver DONE: RTOS-757 --- _targets/Makefile.armv8m33-nrf9160 | 11 + multi/nrf91-multi/Makefile | 15 + multi/nrf91-multi/common.h | 30 ++ multi/nrf91-multi/fs.c | 174 ++++++++++ multi/nrf91-multi/fs.h | 18 + multi/nrf91-multi/nrf91-multi.c | 121 +++++++ multi/nrf91-multi/nrf91-multi.h | 19 + multi/nrf91-multi/uart.c | 536 +++++++++++++++++++++++++++++ multi/nrf91-multi/uart.h | 32 ++ 9 files changed, 956 insertions(+) create mode 100644 _targets/Makefile.armv8m33-nrf9160 create mode 100644 multi/nrf91-multi/Makefile create mode 100644 multi/nrf91-multi/common.h create mode 100644 multi/nrf91-multi/fs.c create mode 100644 multi/nrf91-multi/fs.h create mode 100644 multi/nrf91-multi/nrf91-multi.c create mode 100644 multi/nrf91-multi/nrf91-multi.h create mode 100644 multi/nrf91-multi/uart.c create mode 100644 multi/nrf91-multi/uart.h diff --git a/_targets/Makefile.armv8m33-nrf9160 b/_targets/Makefile.armv8m33-nrf9160 new file mode 100644 index 000000000..0328a7d0d --- /dev/null +++ b/_targets/Makefile.armv8m33-nrf9160 @@ -0,0 +1,11 @@ +# +# Makefile for Phoenix-RTOS 3 device drivers +# +# NRF9160 drivers +# +# Copyright 2022 Phoenix Systems +# + +CFLAGS += -DTARGET_NRF91 -DTARGET_NRF91 + +DEFAULT_COMPONENTS := nrf91-multi diff --git a/multi/nrf91-multi/Makefile b/multi/nrf91-multi/Makefile new file mode 100644 index 000000000..490a33730 --- /dev/null +++ b/multi/nrf91-multi/Makefile @@ -0,0 +1,15 @@ +# +# Makefile for Phoenix-RTOS nrf91-multi +# +# Copyright 2024 Phoenix Systems +# + +LOCAL_PATH := $(call my-dir) + +NAME := nrf91-multi +SRCS := $(wildcard $(LOCAL_PATH)*.c) +LOCAL_HEADERS := nrf91-multi.h +DEP_LIBS := libtty libklog +LIBS := libdummyfs libklog + +include $(binary.mk) diff --git a/multi/nrf91-multi/common.h b/multi/nrf91-multi/common.h new file mode 100644 index 000000000..3cedb96a4 --- /dev/null +++ b/multi/nrf91-multi/common.h @@ -0,0 +1,30 @@ +/* + * Phoenix-RTOS + * + * nRF91 multidriver common + * + * Copyright 2017, 2018, 2023 Phoenix Systems + * Author: Aleksander Kaminski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include +#include +#include +#include + +#include + + +static inline void dataBarier(void) +{ + __asm__ volatile("dmb"); +} + +#endif diff --git a/multi/nrf91-multi/fs.c b/multi/nrf91-multi/fs.c new file mode 100644 index 000000000..2a61717ab --- /dev/null +++ b/multi/nrf91-multi/fs.c @@ -0,0 +1,174 @@ +/* + * Phoenix-RTOS + * + * nRF9160 Filesystem driver + * + * Copyright 2021, 2023 Phoenix Systems + * Author: Maciej Purski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "fs.h" + +#define MSGTHR_STACKSZ 4096 + +static struct { + char stack[MSGTHR_STACKSZ] __attribute__((aligned(8))); + unsigned port; +} fs_common; + + +static int syspage_create(void *ctx, oid_t *root) +{ + oid_t sysoid = { 0 }; + oid_t toid = { 0 }; + syspageprog_t prog; + int i, progsz; + + progsz = syspageprog(NULL, -1); + if (progsz < 0) { + return -1; + } + + if (dummyfs_create(ctx, root, "syspage", &sysoid, S_IRWXU | S_IRWXG | S_IRWXO, otDir, NULL) != 0) { + return -ENOMEM; + } + + for (i = 0; i < progsz; i++) { + if (syspageprog(&prog, i) != 0) { + continue; + } + + dummyfs_createMapped(ctx, &sysoid, prog.name, (void *)prog.addr, prog.size, &toid); + } + + return 0; +} + + +static void msgthr(void *ctx) +{ + msg_t msg; + msg_rid_t rid; + + for (;;) { + if (msgRecv(fs_common.port, &msg, &rid) < 0) { + continue; + } + + switch (msg.type) { + case mtOpen: + msg.o.io.err = dummyfs_open(ctx, &msg.i.openclose.oid); + break; + + case mtClose: + msg.o.io.err = dummyfs_close(ctx, &msg.i.openclose.oid); + break; + + case mtRead: + msg.o.io.err = dummyfs_read(ctx, &msg.i.io.oid, msg.i.io.offs, msg.o.data, msg.o.size); + break; + + case mtWrite: + msg.o.io.err = dummyfs_write(ctx, &msg.i.io.oid, msg.i.io.offs, msg.i.data, msg.i.size); + break; + + case mtTruncate: + msg.o.io.err = dummyfs_truncate(ctx, &msg.i.io.oid, msg.i.io.len); + break; + + case mtDevCtl: + msg.o.io.err = -EINVAL; + break; + + case mtCreate: + msg.o.create.err = dummyfs_create(ctx, &msg.i.create.dir, msg.i.data, &msg.o.create.oid, msg.i.create.mode, msg.i.create.type, &msg.i.create.dev); + break; + + case mtDestroy: + msg.o.io.err = dummyfs_destroy(ctx, &msg.i.destroy.oid); + break; + + case mtSetAttr: + msg.o.attr.err = dummyfs_setattr(ctx, &msg.i.attr.oid, msg.i.attr.type, msg.i.attr.val, msg.i.data, msg.i.size); + break; + + case mtGetAttr: + msg.o.attr.err = dummyfs_getattr(ctx, &msg.i.attr.oid, msg.i.attr.type, &msg.o.attr.val); + break; + + case mtLookup: + msg.o.lookup.err = dummyfs_lookup(ctx, &msg.i.lookup.dir, msg.i.data, &msg.o.lookup.fil, &msg.o.lookup.dev); + break; + + case mtLink: + msg.o.io.err = dummyfs_link(ctx, &msg.i.ln.dir, msg.i.data, &msg.i.ln.oid); + break; + + case mtUnlink: + msg.o.io.err = dummyfs_unlink(ctx, &msg.i.ln.dir, msg.i.data); + break; + + case mtReaddir: + msg.o.io.err = dummyfs_readdir(ctx, &msg.i.readdir.dir, msg.i.readdir.offs, + msg.o.data, msg.o.size); + break; + default: + msg.o.io.err = -EINVAL; + break; + } + msgRespond(fs_common.port, &msg, rid); + } +} + + +int fs_init(void) +{ + void *ctx; + oid_t root = { 0 }; + + if (portCreate(&fs_common.port) != 0) { + return -1; + } + + if (portRegister(fs_common.port, "/", &root) != 0) { + portDestroy(fs_common.port); + return -1; + } + + root.port = fs_common.port; + if (dummyfs_mount(&ctx, NULL, 0, &root) != 0) { + printf("dummyfs mount failed\n"); + portDestroy(fs_common.port); + return -1; + } + + if (syspage_create(ctx, &root) != 0) { + dummyfs_unmount(ctx); + portDestroy(fs_common.port); + return -1; + } + + if (beginthread(msgthr, 4, fs_common.stack, MSGTHR_STACKSZ, ctx) != 0) { + dummyfs_unmount(ctx); + portDestroy(fs_common.port); + return -1; + } + + return 0; +} diff --git a/multi/nrf91-multi/fs.h b/multi/nrf91-multi/fs.h new file mode 100644 index 000000000..15cf47826 --- /dev/null +++ b/multi/nrf91-multi/fs.h @@ -0,0 +1,18 @@ +/* + * Phoenix-RTOS + * + * STM32L4/nRF91 Filesystem driver header + * + * Copyright 2021, 2023 Phoenix Systems + * Author: Maciej Purski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ +#ifndef FS_H_ +#define FS_H_ + +extern int fs_init(void); + +#endif /* FS_H_ */ diff --git a/multi/nrf91-multi/nrf91-multi.c b/multi/nrf91-multi/nrf91-multi.c new file mode 100644 index 000000000..2f9754f91 --- /dev/null +++ b/multi/nrf91-multi/nrf91-multi.c @@ -0,0 +1,121 @@ +/* + * Phoenix-RTOS + * + * nRF91 multi driver server + * + * Copyright 2023, 2024 Phoenix Systems + * Author: Aleksander Kaminski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" + +#include "nrf91-multi.h" +#include "fs.h" +#include "uart.h" + +#define THREADS_CNT 3 +#define THREAD_PRIORITY 1 +#define THREAD_STACKSZ 640 + + +static struct { + char stack[THREADS_CNT - 1][THREAD_STACKSZ] __attribute__((aligned(8))); + + unsigned int port; +} multi_common; + + +static void multi_thread(void *arg) +{ + msg_t msg; + msg_rid_t rid; + + while (1) { + while (msgRecv(multi_common.port, &msg, &rid) < 0) { + } + + priority(msg.priority); + + switch (msg.type) { + case mtOpen: + case mtClose: + msg.o.io.err = 0; + break; + + case mtRead: + msg.o.io.err = uart_read(msg.o.data, msg.o.size, msg.i.io.mode); + break; + + case mtWrite: + msg.o.io.err = uart_log(msg.i.data, msg.i.size, msg.i.io.mode); + break; + + case mtDevCtl: + /* TODO: add implementation */ + msg.o.io.err = -EINVAL; + break; + + case mtCreate: + msg.o.create.err = -EINVAL; + break; + + case mtLookup: + msg.o.lookup.err = -EINVAL; + break; + + default: + msg.o.io.err = -EINVAL; + break; + } + + msgRespond(multi_common.port, &msg, rid); + + priority(THREAD_PRIORITY); + } +} + + +int main(void) +{ + int i; + oid_t oid; + + priority(THREAD_PRIORITY); + + portCreate(&multi_common.port); + + fs_init(); + uart_init(); + libklog_init(uart_log); + + /* Do this after klog init to keep shell from overtaking klog */ + uart_createConsoleDev(); + + portRegister(multi_common.port, "/multi", &oid); + + /* 2 threads launched in for loop and another one in the main thread */ + for (i = 0; i < THREADS_CNT - 1; ++i) { + beginthread(&multi_thread, THREAD_PRIORITY, multi_common.stack[i], THREAD_STACKSZ, (void *)i); + } + + printf("multidrv: Started\n"); + + multi_thread((void *)i); + + return 0; +} diff --git a/multi/nrf91-multi/nrf91-multi.h b/multi/nrf91-multi/nrf91-multi.h new file mode 100644 index 000000000..567c51247 --- /dev/null +++ b/multi/nrf91-multi/nrf91-multi.h @@ -0,0 +1,19 @@ +/* + * Phoenix-RTOS + * + * nRF91 multidriver + * + * Copyright 2018, 2024 Phoenix Systems + * Author: Aleksander Kaminski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef NRF91_MULTI_H_ +#define NRF91_MULTI_H_ + +#include + +#endif diff --git a/multi/nrf91-multi/uart.c b/multi/nrf91-multi/uart.c new file mode 100644 index 000000000..9fb11dd15 --- /dev/null +++ b/multi/nrf91-multi/uart.c @@ -0,0 +1,536 @@ +/* + * Phoenix-RTOS + * + * nRF91 UART driver + * + * Copyright 2023, 2024 Phoenix Systems + * Author: Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "nrf91-multi.h" +#include "common.h" +#include "uart.h" + +#define UART_CNT (UART0 + UART1 + UART2 + UART3) + +#define THREADS_CNT 3 +#define THREAD_STACKSZ 768 +#define THREAD_PRIORITY 1 + +typedef struct { + char stack[512] __attribute__((aligned(8))); + + volatile unsigned int *base; + volatile char *txDma; + volatile char *rxDma; + + unsigned char stopBits; + int parity; + int baud; + int cnt; + bool init; + bool resetCnt; + + handle_t cond; + handle_t irqlock; + + libtty_common_t ttyCommon; + + volatile bool rxdrdy; + int rxdCount; +} uart_ctx_t; + + +static struct { + unsigned char stack[THREADS_CNT][THREAD_STACKSZ] __attribute__((aligned(8))); + uart_ctx_t ctx[UART_CNT]; + + unsigned int port; +} uart_common; + + +enum { uarte_startrx = 0, + uarte_stoprx, + uarte_starttx, + uarte_stoptx, + uarte_flushrx = 11, + uarte_events_cts = 64, + uarte_events_ncts, + uarte_events_rxdrdy, + uarte_events_endrx = 68, + uarte_events_txdrdy = 71, + uarte_events_endtx, + uarte_events_error, + uarte_events_rxto = 81, + uarte_events_rxstarted = 83, + uarte_events_txstarted, + uarte_events_txstopped = 86, + uarte_inten = 192, + uarte_intenset, + uarte_intenclr, + uarte_errorsrc = 288, + uarte_enable = 320, + uarte_psel_rts = 322, + uarte_psel_txd, + uarte_psel_cts, + uarte_psel_rxd, + uarte_baudrate = 329, + uarte_rxd_ptr = 333, + uarte_rxd_maxcnt, + uarte_rxd_amount, + uarte_txd_ptr = 337, + uarte_txd_maxcnt, + uarte_txd_amount, + uarte_config = 347 }; + + +enum { no_parity, + parity_even +}; + + +enum { baud_9600 = 0x00275000, + baud_115200 = 0x01d60000, + baud_230400 = 0x03b00000, + baud_250000 = 0x04000000, + baud_460800 = 0x07400000, + baud_921600 = 0x0f000000, + baud_1000000 = 0x10000000 }; + + +enum { uart0 = 0, + uart1, + uart2, + uart3 }; + + +/* indicates whether the tx line is ready to transmit new data */ +static bool uart_txready(uart_ctx_t *ctx) +{ + bool ret; + ret = ctx->init; + + mutexLock(ctx->irqlock); + /* before the first transaction tx is also ready even if the event hasn't occurred */ + if (ctx->init == false) { + /* true means that the data has been sent from txd */ + ret = ctx->base[uarte_events_txdrdy]; + ctx->base[uarte_events_txdrdy] = 0u; + ctx->init = false; + } + mutexUnlock(ctx->irqlock); + + return ret; +} + + +static int uart_irqHandler(unsigned int n, void *arg) +{ + uart_ctx_t *ctx = (uart_ctx_t *)arg; + + if (ctx->base[uarte_events_rxdrdy] != 0u) { + /* clear rxdrdy event flag */ + ctx->base[uarte_events_rxdrdy] = 0u; + ctx->rxdCount++; + ctx->rxdrdy = true; + } + + if (ctx->base[uarte_events_endtx] != 0u) { + /* disable endtx interrupt and clear flag */ + ctx->base[uarte_events_endtx] = 0u; + ctx->base[uarte_intenclr] = 0x100u; + } + + if (ctx->base[uarte_events_endrx] != 0u) { + /* clear endrx event flag */ + ctx->base[uarte_events_endrx] = 0u; + ctx->resetCnt = true; + ctx->base[uarte_startrx] = 1u; + } + + return 0; +} + + +static void uart_irqthread(void *arg) +{ + uart_ctx_t *ctx = (uart_ctx_t *)arg; + bool keptIdle = false; + int i = 0; + + while (true) { + mutexLock(ctx->irqlock); + /* wait until new data is received and libtty fifo is not empty */ + while (!ctx->rxdrdy && (libtty_txready(&ctx->ttyCommon) == 0)) { + condWait(ctx->cond, ctx->irqlock, 0); + } + mutexUnlock(ctx->irqlock); + + ctx->rxdrdy = false; + dataBarier(); + + /* send the data directly from dma */ + for (; (ctx->cnt < ctx->rxdCount) && (ctx->cnt < UART_RX_DMA_SIZE); ctx->cnt++) { + libtty_putchar(&ctx->ttyCommon, ctx->rxDma[ctx->cnt], NULL); + } + + /* check whether all bytes from the previous transaction have been read */ + if (ctx->resetCnt && (ctx->cnt >= UART_RX_DMA_SIZE)) { + ctx->cnt = 0; + ctx->rxdCount = ctx->rxdCount - UART_RX_DMA_SIZE; + } + + if (libtty_txready(&ctx->ttyCommon) != 0) { + if (uart_txready(ctx)) { + ctx->txDma[0] = libtty_getchar(&ctx->ttyCommon, NULL); + /* enable endtx interrupt and start transmission */ + ctx->base[uarte_intenset] = 0x100; + ctx->base[uarte_starttx] = 1u; + } + } + } +} + + +static void uart_signalTxReady(void *ctx) +{ + condSignal(((uart_ctx_t *)ctx)->cond); +} + + +static void _uart_clearUartEvents(uart_ctx_t *ctx) +{ + ctx->base[uarte_events_cts] = 0u; + ctx->base[uarte_events_ncts] = 0u; + ctx->base[uarte_events_rxdrdy] = 0u; + ctx->base[uarte_events_endrx] = 0u; + + ctx->base[uarte_events_txdrdy] = 0u; + ctx->base[uarte_events_endtx] = 0u; + ctx->base[uarte_events_error] = 0u; + + ctx->base[uarte_events_rxto] = 0u; + ctx->base[uarte_events_rxstarted] = 0u; + ctx->base[uarte_events_txstarted] = 0u; + ctx->base[uarte_events_txstopped] = 0u; +} + + +static void _uart_configure(uart_ctx_t *ctx) +{ + /* Disable uart instance before initialization */ + ctx->base[uarte_enable] = 0u; + dataBarier(); + + /* Reset config: + * Default settings - hardware flow control disabled, exclude parity bit, one stop bit */ + ctx->base[uarte_config] = 0u; + dataBarier(); + + if (ctx->parity == parity_even) { + /* Include even parity bit */ + ctx->base[uarte_config] = (0x7 << 1); + } + + if (ctx->stopBits == 2) { + ctx->base[uarte_config] |= (1u << 4); + } + /* TODO: add pins configuration and selecting them, now it's done in plo + + /* Set default max number of bytes in specific buffers */ + ctx->base[uarte_txd_maxcnt] = 1u; + ctx->base[uarte_rxd_maxcnt] = UART_RX_DMA_SIZE; + + /* Set default memory regions for uart dma */ + ctx->base[uarte_txd_ptr] = (unsigned int)ctx->txDma; + ctx->base[uarte_rxd_ptr] = (unsigned int)ctx->rxDma; + + /* clear all event flags */ + _uart_clearUartEvents(ctx); + + /* Disable all uart interrupts */ + ctx->base[uarte_intenclr] = 0xffffffffu; + /* Enable rxdrdy and endrx interruts */ + ctx->base[uarte_intenset] = 0x14; + dataBarier(); + + /* Enable uarte instance */ + ctx->base[uarte_enable] = 0x8; + dataBarier(); + ctx->cnt = 0; + ctx->base[uarte_startrx] = 1u; + dataBarier(); +} + + +static void _uart_setCflag(uart_ctx_t *ctx, const tcflag_t *cflag) +{ + int parity = 0; + int stopBits = 1; + + /* CS bits ignored - character size is 8 and can't be changed on this target */ + + /* PARODD ignored - not possible to set odd parity in nrf uart module + * if parity is enabled it's always even + */ + if ((*cflag & PARENB) != 0u) { + parity = parity_even; + } + + if ((*cflag & CSTOPB) != 0u) { + stopBits = 2; + } + + if ((parity != ctx->parity) || (stopBits != ctx->stopBits)) { + ctx->parity = parity; + ctx->stopBits = stopBits; + _uart_configure(ctx); + condSignal(ctx->cond); + } +} + + +static void _uart_setBaudrate(uart_ctx_t *ctx, speed_t baud) +{ + int baudr = libtty_baudrate_to_int(baud); + + if (ctx->baud != baudr) { + switch (baudr) { + case 9600: + ctx->base[uarte_baudrate] = baud_9600; + break; + case 115200: + ctx->base[uarte_baudrate] = baud_115200; + break; + case 23040: + ctx->base[uarte_baudrate] = baud_230400; + break; + case 460800: + ctx->base[uarte_baudrate] = baud_460800; + break; + case 921600: + ctx->base[uarte_baudrate] = baud_921600; + break; + case 1000000: + ctx->base[uarte_baudrate] = baud_1000000; + break; + default: + ctx->base[uarte_baudrate] = baud_115200; + break; + } + dataBarier(); + } + + ctx->baud = baudr; +} + + +static uart_ctx_t *uart_getCtx(id_t id) +{ + uart_ctx_t *ctx = NULL; + + if ((id >= uart0) && (id <= uart3)) { + ctx = &uart_common.ctx[id]; + } + + return ctx; +} + + +static void uart_thread(void *arg) +{ + msg_t msg; + msg_rid_t rid; + uart_ctx_t *ctx; + unsigned long request; + const void *in_data, *out_data = NULL; + pid_t pid; + int err; + id_t id; + + while (1) { + while (msgRecv(uart_common.port, &msg, &rid) < 0) { + } + + priority(msg.priority); + + switch (msg.type) { + case mtOpen: + case mtClose: + ctx = uart_getCtx(msg.i.io.oid.id); + if (ctx == NULL) { + msg.o.io.err = -EINVAL; + break; + } + msg.o.io.err = EOK; + break; + + case mtWrite: + ctx = uart_getCtx(msg.i.io.oid.id); + if (ctx == NULL) { + msg.o.io.err = -EINVAL; + break; + } + msg.o.io.err = libtty_write(&ctx->ttyCommon, msg.i.data, msg.i.size, msg.i.io.mode); + break; + + case mtRead: + if ((ctx = uart_getCtx(msg.i.io.oid.id)) == NULL) { + msg.o.io.err = -EINVAL; + break; + } + msg.o.io.err = libtty_read(&ctx->ttyCommon, msg.o.data, msg.o.size, msg.i.io.mode); + break; + + case mtGetAttr: + if ((msg.i.attr.type != atPollStatus) || ((ctx = uart_getCtx(msg.i.attr.oid.id)) == NULL)) { + msg.o.attr.err = -EINVAL; + break; + } + msg.o.attr.val = libtty_poll_status(&ctx->ttyCommon); + msg.o.attr.err = EOK; + break; + + case mtDevCtl: + in_data = ioctl_unpack(&msg, &request, &id); + if ((ctx = uart_getCtx(id)) == NULL) { + err = -EINVAL; + } + else { + pid = ioctl_getSenderPid(&msg); + err = libtty_ioctl(&ctx->ttyCommon, pid, request, in_data, &out_data); + } + ioctl_setResponse(&msg, request, err, out_data); + break; + default: + msg.o.io.err = -EINVAL; + break; + } + + msgRespond(uart_common.port, &msg, rid); + + priority(THREAD_PRIORITY); + } +} + + +ssize_t uart_read(const char *str, size_t len, unsigned int mode) +{ + return libtty_read(&uart_getCtx(UART_CONSOLE)->ttyCommon, str, len, mode); +} + + +ssize_t uart_log(const char *str, size_t len, unsigned int mode) +{ + return libtty_write(&uart_getCtx(UART_CONSOLE)->ttyCommon, str, len, mode); +} + + +void uart_createConsoleDev(void) +{ + oid_t oid; + + oid.port = uart_common.port; + /* id 0 is reserved for a console */ + oid.id = 0; + create_dev(&oid, _PATH_CONSOLE); +} + + +int uart_init(void) +{ + const int uartConfig[] = { UART0, UART1, UART2, UART3 }; + unsigned int uart; + char fname[] = "uartx"; + speed_t baudrate = UART_BAUDRATE_TERMIOS; + oid_t oid; + libtty_callbacks_t callbacks; + uart_ctx_t *ctx; + + static const struct { + volatile uint32_t *base; + unsigned int irq; + volatile char *txDma; + volatile char *rxDma; + } info[] = { + { (void *)0x50008000, uarte0_irq + 16, (volatile char *)0x2003C000, (volatile char *)0x20038000 }, + { (void *)0x50009000, uarte1_irq + 16, (volatile char *)0x20038000, (volatile char *)0x2003A000 }, + { (void *)0x5000A000, uarte2_irq + 16, (volatile char *)0x2003C000, (volatile char *)0x20038000 }, + { (void *)0x5000B000, uarte3_irq + 16, (volatile char *)0x20038000, (volatile char *)0x2003A000 } + }; + + portCreate(&uart_common.port); + oid.port = uart_common.port; + + for (uart = uart0; uart <= uart3; uart++) { + if (uartConfig[uart] == 0) { + continue; + } + + ctx = &uart_common.ctx[uart]; + + callbacks.arg = ctx; + callbacks.set_baudrate = _uart_setBaudrate; + callbacks.set_cflag = _uart_setCflag; + callbacks.signal_txready = uart_signalTxReady; + + if (libtty_init(&ctx->ttyCommon, &callbacks, 512, baudrate) < 0) { + return -1; + } + + mutexCreate(&ctx->irqlock); + condCreate(&ctx->cond); + + ctx->base = info[uart - uart0].base; + ctx->txDma = info[uart - uart0].txDma; + ctx->rxDma = info[uart - uart0].rxDma; + ctx->rxdrdy = false; + ctx->parity = no_parity; + ctx->stopBits = 1; + ctx->baud = -1; + ctx->init = true; + ctx->cnt = 0u; + ctx->resetCnt = false; + + _uart_configure(ctx); + _uart_setBaudrate(ctx, baudrate); + + interrupt(info[uart - uart0].irq, uart_irqHandler, (void *)ctx, ctx->cond, NULL); + + beginthread(uart_irqthread, 1, ctx->stack, sizeof(ctx->stack), (void *)ctx); + + fname[sizeof(fname) - 2] = '0' + uart - uart0; + /* id 0 - console, 1 - uart0, 2 - uart1... */ + oid.id = uart - uart0 + 1; + create_dev(&oid, fname); + } + + for (int i = 0; i < THREADS_CNT; ++i) { + beginthread(uart_thread, THREAD_PRIORITY, uart_common.stack[i], sizeof(uart_common.stack[i]), (void *)i); + } + + return 0; +} diff --git a/multi/nrf91-multi/uart.h b/multi/nrf91-multi/uart.h new file mode 100644 index 000000000..38bd21e98 --- /dev/null +++ b/multi/nrf91-multi/uart.h @@ -0,0 +1,32 @@ +/* + * Phoenix-RTOS + * + * nRF91 TTY driver + * + * Copyright 2017, 2018, 2022 Phoenix Systems + * Author: Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef UART_H_ +#define UART_H_ + +#include + + +ssize_t uart_log(const char *str, size_t len, unsigned int mode); + + +ssize_t uart_read(const char *str, size_t len, unsigned int mode); + + +void uart_createConsoleDev(void); + + +int uart_init(void); + + +#endif