Merge #853
853: Add embedded_hal_async support for embassy-rp r=Dirbaio a=danbev This commit adds support for embedded-hal-async to the Embassy Raspberry PI crate. Co-authored-by: Daniel Bevenius <daniel.bevenius@gmail.com>
This commit is contained in:
		@@ -38,6 +38,7 @@ log = { version = "0.4.14", optional = true }
 | 
				
			|||||||
cortex-m-rt = ">=0.6.15,<0.8"
 | 
					cortex-m-rt = ">=0.6.15,<0.8"
 | 
				
			||||||
cortex-m = "0.7.3"
 | 
					cortex-m = "0.7.3"
 | 
				
			||||||
critical-section = "0.2.5"
 | 
					critical-section = "0.2.5"
 | 
				
			||||||
 | 
					futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="9ad7223a48a065e612bc7dc7be5bf5bd0b41cfc4", features = ["rt"] }
 | 
					rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="9ad7223a48a065e612bc7dc7be5bf5bd0b41cfc4", features = ["rt"] }
 | 
				
			||||||
#rp2040-pac2 = { path = "../../rp/rp2040-pac2", features = ["rt"] }
 | 
					#rp2040-pac2 = { path = "../../rp/rp2040-pac2", features = ["rt"] }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,20 @@
 | 
				
			|||||||
use core::convert::Infallible;
 | 
					use core::convert::Infallible;
 | 
				
			||||||
 | 
					use core::future::Future;
 | 
				
			||||||
use core::marker::PhantomData;
 | 
					use core::marker::PhantomData;
 | 
				
			||||||
 | 
					use core::pin::Pin as FuturePin;
 | 
				
			||||||
 | 
					use core::task::{Context, Poll};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use embassy::waitqueue::AtomicWaker;
 | 
				
			||||||
 | 
					use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
 | 
				
			||||||
use embassy_hal_common::{unborrow, unsafe_impl_unborrow};
 | 
					use embassy_hal_common::{unborrow, unsafe_impl_unborrow};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::pac::common::{Reg, RW};
 | 
					use crate::pac::common::{Reg, RW};
 | 
				
			||||||
use crate::pac::SIO;
 | 
					use crate::pac::SIO;
 | 
				
			||||||
use crate::{pac, peripherals, Unborrow};
 | 
					use crate::{interrupt, pac, peripherals, Unborrow};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PIN_COUNT: usize = 30;
 | 
				
			||||||
 | 
					const NEW_AW: AtomicWaker = AtomicWaker::new();
 | 
				
			||||||
 | 
					static INTERRUPT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AW; PIN_COUNT];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Represents a digital input or output level.
 | 
					/// Represents a digital input or output level.
 | 
				
			||||||
#[derive(Debug, Eq, PartialEq)]
 | 
					#[derive(Debug, Eq, PartialEq)]
 | 
				
			||||||
@@ -75,6 +84,204 @@ impl<'d, T: Pin> Input<'d, T> {
 | 
				
			|||||||
    pub fn get_level(&self) -> Level {
 | 
					    pub fn get_level(&self) -> Level {
 | 
				
			||||||
        self.pin.get_level()
 | 
					        self.pin.get_level()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn wait_for_high<'a>(&mut self) {
 | 
				
			||||||
 | 
					        self.pin.wait_for_high().await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn wait_for_low<'a>(&mut self) {
 | 
				
			||||||
 | 
					        self.pin.wait_for_low().await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn wait_for_rising_edge<'a>(&mut self) {
 | 
				
			||||||
 | 
					        self.pin.wait_for_rising_edge().await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn wait_for_falling_edge<'a>(&mut self) {
 | 
				
			||||||
 | 
					        self.pin.wait_for_falling_edge().await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn wait_for_any_edge<'a>(&mut self) {
 | 
				
			||||||
 | 
					        self.pin.wait_for_any_edge().await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Interrupt trigger levels.
 | 
				
			||||||
 | 
					#[derive(Debug, Eq, PartialEq, Copy, Clone)]
 | 
				
			||||||
 | 
					#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
				
			||||||
 | 
					pub enum InterruptTrigger {
 | 
				
			||||||
 | 
					    LevelLow,
 | 
				
			||||||
 | 
					    LevelHigh,
 | 
				
			||||||
 | 
					    EdgeLow,
 | 
				
			||||||
 | 
					    EdgeHigh,
 | 
				
			||||||
 | 
					    AnyEdge,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl InterruptTrigger {
 | 
				
			||||||
 | 
					    fn from_u32(value: u32) -> Option<InterruptTrigger> {
 | 
				
			||||||
 | 
					        match value {
 | 
				
			||||||
 | 
					            1 => Some(InterruptTrigger::LevelLow),
 | 
				
			||||||
 | 
					            2 => Some(InterruptTrigger::LevelHigh),
 | 
				
			||||||
 | 
					            3 => Some(InterruptTrigger::EdgeLow),
 | 
				
			||||||
 | 
					            4 => Some(InterruptTrigger::EdgeHigh),
 | 
				
			||||||
 | 
					            _ => None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[interrupt]
 | 
				
			||||||
 | 
					unsafe fn IO_IRQ_BANK0() {
 | 
				
			||||||
 | 
					    let cpu = SIO.cpuid().read() as usize;
 | 
				
			||||||
 | 
					    // There are two sets of interrupt registers, one for cpu0 and one for cpu1
 | 
				
			||||||
 | 
					    // and here we are selecting the set that belongs to the currently executing
 | 
				
			||||||
 | 
					    // cpu.
 | 
				
			||||||
 | 
					    let proc_intx: pac::io::Int = pac::IO_BANK0.int_proc(cpu);
 | 
				
			||||||
 | 
					    for pin in 0..PIN_COUNT {
 | 
				
			||||||
 | 
					        // There are 4 raw interrupt status registers, PROCx_INTS0, PROCx_INTS1,
 | 
				
			||||||
 | 
					        // PROCx_INTS2, and PROCx_INTS3, and we are selecting the one that the
 | 
				
			||||||
 | 
					        // current pin belongs to.
 | 
				
			||||||
 | 
					        let intsx = proc_intx.ints(pin / 8);
 | 
				
			||||||
 | 
					        // The status register is divided into groups of four, one group for
 | 
				
			||||||
 | 
					        // each pin. Each group consists of four trigger levels LEVEL_LOW,
 | 
				
			||||||
 | 
					        // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin.
 | 
				
			||||||
 | 
					        let pin_group = (pin % 8) as usize;
 | 
				
			||||||
 | 
					        let event = (intsx.read().0 >> pin_group * 4) & 0xf as u32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(trigger) = InterruptTrigger::from_u32(event) {
 | 
				
			||||||
 | 
					            proc_intx.inte(pin / 8).write(|w| match trigger {
 | 
				
			||||||
 | 
					                InterruptTrigger::AnyEdge => {
 | 
				
			||||||
 | 
					                    w.set_edge_high(pin_group, false);
 | 
				
			||||||
 | 
					                    w.set_edge_low(pin_group, false);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                InterruptTrigger::LevelHigh => {
 | 
				
			||||||
 | 
					                    debug!("IO_IRQ_BANK0 pin {} LevelHigh triggered\n", pin);
 | 
				
			||||||
 | 
					                    w.set_level_high(pin_group, false);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                InterruptTrigger::LevelLow => {
 | 
				
			||||||
 | 
					                    w.set_level_low(pin_group, false);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                InterruptTrigger::EdgeHigh => {
 | 
				
			||||||
 | 
					                    w.set_edge_high(pin_group, false);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                InterruptTrigger::EdgeLow => {
 | 
				
			||||||
 | 
					                    w.set_edge_low(pin_group, false);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            INTERRUPT_WAKERS[pin as usize].wake();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct InputFuture<'a, T: Pin> {
 | 
				
			||||||
 | 
					    pin: &'a mut T,
 | 
				
			||||||
 | 
					    level: InterruptTrigger,
 | 
				
			||||||
 | 
					    phantom: PhantomData<&'a mut AnyPin>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'d, T: Pin> InputFuture<'d, T> {
 | 
				
			||||||
 | 
					    pub fn new(pin: &'d mut T, level: InterruptTrigger) -> Self {
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            let irq = interrupt::IO_IRQ_BANK0::steal();
 | 
				
			||||||
 | 
					            irq.disable();
 | 
				
			||||||
 | 
					            irq.set_priority(interrupt::Priority::P6);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Each INTR register is divided into 8 groups, one group for each
 | 
				
			||||||
 | 
					            // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
 | 
				
			||||||
 | 
					            // and EGDE_HIGH.
 | 
				
			||||||
 | 
					            let pin_group = (pin.pin() % 8) as usize;
 | 
				
			||||||
 | 
					            pin.int_proc().inte((pin.pin() / 8) as usize).write(|w| match level {
 | 
				
			||||||
 | 
					                InterruptTrigger::LevelHigh => {
 | 
				
			||||||
 | 
					                    debug!("InputFuture::new enable LevelHigh for pin {} \n", pin.pin());
 | 
				
			||||||
 | 
					                    w.set_level_high(pin_group, true);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                InterruptTrigger::LevelLow => {
 | 
				
			||||||
 | 
					                    w.set_level_low(pin_group, true);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                InterruptTrigger::EdgeHigh => {
 | 
				
			||||||
 | 
					                    w.set_edge_high(pin_group, true);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                InterruptTrigger::EdgeLow => {
 | 
				
			||||||
 | 
					                    w.set_edge_low(pin_group, true);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                InterruptTrigger::AnyEdge => {
 | 
				
			||||||
 | 
					                    // noop
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            irq.enable();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            pin,
 | 
				
			||||||
 | 
					            level,
 | 
				
			||||||
 | 
					            phantom: PhantomData,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'d, T: Pin> Future for InputFuture<'d, T> {
 | 
				
			||||||
 | 
					    type Output = ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
 | 
				
			||||||
 | 
					        // We need to register/re-register the waker for each poll because any
 | 
				
			||||||
 | 
					        // calls to wake will deregister the waker.
 | 
				
			||||||
 | 
					        INTERRUPT_WAKERS[self.pin.pin() as usize].register(cx.waker());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // self.int_proc() will get the register offset for the current cpu,
 | 
				
			||||||
 | 
					        // then we want to access the interrupt enable register for our
 | 
				
			||||||
 | 
					        // pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and
 | 
				
			||||||
 | 
					        // PROC0_INTE3 per cpu).
 | 
				
			||||||
 | 
					        let inte: pac::io::regs::Int = unsafe { self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read() };
 | 
				
			||||||
 | 
					        // The register is divided into groups of four, one group for
 | 
				
			||||||
 | 
					        // each pin. Each group consists of four trigger levels LEVEL_LOW,
 | 
				
			||||||
 | 
					        // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin.
 | 
				
			||||||
 | 
					        let pin_group = (self.pin.pin() % 8) as usize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // This should check the the level of the interrupt trigger level of
 | 
				
			||||||
 | 
					        // the pin and if it has been disabled that means it was done by the
 | 
				
			||||||
 | 
					        // interrupt service routine, so we then know that the event/trigger
 | 
				
			||||||
 | 
					        // happened and Poll::Ready will be returned.
 | 
				
			||||||
 | 
					        debug!("{:?} for pin {}\n", self.level, self.pin.pin());
 | 
				
			||||||
 | 
					        match self.level {
 | 
				
			||||||
 | 
					            InterruptTrigger::AnyEdge => {
 | 
				
			||||||
 | 
					                if !inte.edge_high(pin_group) && !inte.edge_low(pin_group) {
 | 
				
			||||||
 | 
					                    #[rustfmt::skip]
 | 
				
			||||||
 | 
					                    debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin());
 | 
				
			||||||
 | 
					                    return Poll::Ready(());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            InterruptTrigger::LevelHigh => {
 | 
				
			||||||
 | 
					                if !inte.level_high(pin_group) {
 | 
				
			||||||
 | 
					                    #[rustfmt::skip]
 | 
				
			||||||
 | 
					                    debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin());
 | 
				
			||||||
 | 
					                    return Poll::Ready(());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            InterruptTrigger::LevelLow => {
 | 
				
			||||||
 | 
					                if !inte.level_low(pin_group) {
 | 
				
			||||||
 | 
					                    #[rustfmt::skip]
 | 
				
			||||||
 | 
					                    debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin());
 | 
				
			||||||
 | 
					                    return Poll::Ready(());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            InterruptTrigger::EdgeHigh => {
 | 
				
			||||||
 | 
					                if !inte.edge_high(pin_group) {
 | 
				
			||||||
 | 
					                    #[rustfmt::skip]
 | 
				
			||||||
 | 
					                    debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin());
 | 
				
			||||||
 | 
					                    return Poll::Ready(());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            InterruptTrigger::EdgeLow => {
 | 
				
			||||||
 | 
					                if !inte.edge_low(pin_group) {
 | 
				
			||||||
 | 
					                    #[rustfmt::skip]
 | 
				
			||||||
 | 
					                    debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin());
 | 
				
			||||||
 | 
					                    return Poll::Ready(());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        debug!("InputFuture::poll return Poll::Pending\n");
 | 
				
			||||||
 | 
					        Poll::Pending
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Output<'d, T: Pin> {
 | 
					pub struct Output<'d, T: Pin> {
 | 
				
			||||||
@@ -340,6 +547,32 @@ impl<'d, T: Pin> Flex<'d, T> {
 | 
				
			|||||||
    pub fn toggle(&mut self) {
 | 
					    pub fn toggle(&mut self) {
 | 
				
			||||||
        unsafe { self.pin.sio_out().value_xor().write_value(self.bit()) }
 | 
					        unsafe { self.pin.sio_out().value_xor().write_value(self.bit()) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn wait_for_high<'a>(&mut self) {
 | 
				
			||||||
 | 
					        InputFuture::new(&mut self.pin, InterruptTrigger::LevelHigh).await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn wait_for_low<'a>(&mut self) {
 | 
				
			||||||
 | 
					        InputFuture::new(&mut self.pin, InterruptTrigger::LevelLow).await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn wait_for_rising_edge<'a>(&mut self) {
 | 
				
			||||||
 | 
					        self.wait_for_low().await;
 | 
				
			||||||
 | 
					        self.wait_for_high().await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn wait_for_falling_edge<'a>(&mut self) {
 | 
				
			||||||
 | 
					        self.wait_for_high().await;
 | 
				
			||||||
 | 
					        self.wait_for_low().await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn wait_for_any_edge<'a>(&mut self) {
 | 
				
			||||||
 | 
					        if self.is_high() {
 | 
				
			||||||
 | 
					            self.wait_for_low().await;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            self.wait_for_high().await;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'d, T: Pin> Drop for Flex<'d, T> {
 | 
					impl<'d, T: Pin> Drop for Flex<'d, T> {
 | 
				
			||||||
@@ -401,6 +634,15 @@ pub(crate) mod sealed {
 | 
				
			|||||||
        fn sio_in(&self) -> Reg<u32, RW> {
 | 
					        fn sio_in(&self) -> Reg<u32, RW> {
 | 
				
			||||||
            SIO.gpio_in(self.bank() as _)
 | 
					            SIO.gpio_in(self.bank() as _)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fn int_proc(&self) -> pac::io::Int {
 | 
				
			||||||
 | 
					            let io_block = match self.bank() {
 | 
				
			||||||
 | 
					                Bank::Bank0 => crate::pac::IO_BANK0,
 | 
				
			||||||
 | 
					                Bank::Qspi => crate::pac::IO_QSPI,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            let proc = unsafe { SIO.cpuid().read() };
 | 
				
			||||||
 | 
					            io_block.int_proc(proc as _)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -478,6 +720,8 @@ impl_pin!(PIN_QSPI_SD3, Bank::Qspi, 5);
 | 
				
			|||||||
// ====================
 | 
					// ====================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod eh02 {
 | 
					mod eh02 {
 | 
				
			||||||
 | 
					    use futures::FutureExt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> {
 | 
					    impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> {
 | 
				
			||||||
@@ -595,6 +839,62 @@ mod eh02 {
 | 
				
			|||||||
            Ok(self.toggle())
 | 
					            Ok(self.toggle())
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use core::convert::Infallible;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    impl<'d, T: Pin> embedded_hal_async::digital::Wait for Flex<'d, T> {
 | 
				
			||||||
 | 
					        type WaitForHighFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
 | 
				
			||||||
 | 
					        fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> {
 | 
				
			||||||
 | 
					            self.wait_for_high().map(Ok)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        type WaitForLowFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
 | 
				
			||||||
 | 
					        fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> {
 | 
				
			||||||
 | 
					            self.wait_for_low().map(Ok)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        type WaitForRisingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
 | 
				
			||||||
 | 
					        fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> {
 | 
				
			||||||
 | 
					            self.wait_for_rising_edge().map(Ok)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        type WaitForFallingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
 | 
				
			||||||
 | 
					        fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> {
 | 
				
			||||||
 | 
					            self.wait_for_falling_edge().map(Ok)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        type WaitForAnyEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
 | 
				
			||||||
 | 
					        fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> {
 | 
				
			||||||
 | 
					            self.wait_for_any_edge().map(Ok)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    impl<'d, T: Pin> embedded_hal_async::digital::Wait for Input<'d, T> {
 | 
				
			||||||
 | 
					        type WaitForHighFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
 | 
				
			||||||
 | 
					        fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> {
 | 
				
			||||||
 | 
					            self.wait_for_high().map(Ok)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        type WaitForLowFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
 | 
				
			||||||
 | 
					        fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> {
 | 
				
			||||||
 | 
					            self.wait_for_low().map(Ok)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        type WaitForRisingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
 | 
				
			||||||
 | 
					        fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> {
 | 
				
			||||||
 | 
					            self.wait_for_rising_edge().map(Ok)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        type WaitForFallingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
 | 
				
			||||||
 | 
					        fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> {
 | 
				
			||||||
 | 
					            self.wait_for_falling_edge().map(Ok)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        type WaitForAnyEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
 | 
				
			||||||
 | 
					        fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> {
 | 
				
			||||||
 | 
					            self.wait_for_any_edge().map(Ok)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(feature = "unstable-traits")]
 | 
					#[cfg(feature = "unstable-traits")]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										38
									
								
								examples/rp/src/bin/gpio_async.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								examples/rp/src/bin/gpio_async.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					#![no_std]
 | 
				
			||||||
 | 
					#![no_main]
 | 
				
			||||||
 | 
					#![feature(type_alias_impl_trait)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use defmt::*;
 | 
				
			||||||
 | 
					use embassy::executor::Spawner;
 | 
				
			||||||
 | 
					use embassy::time::{Duration, Timer};
 | 
				
			||||||
 | 
					use embassy_rp::{gpio, Peripherals};
 | 
				
			||||||
 | 
					use gpio::{Input, Level, Output, Pull};
 | 
				
			||||||
 | 
					use {defmt_rtt as _, panic_probe as _};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// This example shows how async gpio can be used with a RP2040.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// It requires an external signal to be manually triggered on PIN 16. For
 | 
				
			||||||
 | 
					/// example, this could be accomplished using an external power source with a
 | 
				
			||||||
 | 
					/// button so that it is possible to toggle the signal from low to high.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// This example will begin with turning on the LED on the board and wait for a
 | 
				
			||||||
 | 
					/// high signal on PIN 16. Once the high event/signal occurs the program will
 | 
				
			||||||
 | 
					/// continue and turn off the LED, and then wait for 2 seconds before completing
 | 
				
			||||||
 | 
					/// the loop and starting over again.
 | 
				
			||||||
 | 
					#[embassy::main]
 | 
				
			||||||
 | 
					async fn main(_spawner: Spawner, p: Peripherals) {
 | 
				
			||||||
 | 
					    let mut led = Output::new(p.PIN_25, Level::Low);
 | 
				
			||||||
 | 
					    let mut async_input = Input::new(p.PIN_16, Pull::None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {
 | 
				
			||||||
 | 
					        info!("wait_for_high. Turn on LED");
 | 
				
			||||||
 | 
					        led.set_high();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async_input.wait_for_high().await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        info!("done wait_for_high. Turn off LED");
 | 
				
			||||||
 | 
					        led.set_low();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Timer::after(Duration::from_secs(2)).await;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -16,6 +16,7 @@ embedded-hal = "0.2.6"
 | 
				
			|||||||
embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" }
 | 
					embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" }
 | 
				
			||||||
embedded-hal-async = { version = "0.1.0-alpha.1" }
 | 
					embedded-hal-async = { version = "0.1.0-alpha.1" }
 | 
				
			||||||
panic-probe = { version = "0.3.0", features = ["print-defmt"] }
 | 
					panic-probe = { version = "0.3.0", features = ["print-defmt"] }
 | 
				
			||||||
 | 
					futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[profile.dev]
 | 
					[profile.dev]
 | 
				
			||||||
debug = 2
 | 
					debug = 2
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										148
									
								
								tests/rp/src/bin/gpio_async.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								tests/rp/src/bin/gpio_async.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
				
			|||||||
 | 
					#![no_std]
 | 
				
			||||||
 | 
					#![no_main]
 | 
				
			||||||
 | 
					#![feature(type_alias_impl_trait)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use defmt::{assert, *};
 | 
				
			||||||
 | 
					use embassy::executor::Spawner;
 | 
				
			||||||
 | 
					use embassy::time::{Duration, Instant, Timer};
 | 
				
			||||||
 | 
					use embassy_rp::gpio::{Input, Level, Output, Pull};
 | 
				
			||||||
 | 
					use embassy_rp::Peripherals;
 | 
				
			||||||
 | 
					use futures::future::join;
 | 
				
			||||||
 | 
					use {defmt_rtt as _, panic_probe as _};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[embassy::main]
 | 
				
			||||||
 | 
					async fn main(_spawner: Spawner, p: Peripherals) {
 | 
				
			||||||
 | 
					    info!("embassy-rp gpio_async test");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // On the CI device the following pins are connected with each other.
 | 
				
			||||||
 | 
					    let (mut output_pin, mut input_pin) = (p.PIN_0, p.PIN_1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        info!("test wait_for_high");
 | 
				
			||||||
 | 
					        let mut output = Output::new(&mut output_pin, Level::Low);
 | 
				
			||||||
 | 
					        let mut input = Input::new(&mut input_pin, Pull::None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert!(input.is_low(), "input was expected to be low");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let set_high_future = async {
 | 
				
			||||||
 | 
					            // Allow time for wait_for_high_future to await wait_for_high().
 | 
				
			||||||
 | 
					            Timer::after(Duration::from_millis(10)).await;
 | 
				
			||||||
 | 
					            output.set_high();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let wait_for_high_future = async {
 | 
				
			||||||
 | 
					            let start = Instant::now();
 | 
				
			||||||
 | 
					            input.wait_for_high().await;
 | 
				
			||||||
 | 
					            assert_duration(start);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        join(set_high_future, wait_for_high_future).await;
 | 
				
			||||||
 | 
					        info!("test wait_for_high: OK\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        info!("test wait_for_low");
 | 
				
			||||||
 | 
					        let mut output = Output::new(&mut output_pin, Level::High);
 | 
				
			||||||
 | 
					        let mut input = Input::new(&mut input_pin, Pull::None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert!(input.is_high(), "input was expected to be high");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let set_low_future = async {
 | 
				
			||||||
 | 
					            Timer::after(Duration::from_millis(10)).await;
 | 
				
			||||||
 | 
					            output.set_low();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let wait_for_low_future = async {
 | 
				
			||||||
 | 
					            let start = Instant::now();
 | 
				
			||||||
 | 
					            input.wait_for_low().await;
 | 
				
			||||||
 | 
					            assert_duration(start);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        join(set_low_future, wait_for_low_future).await;
 | 
				
			||||||
 | 
					        info!("test wait_for_low: OK\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        info!("test wait_for_rising_edge");
 | 
				
			||||||
 | 
					        let mut output = Output::new(&mut output_pin, Level::Low);
 | 
				
			||||||
 | 
					        let mut input = Input::new(&mut input_pin, Pull::None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert!(input.is_low(), "input was expected to be low");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let set_high_future = async {
 | 
				
			||||||
 | 
					            Timer::after(Duration::from_millis(10)).await;
 | 
				
			||||||
 | 
					            output.set_high();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let wait_for_rising_edge_future = async {
 | 
				
			||||||
 | 
					            let start = Instant::now();
 | 
				
			||||||
 | 
					            input.wait_for_rising_edge().await;
 | 
				
			||||||
 | 
					            assert_duration(start);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        join(set_high_future, wait_for_rising_edge_future).await;
 | 
				
			||||||
 | 
					        info!("test wait_for_rising_edge: OK\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        info!("test wait_for_falling_edge");
 | 
				
			||||||
 | 
					        let mut output = Output::new(&mut output_pin, Level::High);
 | 
				
			||||||
 | 
					        let mut input = Input::new(&mut input_pin, Pull::None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert!(input.is_high(), "input was expected to be high");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let set_low_future = async {
 | 
				
			||||||
 | 
					            Timer::after(Duration::from_millis(10)).await;
 | 
				
			||||||
 | 
					            output.set_low();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let wait_for_falling_edge_future = async {
 | 
				
			||||||
 | 
					            let start = Instant::now();
 | 
				
			||||||
 | 
					            input.wait_for_falling_edge().await;
 | 
				
			||||||
 | 
					            assert_duration(start);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        join(set_low_future, wait_for_falling_edge_future).await;
 | 
				
			||||||
 | 
					        info!("test wait_for_falling_edge: OK\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        info!("test wait_for_any_edge (falling)");
 | 
				
			||||||
 | 
					        let mut output = Output::new(&mut output_pin, Level::High);
 | 
				
			||||||
 | 
					        let mut input = Input::new(&mut input_pin, Pull::None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert!(input.is_high(), "input was expected to be high");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let set_low_future = async {
 | 
				
			||||||
 | 
					            Timer::after(Duration::from_millis(10)).await;
 | 
				
			||||||
 | 
					            output.set_low();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let wait_for_any_edge_future = async {
 | 
				
			||||||
 | 
					            let start = Instant::now();
 | 
				
			||||||
 | 
					            input.wait_for_any_edge().await;
 | 
				
			||||||
 | 
					            assert_duration(start);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        join(set_low_future, wait_for_any_edge_future).await;
 | 
				
			||||||
 | 
					        info!("test wait_for_any_edge (falling): OK\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        info!("test wait_for_any_edge (rising)");
 | 
				
			||||||
 | 
					        let mut output = Output::new(&mut output_pin, Level::Low);
 | 
				
			||||||
 | 
					        let mut input = Input::new(&mut input_pin, Pull::None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert!(input.is_low(), "input was expected to be low");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let set_high_future = async {
 | 
				
			||||||
 | 
					            Timer::after(Duration::from_millis(10)).await;
 | 
				
			||||||
 | 
					            output.set_high();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let wait_for_any_edge_future = async {
 | 
				
			||||||
 | 
					            let start = Instant::now();
 | 
				
			||||||
 | 
					            input.wait_for_any_edge().await;
 | 
				
			||||||
 | 
					            assert_duration(start);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        join(set_high_future, wait_for_any_edge_future).await;
 | 
				
			||||||
 | 
					        info!("test wait_for_any_edge (rising): OK\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    info!("Test OK");
 | 
				
			||||||
 | 
					    cortex_m::asm::bkpt();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn assert_duration(start: Instant) {
 | 
				
			||||||
 | 
					        let dur = Instant::now() - start;
 | 
				
			||||||
 | 
					        assert!(dur >= Duration::from_millis(10) && dur < Duration::from_millis(11));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user