From 9f05489b3a07a0005ff4949ae28a8ebdce1dbe71 Mon Sep 17 00:00:00 2001 From: Timo Schneider Date: Wed, 11 Mar 2026 20:34:44 +0100 Subject: [PATCH] added poll api passthrough --- .gitignore | 1 + CMakeLists.txt | 13 ++ boards/xiao_nrf54l15_nrf54l15_cpuapp.conf | 3 + boards/xiao_nrf54l15_nrf54l15_cpuapp.overlay | 18 +++ .../uart-interrupt-poll-bridge/CMakeLists.txt | 1 + modules/uart-interrupt-poll-bridge/Kconfig | 1 + .../uart-interrupt-poll-bridge/CMakeLists.txt | 1 + .../serial/uart-interrupt-poll-bridge/Kconfig | 7 + .../uart-interrupt-poll-bridge.c | 125 ++++++++++++++++++ .../dts/bindings/interrupt-poll-bridge.yaml | 17 +++ .../zephyr/module.yml | 8 ++ prj.conf | 2 + src/main.cpp | 21 +++ 13 files changed, 218 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 boards/xiao_nrf54l15_nrf54l15_cpuapp.conf create mode 100644 boards/xiao_nrf54l15_nrf54l15_cpuapp.overlay create mode 100644 modules/uart-interrupt-poll-bridge/CMakeLists.txt create mode 100644 modules/uart-interrupt-poll-bridge/Kconfig create mode 100644 modules/uart-interrupt-poll-bridge/drivers/serial/uart-interrupt-poll-bridge/CMakeLists.txt create mode 100644 modules/uart-interrupt-poll-bridge/drivers/serial/uart-interrupt-poll-bridge/Kconfig create mode 100644 modules/uart-interrupt-poll-bridge/drivers/serial/uart-interrupt-poll-bridge/uart-interrupt-poll-bridge.c create mode 100644 modules/uart-interrupt-poll-bridge/dts/bindings/interrupt-poll-bridge.yaml create mode 100644 modules/uart-interrupt-poll-bridge/zephyr/module.yml create mode 100644 prj.conf create mode 100644 src/main.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d163863 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..21e86f2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.20.0) + +list(APPEND ZEPHYR_EXTRA_MODULES ${CMAKE_CURRENT_SOURCE_DIR}/modules/uart-interrupt-poll-bridge) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(zephyr-uart-polling-interrupt-bridge C CXX) + +set(CMAKE_BUILD_TYPE Debug) +target_compile_options(app PRIVATE -O0 -g) + +target_sources(app PRIVATE + src/main.cpp +) \ No newline at end of file diff --git a/boards/xiao_nrf54l15_nrf54l15_cpuapp.conf b/boards/xiao_nrf54l15_nrf54l15_cpuapp.conf new file mode 100644 index 0000000..ce3e0ea --- /dev/null +++ b/boards/xiao_nrf54l15_nrf54l15_cpuapp.conf @@ -0,0 +1,3 @@ +CONFIG_SERIAL=y + +CONFIG_UART_INTERRUPT_POLL_BRIDGE=y \ No newline at end of file diff --git a/boards/xiao_nrf54l15_nrf54l15_cpuapp.overlay b/boards/xiao_nrf54l15_nrf54l15_cpuapp.overlay new file mode 100644 index 0000000..dc99e27 --- /dev/null +++ b/boards/xiao_nrf54l15_nrf54l15_cpuapp.overlay @@ -0,0 +1,18 @@ +/ { + aliases { + testuart = &test_uart; + }; + + test_uart: test_uart { + compatible = "uart-interrupt-poll-bridge"; + uart = <&uart20>; + timer = <&timer00>; + interrupts = <1 2>; + interrupt-parent = <&nvic>; + status = "okay"; + }; +}; + +&timer00 { + status = "okay"; +}; diff --git a/modules/uart-interrupt-poll-bridge/CMakeLists.txt b/modules/uart-interrupt-poll-bridge/CMakeLists.txt new file mode 100644 index 0000000..c0f5b2d --- /dev/null +++ b/modules/uart-interrupt-poll-bridge/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(drivers/serial/uart-interrupt-poll-bridge) \ No newline at end of file diff --git a/modules/uart-interrupt-poll-bridge/Kconfig b/modules/uart-interrupt-poll-bridge/Kconfig new file mode 100644 index 0000000..d1782fb --- /dev/null +++ b/modules/uart-interrupt-poll-bridge/Kconfig @@ -0,0 +1 @@ +rsource "drivers/serial/uart-interrupt-poll-bridge/Kconfig" \ No newline at end of file diff --git a/modules/uart-interrupt-poll-bridge/drivers/serial/uart-interrupt-poll-bridge/CMakeLists.txt b/modules/uart-interrupt-poll-bridge/drivers/serial/uart-interrupt-poll-bridge/CMakeLists.txt new file mode 100644 index 0000000..34187e0 --- /dev/null +++ b/modules/uart-interrupt-poll-bridge/drivers/serial/uart-interrupt-poll-bridge/CMakeLists.txt @@ -0,0 +1 @@ +zephyr_library_sources_ifdef(CONFIG_UART_INTERRUPT_POLL_BRIDGE uart-interrupt-poll-bridge.c) \ No newline at end of file diff --git a/modules/uart-interrupt-poll-bridge/drivers/serial/uart-interrupt-poll-bridge/Kconfig b/modules/uart-interrupt-poll-bridge/drivers/serial/uart-interrupt-poll-bridge/Kconfig new file mode 100644 index 0000000..97a0720 --- /dev/null +++ b/modules/uart-interrupt-poll-bridge/drivers/serial/uart-interrupt-poll-bridge/Kconfig @@ -0,0 +1,7 @@ +config UART_INTERRUPT_POLL_BRIDGE + bool "UART interrupt/poll bridge driver" + default y + +config UART_INTERRUPT_POLL_BRIDGE_QUEUE_SIZE + int "UART interrupt/poll bridge driver rx / tx buffer size" + default 256 \ No newline at end of file diff --git a/modules/uart-interrupt-poll-bridge/drivers/serial/uart-interrupt-poll-bridge/uart-interrupt-poll-bridge.c b/modules/uart-interrupt-poll-bridge/drivers/serial/uart-interrupt-poll-bridge/uart-interrupt-poll-bridge.c new file mode 100644 index 0000000..a2d7108 --- /dev/null +++ b/modules/uart-interrupt-poll-bridge/drivers/serial/uart-interrupt-poll-bridge/uart-interrupt-poll-bridge.c @@ -0,0 +1,125 @@ +#define DT_DRV_COMPAT uart_interrupt_poll_bridge + +#include +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +#include +#endif + +struct uart_pti_bridge_config { + const struct device *uart; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + const struct device *timer; + const uint8_t interrupt_line; +#endif +}; + +struct uart_pti_bridge_data { +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + struct ring_buf *rx_buf; + struct ring_buf *tx_buf; +#endif +}; + +int uart_pti_bridge_init(const struct device *dev) { + ARG_UNUSED(dev); + return 0; +} + + +static int uart_pti_bridge_poll_in(const struct device *dev, unsigned char *c) { + const struct uart_pti_bridge_config *config = dev->config; + + return uart_poll_in(config->uart, c); +} + + +static void uart_pti_bridge_poll_out(const struct device *dev, + unsigned char c) { + const struct uart_pti_bridge_config *config = dev->config; + + return uart_poll_out(config->uart, c); +} + + +static int uart_pti_bridge_err_check(const struct device *dev) { + const struct uart_pti_bridge_config *config = dev->config; + + return uart_err_check(config->uart); +} + + +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE +static int uart_pti_bridge_configure(const struct device *dev, + const struct uart_config *cfg) { + ARG_UNUSED(dev); + ARG_UNUSED(cfg); + return 0; +} + +static int uart_pti_bridge_config_get(const struct device *dev, + struct uart_config *cfg) { + const struct uart_pti_bridge_config *config = dev->config; + + return uart_config_get(config->uart, cfg); +} +#endif + +static DEVICE_API(uart, uart_interrupt_poll_bridge_api) = { + .poll_in = uart_pti_bridge_poll_in, + .poll_out = uart_pti_bridge_poll_out, + .err_check = uart_pti_bridge_err_check, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE + .configure = uart_pti_bridge_configure, + .config_get = uart_pti_bridge_config_get, +#endif +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = NULL, + .fifo_read = NULL, + .irq_tx_enable = NULL, + .irq_tx_disable = NULL, + .irq_tx_ready = NULL, + .irq_tx_complete = NULL, + .irq_rx_enable = NULL, + .irq_rx_disable = NULL, + .irq_rx_ready = NULL, + .irq_err_enable = NULL, + .irq_err_disable = NULL, + .irq_is_pending = NULL, + .irq_update = NULL, + .irq_callback_set = NULL, +#endif +}; + + +#define BRIDGE_DEFINE(inst) \ + COND_CODE_1(CONFIG_UART_INTERRUPT_DRIVEN, ( \ + RING_BUF_DECLARE(uart_pti_bridge_rx_buf##inst, CONFIG_UART_INTERRUPT_POLL_BRIDGE_QUEUE_SIZE); \ + RING_BUF_DECLARE(uart_pti_bridge_tx_buf##inst, CONFIG_UART_INTERRUPT_POLL_BRIDGE_QUEUE_SIZE); \ + ), ()) \ + \ + static struct uart_pti_bridge_data uart_pti_bridge_data_##inst = { \ + COND_CODE_1(CONFIG_UART_INTERRUPT_DRIVEN, ( \ + .rx_buf = &uart_pti_bridge_rx_buf##inst, \ + .tx_buf = &uart_pti_bridge_tx_buf##inst, \ + ), ()) \ + }; \ + \ + static const struct uart_pti_bridge_config uart_pti_bridge_config_##inst = { \ + .uart = DEVICE_DT_GET(DT_INST_PHANDLE(inst, uart)), \ + COND_CODE_1(CONFIG_UART_INTERRUPT_DRIVEN, ( \ + .timer = DEVICE_DT_GET(DT_INST_PHANDLE(inst, timer)), \ + .interrupt_line = DT_INST_IRQN(inst), \ + ), ()) \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, \ + uart_pti_bridge_init, \ + NULL, \ + &uart_pti_bridge_data_##inst, \ + &uart_pti_bridge_config_##inst, \ + POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &uart_interrupt_poll_bridge_api); + + +DT_INST_FOREACH_STATUS_OKAY(BRIDGE_DEFINE) \ No newline at end of file diff --git a/modules/uart-interrupt-poll-bridge/dts/bindings/interrupt-poll-bridge.yaml b/modules/uart-interrupt-poll-bridge/dts/bindings/interrupt-poll-bridge.yaml new file mode 100644 index 0000000..d940686 --- /dev/null +++ b/modules/uart-interrupt-poll-bridge/dts/bindings/interrupt-poll-bridge.yaml @@ -0,0 +1,17 @@ +description: Uart interrupt driven api for poll only devices via timer instead of busy cpu time + +compatible: "uart-interrupt-poll-bridge" + +properties: + interrupt-parent: + type: phandle + required: true + interrupts: + type: array + required: true + timer: + type: phandle + required: true + uart: + type: phandle + required: true \ No newline at end of file diff --git a/modules/uart-interrupt-poll-bridge/zephyr/module.yml b/modules/uart-interrupt-poll-bridge/zephyr/module.yml new file mode 100644 index 0000000..72afacc --- /dev/null +++ b/modules/uart-interrupt-poll-bridge/zephyr/module.yml @@ -0,0 +1,8 @@ +name: uart-interrupt-poll-bridge + +build: + cmake: . + kconfig: Kconfig + + settings: + dts_root: . \ No newline at end of file diff --git a/prj.conf b/prj.conf new file mode 100644 index 0000000..41d45fb --- /dev/null +++ b/prj.conf @@ -0,0 +1,2 @@ +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_COUNTER=y \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..ab87bd9 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,21 @@ +#include +#include +#include + +const struct device *test_uart = DEVICE_DT_GET(DT_ALIAS(testuart)); + + + +int main(void) { + + const char msg [] = "Hello World"; + + while (1) { + for (char c : msg) { + uart_poll_out(test_uart, c); + } + + k_sleep(K_MSEC(100)); + } + return 0; +} \ No newline at end of file