esp-hal/hil-test/tests/embassy_interrupt_executor.rs
Dániel Buga 571760884b
Update our time driver for upcoming embassy changes (#2701)
* Add a timer-driven task

* Spawn another timer

* Log

* foo

* Do not access current time on each schedule

* Update generic queue

* Minimize alarm priorities

* Point to github with patches

* Fix build without any queue impl selected

* Remove explicit generic-queue features

* Define cfgs, fix calling something uninitialized

* Clean up RefCell+generic queue

* Fix arg order

* Feature

* Fix single integrated-timer queue

* Fix next expiration when arming

* Add note

* Adjust impl to latest changes

* Local patch

* Refactor the refactor refactor

* Track the timer item's owner

* Clear owner on dequeue

* Clean up

* Point at the right branch

* Fix panic message

* Hide private function

* Remove integrated-timer references

* Point at upstream embassy

* Configure via esp-config

* Document, clean up, fix

* Hack

* Remove patches

* Update config separator, test the complex variant

* Undo esp-config hack

* Remove trouble example, update edge-net

* Update test deps

* Document

* Update bt-hci.

* Fix generic queue

* Fix panic message

* Fix UB

* Fix rebase

* Resolve UB

* Avoid mutable reference in interrupt executor

---------

Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
2025-01-14 16:17:58 +00:00

171 lines
5.2 KiB
Rust

//! Test that the interrupt executor correctly gives back control to thread mode
//! code.
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: unstable embassy
#![no_std]
#![no_main]
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal};
#[cfg(multi_core)]
use esp_hal::cpu_control::{CpuControl, Stack};
use esp_hal::{
interrupt::{
software::{SoftwareInterrupt, SoftwareInterruptControl},
Priority,
},
timer::AnyTimer,
};
#[cfg(multi_core)]
use esp_hal_embassy::Executor;
use esp_hal_embassy::InterruptExecutor;
use hil_test as _;
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
}};
}
#[embassy_executor::task]
async fn responder_task(
signal: &'static Signal<CriticalSectionRawMutex, ()>,
response: &'static Signal<CriticalSectionRawMutex, ()>,
) {
response.signal(());
loop {
signal.wait().await;
response.signal(());
}
}
struct Context {
interrupt: SoftwareInterrupt<1>,
#[cfg(multi_core)]
cpu_control: CpuControl<'static>,
}
#[cfg(test)]
#[embedded_test::tests(default_timeout = 3, executor = hil_test::Executor::new())]
mod test {
use super::*;
#[init]
fn init() -> Context {
let peripherals = esp_hal::init(esp_hal::Config::default());
cfg_if::cfg_if! {
if #[cfg(timg_timer1)] {
use esp_hal::timer::timg::TimerGroup;
let timg0 = TimerGroup::new(peripherals.TIMG0);
esp_hal_embassy::init([
AnyTimer::from(timg0.timer0),
AnyTimer::from(timg0.timer1),
]);
} else if #[cfg(timg1)] {
use esp_hal::timer::timg::TimerGroup;
let timg0 = TimerGroup::new(peripherals.TIMG0);
let timg1 = TimerGroup::new(peripherals.TIMG1);
esp_hal_embassy::init([
AnyTimer::from(timg0.timer0),
AnyTimer::from(timg1.timer0),
]);
} else if #[cfg(systimer)] {
use esp_hal::timer::systimer::SystemTimer;
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init([
AnyTimer::from(systimer.alarm0),
AnyTimer::from(systimer.alarm1),
]);
}
}
let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
Context {
interrupt: sw_ints.software_interrupt1,
#[cfg(multi_core)]
cpu_control: CpuControl::new(peripherals.CPU_CTRL),
}
}
#[test]
async fn run_interrupt_executor_test(ctx: Context) {
let interrupt_executor =
mk_static!(InterruptExecutor<1>, InterruptExecutor::new(ctx.interrupt));
let signal = mk_static!(Signal<CriticalSectionRawMutex, ()>, Signal::new());
let response = mk_static!(Signal<CriticalSectionRawMutex, ()>, Signal::new());
let spawner = interrupt_executor.start(Priority::Priority3);
spawner.spawn(responder_task(signal, response)).unwrap();
response.wait().await;
for _ in 0..3 {
signal.signal(());
response.wait().await;
}
}
#[test]
#[cfg(multi_core)]
async fn run_interrupt_executor_test_on_core_1(mut ctx: Context) {
let app_core_stack = mk_static!(Stack<8192>, Stack::new());
let response = &*mk_static!(Signal<CriticalSectionRawMutex, ()>, Signal::new());
let signal = &*mk_static!(Signal<CriticalSectionRawMutex, ()>, Signal::new());
let cpu1_fnctn = {
move || {
let interrupt_executor =
mk_static!(InterruptExecutor<1>, InterruptExecutor::new(ctx.interrupt));
let spawner = interrupt_executor.start(Priority::Priority3);
spawner.spawn(responder_task(signal, response)).unwrap();
loop {}
}
};
let _guard = ctx
.cpu_control
.start_app_core(app_core_stack, cpu1_fnctn)
.unwrap();
response.wait().await;
for _ in 0..3 {
signal.signal(());
response.wait().await;
}
}
#[test]
#[cfg(multi_core)]
async fn run_thread_executor_test_on_core_1(mut ctx: Context) {
let app_core_stack = mk_static!(Stack<8192>, Stack::new());
let signal = mk_static!(Signal<CriticalSectionRawMutex, ()>, Signal::new());
let response = mk_static!(Signal<CriticalSectionRawMutex, ()>, Signal::new());
let cpu1_fnctn = || {
let executor = mk_static!(Executor, Executor::new());
executor.run(|spawner| {
spawner.spawn(responder_task(signal, response)).ok();
});
};
let _guard = ctx
.cpu_control
.start_app_core(app_core_stack, cpu1_fnctn)
.unwrap();
response.wait().await;
for _ in 0..3 {
signal.signal(());
response.wait().await;
}
}
}