nrf/gpiote: new api: switch to owned structs, implement WaitForHigh/WaitForLow.

This commit is contained in:
Dario Nieuwenhuis 2021-02-04 23:56:17 +01:00
parent 1879703153
commit a7797a918d
3 changed files with 324 additions and 329 deletions

View File

@ -12,7 +12,7 @@ use nrf52840_hal::gpio;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
use embassy::util::Forever; use embassy::util::Forever;
use embassy_nrf::gpiote; use embassy_nrf::gpiote::{Channels, Gpiote, InputChannel, InputChannelPolarity};
use embassy_nrf::interrupt; use embassy_nrf::interrupt;
#[task] #[task]
@ -20,46 +20,44 @@ async fn run() {
let p = unwrap!(embassy_nrf::pac::Peripherals::take()); let p = unwrap!(embassy_nrf::pac::Peripherals::take());
let port0 = gpio::p0::Parts::new(p.P0); let port0 = gpio::p0::Parts::new(p.P0);
let g = gpiote::Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); let (g, chs) = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE));
info!("Starting!"); info!("Starting!");
let pin1 = port0.p0_11.into_pullup_input().degrade(); let pin1 = port0.p0_11.into_pullup_input().degrade();
let button1 = async { let pin2 = port0.p0_12.into_pullup_input().degrade();
let ch = unwrap!(g.new_input_channel(pin1, gpiote::InputChannelPolarity::HiToLo)); let pin3 = port0.p0_24.into_pullup_input().degrade();
let pin4 = port0.p0_25.into_pullup_input().degrade();
let ch1 = InputChannel::new(g, chs.ch0, pin1, InputChannelPolarity::HiToLo);
let ch2 = InputChannel::new(g, chs.ch1, pin2, InputChannelPolarity::LoToHi);
let ch3 = InputChannel::new(g, chs.ch2, pin3, InputChannelPolarity::Toggle);
let ch4 = InputChannel::new(g, chs.ch3, pin4, InputChannelPolarity::Toggle);
let button1 = async {
loop { loop {
ch.wait().await; ch1.wait().await;
info!("Button 1 pressed") info!("Button 1 pressed")
} }
}; };
let pin2 = port0.p0_12.into_pullup_input().degrade();
let button2 = async { let button2 = async {
let ch = unwrap!(g.new_input_channel(pin2, gpiote::InputChannelPolarity::LoToHi));
loop { loop {
ch.wait().await; ch2.wait().await;
info!("Button 2 released") info!("Button 2 released")
} }
}; };
let pin3 = port0.p0_24.into_pullup_input().degrade();
let button3 = async { let button3 = async {
let ch = unwrap!(g.new_input_channel(pin3, gpiote::InputChannelPolarity::Toggle));
loop { loop {
ch.wait().await; ch3.wait().await;
info!("Button 3 toggled") info!("Button 3 toggled")
} }
}; };
let pin4 = port0.p0_25.into_pullup_input().degrade();
let button4 = async { let button4 = async {
let ch = unwrap!(g.new_input_channel(pin4, gpiote::InputChannelPolarity::Toggle));
loop { loop {
ch.wait().await; ch4.wait().await;
info!("Button 4 toggled") info!("Button 4 toggled")
} }
}; };

View File

@ -7,20 +7,22 @@ mod example_common;
use example_common::*; use example_common::*;
use core::mem; use core::mem;
use core::pin::Pin;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::panic; use defmt::panic;
use nrf52840_hal::gpio; use nrf52840_hal::gpio;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
use embassy::gpio::{WaitForHigh, WaitForLow};
use embassy::util::Forever; use embassy::util::Forever;
use embassy_nrf::gpiote::{Gpiote, PortInputPolarity}; use embassy_nrf::gpiote::{Gpiote, GpiotePin};
use embassy_nrf::interrupt; use embassy_nrf::interrupt;
async fn button(g: &Gpiote, n: usize, pin: gpio::Pin<gpio::Input<gpio::PullUp>>) { async fn button(n: usize, mut pin: GpiotePin<gpio::PullUp>) {
loop { loop {
g.wait_port_input(&pin, PortInputPolarity::Low).await; Pin::new(&mut pin).wait_for_low().await;
info!("Button {:?} pressed!", n); info!("Button {:?} pressed!", n);
g.wait_port_input(&pin, PortInputPolarity::High).await; Pin::new(&mut pin).wait_for_high().await;
info!("Button {:?} released!", n); info!("Button {:?} released!", n);
} }
} }
@ -30,19 +32,24 @@ async fn run() {
let p = unwrap!(embassy_nrf::pac::Peripherals::take()); let p = unwrap!(embassy_nrf::pac::Peripherals::take());
let port0 = gpio::p0::Parts::new(p.P0); let port0 = gpio::p0::Parts::new(p.P0);
let g = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); let (g, _) = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE));
info!(
"sizeof Signal<()> = {:usize}", let button1 = button(
mem::size_of::<embassy::util::Signal<()>>() 1,
GpiotePin::new(g, port0.p0_11.into_pullup_input().degrade()),
);
let button2 = button(
2,
GpiotePin::new(g, port0.p0_12.into_pullup_input().degrade()),
);
let button3 = button(
3,
GpiotePin::new(g, port0.p0_24.into_pullup_input().degrade()),
);
let button4 = button(
4,
GpiotePin::new(g, port0.p0_25.into_pullup_input().degrade()),
); );
info!("sizeof gpiote = {:usize}", mem::size_of::<Gpiote>());
info!("Starting!");
let button1 = button(&g, 1, port0.p0_11.into_pullup_input().degrade());
let button2 = button(&g, 2, port0.p0_12.into_pullup_input().degrade());
let button3 = button(&g, 3, port0.p0_24.into_pullup_input().degrade());
let button4 = button(&g, 4, port0.p0_25.into_pullup_input().degrade());
futures::join!(button1, button2, button3, button4); futures::join!(button1, button2, button3, button4);
} }

View File

@ -1,18 +1,20 @@
use crate::fmt::{panic, *};
use core::cell::Cell;
use core::future::Future; use core::future::Future;
use core::mem::ManuallyDrop;
use core::ops::Deref;
use core::pin::Pin;
use core::ptr; use core::ptr;
use core::task::{Context, Poll}; use core::task::{Context, Poll};
use embassy::gpio::{WaitForHigh, WaitForLow};
use embassy::util::Signal; use embassy::util::Signal;
use crate::hal::gpio::{Input, Level, Output, Pin, Port}; use crate::fmt::{panic, *};
use crate::hal::gpio::{Input, Level, Output, Pin as GpioPin, Port};
use crate::interrupt; use crate::interrupt;
use crate::interrupt::OwnedInterrupt; use crate::interrupt::OwnedInterrupt;
use crate::pac;
use crate::pac::generic::Reg; use crate::pac::generic::Reg;
use crate::pac::gpiote::_TASKS_OUT; use crate::pac::gpiote::_TASKS_OUT;
#[cfg(any(feature = "52833", feature = "52840"))] use crate::pac::{p0 as pac_gpio, GPIOTE};
use crate::pac::P1;
use crate::pac::{p0 as gpio, GPIOTE, P0};
#[cfg(not(feature = "51"))] #[cfg(not(feature = "51"))]
use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET}; use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET};
@ -24,19 +26,50 @@ pub const PIN_COUNT: usize = 48;
#[cfg(not(any(feature = "52833", feature = "52840")))] #[cfg(not(any(feature = "52833", feature = "52840")))]
pub const PIN_COUNT: usize = 32; pub const PIN_COUNT: usize = 32;
pub struct Gpiote { pub trait ChannelID {
inner: GPIOTE, fn number(&self) -> usize;
free_channels: Cell<u8>, // 0 = used, 1 = free. 8 bits for 8 channelself.
channel_signals: [Signal<()>; CHANNEL_COUNT],
port_signals: [Signal<()>; PIN_COUNT],
} }
static mut INSTANCE: *const Gpiote = ptr::null_mut(); macro_rules! impl_channel {
($ChX:ident, $n:expr) => {
pub enum PortInputPolarity { pub struct $ChX(());
High, impl $ChX {
Low, pub fn degrade(self) -> ChAny {
ChAny($n)
} }
}
impl ChannelID for $ChX {
fn number(&self) -> usize {
$n
}
}
};
}
impl_channel!(Ch0, 0);
impl_channel!(Ch1, 1);
impl_channel!(Ch2, 2);
impl_channel!(Ch3, 3);
impl_channel!(Ch4, 4);
impl_channel!(Ch5, 5);
impl_channel!(Ch6, 6);
impl_channel!(Ch7, 7);
pub struct ChAny(u8);
impl ChannelID for ChAny {
fn number(&self) -> usize {
self.0 as usize
}
}
#[derive(Clone, Copy)]
pub struct Gpiote(());
const NEW_SIGNAL: Signal<()> = Signal::new();
static CHANNEL_SIGNALS: [Signal<()>; CHANNEL_COUNT] = [NEW_SIGNAL; CHANNEL_COUNT];
static PORT_SIGNALS: [Signal<()>; PIN_COUNT] = [NEW_SIGNAL; PIN_COUNT];
pub enum InputChannelPolarity { pub enum InputChannelPolarity {
None, None,
@ -58,12 +91,23 @@ pub enum NewChannelError {
NoFreeChannels, NoFreeChannels,
} }
pub struct Channels {
pub ch0: Ch0,
pub ch1: Ch1,
pub ch2: Ch2,
pub ch3: Ch3,
pub ch4: Ch4,
pub ch5: Ch5,
pub ch6: Ch6,
pub ch7: Ch7,
}
impl Gpiote { impl Gpiote {
pub fn new(gpiote: GPIOTE, irq: interrupt::GPIOTEInterrupt) -> Self { pub fn new(gpiote: GPIOTE, irq: interrupt::GPIOTEInterrupt) -> (Self, Channels) {
#[cfg(any(feature = "52833", feature = "52840"))] #[cfg(any(feature = "52833", feature = "52840"))]
let ports = unsafe { &[&*P0::ptr(), &*P1::ptr()] }; let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] };
#[cfg(not(any(feature = "52833", feature = "52840")))] #[cfg(not(any(feature = "52833", feature = "52840")))]
let ports = unsafe { &[&*P0::ptr()] }; let ports = unsafe { &[&*pac::P0::ptr()] };
for &p in ports { for &p in ports {
// Enable latched detection // Enable latched detection
@ -79,158 +123,104 @@ impl Gpiote {
irq.unpend(); irq.unpend();
irq.enable(); irq.enable();
Self { (
inner: gpiote, Self(()),
free_channels: Cell::new(0xFF), // all 8 channels free Channels {
channel_signals: [ ch0: Ch0(()),
Signal::new(), ch1: Ch1(()),
Signal::new(), ch2: Ch2(()),
Signal::new(), ch3: Ch3(()),
Signal::new(), ch4: Ch4(()),
Signal::new(), ch5: Ch5(()),
Signal::new(), ch6: Ch6(()),
Signal::new(), ch7: Ch7(()),
Signal::new(), },
], )
// This is just horrible }
unsafe fn on_irq(_ctx: *mut ()) {
let g = &*GPIOTE::ptr();
for i in 0..8 {
if g.events_in[i].read().bits() != 0 {
g.events_in[i].write(|w| w);
CHANNEL_SIGNALS[i].signal(());
}
}
if g.events_port.read().bits() != 0 {
g.events_port.write(|w| w);
#[cfg(any(feature = "52833", feature = "52840"))] #[cfg(any(feature = "52833", feature = "52840"))]
port_signals: [ let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()];
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
],
#[cfg(not(any(feature = "52833", feature = "52840")))] #[cfg(not(any(feature = "52833", feature = "52840")))]
port_signals: [ let ports = &[&*pac::P0::ptr()];
Signal::new(),
Signal::new(), let mut work = true;
Signal::new(), while work {
Signal::new(), work = false;
Signal::new(), for (port, &p) in ports.iter().enumerate() {
Signal::new(), for pin in BitIter(p.latch.read().bits()) {
Signal::new(), work = true;
Signal::new(), p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled());
Signal::new(), p.latch.write(|w| w.bits(1 << pin));
Signal::new(), PORT_SIGNALS[port * 32 + pin as usize].signal(());
Signal::new(), }
Signal::new(), }
Signal::new(), }
Signal::new(), }
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
Signal::new(),
],
} }
} }
fn allocate_channel(&self) -> Result<u8, NewChannelError> { fn pin_num<T>(pin: &GpioPin<T>) -> usize {
interrupt::free(|_| { let port = match pin.port() {
let chs = self.free_channels.get(); Port::Port0 => 0,
let index = chs.trailing_zeros() as usize; #[cfg(any(feature = "52833", feature = "52840"))]
if index == 8 { Port::Port1 => 32,
return Err(NewChannelError::NoFreeChannels); };
}
self.free_channels.set(chs & !(1 << index)); port + pin.pin() as usize
Ok(index as u8)
})
} }
fn free_channel(&self, index: u8) { fn pin_block<T>(pin: &GpioPin<T>) -> &pac_gpio::RegisterBlock {
interrupt::free(|_| { let ptr = match pin.port() {
self.inner.config[index as usize].write(|w| w.mode().disabled()); Port::Port0 => pac::P0::ptr(),
self.inner.intenclr.write(|w| unsafe { w.bits(1 << index) }); #[cfg(any(feature = "52833", feature = "52840"))]
Port::Port1 => pac::P1::ptr(),
};
self.free_channels unsafe { &*ptr }
.set(self.free_channels.get() | 1 << index);
trace!("freed ch {:?}", index);
})
} }
pub fn wait_port_input<'a, T>( fn pin_conf<T>(pin: &GpioPin<T>) -> &pac_gpio::PIN_CNF {
&'a self, &pin_block(pin).pin_cnf[pin.pin() as usize]
pin: &'a Pin<Input<T>>,
polarity: PortInputPolarity,
) -> PortInputFuture<'a, T> {
interrupt::free(|_| {
unsafe { INSTANCE = self };
PortInputFuture {
gpiote: self,
pin,
polarity,
}
})
} }
pub fn new_input_channel<'a, T>( pub struct InputChannel<C: ChannelID, T> {
&'a self, ch: C,
pin: Pin<Input<T>>, pin: GpioPin<Input<T>>,
}
impl<C: ChannelID, T> Drop for InputChannel<C, T> {
fn drop(&mut self) {
let g = unsafe { &*GPIOTE::ptr() };
let index = self.ch.number();
g.config[index].write(|w| w.mode().disabled());
g.intenclr.write(|w| unsafe { w.bits(1 << index) });
}
}
impl<C: ChannelID, T> InputChannel<C, T> {
pub fn new(
_gpiote: Gpiote,
ch: C,
pin: GpioPin<Input<T>>,
polarity: InputChannelPolarity, polarity: InputChannelPolarity,
) -> Result<InputChannel<'a, T>, NewChannelError> { ) -> Self {
interrupt::free(|_| { let g = unsafe { &*GPIOTE::ptr() };
unsafe { INSTANCE = self }; let index = ch.number();
let index = self.allocate_channel()?;
trace!("allocated in ch {:?}", index as u8);
self.inner.config[index as usize].write(|w| { g.config[index].write(|w| {
match polarity { match polarity {
InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(), InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(),
InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(), InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(),
@ -245,29 +235,57 @@ impl Gpiote {
unsafe { w.psel().bits(pin.pin()) } unsafe { w.psel().bits(pin.pin()) }
}); });
// Enable interrupt CHANNEL_SIGNALS[index].reset();
self.inner.intenset.write(|w| unsafe { w.bits(1 << index) });
Ok(InputChannel { // Enable interrupt
gpiote: self, g.intenset.write(|w| unsafe { w.bits(1 << index) });
index,
pin, InputChannel { ch, pin }
})
})
} }
pub fn new_output_channel<'a, T>( pub fn free(self) -> (C, GpioPin<Input<T>>) {
&'a self, let m = ManuallyDrop::new(self);
pin: Pin<Output<T>>, let ch = unsafe { ptr::read(&m.ch) };
let pin = unsafe { ptr::read(&m.pin) };
(ch, pin)
}
pub async fn wait(&self) {
let index = self.ch.number();
CHANNEL_SIGNALS[index].wait().await;
}
pub fn pin(&self) -> &GpioPin<Input<T>> {
&self.pin
}
}
pub struct OutputChannel<C: ChannelID, T> {
ch: C,
pin: GpioPin<Output<T>>,
}
impl<C: ChannelID, T> Drop for OutputChannel<C, T> {
fn drop(&mut self) {
let g = unsafe { &*GPIOTE::ptr() };
let index = self.ch.number();
g.config[index].write(|w| w.mode().disabled());
g.intenclr.write(|w| unsafe { w.bits(1 << index) });
}
}
impl<C: ChannelID, T> OutputChannel<C, T> {
pub fn new(
_gpiote: Gpiote,
ch: C,
pin: GpioPin<Output<T>>,
level: Level, level: Level,
polarity: OutputChannelPolarity, polarity: OutputChannelPolarity,
) -> Result<OutputChannel<'a>, NewChannelError> { ) -> Self {
interrupt::free(|_| { let g = unsafe { &*GPIOTE::ptr() };
unsafe { INSTANCE = self }; let index = ch.number();
let index = self.allocate_channel()?;
trace!("allocated out ch {:?}", index);
self.inner.config[index as usize].write(|w| { g.config[index].write(|w| {
w.mode().task(); w.mode().task();
match level { match level {
Level::High => w.outinit().high(), Level::High => w.outinit().high(),
@ -287,164 +305,66 @@ impl Gpiote {
}); });
// Enable interrupt // Enable interrupt
self.inner.intenset.write(|w| unsafe { w.bits(1 << index) }); g.intenset.write(|w| unsafe { w.bits(1 << index) });
Ok(OutputChannel { OutputChannel { ch, pin }
gpiote: self,
index,
})
})
} }
unsafe fn on_irq(_ctx: *mut ()) { pub fn free(self) -> (C, GpioPin<Output<T>>) {
let s = &(*INSTANCE); let m = ManuallyDrop::new(self);
let ch = unsafe { ptr::read(&m.ch) };
for i in 0..8 { let pin = unsafe { ptr::read(&m.pin) };
if s.inner.events_in[i].read().bits() != 0 { (ch, pin)
s.inner.events_in[i].write(|w| w);
s.channel_signals[i].signal(());
}
} }
if s.inner.events_port.read().bits() != 0 {
s.inner.events_port.write(|w| w);
#[cfg(any(feature = "52833", feature = "52840"))]
let ports = &[&*P0::ptr(), &*P1::ptr()];
#[cfg(not(any(feature = "52833", feature = "52840")))]
let ports = &[&*P0::ptr()];
let mut work = true;
while work {
work = false;
for (port, &p) in ports.iter().enumerate() {
for pin in BitIter(p.latch.read().bits()) {
work = true;
p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled());
p.latch.write(|w| w.bits(1 << pin));
s.port_signals[port * 32 + pin as usize].signal(());
}
}
}
}
}
}
pub struct PortInputFuture<'a, T> {
gpiote: &'a Gpiote,
pin: &'a Pin<Input<T>>,
polarity: PortInputPolarity,
}
impl<'a, T> Drop for PortInputFuture<'a, T> {
fn drop(&mut self) {
pin_conf(&self.pin).modify(|_, w| w.sense().disabled());
self.gpiote.port_signals[pin_num(&self.pin)].reset();
}
}
impl<'a, T> Future for PortInputFuture<'a, T> {
type Output = ();
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
pin_conf(&self.pin).modify(|_, w| match self.polarity {
PortInputPolarity::Low => w.sense().low(),
PortInputPolarity::High => w.sense().high(),
});
self.gpiote.port_signals[pin_num(&self.pin)].poll_wait(cx)
}
}
fn pin_num<T>(pin: &Pin<T>) -> usize {
let port = match pin.port() {
Port::Port0 => 0,
#[cfg(any(feature = "52833", feature = "52840"))]
Port::Port1 => 32,
};
port + pin.pin() as usize
}
fn pin_block<T>(pin: &Pin<T>) -> &gpio::RegisterBlock {
let ptr = match pin.port() {
Port::Port0 => P0::ptr(),
#[cfg(any(feature = "52833", feature = "52840"))]
Port::Port1 => P1::ptr(),
};
unsafe { &*ptr }
}
fn pin_conf<T>(pin: &Pin<T>) -> &gpio::PIN_CNF {
&pin_block(pin).pin_cnf[pin.pin() as usize]
}
pub struct InputChannel<'a, T> {
gpiote: &'a Gpiote,
pin: Pin<Input<T>>,
index: u8,
}
impl<'a, T> Drop for InputChannel<'a, T> {
fn drop(&mut self) {
self.gpiote.free_channel(self.index);
}
}
impl<'a, T> InputChannel<'a, T> {
pub async fn wait(&self) {
self.gpiote.channel_signals[self.index as usize]
.wait()
.await;
}
pub fn pin(&self) -> &Pin<Input<T>> {
&self.pin
}
}
pub struct OutputChannel<'a> {
gpiote: &'a Gpiote,
index: u8,
}
impl<'a> Drop for OutputChannel<'a> {
fn drop(&mut self) {
self.gpiote.free_channel(self.index);
}
}
impl<'a> OutputChannel<'a> {
/// Triggers `task out` (as configured with task_out_polarity, defaults to Toggle). /// Triggers `task out` (as configured with task_out_polarity, defaults to Toggle).
pub fn out(&self) { pub fn out(&self) {
self.gpiote.inner.tasks_out[self.index as usize].write(|w| unsafe { w.bits(1) }); let g = unsafe { &*GPIOTE::ptr() };
let index = self.ch.number();
g.tasks_out[index].write(|w| unsafe { w.bits(1) });
} }
/// Triggers `task set` (set associated pin high). /// Triggers `task set` (set associated pin high).
#[cfg(not(feature = "51"))] #[cfg(not(feature = "51"))]
pub fn set(&self) { pub fn set(&self) {
self.gpiote.inner.tasks_set[self.index as usize].write(|w| unsafe { w.bits(1) }); let g = unsafe { &*GPIOTE::ptr() };
let index = self.ch.number();
g.tasks_set[index].write(|w| unsafe { w.bits(1) });
} }
/// Triggers `task clear` (set associated pin low). /// Triggers `task clear` (set associated pin low).
#[cfg(not(feature = "51"))] #[cfg(not(feature = "51"))]
pub fn clear(&self) { pub fn clear(&self) {
self.gpiote.inner.tasks_clr[self.index as usize].write(|w| unsafe { w.bits(1) }); let g = unsafe { &*GPIOTE::ptr() };
let index = self.ch.number();
g.tasks_clr[index].write(|w| unsafe { w.bits(1) });
} }
/// Returns reference to task_out endpoint for PPI. /// Returns reference to task_out endpoint for PPI.
pub fn task_out(&self) -> &Reg<u32, _TASKS_OUT> { pub fn task_out(&self) -> &Reg<u32, _TASKS_OUT> {
&self.gpiote.inner.tasks_out[self.index as usize] let g = unsafe { &*GPIOTE::ptr() };
let index = self.ch.number();
&g.tasks_out[index]
} }
/// Returns reference to task_clr endpoint for PPI. /// Returns reference to task_clr endpoint for PPI.
#[cfg(not(feature = "51"))] #[cfg(not(feature = "51"))]
pub fn task_clr(&self) -> &Reg<u32, _TASKS_CLR> { pub fn task_clr(&self) -> &Reg<u32, _TASKS_CLR> {
&self.gpiote.inner.tasks_clr[self.index as usize] let g = unsafe { &*GPIOTE::ptr() };
let index = self.ch.number();
&g.tasks_clr[index]
} }
/// Returns reference to task_set endpoint for PPI. /// Returns reference to task_set endpoint for PPI.
#[cfg(not(feature = "51"))] #[cfg(not(feature = "51"))]
pub fn task_set(&self) -> &Reg<u32, _TASKS_SET> { pub fn task_set(&self) -> &Reg<u32, _TASKS_SET> {
&self.gpiote.inner.tasks_set[self.index as usize] let g = unsafe { &*GPIOTE::ptr() };
let index = self.ch.number();
&g.tasks_set[index]
} }
} }
@ -463,3 +383,73 @@ impl Iterator for BitIter {
} }
} }
} }
pub struct GpiotePin<T> {
pin: GpioPin<Input<T>>,
}
impl<T> Unpin for GpiotePin<T> {}
impl<T> GpiotePin<T> {
pub fn new(_gpiote: Gpiote, pin: GpioPin<Input<T>>) -> Self {
Self { pin }
}
}
impl<T: 'static> WaitForHigh for GpiotePin<T> {
type Future<'a> = PortInputFuture<'a, T>;
fn wait_for_high<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
PortInputFuture {
pin: &self.get_mut().pin,
polarity: PortInputPolarity::High,
}
}
}
impl<T: 'static> WaitForLow for GpiotePin<T> {
type Future<'a> = PortInputFuture<'a, T>;
fn wait_for_low<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
PortInputFuture {
pin: &self.get_mut().pin,
polarity: PortInputPolarity::Low,
}
}
}
impl<T> Deref for GpiotePin<T> {
type Target = GpioPin<Input<T>>;
fn deref(&self) -> &Self::Target {
&self.pin
}
}
enum PortInputPolarity {
High,
Low,
}
pub struct PortInputFuture<'a, T> {
pin: &'a GpioPin<Input<T>>,
polarity: PortInputPolarity,
}
impl<'a, T> Drop for PortInputFuture<'a, T> {
fn drop(&mut self) {
pin_conf(&self.pin).modify(|_, w| w.sense().disabled());
PORT_SIGNALS[pin_num(&self.pin)].reset();
}
}
impl<'a, T> Future for PortInputFuture<'a, T> {
type Output = ();
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
pin_conf(&self.pin).modify(|_, w| match self.polarity {
PortInputPolarity::Low => w.sense().low(),
PortInputPolarity::High => w.sense().high(),
});
PORT_SIGNALS[pin_num(&self.pin)].poll_wait(cx)
}
}