diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0adbdc59f..1ae3a8d63 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,14 +18,12 @@ on: paths-ignore: - "**/CHANGELOG.md" - "**/README.md" - - "**/hil-test/**" push: branches-ignore: - "gh-readonly-queue/**" paths-ignore: - "**/CHANGELOG.md" - "**/README.md" - - "**/hil-test/**" merge_group: workflow_dispatch: diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index 098f6d8e7..bdd5af2d8 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -35,6 +35,7 @@ embedded-hal-async = { version = "1.0.0", optional = true } 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" } +critical-section = { version = "1.1.2" } [dev-dependencies] embassy-executor = { version = "0.5.0", default-features = false, features = ["executor-thread", "arch-riscv32"] } diff --git a/hil-test/tests/gpio.rs b/hil-test/tests/gpio.rs index 3e53a829a..7ac868d79 100644 --- a/hil-test/tests/gpio.rs +++ b/hil-test/tests/gpio.rs @@ -7,40 +7,77 @@ #![no_std] #![no_main] +use core::cell::RefCell; + +use critical_section::Mutex; use defmt_rtt as _; use embedded_hal::digital::{InputPin as _, OutputPin as _, StatefulOutputPin as _}; use esp_hal::{ - gpio::{GpioPin, Input, Output, PullDown, PushPull, IO}, + clock::ClockControl, + delay::Delay, + gpio::{GpioPin, Input, Output, OutputPin, PullDown, PushPull, IO}, + macros::handler, peripherals::Peripherals, + system::SystemExt, }; +static COUNTER: Mutex> = Mutex::new(RefCell::new(0)); +static INPUT_PIN: Mutex>>>> = + Mutex::new(RefCell::new(None)); + struct Context { io2: GpioPin, 2>, io4: GpioPin, 4>, + delay: Delay, } impl Context { pub fn init() -> Self { let peripherals = Peripherals::take(); - let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + let system = peripherals.SYSTEM.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + let mut io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + io.set_interrupt_handler(interrupt_handler); + + let delay = Delay::new(&clocks); Context { io2: io.pins.gpio2.into_pull_down_input(), io4: io.pins.gpio4.into_push_pull_output(), + delay, } } } +#[handler] +pub fn interrupt_handler() { + critical_section::with(|cs| { + use esp_hal::gpio::Pin; + + *COUNTER.borrow_ref_mut(cs) += 1; + INPUT_PIN + .borrow_ref_mut(cs) + .as_mut() + .unwrap() + .clear_interrupt(); + }); +} + #[cfg(test)] #[embedded_test::tests] mod tests { use defmt::assert_eq; + use esp_hal::gpio::{Event, Pin}; use super::*; #[init] fn init() -> Context { - Context::init() + let mut ctx = Context::init(); + // make sure tests don't interfere with each other + ctx.io4.set_low().ok(); + ctx } #[test] @@ -69,4 +106,73 @@ mod tests { // Leave in initial state for next test assert!(ctx.io4.toggle().is_ok()); } + + #[test] + fn test_gpio_interrupt(mut ctx: Context) { + critical_section::with(|cs| { + *COUNTER.borrow_ref_mut(cs) = 0; + ctx.io2.listen(Event::AnyEdge); + INPUT_PIN.borrow_ref_mut(cs).replace(ctx.io2); + }); + assert!(ctx.io4.set_high().is_ok()); + ctx.delay.delay_millis(1); + assert!(ctx.io4.set_low().is_ok()); + ctx.delay.delay_millis(1); + assert!(ctx.io4.set_high().is_ok()); + ctx.delay.delay_millis(1); + assert!(ctx.io4.set_low().is_ok()); + ctx.delay.delay_millis(1); + assert!(ctx.io4.set_high().is_ok()); + ctx.delay.delay_millis(1); + assert!(ctx.io4.set_low().is_ok()); + ctx.delay.delay_millis(1); + assert!(ctx.io4.set_high().is_ok()); + ctx.delay.delay_millis(1); + assert!(ctx.io4.set_low().is_ok()); + ctx.delay.delay_millis(1); + assert!(ctx.io4.set_high().is_ok()); + ctx.delay.delay_millis(1); + + let count = critical_section::with(|cs| *COUNTER.borrow_ref(cs)); + assert_eq!(count, 9); + + ctx.io2 = critical_section::with(|cs| INPUT_PIN.borrow_ref_mut(cs).take().unwrap()); + ctx.io2.unlisten(); + } + + #[test] + fn test_gpio_od(ctx: Context) { + let mut io2 = ctx.io2.into_open_drain_output(); + io2.internal_pull_up(true); + let mut io4 = ctx.io4.into_open_drain_output(); + io4.internal_pull_up(true); + + assert!(io2.set_high().is_ok()); + assert!(io4.set_high().is_ok()); + ctx.delay.delay_millis(1); + + assert_eq!(io2.is_high(), Ok(true)); + assert_eq!(io4.is_high(), Ok(true)); + + assert!(io2.set_low().is_ok()); + assert!(io4.set_high().is_ok()); + ctx.delay.delay_millis(1); + + assert_eq!(io2.is_low(), Ok(true)); + assert_eq!(io4.is_low(), Ok(true)); + + assert!(io2.set_high().is_ok()); + assert!(io4.set_high().is_ok()); + ctx.delay.delay_millis(1); + + assert_eq!(io2.is_high(), Ok(true)); + assert_eq!(io4.is_high(), Ok(true)); + + assert!(io2.set_high().is_ok()); + assert!(io4.set_low().is_ok()); + ctx.delay.delay_millis(1); + + assert_eq!(io2.is_low(), Ok(true)); + assert_eq!(io4.is_low(), Ok(true)); + } }