esp-hal/hil-test/tests/embassy_timers_executors.rs
Sergio Gasquez Arcos c88dbefff8
Avoid using nb::Result as a return type (#2882)
* feat: Avoid using nb::Result in spi

* feat: Avoid using nb::Result in hmac

* feat: Avoid using nb::Result in sha

* feat: Avoid using nb::Result in usb_serial_jtag

* feat: Avoid using nb::Result in adc::read_oneshot

* feat: Avoid using nb::Result in rsa::ready

* feat: Avoid using nb::Result in timer::wait

* feat: Avoid using nb in uart and twai. Udpate examples and tests to avoid using block!

* feat: Block on sha calls, remove Option<> results

* feat: Block on hmac calls, remove Option<> results

* fix: Clippy lints

* feat: Block on spi calls, remove Option<> results

* feat: Block on timer calls, remove Option<> results

* feat: Block on twai calls, remove Option<> results

* docs: Fix wait docstring

* feat: Remove embedded_hal_nb traits

* feat: Block on uart calls, remove Option<> results

* feat: Remove nb stuff from usb_serial_jtag

* feat: Block on rsa calls, remove Option<> results

* feat: Clippy lints

* feat: Make read_bytes return how many bytes it read from the fifo and fix docs/tests

* fix: run_test_periodic_timer test

* feat: Only remove nb from stabilizing drivers

* feat: Remove unused functions

* feat: Remove emnbedded-hal-nb

* test: Adapt tests

* docs: Update changelog and migration

* test: Adapt tests

* docs: Update migration guide

* docs: Update migration

Co-authored-by: Dániel Buga <bugadani@gmail.com>

* docs: Update changelog and migration guide

* feat: Make `write_bytes` return an Result

---------

Co-authored-by: Dániel Buga <bugadani@gmail.com>
2025-01-17 15:46:20 +00:00

277 lines
7.9 KiB
Rust

//! Embassy timer and executor Test
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: unstable embassy
#![no_std]
#![no_main]
use embassy_time::{Duration, Ticker, Timer};
#[cfg(not(feature = "esp32"))]
use esp_hal::{
interrupt::software::SoftwareInterruptControl,
interrupt::Priority,
timer::systimer::SystemTimer,
timer::AnyTimer,
};
use esp_hal::{
peripherals::Peripherals,
time::ExtU64,
timer::{timg::TimerGroup, OneShotTimer, PeriodicTimer},
};
#[cfg(not(feature = "esp32"))]
use esp_hal_embassy::InterruptExecutor;
use hil_test as _;
#[cfg(not(feature = "esp32"))]
macro_rules! mk_static {
($t:ty,$val:expr) => {{
static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new();
#[deny(unused_attributes)]
let x = STATIC_CELL.uninit().write(($val));
x
}};
}
// List of the functions that are ACTUALLY TESTS but are called in the invokers
mod test_helpers {
use super::*;
#[embassy_executor::task]
pub async fn e_task30ms() {
Timer::after_millis(30).await;
}
}
mod test_cases {
use esp_hal::peripheral::Peripheral;
use super::*;
pub async fn run_test_one_shot_async() {
let t1 = esp_hal::time::now();
Timer::after_millis(50).await;
Timer::after_millis(30).await;
let t2 = esp_hal::time::now();
assert!(t2 > t1, "t2: {:?}, t1: {:?}", t2, t1);
assert!(
(t2 - t1).to_millis() >= 80u64,
"diff: {:?}",
(t2 - t1).to_millis()
);
}
pub fn run_test_periodic_timer<T: esp_hal::timer::Timer>(timer: impl Peripheral<P = T>) {
let mut periodic = PeriodicTimer::new(timer);
let t1 = esp_hal::time::now();
periodic.start(100.millis()).unwrap();
periodic.wait();
let t2 = esp_hal::time::now();
assert!(t2 > t1, "t2: {:?}, t1: {:?}", t2, t1);
assert!(
(t2 - t1).to_millis() >= 100u64,
"diff: {:?}",
(t2 - t1).to_millis()
);
}
pub fn run_test_oneshot_timer<T: esp_hal::timer::Timer>(timer: impl Peripheral<P = T>) {
let mut timer = OneShotTimer::new(timer);
let t1 = esp_hal::time::now();
timer.delay_millis(50);
let t2 = esp_hal::time::now();
assert!(t2 > t1, "t2: {:?}, t1: {:?}", t2, t1);
assert!(
(t2 - t1).to_millis() >= 50u64,
"diff: {:?}",
(t2 - t1).to_millis()
);
}
pub async fn run_join_test() {
let t1 = esp_hal::time::now();
embassy_futures::join::join(Timer::after_millis(50), Timer::after_millis(30)).await;
Timer::after_millis(50).await;
let t2 = esp_hal::time::now();
assert!(t2 > t1, "t2: {:?}, t1: {:?}", t2, t1);
assert!(
(t2 - t1).to_millis() >= 100u64,
"diff: {:?}",
(t2 - t1).to_millis()
);
}
}
fn set_up_embassy_with_timg0(peripherals: Peripherals) {
let timg0 = TimerGroup::new(peripherals.TIMG0);
esp_hal_embassy::init(timg0.timer0);
}
#[cfg(not(feature = "esp32"))]
fn set_up_embassy_with_systimer(peripherals: Peripherals) {
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init(systimer.alarm0);
}
#[cfg(test)]
#[embedded_test::tests(default_timeout = 3, executor = hil_test::Executor::new())]
mod test {
use super::*;
use crate::test_cases::*;
#[cfg(not(feature = "esp32"))]
use crate::test_helpers::*;
#[init]
fn init() -> Peripherals {
esp_hal::init(esp_hal::Config::default())
}
#[test]
async fn test_one_shot_timg(peripherals: Peripherals) {
set_up_embassy_with_timg0(peripherals);
run_test_one_shot_async().await;
}
#[test]
#[cfg(not(feature = "esp32"))]
async fn test_one_shot_systimer(peripherals: Peripherals) {
set_up_embassy_with_systimer(peripherals);
run_test_one_shot_async().await;
}
#[test]
fn test_periodic_timg(peripherals: Peripherals) {
let timg0 = TimerGroup::new(peripherals.TIMG0);
run_test_periodic_timer(timg0.timer0);
}
#[test]
#[cfg(not(feature = "esp32"))]
fn test_periodic_systimer(peripherals: Peripherals) {
let systimer = SystemTimer::new(peripherals.SYSTIMER);
run_test_periodic_timer(systimer.alarm0);
}
#[test]
fn test_periodic_oneshot_timg(peripherals: Peripherals) {
let mut timg0 = TimerGroup::new(peripherals.TIMG0);
run_test_periodic_timer(&mut timg0.timer0);
run_test_oneshot_timer(&mut timg0.timer0);
}
#[test]
#[cfg(not(feature = "esp32"))]
fn test_periodic_oneshot_systimer(peripherals: Peripherals) {
let mut systimer = SystemTimer::new(peripherals.SYSTIMER);
run_test_periodic_timer(&mut systimer.alarm0);
run_test_oneshot_timer(&mut systimer.alarm0);
}
#[test]
async fn test_join_timg(peripherals: Peripherals) {
set_up_embassy_with_timg0(peripherals);
run_join_test().await;
}
#[test]
#[cfg(not(feature = "esp32"))]
async fn test_join_systimer(peripherals: Peripherals) {
set_up_embassy_with_systimer(peripherals);
run_join_test().await;
}
/// Test that the ticker works in tasks ran by the interrupt executors.
#[test]
#[cfg(not(feature = "esp32"))]
async fn test_interrupt_executor(peripherals: Peripherals) {
let timg0 = TimerGroup::new(peripherals.TIMG0);
let timer0: AnyTimer = timg0.timer0.into();
let systimer = SystemTimer::new(peripherals.SYSTIMER);
let alarm0: AnyTimer = systimer.alarm0.into();
esp_hal_embassy::init([timer0, alarm0]);
let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
let executor = mk_static!(
InterruptExecutor<2>,
InterruptExecutor::new(sw_ints.software_interrupt2)
);
#[embassy_executor::task]
#[cfg(not(feature = "esp32"))]
async fn test_interrupt_executor_invoker() {
let outcome = async {
let mut ticker = Ticker::every(Duration::from_millis(30));
let t1 = esp_hal::time::now();
ticker.next().await;
ticker.next().await;
ticker.next().await;
let t2 = esp_hal::time::now();
assert!(t2 > t1, "t2: {:?}, t1: {:?}", t2, t1);
assert!(
(t2 - t1).to_micros() >= 85000u64,
"diff: {:?}",
(t2 - t1).to_micros()
);
};
embedded_test::export::check_outcome(outcome.await);
}
let spawner_int = executor.start(Priority::Priority3);
spawner_int.must_spawn(test_interrupt_executor_invoker());
let spawner = embassy_executor::Spawner::for_current_executor().await;
spawner.must_spawn(e_task30ms());
// The test ends once the interrupt executor's task has finished
loop {}
}
/// Test that timg0 and systimer don't have vastly different tick rates.
#[test]
async fn tick_test_timer_tick_rates(peripherals: Peripherals) {
set_up_embassy_with_timg0(peripherals);
// We are retrying 5 times because probe-rs polling RTT may introduce some
// jitter.
for _ in 0..5 {
let t1 = esp_hal::time::now();
let mut ticker = Ticker::every(Duration::from_hz(100_000));
for _ in 0..2000 {
ticker.next().await;
}
let t2 = esp_hal::time::now();
assert!(t2 > t1, "t2: {:?}, t1: {:?}", t2, t1);
let duration = (t2 - t1).to_micros();
assert!(duration >= 19000, "diff: {:?}", (t2 - t1).to_micros());
if duration <= 21000 {
return;
}
}
assert!(false, "Test failed after 5 retries");
}
}