From 9b64e648e5f98c73400ec61f135b9bf3be95ce54 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Tue, 26 Mar 2024 10:10:17 +0000 Subject: [PATCH] Add async UART HIL test (#1345) * wip * Clean up Cargo config/manifest, update dependencies * Remove TODO comment from test --------- Co-authored-by: Scott Mabin --- esp-hal/src/uart.rs | 12 ++--- hil-test/Cargo.toml | 39 +++++++++-------- hil-test/tests/uart_async.rs | 85 ++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 23 deletions(-) create mode 100644 hil-test/tests/uart_async.rs diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index 576f57ebf..64fcc7ff6 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -1763,15 +1763,15 @@ mod asynch { T: Instance, { /// See [`UartRx::read_async`] - async fn read_async(&mut self, buf: &mut [u8]) -> Result { + pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { self.rx.read_async(buf).await } - async fn write_async(&mut self, words: &[u8]) -> Result { + pub async fn write_async(&mut self, words: &[u8]) -> Result { self.tx.write_async(words).await } - async fn flush_async(&mut self) -> Result<(), Error> { + pub async fn flush_async(&mut self) -> Result<(), Error> { self.tx.flush_async().await } } @@ -1780,7 +1780,7 @@ mod asynch { where T: Instance, { - async fn write_async(&mut self, words: &[u8]) -> Result { + pub async fn write_async(&mut self, words: &[u8]) -> Result { let mut count = 0; let mut offset: usize = 0; loop { @@ -1805,7 +1805,7 @@ mod asynch { Ok(count) } - async fn flush_async(&mut self) -> Result<(), Error> { + pub async fn flush_async(&mut self) -> Result<(), Error> { let count = T::get_tx_fifo_count(); if count > 0 { UartTxFuture::::new(TxEvent::TxDone.into()).await; @@ -1839,7 +1839,7 @@ mod asynch { /// # Ok /// When successful, returns the number of bytes written to buf. /// This method will never return Ok(0), unless buf.len() == 0. - async fn read_async(&mut self, buf: &mut [u8]) -> Result { + pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { if buf.len() == 0 { return Ok(0); } diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index 39e6c18aa..098f6d8e7 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -20,22 +20,30 @@ harness = false name = "uart" harness = false +[[test]] +name = "uart_async" +harness = false +required-features = ["async", "embassy"] + [dependencies] -defmt = { version = "0.3.5" } -defmt-rtt = { version = "0.4.0" } -esp-hal = { path = "../esp-hal", features = ["embedded-hal", "embedded-hal-02", "defmt"], optional = true } -embedded-hal-02 = { version = "0.2.7", package = "embedded-hal", features = ["unproven"] } +defmt = { version = "0.3.6" } +defmt-rtt = { version = "0.4.0" } +embassy-time = { version = "0.3.0", features = ["generic-queue-8"] } +embedded-hal = { version = "1.0.0" } +embedded-hal-02 = { version = "0.2.7", package = "embedded-hal", features = ["unproven"] } embedded-hal-async = { version = "1.0.0", optional = true } -embedded-hal = { version = "1.0.0" } -embedded-hal-nb = { version = "1.0.0", optional = true } -embassy-executor = { default-features = false, version = "0.5.0", features = ["executor-thread", "arch-riscv32"], optional = true } -semihosting = "0.1.6" +embedded-hal-nb = { version = "1.0.0", optional = true } +esp-hal = { path = "../esp-hal", features = ["defmt", "embedded-hal", "embedded-hal-02"], optional = true } +semihosting = { git = "https://github.com/taiki-e/semihosting", rev = "c829c19" } [dev-dependencies] +embassy-executor = { version = "0.5.0", default-features = false, features = ["executor-thread", "arch-riscv32"] } # Add the `embedded-test/defmt` feature for more verbose testing -embedded-test = {git = "https://github.com/probe-rs/embedded-test", rev = "8e3f925"} +embedded-test = {git = "https://github.com/probe-rs/embedded-test", rev = "8e3f925" } [features] +default = ["async", "embassy", "embassy-time-timg0"] + # Device support (required!): esp32 = ["esp-hal/esp32"] esp32c2 = ["esp-hal/esp32c2"] @@ -45,13 +53,13 @@ esp32h2 = ["esp-hal/esp32h2"] esp32s2 = ["esp-hal/esp32s2"] esp32s3 = ["esp-hal/esp32s3"] # Async & Embassy: -async = ["dep:embedded-hal-async", "esp-hal?/async"] -embassy = ["esp-hal?/embassy", "embedded-test/embassy", "dep:embassy-executor"] +async = ["dep:embedded-hal-async", "esp-hal?/async"] +embassy = ["esp-hal?/embassy", "embedded-test/embassy"] embassy-executor-interrupt = ["esp-hal?/embassy-executor-interrupt"] embassy-executor-thread = ["esp-hal?/embassy-executor-thread"] embassy-time-systick-16mhz = ["esp-hal?/embassy-time-systick-16mhz"] embassy-time-systick-80mhz = ["esp-hal?/embassy-time-systick-80mhz"] -embassy-time-timg0 = ["esp-hal?/embassy-time-timg0"] +embassy-time-timg0 = ["esp-hal?/embassy-time-timg0"] # https://doc.rust-lang.org/cargo/reference/profiles.html#test # Test and bench profiles inherit from dev and release respectively. @@ -61,7 +69,7 @@ codegen-units = 1 debug = 2 debug-assertions = true incremental = false -opt-level = 'z' +opt-level = "z" overflow-checks = true [profile.release] @@ -70,8 +78,5 @@ debug = 2 debug-assertions = false incremental = false opt-level = 3 -lto = 'fat' +lto = "fat" overflow-checks = false - -[patch.crates-io] -semihosting = { git = "https://github.com/taiki-e/semihosting", rev = "c829c19" } diff --git a/hil-test/tests/uart_async.rs b/hil-test/tests/uart_async.rs new file mode 100644 index 000000000..603358505 --- /dev/null +++ b/hil-test/tests/uart_async.rs @@ -0,0 +1,85 @@ +//! UART Test +//! +//! Folowing pins are used: +//! TX GPIP2 +//! RX GPIO4 +//! +//! Connect TX (GPIO2) and RX (GPIO4) pins. + +#![no_std] +#![no_main] + +use defmt_rtt as _; +use esp_hal::{ + clock::ClockControl, + gpio::IO, + peripherals::{Peripherals, UART0}, + prelude::*, + uart::{ + config::{Config, DataBits, Parity, StopBits}, + TxRxPins, + Uart, + UartRx, + UartTx, + }, + Async, +}; + +struct Context { + tx: UartTx<'static, UART0, Async>, + rx: UartRx<'static, UART0, Async>, +} + +impl Context { + pub fn init() -> Self { + let peripherals = Peripherals::take(); + let system = peripherals.SYSTEM.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + let pins = TxRxPins::new_tx_rx( + io.pins.gpio2.into_push_pull_output(), + io.pins.gpio4.into_floating_input(), + ); + let config = Config { + baudrate: 115200, + data_bits: DataBits::DataBits8, + parity: Parity::ParityNone, + stop_bits: StopBits::STOP1, + }; + + let uart = Uart::new_async_with_config(peripherals.UART0, config, Some(pins), &clocks); + let (tx, rx) = uart.split(); + + Context { rx, tx } + } +} + +#[cfg(test)] +#[embedded_test::tests] +mod tests { + use defmt::assert_eq; + + use super::*; + + #[init] + async fn init() -> Context { + Context::init() + } + + #[test] + #[timeout(3)] + async fn test_send_receive(mut ctx: Context) { + const SEND: &[u8] = &*b"Hello ESP32"; + let mut buf = [0u8; SEND.len()]; + + // Drain the FIFO to clear previous message: + ctx.tx.flush_async().await.unwrap(); + while ctx.rx.drain_fifo(&mut buf[..]) > 0 {} + + ctx.tx.write_async(&SEND).await.unwrap(); + ctx.tx.flush_async().await.unwrap(); + + ctx.rx.read_async(&mut buf[..]).await.unwrap(); + assert_eq!(&buf[..], SEND); + } +}