Optionally type-erased GPIO drivers (#2075)

* Remove type erased gpio structs

* Implement Peripheral for ErasedPin

* Simpler type erasing, accept ErasedPin in pin drivers, remove type erased drivers

* Reformulate pin drivers using Flex

* Erase gpio types by default

* Accept any pin in AnyPin

* Add changelog and migration guide

* Fix tests and examples

* Undo rename of clone_unchecked
This commit is contained in:
Dániel Buga 2024-09-05 16:14:51 +02:00 committed by GitHub
parent a5ab73959e
commit f11c18a6b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 554 additions and 980 deletions

View File

@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Implement `embedded-hal` output pin traits for `DummyPin` (#2019) - Implement `embedded-hal` output pin traits for `DummyPin` (#2019)
- Added `esp_hal::init` to simplify HAL initialisation (#1970, #1999) - Added `esp_hal::init` to simplify HAL initialisation (#1970, #1999)
- Added GpioPin::degrade to create ErasePins easily. Same for AnyPin by accident. (#2075)
- Added missing functions to `Flex`: `unlisten`, `is_interrupt_set`, `wakeup_enable`, `wait_for_high`, `wait_for_low`, `wait_for_rising_edge`, `wait_for_falling_edge`, `wait_for_any_edge`. (#2075)
- `Flex` now implements `Wait`. (#2075)
- Added sleep and wakeup support for esp32c2 (#1922) - Added sleep and wakeup support for esp32c2 (#1922)
### Changed ### Changed
@ -18,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Delay::new()` is now a `const` function (#1999) - `Delay::new()` is now a `const` function (#1999)
- You can now create an `AnyPin` out of an `ErasedPin`. (#2072) - You can now create an `AnyPin` out of an `ErasedPin`. (#2072)
- `Input`, `Output`, `OutputOpenDrain` and `Flex` are now type-erased by default. Use the new `new_typed` constructor to keep using the ZST pin types. (#2075)
### Fixed ### Fixed
- SHA driver can now be safely used in multiple contexts concurrently (#2049) - SHA driver can now be safely used in multiple contexts concurrently (#2049)

View File

@ -41,3 +41,13 @@ Instead of manually grabbing peripherals and setting up clocks, you should now c
- The `GpioN` type aliasses are no longer available. You can use `GpioPin<N>` instead. - The `GpioN` type aliasses are no longer available. You can use `GpioPin<N>` instead.
- The `AnyInputOnlyPin` has been removed. Replace any use with `AnyPin`. - The `AnyInputOnlyPin` has been removed. Replace any use with `AnyPin`.
- The `NoPinType` has been removed. You can use `DummyPin` in its place. - The `NoPinType` has been removed. You can use `DummyPin` in its place.
### Type-erased GPIO drivers
You no longer have to spell out the GPIO pin type for `Input`, `Output`, `OutputOpenDrain` or `Flex`.
However, if you want to, you can keep using their typed form!
```rust
let pin = Input::new(io.gpio0); // pin will have the type `Input<'some>` (or `Input<'some, ErasedPin>` if you want to be explicit about it)
let pin = Input::new_typed(io.gpio0); // pin will have the type `Input<'some, GpioPin<0>>`
```

View File

@ -13,9 +13,12 @@ pub struct AnyPin<'d> {
impl<'d> AnyPin<'d> { impl<'d> AnyPin<'d> {
/// Create wrapper for the given pin. /// Create wrapper for the given pin.
#[inline] #[inline]
pub fn new<P: CreateErasedPin>(pin: impl crate::peripheral::Peripheral<P = P> + 'd) -> Self { pub fn new<P>(pin: impl crate::peripheral::Peripheral<P = P> + 'd) -> Self
where
P: Pin,
{
crate::into_ref!(pin); crate::into_ref!(pin);
let pin = pin.erased_pin(private::Internal); let pin = pin.degrade_internal(private::Internal);
Self { Self {
pin, pin,
@ -27,11 +30,12 @@ impl<'d> AnyPin<'d> {
/// Create wrapper for the given pin. The peripheral signal will be /// Create wrapper for the given pin. The peripheral signal will be
/// inverted. /// inverted.
#[inline] #[inline]
pub fn new_inverted<P: OutputPin + InputPin + CreateErasedPin>( pub fn new_inverted<P>(pin: impl crate::peripheral::Peripheral<P = P> + 'd) -> Self
pin: impl crate::peripheral::Peripheral<P = P> + 'd, where
) -> Self { P: Pin,
{
crate::into_ref!(pin); crate::into_ref!(pin);
let pin = pin.erased_pin(private::Internal); let pin = pin.degrade_internal(private::Internal);
Self { Self {
pin, pin,
@ -59,6 +63,7 @@ impl<'d> Pin for AnyPin<'d> {
delegate::delegate! { delegate::delegate! {
to self.pin { to self.pin {
fn number(&self, _internal: private::Internal) -> u8; fn number(&self, _internal: private::Internal) -> u8;
fn degrade_internal(&self, _internal: private::Internal) -> ErasedPin;
fn sleep_mode(&mut self, on: bool, _internal: private::Internal); fn sleep_mode(&mut self, on: bool, _internal: private::Internal);
fn set_alternate_function(&mut self, alternate: AlternateFunction, _internal: private::Internal); fn set_alternate_function(&mut self, alternate: AlternateFunction, _internal: private::Internal);
fn is_listening(&self, _internal: private::Internal) -> bool; fn is_listening(&self, _internal: private::Internal) -> bool;

View File

@ -32,6 +32,10 @@ impl Pin for DummyPin {
panic!("DummyPin not supported here!"); panic!("DummyPin not supported here!");
} }
fn degrade_internal(&self, _: private::Internal) -> ErasedPin {
panic!("Can not type erase the DummyPin!");
}
fn sleep_mode(&mut self, _on: bool, _: private::Internal) {} fn sleep_mode(&mut self, _on: bool, _: private::Internal) {}
fn set_alternate_function(&mut self, _alternate: AlternateFunction, _: private::Internal) {} fn set_alternate_function(&mut self, _alternate: AlternateFunction, _: private::Internal) {}

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal::{ use esp_hal::{
delay::Delay, delay::Delay,
gpio::{AnyInput, AnyOutput, Io, Level, Pull}, gpio::{ErasedPin, Input, Io, Level, Output, Pin, Pull},
prelude::*, prelude::*,
}; };
@ -25,17 +25,17 @@ fn main() -> ! {
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
// Set LED GPIOs as an output: // Set LED GPIOs as an output:
let led1 = AnyOutput::new(io.pins.gpio2, Level::Low); let led1 = Output::new(io.pins.gpio2.degrade(), Level::Low);
let led2 = AnyOutput::new(io.pins.gpio4, Level::Low); let led2 = Output::new(io.pins.gpio4.degrade(), Level::Low);
let led3 = AnyOutput::new(io.pins.gpio5, Level::Low); let led3 = Output::new(io.pins.gpio5.degrade(), Level::Low);
// Use boot button as an input: // Use boot button as an input:
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))] #[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
let button = io.pins.gpio0; let button = io.pins.gpio0.degrade();
#[cfg(not(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3")))] #[cfg(not(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3")))]
let button = io.pins.gpio9; let button = io.pins.gpio9.degrade();
let button = AnyInput::new(button, Pull::Up); let button = Input::new(button, Pull::Up);
let mut pins = [led1, led2, led3]; let mut pins = [led1, led2, led3];
@ -47,7 +47,7 @@ fn main() -> ! {
} }
} }
fn toggle_pins(leds: &mut [AnyOutput], button: &AnyInput) { fn toggle_pins(leds: &mut [Output<ErasedPin>], button: &Input<ErasedPin>) {
for pin in leds.iter_mut() { for pin in leds.iter_mut() {
pin.toggle(); pin.toggle();
} }

View File

@ -21,7 +21,7 @@ use esp_backtrace as _;
use esp_hal::{ use esp_hal::{
cpu_control::{CpuControl, Stack}, cpu_control::{CpuControl, Stack},
get_core, get_core,
gpio::{AnyOutput, Io, Level}, gpio::{ErasedPin, Io, Level, Output, Pin},
timer::{timg::TimerGroup, ErasedTimer}, timer::{timg::TimerGroup, ErasedTimer},
}; };
use esp_hal_embassy::Executor; use esp_hal_embassy::Executor;
@ -34,7 +34,7 @@ static mut APP_CORE_STACK: Stack<8192> = Stack::new();
/// duration of time. /// duration of time.
#[embassy_executor::task] #[embassy_executor::task]
async fn control_led( async fn control_led(
mut led: AnyOutput<'static>, mut led: Output<'static, ErasedPin>,
control: &'static Signal<CriticalSectionRawMutex, bool>, control: &'static Signal<CriticalSectionRawMutex, bool>,
) { ) {
println!("Starting control_led() on core {}", get_core() as usize); println!("Starting control_led() on core {}", get_core() as usize);
@ -65,7 +65,7 @@ async fn main(_spawner: Spawner) {
static LED_CTRL: StaticCell<Signal<CriticalSectionRawMutex, bool>> = StaticCell::new(); static LED_CTRL: StaticCell<Signal<CriticalSectionRawMutex, bool>> = StaticCell::new();
let led_ctrl_signal = &*LED_CTRL.init(Signal::new()); let led_ctrl_signal = &*LED_CTRL.init(Signal::new());
let led = AnyOutput::new(io.pins.gpio0, Level::Low); let led = Output::new(io.pins.gpio0.degrade(), Level::Low);
let _guard = cpu_control let _guard = cpu_control
.start_app_core(unsafe { &mut *addr_of_mut!(APP_CORE_STACK) }, move || { .start_app_core(unsafe { &mut *addr_of_mut!(APP_CORE_STACK) }, move || {

View File

@ -20,7 +20,7 @@ use esp_backtrace as _;
use esp_hal::{ use esp_hal::{
cpu_control::{CpuControl, Stack}, cpu_control::{CpuControl, Stack},
get_core, get_core,
gpio::{AnyOutput, Io, Level}, gpio::{ErasedPin, Io, Level, Output, Pin},
interrupt::{software::SoftwareInterruptControl, Priority}, interrupt::{software::SoftwareInterruptControl, Priority},
prelude::*, prelude::*,
timer::{timg::TimerGroup, ErasedTimer}, timer::{timg::TimerGroup, ErasedTimer},
@ -35,7 +35,7 @@ static mut APP_CORE_STACK: Stack<8192> = Stack::new();
/// duration of time. /// duration of time.
#[embassy_executor::task] #[embassy_executor::task]
async fn control_led( async fn control_led(
mut led: AnyOutput<'static>, mut led: Output<'static, ErasedPin>,
control: &'static Signal<CriticalSectionRawMutex, bool>, control: &'static Signal<CriticalSectionRawMutex, bool>,
) { ) {
println!("Starting control_led() on core {}", get_core() as usize); println!("Starting control_led() on core {}", get_core() as usize);
@ -87,7 +87,7 @@ fn main() -> ! {
static LED_CTRL: StaticCell<Signal<CriticalSectionRawMutex, bool>> = StaticCell::new(); static LED_CTRL: StaticCell<Signal<CriticalSectionRawMutex, bool>> = StaticCell::new();
let led_ctrl_signal = &*LED_CTRL.init(Signal::new()); let led_ctrl_signal = &*LED_CTRL.init(Signal::new());
let led = AnyOutput::new(io.pins.gpio0, Level::Low); let led = Output::new(io.pins.gpio0.degrade(), Level::Low);
static EXECUTOR_CORE_1: StaticCell<InterruptExecutor<1>> = StaticCell::new(); static EXECUTOR_CORE_1: StaticCell<InterruptExecutor<1>> = StaticCell::new();
let executor_core1 = InterruptExecutor::new(sw_ints.software_interrupt1); let executor_core1 = InterruptExecutor::new(sw_ints.software_interrupt1);

View File

@ -13,7 +13,7 @@ use embassy_executor::Spawner;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal::{ use esp_hal::{
gpio::{GpioPin, Io, Level, Output}, gpio::{Io, Level, Output},
prelude::*, prelude::*,
rmt::{asynch::RxChannelAsync, PulseCode, Rmt, RxChannelConfig, RxChannelCreatorAsync}, rmt::{asynch::RxChannelAsync, PulseCode, Rmt, RxChannelConfig, RxChannelCreatorAsync},
timer::timg::TimerGroup, timer::timg::TimerGroup,
@ -26,7 +26,7 @@ const WIDTH: usize = 80;
compile_error!("Run this example in release mode"); compile_error!("Run this example in release mode");
#[embassy_executor::task] #[embassy_executor::task]
async fn signal_task(mut pin: Output<'static, GpioPin<5>>) { async fn signal_task(mut pin: Output<'static>) {
loop { loop {
for _ in 0..10 { for _ in 0..10 {
pin.toggle(); pin.toggle();

View File

@ -17,20 +17,12 @@ use critical_section::Mutex;
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal::{ use esp_hal::{
delay::Delay, delay::Delay,
gpio::{Event, GpioPin, Input, Io, Level, Output, Pull}, gpio::{Event, Input, Io, Level, Output, Pull},
macros::ram, macros::ram,
prelude::*, prelude::*,
}; };
cfg_if::cfg_if! { static BUTTON: Mutex<RefCell<Option<Input>>> = Mutex::new(RefCell::new(None));
if #[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))] {
const BUTTON_PIN: u8 = 0;
} else {
const BUTTON_PIN: u8 = 9;
}
}
static BUTTON: Mutex<RefCell<Option<Input<GpioPin<BUTTON_PIN>>>>> = Mutex::new(RefCell::new(None));
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {

View File

@ -34,7 +34,7 @@ use esp_hal::{
delay::Delay, delay::Delay,
dma::{Dma, DmaPriority}, dma::{Dma, DmaPriority},
dma_buffers, dma_buffers,
gpio::{GpioPin, Input, Io, Level, Output, Pull}, gpio::{Input, Io, Level, Output, Pull},
prelude::*, prelude::*,
spi::{ spi::{
slave::{prelude::*, Spi}, slave::{prelude::*, Spi},
@ -48,17 +48,16 @@ fn main() -> ! {
let peripherals = esp_hal::init(esp_hal::Config::default()); let peripherals = esp_hal::init(esp_hal::Config::default());
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let slave_sclk = io.pins.gpio0;
let mut master_sclk = Output::new(io.pins.gpio4, Level::Low); let mut master_sclk = Output::new(io.pins.gpio4, Level::Low);
let slave_miso = io.pins.gpio1;
let master_miso = Input::new(io.pins.gpio5, Pull::None); let master_miso = Input::new(io.pins.gpio5, Pull::None);
let slave_mosi = io.pins.gpio2;
let mut master_mosi = Output::new(io.pins.gpio8, Level::Low); let mut master_mosi = Output::new(io.pins.gpio8, Level::Low);
let mut master_cs = Output::new(io.pins.gpio9, Level::High);
let slave_sclk = io.pins.gpio0;
let slave_miso = io.pins.gpio1;
let slave_mosi = io.pins.gpio2;
let slave_cs = io.pins.gpio3; let slave_cs = io.pins.gpio3;
let mut master_cs = Output::new(io.pins.gpio9, Level::Low);
master_cs.set_high();
master_sclk.set_low();
master_mosi.set_low();
let dma = Dma::new(peripherals.DMA); let dma = Dma::new(peripherals.DMA);
cfg_if::cfg_if! { cfg_if::cfg_if! {
@ -189,10 +188,10 @@ fn main() -> ! {
fn bitbang_master( fn bitbang_master(
master_send: &[u8], master_send: &[u8],
master_receive: &mut [u8], master_receive: &mut [u8],
master_cs: &mut Output<GpioPin<9>>, master_cs: &mut Output,
master_mosi: &mut Output<GpioPin<8>>, master_mosi: &mut Output,
master_sclk: &mut Output<GpioPin<4>>, master_sclk: &mut Output,
master_miso: &Input<GpioPin<5>>, master_miso: &Input,
) { ) {
// Bit-bang out the contents of master_send and read into master_receive // Bit-bang out the contents of master_send and read into master_receive
// as quickly as manageable. MSB first. Mode 0, so sampled on the rising // as quickly as manageable. MSB first. Mode 0, so sampled on the rising

View File

@ -49,8 +49,7 @@ macro_rules! common_test_pins {
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(any(esp32s2, esp32s3))] { if #[cfg(any(esp32s2, esp32s3))] {
($io.pins.gpio9, $io.pins.gpio10) ($io.pins.gpio9, $io.pins.gpio10)
} } else {
else {
($io.pins.gpio2, $io.pins.gpio3) ($io.pins.gpio2, $io.pins.gpio3)
} }
} }

View File

@ -14,7 +14,6 @@ use esp_hal::{
dma::{Dma, DmaPriority}, dma::{Dma, DmaPriority},
dma_buffers, dma_buffers,
peripherals::Peripherals, peripherals::Peripherals,
prelude::*,
}; };
use hil_test as _; use hil_test as _;

View File

@ -20,7 +20,7 @@ mod tests {
#[init] #[init]
fn init() -> Context { fn init() -> Context {
let peripherals = esp_hal::init(esp_hal::Config::default()); let _peripherals = esp_hal::init(esp_hal::Config::default());
let delay = Delay::new(); let delay = Delay::new();
Context { delay } Context { delay }

View File

@ -61,7 +61,7 @@ mod tests {
#[test] #[test]
#[timeout(3)] #[timeout(3)]
fn test_current_time_construct_timg0(ctx: Context) { fn test_current_time_construct_timg0(ctx: Context) {
time_moves_forward_during(ctx, |ctx| { time_moves_forward_during(ctx, |_| {
// construct the timer in between calls to current_time // construct the timer in between calls to current_time
let _ = esp_hal::timer::timg::TimerGroup::new(unsafe { let _ = esp_hal::timer::timg::TimerGroup::new(unsafe {
esp_hal::peripherals::TIMG0::steal() esp_hal::peripherals::TIMG0::steal()

View File

@ -15,7 +15,7 @@ use core::cell::RefCell;
use critical_section::Mutex; use critical_section::Mutex;
use esp_hal::{ use esp_hal::{
delay::Delay, delay::Delay,
gpio::{AnyPin, GpioPin, Input, Io, Level, Output, Pull}, gpio::{AnyPin, ErasedPin, Input, Io, Level, Output, Pin, Pull},
macros::handler, macros::handler,
timer::timg::TimerGroup, timer::timg::TimerGroup,
InterruptConfigurable, InterruptConfigurable,
@ -23,22 +23,11 @@ use esp_hal::{
use hil_test as _; use hil_test as _;
static COUNTER: Mutex<RefCell<u32>> = Mutex::new(RefCell::new(0)); static COUNTER: Mutex<RefCell<u32>> = Mutex::new(RefCell::new(0));
static INPUT_PIN: Mutex<RefCell<Option<Input<'static, TestGpio1>>>> = static INPUT_PIN: Mutex<RefCell<Option<Input>>> = Mutex::new(RefCell::new(None));
Mutex::new(RefCell::new(None));
cfg_if::cfg_if! { struct Context {
if #[cfg(not(any(esp32s2, esp32s3)))] { test_gpio1: ErasedPin,
pub type TestGpio1 = GpioPin<2>; test_gpio2: ErasedPin,
pub type TestGpio2 = GpioPin<3>;
} else if #[cfg(any(esp32s2, esp32s3))] {
pub type TestGpio1 = GpioPin<9>;
pub type TestGpio2 = GpioPin<10>;
}
}
struct Context<'d> {
test_gpio1: Input<'d, TestGpio1>,
test_gpio2: Output<'d, TestGpio2>,
delay: Delay, delay: Delay,
} }
@ -64,7 +53,7 @@ mod tests {
use super::*; use super::*;
#[init] #[init]
fn init() -> Context<'static> { fn init() -> Context {
let peripherals = esp_hal::init(esp_hal::Config::default()); let peripherals = esp_hal::init(esp_hal::Config::default());
let mut io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let mut io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
@ -78,20 +67,22 @@ mod tests {
esp_hal_embassy::init(timg0.timer0); esp_hal_embassy::init(timg0.timer0);
Context { Context {
test_gpio1: Input::new(gpio1, Pull::Down), test_gpio1: gpio1.degrade(),
test_gpio2: Output::new(gpio2, Level::Low), test_gpio2: gpio2.degrade(),
delay, delay,
} }
} }
#[test] #[test]
async fn test_async_edge(ctx: Context<'static>) { async fn test_async_edge(ctx: Context) {
let counter = AtomicUsize::new(0); let counter = AtomicUsize::new(0);
let Context { let Context {
mut test_gpio1, test_gpio1,
mut test_gpio2, test_gpio2,
.. ..
} = ctx; } = ctx;
let mut test_gpio1 = Input::new(test_gpio1, Pull::Down);
let mut test_gpio2 = Output::new(test_gpio2, Level::Low);
embassy_futures::select::select( embassy_futures::select::select(
async { async {
loop { loop {
@ -113,8 +104,8 @@ mod tests {
} }
#[test] #[test]
async fn test_a_pin_can_wait(_ctx: Context<'static>) { async fn test_a_pin_can_wait(ctx: Context) {
let mut first = Input::new(unsafe { GpioPin::<0>::steal() }, Pull::Down); let mut first = Input::new(ctx.test_gpio1, Pull::Down);
embassy_futures::select::select( embassy_futures::select::select(
first.wait_for_rising_edge(), first.wait_for_rising_edge(),
@ -126,69 +117,74 @@ mod tests {
} }
#[test] #[test]
fn test_gpio_input(ctx: Context<'static>) { fn test_gpio_input(ctx: Context) {
let test_gpio1 = Input::new(ctx.test_gpio1, Pull::Down);
// `InputPin`: // `InputPin`:
assert_eq!(ctx.test_gpio1.is_low(), true); assert_eq!(test_gpio1.is_low(), true);
assert_eq!(ctx.test_gpio1.is_high(), false); assert_eq!(test_gpio1.is_high(), false);
} }
#[test] #[test]
fn test_gpio_output(mut ctx: Context<'static>) { fn test_gpio_output(ctx: Context) {
let mut test_gpio2 = Output::new(ctx.test_gpio2, Level::Low);
// `StatefulOutputPin`: // `StatefulOutputPin`:
assert_eq!(ctx.test_gpio2.is_set_low(), true); assert_eq!(test_gpio2.is_set_low(), true);
assert_eq!(ctx.test_gpio2.is_set_high(), false); assert_eq!(test_gpio2.is_set_high(), false);
ctx.test_gpio2.set_high(); test_gpio2.set_high();
assert_eq!(ctx.test_gpio2.is_set_low(), false); assert_eq!(test_gpio2.is_set_low(), false);
assert_eq!(ctx.test_gpio2.is_set_high(), true); assert_eq!(test_gpio2.is_set_high(), true);
// `ToggleableOutputPin`: // `ToggleableOutputPin`:
ctx.test_gpio2.toggle(); test_gpio2.toggle();
assert_eq!(ctx.test_gpio2.is_set_low(), true); assert_eq!(test_gpio2.is_set_low(), true);
assert_eq!(ctx.test_gpio2.is_set_high(), false); assert_eq!(test_gpio2.is_set_high(), false);
ctx.test_gpio2.toggle(); test_gpio2.toggle();
assert_eq!(ctx.test_gpio2.is_set_low(), false); assert_eq!(test_gpio2.is_set_low(), false);
assert_eq!(ctx.test_gpio2.is_set_high(), true); assert_eq!(test_gpio2.is_set_high(), true);
} }
#[test] #[test]
fn test_gpio_interrupt(mut ctx: Context<'static>) { fn test_gpio_interrupt(ctx: Context) {
let mut test_gpio1 = Input::new(ctx.test_gpio1, Pull::Down);
let mut test_gpio2 = Output::new(ctx.test_gpio2, Level::Low);
critical_section::with(|cs| { critical_section::with(|cs| {
*COUNTER.borrow_ref_mut(cs) = 0; *COUNTER.borrow_ref_mut(cs) = 0;
ctx.test_gpio1.listen(Event::AnyEdge); test_gpio1.listen(Event::AnyEdge);
INPUT_PIN.borrow_ref_mut(cs).replace(ctx.test_gpio1); INPUT_PIN.borrow_ref_mut(cs).replace(test_gpio1);
}); });
ctx.test_gpio2.set_high(); test_gpio2.set_high();
ctx.delay.delay_millis(1); ctx.delay.delay_millis(1);
ctx.test_gpio2.set_low(); test_gpio2.set_low();
ctx.delay.delay_millis(1); ctx.delay.delay_millis(1);
ctx.test_gpio2.set_high(); test_gpio2.set_high();
ctx.delay.delay_millis(1); ctx.delay.delay_millis(1);
ctx.test_gpio2.set_low(); test_gpio2.set_low();
ctx.delay.delay_millis(1); ctx.delay.delay_millis(1);
ctx.test_gpio2.set_high(); test_gpio2.set_high();
ctx.delay.delay_millis(1); ctx.delay.delay_millis(1);
ctx.test_gpio2.set_low(); test_gpio2.set_low();
ctx.delay.delay_millis(1); ctx.delay.delay_millis(1);
ctx.test_gpio2.set_high(); test_gpio2.set_high();
ctx.delay.delay_millis(1); ctx.delay.delay_millis(1);
ctx.test_gpio2.set_low(); test_gpio2.set_low();
ctx.delay.delay_millis(1); ctx.delay.delay_millis(1);
ctx.test_gpio2.set_high(); test_gpio2.set_high();
ctx.delay.delay_millis(1); ctx.delay.delay_millis(1);
let count = critical_section::with(|cs| *COUNTER.borrow_ref(cs)); let count = critical_section::with(|cs| *COUNTER.borrow_ref(cs));
assert_eq!(count, 9); assert_eq!(count, 9);
ctx.test_gpio1 = critical_section::with(|cs| INPUT_PIN.borrow_ref_mut(cs).take().unwrap());
ctx.test_gpio1.unlisten();
}
#[test]
fn test_gpio_od(ctx: Context<'static>) {
let mut test_gpio1 = let mut test_gpio1 =
OutputOpenDrain::new(unsafe { TestGpio1::steal() }, Level::High, Pull::Up); critical_section::with(|cs| INPUT_PIN.borrow_ref_mut(cs).take().unwrap());
let mut test_gpio2 = test_gpio1.unlisten();
OutputOpenDrain::new(unsafe { TestGpio2::steal() }, Level::High, Pull::Up); }
#[test]
fn test_gpio_od(ctx: Context) {
let mut test_gpio1 = OutputOpenDrain::new(ctx.test_gpio1, Level::High, Pull::Up);
let mut test_gpio2 = OutputOpenDrain::new(ctx.test_gpio2, Level::High, Pull::Up);
ctx.delay.delay_millis(1); ctx.delay.delay_millis(1);
@ -232,9 +228,9 @@ mod tests {
} }
#[test] #[test]
fn test_gpio_flex(ctx: Context<'static>) { fn test_gpio_flex(ctx: Context) {
let mut test_gpio1 = Flex::new(unsafe { TestGpio1::steal() }); let mut test_gpio1 = Flex::new(ctx.test_gpio1);
let mut test_gpio2 = Flex::new(unsafe { TestGpio2::steal() }); let mut test_gpio2 = Flex::new(ctx.test_gpio2);
test_gpio1.set_high(); test_gpio1.set_high();
test_gpio1.set_as_output(); test_gpio1.set_as_output();
@ -274,9 +270,9 @@ mod tests {
// Tests touch pin (GPIO2) as AnyPin and Output // Tests touch pin (GPIO2) as AnyPin and Output
// https://github.com/esp-rs/esp-hal/issues/1943 // https://github.com/esp-rs/esp-hal/issues/1943
#[test] #[test]
fn test_gpio_touch_anypin_output() { fn test_gpio_touch_anypin_output(ctx: Context) {
let any_pin2 = AnyPin::new(unsafe { TestGpio1::steal() }); let any_pin2 = AnyPin::new(ctx.test_gpio1);
let any_pin3 = AnyPin::new(unsafe { TestGpio2::steal() }); let any_pin3 = AnyPin::new(ctx.test_gpio2);
let out_pin = Output::new(any_pin2, Level::High); let out_pin = Output::new(any_pin2, Level::High);
let in_pin = Input::new(any_pin3, Pull::Down); let in_pin = Input::new(any_pin3, Pull::Down);
@ -288,9 +284,9 @@ mod tests {
// Tests touch pin (GPIO2) as AnyPin and Input // Tests touch pin (GPIO2) as AnyPin and Input
// https://github.com/esp-rs/esp-hal/issues/1943 // https://github.com/esp-rs/esp-hal/issues/1943
#[test] #[test]
fn test_gpio_touch_anypin_input() { fn test_gpio_touch_anypin_input(ctx: Context) {
let any_pin2 = AnyPin::new(unsafe { TestGpio1::steal() }); let any_pin2 = AnyPin::new(ctx.test_gpio1);
let any_pin3 = AnyPin::new(unsafe { TestGpio2::steal() }); let any_pin3 = AnyPin::new(ctx.test_gpio2);
let out_pin = Output::new(any_pin3, Level::Low); let out_pin = Output::new(any_pin3, Level::Low);
let in_pin = Input::new(any_pin2, Pull::Down); let in_pin = Input::new(any_pin2, Pull::Down);

View File

@ -15,7 +15,7 @@
use esp_hal::{ use esp_hal::{
dma::{Channel, Dma, DmaPriority, DmaRxBuf}, dma::{Channel, Dma, DmaPriority, DmaRxBuf},
dma_buffers, dma_buffers,
gpio::{AnyOutput, AnyPin, Io, Level}, gpio::{ErasedPin, Io, Level, Output},
prelude::*, prelude::*,
spi::{ spi::{
master::{Address, Command, Spi, SpiDma}, master::{Address, Command, Spi, SpiDma},
@ -41,13 +41,13 @@ cfg_if::cfg_if! {
struct Context { struct Context {
spi: esp_hal::peripherals::SPI2, spi: esp_hal::peripherals::SPI2,
dma_channel: Channel<'static, DmaChannel0, Blocking>, dma_channel: Channel<'static, DmaChannel0, Blocking>,
miso: AnyPin<'static>, miso: ErasedPin,
miso_mirror: AnyOutput<'static>, miso_mirror: Output<'static>,
} }
fn execute( fn execute(
mut spi: SpiDma<'static, esp_hal::peripherals::SPI2, DmaChannel0, HalfDuplexMode, Blocking>, mut spi: SpiDma<'static, esp_hal::peripherals::SPI2, DmaChannel0, HalfDuplexMode, Blocking>,
mut miso_mirror: AnyOutput<'static>, mut miso_mirror: Output<'static>,
wanted: u8, wanted: u8,
) { ) {
const DMA_BUFFER_SIZE: usize = 4; const DMA_BUFFER_SIZE: usize = 4;
@ -103,8 +103,8 @@ mod tests {
let (miso, miso_mirror) = hil_test::common_test_pins!(io); let (miso, miso_mirror) = hil_test::common_test_pins!(io);
let miso = AnyPin::new(miso); let miso = miso.degrade();
let miso_mirror = AnyOutput::new(miso_mirror, Level::High); let miso_mirror = Output::new(miso_mirror, Level::High);
let dma = Dma::new(peripherals.DMA); let dma = Dma::new(peripherals.DMA);

View File

@ -17,7 +17,7 @@
use esp_hal::{ use esp_hal::{
dma::{Channel, Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, dma::{Channel, Dma, DmaPriority, DmaRxBuf, DmaTxBuf},
dma_buffers, dma_buffers,
gpio::{AnyOutput, AnyPin, Io, Level}, gpio::{ErasedPin, Io, Level, Output},
prelude::*, prelude::*,
spi::{ spi::{
master::{Address, Command, Spi, SpiDma}, master::{Address, Command, Spi, SpiDma},
@ -43,13 +43,13 @@ cfg_if::cfg_if! {
struct Context { struct Context {
spi: esp_hal::peripherals::SPI2, spi: esp_hal::peripherals::SPI2,
dma_channel: Channel<'static, DmaChannel0, Blocking>, dma_channel: Channel<'static, DmaChannel0, Blocking>,
mosi: AnyPin<'static>, mosi: ErasedPin,
mosi_mirror: AnyOutput<'static>, mosi_mirror: Output<'static>,
} }
fn execute( fn execute(
mut spi: SpiDma<'static, esp_hal::peripherals::SPI2, DmaChannel0, HalfDuplexMode, Blocking>, mut spi: SpiDma<'static, esp_hal::peripherals::SPI2, DmaChannel0, HalfDuplexMode, Blocking>,
mut mosi_mirror: AnyOutput<'static>, mut mosi_mirror: Output<'static>,
wanted: u8, wanted: u8,
) { ) {
const DMA_BUFFER_SIZE: usize = 4; const DMA_BUFFER_SIZE: usize = 4;
@ -105,8 +105,8 @@ mod tests {
let (mosi, mosi_mirror) = hil_test::common_test_pins!(io); let (mosi, mosi_mirror) = hil_test::common_test_pins!(io);
let mosi = AnyPin::new(mosi); let mosi = mosi.degrade();
let mosi_mirror = AnyOutput::new(mosi_mirror, Level::High); let mosi_mirror = Output::new(mosi_mirror, Level::High);
let dma = Dma::new(peripherals.DMA); let dma = Dma::new(peripherals.DMA);

View File

@ -24,7 +24,7 @@ use embedded_hal_async::spi::SpiBus;
use esp_hal::{ use esp_hal::{
dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf},
dma_buffers, dma_buffers,
gpio::{AnyPin, GpioPin, Io, Level, Output, Pull}, gpio::{ErasedPin, Io, Level, Output, Pull},
pcnt::{ pcnt::{
channel::{EdgeMode, PcntInputConfig, PcntSource}, channel::{EdgeMode, PcntInputConfig, PcntSource},
unit::Unit, unit::Unit,
@ -57,8 +57,8 @@ const DMA_BUFFER_SIZE: usize = 5;
struct Context { struct Context {
spi: SpiDmaBus<'static, SPI2, DmaChannel0, FullDuplexMode, Async>, spi: SpiDmaBus<'static, SPI2, DmaChannel0, FullDuplexMode, Async>,
pcnt_unit: Unit<'static, 0>, pcnt_unit: Unit<'static, 0>,
out_pin: Output<'static, GpioPin<5>>, out_pin: Output<'static>,
mosi_mirror: AnyPin<'static>, mosi_mirror: ErasedPin,
} }
#[cfg(test)] #[cfg(test)]
@ -79,7 +79,7 @@ mod tests {
let (mosi_mirror, mosi) = hil_test::common_test_pins!(io); let (mosi_mirror, mosi) = hil_test::common_test_pins!(io);
let miso = io.pins.gpio4; let miso = io.pins.gpio4;
let cs = io.pins.gpio8; let cs = io.pins.gpio8;
let mosi_mirror = AnyPin::new(mosi_mirror); let mosi_mirror = mosi_mirror.degrade();
let mut out_pin = Output::new(io.pins.gpio5, Level::Low); let mut out_pin = Output::new(io.pins.gpio5, Level::Low);
out_pin.set_low(); out_pin.set_low();

View File

@ -20,7 +20,7 @@
use esp_hal::{ use esp_hal::{
dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf},
dma_buffers, dma_buffers,
gpio::{AnyPin, GpioPin, Io, Level, Output, Pull}, gpio::{ErasedPin, Io, Level, Output, Pull},
pcnt::{ pcnt::{
channel::{EdgeMode, PcntInputConfig, PcntSource}, channel::{EdgeMode, PcntInputConfig, PcntSource},
unit::Unit, unit::Unit,
@ -51,8 +51,8 @@ cfg_if::cfg_if! {
struct Context { struct Context {
spi: SpiDma<'static, SPI2, DmaChannel0, FullDuplexMode, Blocking>, spi: SpiDma<'static, SPI2, DmaChannel0, FullDuplexMode, Blocking>,
pcnt_unit: Unit<'static, 0>, pcnt_unit: Unit<'static, 0>,
out_pin: Output<'static, GpioPin<5>>, out_pin: Output<'static>,
mosi_mirror: AnyPin<'static>, mosi_mirror: ErasedPin,
} }
#[cfg(test)] #[cfg(test)]
@ -91,7 +91,7 @@ mod tests {
let mut out_pin = Output::new(io.pins.gpio5, Level::Low); let mut out_pin = Output::new(io.pins.gpio5, Level::Low);
out_pin.set_low(); out_pin.set_low();
assert_eq!(out_pin.is_set_low(), true); assert_eq!(out_pin.is_set_low(), true);
let mosi_mirror = AnyPin::new(mosi_mirror); let mosi_mirror = mosi_mirror.degrade();
Context { Context {
spi, spi,

View File

@ -16,7 +16,7 @@
use esp_hal::{ use esp_hal::{
dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf},
dma_buffers, dma_buffers,
gpio::{AnyOutput, Io, Level}, gpio::{Io, Level, Output},
peripherals::SPI2, peripherals::SPI2,
prelude::*, prelude::*,
spi::{ spi::{
@ -42,7 +42,7 @@ cfg_if::cfg_if! {
struct Context { struct Context {
spi: SpiDma<'static, SPI2, DmaChannel0, HalfDuplexMode, Blocking>, spi: SpiDma<'static, SPI2, DmaChannel0, HalfDuplexMode, Blocking>,
miso_mirror: AnyOutput<'static>, miso_mirror: Output<'static>,
} }
#[cfg(test)] #[cfg(test)]
@ -60,7 +60,7 @@ mod tests {
let sclk = io.pins.gpio0; let sclk = io.pins.gpio0;
let (miso, miso_mirror) = hil_test::common_test_pins!(io); let (miso, miso_mirror) = hil_test::common_test_pins!(io);
let miso_mirror = AnyOutput::new(miso_mirror, Level::High); let miso_mirror = Output::new(miso_mirror, Level::High);
let dma = Dma::new(peripherals.DMA); let dma = Dma::new(peripherals.DMA);