Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 8082

Zephyr • Re: Serial echo sample on Pico2

$
0
0
Would certainly be interested to see your code, if only to see whether I've done it "right". (Mine's certainly a mess ATM). I do at least feel fairly comfortable with the basics of serial ports now.
I was lazy and used AI. LOL. No doubt, it's still highly contentious as to whether AI driver LLM's can ever do it "right" but here goes.

Note that I created my own (odd?) logic... Characters sent via either of the 2 UART ports get passed through to the PIO driven UART channel and characters sent via the PIO UART channel get passed through to both UART channels.

Starting with the overlay:

Code:

/* The Pico and Pico 2 are pin compatible. *//* Defining pin control for 2nd standard UART port and the PIO driven UART port */&pinctrl {uart1_default: uart1_default {group1 {pinmux = <UART1_TX_P4>;};group2 {pinmux = <UART1_RX_P5>;input-enable;};};uart2_pio0_default: uart2_pio0_default {rx_pins {pinmux = <PIO0_P3>;input-enable;bias-pull-up;};tx_pins {pinmux = <PIO0_P2>;};};};/* UART settings for the PIO channel */&pio0 {status = "okay";uart2_pio0: uart2_pio0 {pinctrl-0 = <&uart2_pio0_default>;pinctrl-names = "default";compatible = "raspberrypi,pico-uart-pio";current-speed = <115200>;status = "okay";};};&i2c0 {status = "disabled";// done to ensure no mixed use of pins 4 and 5};/* Settings for the 2nd standard UART port */&uart1 {current-speed = <115200>;status = "okay";pinctrl-0 = <&uart1_default>;pinctrl-names = "default";};/ {chosen {uart,passthrough = &uart2_pio0;};aliases {uart-second = &uart1;};};
And here the main.c source:

Code:

/* * Copyright (c) 2025 Gerrikoio (AI assisted). * * SPDX-License-Identifier: Apache-2.0 */#include <zephyr/kernel.h>#include <zephyr/device.h>#include <zephyr/drivers/uart.h>#include <zephyr/sys/ring_buffer.h>#include <stdio.h>#include <string.h>struct patch_info {const uint8_t * const name;const struct device *rx_dev;struct ring_buf *rx_ring_buf;bool rx_error;bool rx_overflow;const struct device *tx_dev;const struct device *tx_dev2;};#define DEV_CONSOLE DEVICE_DT_GET(DT_CHOSEN(zephyr_console))#define DEV_PASSED   DEVICE_DT_GET(DT_CHOSEN(uart_passthrough))#define DEV_SECOND DEVICE_DT_GET(DT_ALIAS(uart_second))#define RING_BUF_SIZE 64RING_BUF_DECLARE(rb_console, RING_BUF_SIZE);struct patch_info patch_c2o_1 = {.name = "c2o-1",.rx_dev = DEV_CONSOLE,.rx_ring_buf = &rb_console,.rx_error = false,.rx_overflow = false,.tx_dev = DEV_PASSED,.tx_dev2 = NULL,};RING_BUF_DECLARE(rb_second, RING_BUF_SIZE);struct patch_info patch_c2o_2 = {.name = "c2o-2",.rx_dev = DEV_SECOND,.rx_ring_buf = &rb_second,.rx_error = false,.rx_overflow = false,.tx_dev = DEV_PASSED,.tx_dev2 = NULL,};RING_BUF_DECLARE(rb_other, RING_BUF_SIZE);struct patch_info patch_o2c = {.name = "o2c",.rx_dev = DEV_PASSED,.rx_ring_buf = &rb_other,.rx_error = false,.rx_overflow = false,.tx_dev = DEV_CONSOLE,.tx_dev2 = DEV_SECOND,};static void uart_cb(const struct device *dev, void *ctx){struct patch_info *patch = (struct patch_info *)ctx;int ret;uint8_t *buf;uint32_t len;while (uart_irq_update(patch->rx_dev) > 0) {ret = uart_irq_rx_ready(patch->rx_dev);if (ret < 0) {patch->rx_error = true;}if (ret <= 0) {break;}len = ring_buf_put_claim(patch->rx_ring_buf, &buf, RING_BUF_SIZE);if (len == 0) {/* no space for Rx, disable the IRQ */uart_irq_rx_disable(patch->rx_dev);patch->rx_overflow = true;break;}ret = uart_fifo_read(patch->rx_dev, buf, len);if (ret < 0) {patch->rx_error = true;}if (ret <= 0) {break;}len = ret;ret = ring_buf_put_finish(patch->rx_ring_buf, len);if (ret != 0) {patch->rx_error = true;break;}}}static void poll_other_rx(struct patch_info *patch){uint8_t c;int ret;ret = uart_poll_in(patch->rx_dev, &c);if (ret == 0) {/* Character received */ret = ring_buf_put(patch->rx_ring_buf, &c, 1);if (ret != 1) {patch->rx_overflow = true;}} else if (ret != -1) {/* A real error occurred */if (uart_err_check(patch->rx_dev)) {/* This will clear the error flags */patch->rx_error = true;}}}static void passthrough(struct patch_info *patch){int ret;uint8_t *buf;uint32_t len;if (patch->rx_error) {printk("<<%s: Rx Error!>>\n", patch->name);patch->rx_error = false;}if (patch->rx_overflow) {printk("<<%s: Rx Overflow!>>\n", patch->name);patch->rx_overflow = false;}len = ring_buf_get_claim(patch->rx_ring_buf, &buf, RING_BUF_SIZE);if (len == 0) {goto done;}if (patch->tx_dev == DEV_PASSED) {/* The PIO UART does not support uart_fifo_fill */for (uint32_t i = 0; i < len; i++) {uart_poll_out(patch->tx_dev, buf[i]);}ret = len;} else {/* Also send to the second Tx device if it exists */if (patch->tx_dev2) {ret = uart_fifo_fill(patch->tx_dev2, buf, len);if (ret < 0) {goto error;}}ret = uart_fifo_fill(patch->tx_dev, buf, len);if (ret < 0) {goto error;}}len = (ret > 0) ? ret : 0;ret = ring_buf_get_finish(patch->rx_ring_buf, len);if (ret < 0) {goto error;}done:uart_irq_rx_enable(patch->rx_dev);return;error:printk("<<%s: Tx Error!>>\n", patch->name);}int main(void){if (!device_is_ready(patch_c2o_1.rx_dev) || !device_is_ready(patch_c2o_2.rx_dev) ||    !device_is_ready(patch_o2c.rx_dev)) {printk("UART devices not ready\n");return 0;}printk("Console Port: %s (%p)\n", patch_c2o_1.name, patch_c2o_1.rx_dev);printk("Second Port:  %s (%p)\n", patch_c2o_2.name, patch_c2o_2.rx_dev);printk("Passthrough Port: %s (%p)\n", patch_o2c.name, patch_o2c.rx_dev);/* Use interrupt-driven API for the console (hardware UART) */uart_irq_callback_user_data_set(patch_c2o_1.rx_dev, uart_cb, (void *)&patch_c2o_1);/* Use interrupt-driven API for the second UART (hardware UART) */uart_irq_callback_user_data_set(patch_c2o_2.rx_dev, uart_cb, (void *)&patch_c2o_2);for (;;) {/* Poll the "other" device (PIO UART) for received data */poll_other_rx(&patch_o2c);passthrough(&patch_c2o_1);passthrough(&patch_c2o_2);passthrough(&patch_o2c);}return 0;}

Statistics: Posted by gerrikoio — Tue Sep 30, 2025 9:17 am



Viewing all articles
Browse latest Browse all 8082

Trending Articles