Skip to content

read_exact_async returns FifoOverflowed when more than 128 bytes is to be received #4523

@jimy-byerley

Description

@jimy-byerley

Bug description

In the following example, i program a esp32-none to simply echo on UART1, and my pc to alternatively send fixed size frames and wait for the echo. for any frame size under 128bytes everything is ok. above i almost systematically get FifoOverflowed on the esp32 side, despite the buffer i give for reception is big enough for the frame and the esp32 has nothing else to do.

The problem is independent of the baud rate it seems: I tested both with 1_500_00 Hz and 115_200 Hz

To Reproduce

On esp32

#![no_std]
#![no_main]
#![deny(
    clippy::mem_forget,
    reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
    holding buffers for the duration of a data transfer."
)]

use esp_backtrace as _;
use esp_hal::{
    clock::CpuClock,
    timer::timg::TimerGroup,
    uart::{DataBits, Parity, StopBits},
};
use embassy_executor::Spawner;
use esp_println as _;
use log::*;
// use embedded_io_async::{Read, Write};


esp_bootloader_esp_idf::esp_app_desc!();

#[esp_rtos::main]
async fn main(_spawner: Spawner) {
    // init hardware
    esp_println::logger::init_logger_from_env();
    
    let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
    let peripherals = esp_hal::init(config);
    
    let timg0 = TimerGroup::new(peripherals.TIMG0);
    esp_rtos::start(timg0.timer0);
    
    // initialize slave
    info!("setting up slave");
    let config = esp_hal::uart::Config::default()
        .with_baudrate(1_500_000)  // same for 115_200
        .with_data_bits(DataBits::_8)
        .with_stop_bits(StopBits::_1)
        .with_parity(Parity::Even)
        ;
    let mut bus = esp_hal::uart::Uart::new(peripherals.UART1, config).unwrap()
        .with_rx(peripherals.GPIO16)
        .with_tx(peripherals.GPIO17)
        .into_async();
    
    info!("start echoing");
    let mut buffer = [0; 129];  // works with 128, but not after
    loop {
        if let Err(err) = bus.read_exact_async(&mut buffer).await {
            debug!("read error: {:?}", err);
            continue
        }
        bus.write_async(&buffer).await.unwrap();
    }
}

on my pc

use std::time::{Duration, Instant};
use serial2_tokio::{SerialPort, CharSize, StopBits, Parity};
use tokio::io::{AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() {
    pretty_env_logger::init();

    // initialize a master on some uart port
    println!("creating master");
    
    // possible baud rates
    // 115_200
    // 1_000_000
    // 1_500_000
    // 2_000_000
    
    let mut bus = SerialPort::open("/dev/ttyUSB1", |mut settings: serial2_tokio::Settings| {
        settings.set_raw();
        settings.set_baud_rate(1_500_000)?;
        settings.set_char_size(CharSize::Bits8);
        settings.set_stop_bits(StopBits::One);
        settings.set_parity(Parity::Even);
        Ok(settings)
        }).unwrap();
        
    println!("running");
    let mut send = [0; 129];  // must match the buffer size on the esp32
    let mut receive = send.clone();
    let timeout = Duration::from_millis(100);
    
    while tokio::time::timeout(timeout, bus.read_exact(&mut receive)).await.is_ok() {}
    
    for j in 0 .. 20 {
        send[0] = j as u8;
        for i in 1 .. send.len() {send[i] = i as u8;}
        
        let start = Instant::now();
        bus.write(&send).await.unwrap();
        let result = tokio::time::timeout(timeout, bus.read_exact(&mut receive)).await;
        let complete_read = start.elapsed();
        
//         if result.is_ok() {
//             println!("    send {:?}", &send);
//             println!("    receive {:?}", &receive);
//         }
        
        println!("elapsed {:?}  result {:?}  equal: {}", complete_read, result.map(|_| ()), send == receive);
    }
}

When the frame has 129 bytes or above get on the pc side

creating master
running
elapsed 101.528823ms  result Err(Elapsed(()))  equal: false
elapsed 100.536611ms  result Err(Elapsed(()))  equal: false
elapsed 101.556393ms  result Err(Elapsed(()))  equal: false
elapsed 100.579971ms  result Err(Elapsed(()))  equal: false
...

and on esp32 side (UART0)

INFO - setting up slave
INFO - start echoing
DEBUG - read error: FifoOverflowed

Expected behavior

When frame is 128 bytes or below I get on pc side:

creating master
running
elapsed 2.411464ms  result Ok(())  equal: true
elapsed 2.270754ms  result Ok(())  equal: true
elapsed 2.279125ms  result Ok(())  equal: true
elapsed 2.354754ms  result Ok(())  equal: true
...

Environment

  • Target device:
    Chip type: esp32 (revision v1.0)
    Crystal frequency: 40 MHz
    Flash size: 4MB
    Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
    MAC address: 24:6f:28:be:3e:d4
    Security features: None

  • Crate name and version: esp-hal 1.0.0 unstable

    esp-bootloader-esp-idf = { version = "0.4.0", features = ["esp32"] }
    esp-hal                = { version = "1.0.0", features = ["esp32", "unstable"] }
    esp-backtrace          = { version = "0.18", features = ["esp32", "println", "colors", "panic-handler"]}
    esp-rtos = { version = "0.2", features = ["esp32", "embassy"] }
    esp-println            = { version = "0.16.1", features = ["esp32", "log-04"] }
    esp-alloc              = { version = "0.9", features = ["esp32"] }
  • UART bridge on pc side: QinHeng Electronics CH340 serial converter

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingperipheral:uartUART peripheral

Type

No type

Projects

Status

Todo

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions