embassy-rs / embassy

Modern embedded framework, using Rust and async.
https://embassy.dev
Apache License 2.0
5.15k stars 713 forks source link

embassy-rp BufferedUart and BufRead impl #2483

Open elpiel opened 7 months ago

elpiel commented 7 months ago

Hello, I'm trying to use the BufferedUart of the embassy-rp hal with 1 kb buffers for a GNSS receive and the embedded-io-async::BufRead trait (fill_buf() + consume() on successful reads), however, it keeps getting an Overrun error (I'm compiling in release).

There is an example of split BufferedUart example in the repo, however, it uses read_exact() and I've tried my code with read_exact and doesn't causes any error.

Is this an know issue in embassy-rp or a bug that needs to be reported? PS: I can't find such an issue in the repo.

For context: https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/uart_buffered_split.rs https://github.com/embassy-rs/embassy/blob/main/embassy-rp/src/uart/buffered.rs

I'll make an example and open a draft PR if I manage to reproduce using TX/RX pins on the board.

elpiel commented 7 months ago

Here's a minimum example (running in nightly). It's not the prettiest thing but it still triggers an Overrun error and I'm not entirely sure why the Writing logs show after the reading ones (maybe defmt-related thing)?!

#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]

teleprobe_meta::target!(b"rpi-pico");

use defmt::{assert_eq, panic, *};
use embassy_executor::Spawner;
use embassy_rp::bind_interrupts;
use embassy_rp::gpio::{Level, Output};
use embassy_rp::clocks::RoscRng;
use embassy_rp::peripherals::UART0;
use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, BufferedUartTx, Config, Error, Instance, Parity};
use embassy_time::Timer;
use embedded_io_async::{Read, ReadExactError, Write, BufRead};
use {defmt_rtt as _, panic_probe as _};

use rand::RngCore;

bind_interrupts!(struct Irqs {
    UART0_IRQ => BufferedInterruptHandler<UART0>;
});

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    let p = embassy_rp::init(Default::default());
    info!("Hello World!");

    let (mut tx, mut rx, mut uart) = (static_cell::make_static!(p.PIN_0), static_cell::make_static!(p.PIN_1), static_cell::make_static!(p.UART0));

    let mut rng = RoscRng;

    let config = Config::default();
        let tx_buf = static_cell::make_static!([0u8; 1024]);
        let rx_buf = static_cell::make_static!([0u8; 1024]);
        let uart = BufferedUart::new(uart, Irqs, tx, rx, tx_buf, rx_buf, config);

    let (mut rx, mut tx) = uart.split();
    let uart_rx = static_cell::make_static!(rx);
    let uart_tx = static_cell::make_static!(tx);

    spawner.must_spawn(reader(uart_rx));
    embassy_time::Timer::after(embassy_time::Duration::from_secs(1)).await;
    let mut data = [0u8; 1024];

    let mut d: usize = 0;
    for i in 0..150_usize {
        rng.fill_bytes(&mut data);
        uart_tx.write_all(&data[(i + d)..]).await.unwrap();
        if d < 800 {
            d += 10;
        } else {
            d = 0;
        }
        info!("{}/150 Done writing", i+1);
    embassy_time::Timer::after(embassy_time::Duration::from_millis(5)).await;

    }

    info!("Test OK");
    cortex_m::asm::bkpt();
}

#[embassy_executor::task]
async fn reader(uart_rx: &'static mut BufferedUartRx<'static, UART0>) {
        for i in 0..150 {
            let buf_len = match uart_rx.fill_buf().await {
                Ok(buf) => {
                    info!("{}/150 Read {} bytes from with BufRead", i+1, buf.len());
                    buf.len()
                },
                Err(err) => {
                    error!("Error: {}", err);
                    continue;
            }
            };

            uart_rx.consume(buf_len);
            info!("{}/150 consumed {} bytes from BufRead", i+1, buf_len);
        }
}