Refactor testing, add defmt, add async gpio test (#1363)

* Refactor testing, add defmt, add async gpio test

* Add test to ensure the some edge case pins can be used in async mode

* Add test for pin0

* clippy

* update test to use constants extracted from esp-idf's soc module

* address review comments

* simplify test to just initialize one pin as async

* changelog
This commit is contained in:
Scott Mabin 2024-04-02 16:28:15 +01:00 committed by GitHub
parent 392ae7dee6
commit 21d833d2a3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 87 additions and 14 deletions

View File

@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Delay::delay(time: fugit::MicrosDurationU64)`
- Added async support for TWAI (#1320)
- Add TWAI support for ESP32-C6 (#1323)
- `GpioPin::steal` unsafe API (#1363)
### Fixed

View File

@ -807,6 +807,20 @@ where
}
}
impl<const GPIONUM: u8> GpioPin<Unknown, GPIONUM>
where
Self: GpioProperties,
{
/// Create a pin out of thin air.
///
/// # Safety
///
/// Ensure that only one instance of a pin exists at one time.
pub unsafe fn steal() -> Self {
Self { _mode: PhantomData }
}
}
impl<MODE, const GPIONUM: u8> Pin for GpioPin<MODE, GPIONUM>
where
Self: GpioProperties,

View File

@ -14,6 +14,7 @@ rustflags = [
"-C", "link-arg=-Tlinkall.x",
"-C", "link-arg=-Tembedded-test.x",
"-C", "link-arg=-Tdefmt.x",
"-C", "force-frame-pointers"
]
[target.'cfg(target_arch = "xtensa")']
@ -25,5 +26,8 @@ rustflags = [
"-C", "link-arg=-Tembedded-test.x",
]
[env]
DEFMT_LOG = "info"
[unstable]
build-std = ["core"]

View File

@ -28,31 +28,34 @@ required-features = ["async", "embassy"]
[dependencies]
defmt = { version = "0.3.6" }
defmt-rtt = { version = "0.4.0" }
embassy-time = { version = "0.3.0", features = ["generic-queue-8"] }
embassy-time = { version = "0.3.0", features = ["generic-queue-64"] }
embassy-futures = { version = "0.1" }
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-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" }
esp-backtrace = { version = "0.11.1", git = "https://github.com/esp-rs/esp-backtrace", rev = "edff83c3945e8aa11081d8467af65803a82434ba", default-features = false, features = ["exception-handler", "panic-handler", "defmt", "semihosting"] }
critical-section = { version = "1.1.2" }
portable-atomic = "1"
cfg-if = "1"
[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 = "b67dec33992f5bd79d414a0e70220dc4142278cf", default-features = false }
[features]
default = ["async", "embassy", "embassy-time-timg0"]
# Device support (required!):
esp32 = ["esp-hal/esp32"]
esp32c2 = ["esp-hal/esp32c2"]
esp32c3 = ["esp-hal/esp32c3"]
esp32c6 = ["esp-hal/esp32c6"]
esp32h2 = ["esp-hal/esp32h2"]
esp32s2 = ["esp-hal/esp32s2"]
esp32s3 = ["esp-hal/esp32s3"]
esp32 = ["esp-hal/esp32", "esp-backtrace/esp32"]
esp32c2 = ["esp-hal/esp32c2", "esp-backtrace/esp32c2"]
esp32c3 = ["esp-hal/esp32c3", "esp-backtrace/esp32c3"]
esp32c6 = ["esp-hal/esp32c6", "esp-backtrace/esp32c6"]
esp32h2 = ["esp-hal/esp32h2", "esp-backtrace/esp32h2"]
esp32s2 = ["esp-hal/esp32s2", "esp-backtrace/esp32s2"]
esp32s3 = ["esp-hal/esp32s3", "esp-backtrace/esp32s3"]
# Async & Embassy:
async = ["dep:embedded-hal-async", "esp-hal?/async"]
embassy = ["esp-hal?/embassy", "embedded-test/embassy"]

View File

@ -4,6 +4,7 @@
#![no_main]
use defmt_rtt as _;
use esp_backtrace as _;
use esp_hal::{
aes::{Aes, Mode},
peripherals::Peripherals,

View File

@ -12,13 +12,16 @@ use core::cell::RefCell;
use critical_section::Mutex;
use defmt_rtt as _;
use embedded_hal::digital::{InputPin as _, OutputPin as _, StatefulOutputPin as _};
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
delay::Delay,
gpio::{GpioPin, Input, Output, OutputPin, PullDown, PushPull, IO},
embassy,
gpio::{GpioPin, Input, Output, OutputPin, PullDown, PushPull, Unknown, IO},
macros::handler,
peripherals::Peripherals,
system::SystemExt,
timer::TimerGroup,
};
static COUNTER: Mutex<RefCell<u32>> = Mutex::new(RefCell::new(0));
@ -42,6 +45,9 @@ impl Context {
let delay = Delay::new(&clocks);
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0);
Context {
io2: io.pins.gpio2.into_pull_down_input(),
io4: io.pins.gpio4.into_push_pull_output(),
@ -58,9 +64,8 @@ pub fn interrupt_handler() {
*COUNTER.borrow_ref_mut(cs) += 1;
INPUT_PIN
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt();
.as_mut() // we can't unwrap as the handler may get called for async operations
.map(|pin| pin.clear_interrupt());
});
}
@ -68,7 +73,10 @@ pub fn interrupt_handler() {
#[embedded_test::tests]
mod tests {
use defmt::assert_eq;
use embassy_time::{Duration, Timer};
use embedded_hal_async::digital::Wait;
use esp_hal::gpio::{Event, Pin};
use portable_atomic::{AtomicUsize, Ordering};
use super::*;
@ -80,6 +88,45 @@ mod tests {
ctx
}
#[test]
async fn test_async_edge(ctx: Context) {
let counter = AtomicUsize::new(0);
let Context {
mut io2, mut io4, ..
} = ctx;
embassy_futures::select::select(
async {
loop {
io2.wait_for_rising_edge().await.unwrap();
counter.fetch_add(1, Ordering::SeqCst);
}
},
async {
for _ in 0..5 {
io4.set_high().unwrap();
Timer::after(Duration::from_millis(25)).await;
io4.set_low().unwrap();
Timer::after(Duration::from_millis(25)).await;
}
},
)
.await;
assert_eq!(counter.load(Ordering::SeqCst), 5);
}
#[test]
async fn test_a_pin_can_wait(_ctx: Context) {
let mut first = unsafe { GpioPin::<Unknown, 0>::steal() }.into_pull_down_input();
embassy_futures::select::select(
first.wait_for_rising_edge(),
// Other futures won't return, this one will, make sure its last so all other futures
// are polled first
embassy_futures::yield_now(),
)
.await;
}
#[test]
fn test_gpio_input(mut ctx: Context) {
// `InputPin`:

View File

@ -13,6 +13,7 @@
use defmt_rtt as _;
use embedded_hal::spi::SpiBus;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
gpio::IO,

View File

@ -11,6 +11,7 @@
use defmt_rtt as _;
use embedded_hal_02::serial::{Read, Write};
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
gpio::IO,

View File

@ -10,6 +10,7 @@
#![no_main]
use defmt_rtt as _;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
gpio::IO,