esp-rs / esp-idf-hal

embedded-hal implementation for Rust on ESP32 and ESP-IDF
https://docs.esp-rs.org/esp-idf-hal/
Apache License 2.0
440 stars 169 forks source link

Example uart_loopback does not compile. TX buffer managment in Uart is broken sending garbage characters. #408

Open joeatbayes opened 4 months ago

joeatbayes commented 4 months ago

The example https://github.com/esp-rs/esp-idf-hal/blob/master/examples/uart_loopback.rs fails to compile due to a missing import. I adapted it to my needs and fixed a couple errors so it both compiles and provides proper response when tested with linux screen.

As shown below the two commented lines to uart.write() and uart_wait_tx_done() end up causing 1 character followed by 10 garbage characters. When the write is replaced with write_nb() which does not use the uart tx buffer it works correctly.

I would greatly appreciate the proper esp_idf_hal example code to reset the watchdog timer at the bottom of the loop so I can remove the sleep_ms(15). I know that we can do this with async or threads but what I really want here is a demonstration of a fast polling loop. I find they scale better and provide more predictable timing than spawning a bunch of threads.

### Results working copied from linux screen correctly echoing keys hit from linux screen connected as uart device on other end

abcdefghijklmnopaewwabcdefghijklmnopabcdefg
### Results copied from linux screen when the write() is used instead of write_nb()

�������������b����������c�555555555�MMMMMMMMMM���555555555�����������e�555555555�����������e������������d����������f�55555555��55555555555555�������i����������j����������k����������l����������m����������n�55555555��SSSSSSSSSSSSSS����������������aSSSSSSSSSSSSSS
                    ��555555555쪪��������c�555555555�����������a�55555555��555555555������������a����������b�55555555��MMMMMMMMMMMMMm��555555555�����������a�555555555�SSSSSSSSSSSS������������d����������e55555555555555�����������g�555555555�������iSSSSSSSSSSSS�����������k�555555555�55555555555������������n����������o�555555555����������

Source that works correctly

//! Non Blocking fast poll Uart RS485 1/2 duplex echo for RS485 style transciever
//! test
//!
//! Folowing pins are used:
//! TX    GPIO43
//! RX    GPIO44
//!//!
//! This example transfers data via UART.
//! Connect TX and RX pins to see the outgoing data is read as incoming data.
//! Echo characters sent from terminal such as linux screen. 
#![allow(unused_imports)]
#![allow(dead_code)]

use anyhow::Result;
use esp_idf_hal::delay::NON_BLOCK;
use esp_idf_hal::gpio;
use esp_idf_hal::gpio::PinDriver;
use esp_idf_hal::delay::Delay;
use esp_idf_hal::peripherals::Peripherals;
use esp_idf_hal::prelude::*;
use esp_idf_hal::uart::*;
use esp_idf_sys;
// TODO:  Figure out how to make WDT work esp_idf_hal https://github.com/esp-rs/esp-hal/blob/main/examples/src/bin/watchdog.rs
// Until then disable WDT in menu config

fn main() -> anyhow::Result<()> {
    esp_idf_hal::sys::link_patches();
    let peripherals = Peripherals::take()?;

    let tx = peripherals.pins.gpio43;
    let rx = peripherals.pins.gpio44;
    let led_pin = peripherals.pins.gpio11;
    let rs_48_en_pin = peripherals.pins.gpio21;
    let delay: Delay = Default::default();
    let mut led = PinDriver::output(led_pin)?;
    let mut rs48_enable = PinDriver::output(rs_48_en_pin)?;

    println!("Starting UART loopback test");
    let config = config::Config::new().baudrate(Hertz(115_200));
    let uart = UartDriver::new(
        peripherals.uart1,
        tx,
        rx,
        Option::<gpio::Gpio0>::None,
        Option::<gpio::Gpio1>::None,
        &config,
    )?;

    loop {
        let mut buf = [0_u8; 1];        
        uart.read(&mut buf, NON_BLOCK)?;
        // we know read will return a 0 in buf 
        // when nothing is available so we ignore 
        if buf[0] != 0 {            
          println!("Written 0xaa, read {:?} {:?} 0x{:02x}", buf[0] as char, buf[0],buf[0]);
          rs48_enable.set_high()?;
          delay.delay_us(150); // need to allow transceiver time to enter active mode

          // Calling Write directly causes mutliple garbage characters to 
          // be sent.  I think the uart is not properly managing it's buffer.
          //uart.write(&buf)?;
          //uart.wait_tx_done(150);

          uart.write_nb(&mut buf)?;          
          delay.delay_ms(1);
          //buf[0] = 0;                    
          rs48_enable.set_low()?;
          led.toggle()?;
        }
        // Only need this delay because watchdog fires otherwise
        delay.delay_ms(18); // TODO: TO RESET WATCHDOG IN TIGHT LOOP LIKE THIS USING esp_idf_hal

        // TODO: DO SOME OTHER WORK SINCE WE ARE NO LONGER BLOCKING
        // ON DATA IN UART AVAILABILITY

    }
}

### Cargo for this file

[package] name = "ex-uart-non-block-rs485" version = "0.1.0" authors = ["joe ellsworth joexdobs@gmail.com"] edition = "2021" resolver = "2" rust-version = "1.71"

[profile.release] opt-level = "s"

[profile.dev] debug = true # Symbols are nice and they don't increase the size on Flash opt-level = "z"

[features] default = ["std", "embassy", "esp-idf-svc/native"]

pio = ["esp-idf-svc/pio"] std = ["alloc", "esp-idf-svc/binstart", "esp-idf-svc/std"] alloc = ["esp-idf-svc/alloc"] nightly = ["esp-idf-svc/nightly"] experimental = ["esp-idf-svc/experimental"] embassy = ["esp-idf-svc/embassy-sync", "esp-idf-svc/critical-section", "esp-idf-svc/embassy-time-driver"]

[dependencies] log = { version = "0.4", default-features = false } esp-idf-svc = { version = "0.48", default-features = false } esp-idf-hal = "0.43.1" anyhow = "1.0.82" esp-idf-sys = "0.34.1"

[build-dependencies] embuild = "0.31.3"

joeatbayes commented 4 months ago

jesse how do I tell what should be filed here or over in esp-rs. This is the second one of my issues you had to move.