nrf/gpiote: update input channel to new API

This commit is contained in:
Dario Nieuwenhuis 2021-03-27 03:50:18 +01:00
parent a338841797
commit 2bd9323f28
2 changed files with 122 additions and 87 deletions

View File

@ -11,31 +11,44 @@ use example_common::*;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::panic; use defmt::panic;
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::{Gpiote, InputChannel, InputChannelPolarity}; use embassy_nrf::gpio::{Input, Pull};
use embassy_nrf::interrupt; use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity};
use embassy_nrf::{interrupt, Peripherals};
#[task] #[task]
async fn run() { async fn run() {
let p = unwrap!(embassy_nrf::pac::Peripherals::take()); let p = Peripherals::take().unwrap();
let port0 = gpio::p0::Parts::new(p.P0); let g = gpiote::initialize(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 ch1 = InputChannel::new(
let pin2 = port0.p0_12.into_pullup_input().degrade(); g,
let pin3 = port0.p0_24.into_pullup_input().degrade(); p.GPIOTE_CH0,
let pin4 = port0.p0_25.into_pullup_input().degrade(); Input::new(p.P0_11, Pull::Up),
InputChannelPolarity::HiToLo,
let ch1 = InputChannel::new(g, chs.ch0, pin1, InputChannelPolarity::HiToLo); );
let ch2 = InputChannel::new(g, chs.ch1, pin2, InputChannelPolarity::LoToHi); let ch2 = InputChannel::new(
let ch3 = InputChannel::new(g, chs.ch2, pin3, InputChannelPolarity::Toggle); g,
let ch4 = InputChannel::new(g, chs.ch3, pin4, InputChannelPolarity::Toggle); p.GPIOTE_CH1,
Input::new(p.P0_12, Pull::Up),
InputChannelPolarity::LoToHi,
);
let ch3 = InputChannel::new(
g,
p.GPIOTE_CH2,
Input::new(p.P0_24, Pull::Up),
InputChannelPolarity::Toggle,
);
let ch4 = InputChannel::new(
g,
p.GPIOTE_CH3,
Input::new(p.P0_25, Pull::Up),
InputChannelPolarity::Toggle,
);
let button1 = async { let button1 = async {
loop { loop {

View File

@ -10,10 +10,12 @@ use core::task::{Context, Poll};
use embassy::interrupt::InterruptExt; use embassy::interrupt::InterruptExt;
use embassy::traits::gpio::{WaitForHigh, WaitForLow}; use embassy::traits::gpio::{WaitForHigh, WaitForLow};
use embassy::util::{AtomicWaker, PeripheralBorrow, Signal}; use embassy::util::{AtomicWaker, PeripheralBorrow, Signal};
use embassy_extras::impl_unborrow;
use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin};
use futures::future::poll_fn;
use crate::gpio::sealed::Pin as _; use crate::gpio::sealed::Pin as _;
use crate::gpio::{AnyPin, Input, Pin as GpioPin, Pull}; use crate::gpio::{AnyPin, Input, Pin as GpioPin, Port, Pull};
use crate::pac; 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;
@ -30,44 +32,6 @@ 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 trait ChannelID {
fn number(&self) -> usize;
}
macro_rules! impl_channel {
($ChX:ident, $n:expr) => {
pub struct $ChX(());
impl $ChX {
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
}
}
const NEW_AWR: AtomicWaker = AtomicWaker::new(); const NEW_AWR: AtomicWaker = AtomicWaker::new();
static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AWR; CHANNEL_COUNT]; static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AWR; CHANNEL_COUNT];
static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AWR; PIN_COUNT]; static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AWR; PIN_COUNT];
@ -123,7 +87,7 @@ unsafe fn on_irq(_ctx: *mut ()) {
for i in 0..CHANNEL_COUNT { for i in 0..CHANNEL_COUNT {
if g.events_in[i].read().bits() != 0 { if g.events_in[i].read().bits() != 0 {
g.events_in[i].write(|w| w); g.intenclr.write(|w| unsafe { w.bits(1 << i) });
CHANNEL_WAKERS[i].wake(); CHANNEL_WAKERS[i].wake();
} }
} }
@ -163,32 +127,31 @@ impl Iterator for BitIter {
} }
} }
/* pub struct InputChannel<'d, C: Channel, T: GpioPin> {
pub struct InputChannel<C: ChannelID, T> {
ch: C, ch: C,
pin: GpioPin<Input<T>>, pin: Input<'d, T>,
} }
impl<C: ChannelID, T> Drop for InputChannel<C, T> { impl<'d, C: Channel, T: GpioPin> Drop for InputChannel<'d, C, T> {
fn drop(&mut self) { fn drop(&mut self) {
let g = unsafe { &*GPIOTE::ptr() }; let g = unsafe { &*pac::GPIOTE::ptr() };
let index = self.ch.number(); let num = self.ch.number() as usize;
g.config[index].write(|w| w.mode().disabled()); g.config[num].write(|w| w.mode().disabled());
g.intenclr.write(|w| unsafe { w.bits(1 << index) }); g.intenclr.write(|w| unsafe { w.bits(1 << num) });
} }
} }
impl<C: ChannelID, T> InputChannel<C, T> { impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> {
pub fn new( pub fn new(
_init: Initialized, _init: Initialized,
ch: C, ch: C,
pin: GpioPin<Input<T>>, pin: Input<'d, T>,
polarity: InputChannelPolarity, polarity: InputChannelPolarity,
) -> Self { ) -> Self {
let g = unsafe { &*GPIOTE::ptr() }; let g = unsafe { &*pac::GPIOTE::ptr() };
let index = ch.number(); let num = ch.number() as usize;
g.config[index].write(|w| { g.config[num].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(),
@ -196,38 +159,52 @@ impl<C: ChannelID, T> InputChannel<C, T> {
InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(), InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(),
}; };
#[cfg(any(feature = "52833", feature = "52840"))] #[cfg(any(feature = "52833", feature = "52840"))]
w.port().bit(match pin.port() { w.port().bit(match pin.pin.port() {
Port::Port0 => false, Port::Port0 => false,
Port::Port1 => true, Port::Port1 => true,
}); });
unsafe { w.psel().bits(pin.pin()) } unsafe { w.psel().bits(pin.pin.pin()) }
}); });
CHANNEL_WAKERS[index].reset(); g.events_in[num].reset();
// Enable interrupt
g.intenset.write(|w| unsafe { w.bits(1 << index) });
InputChannel { ch, pin } InputChannel { ch, pin }
} }
pub fn free(self) -> (C, GpioPin<Input<T>>) {
let m = ManuallyDrop::new(self);
let ch = unsafe { ptr::read(&m.ch) };
let pin = unsafe { ptr::read(&m.pin) };
(ch, pin)
}
pub async fn wait(&self) { pub async fn wait(&self) {
let index = self.ch.number(); let g = unsafe { &*pac::GPIOTE::ptr() };
CHANNEL_WAKERS[index].wait().await; let num = self.ch.number() as usize;
}
pub fn pin(&self) -> &GpioPin<Input<T>> { // Enable interrupt
&self.pin g.events_in[num].reset();
g.intenset.write(|w| unsafe { w.bits(1 << num) });
poll_fn(|cx| {
CHANNEL_WAKERS[num].register(cx.waker());
if g.events_in[num].read().bits() != 0 {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
} }
} }
impl<'d, C: Channel, T: GpioPin> InputPin for InputChannel<'d, C, T> {
type Error = Infallible;
fn is_high(&self) -> Result<bool, Self::Error> {
self.pin.is_high()
}
fn is_low(&self) -> Result<bool, Self::Error> {
self.pin.is_low()
}
}
/*
pub struct OutputChannel<C: ChannelID, T> { pub struct OutputChannel<C: ChannelID, T> {
ch: C, ch: C,
pin: GpioPin<Output<T>>, pin: GpioPin<Output<T>>,
@ -414,3 +391,48 @@ impl<'a> Future for PortInputFuture<'a> {
} }
} }
} }
mod sealed {
pub trait Channel {
fn number(&self) -> u8;
}
}
pub trait Channel: sealed::Channel + Sized {
fn degrade(self) -> AnyChannel {
AnyChannel {
number: self.number(),
}
}
}
pub struct AnyChannel {
number: u8,
}
impl_unborrow!(AnyChannel);
impl Channel for AnyChannel {}
impl sealed::Channel for AnyChannel {
fn number(&self) -> u8 {
self.number
}
}
macro_rules! impl_channel {
($type:ident, $number:expr) => {
impl sealed::Channel for peripherals::$type {
fn number(&self) -> u8 {
$number
}
}
impl Channel for peripherals::$type {}
};
}
impl_channel!(GPIOTE_CH0, 0);
impl_channel!(GPIOTE_CH1, 1);
impl_channel!(GPIOTE_CH2, 2);
impl_channel!(GPIOTE_CH3, 3);
impl_channel!(GPIOTE_CH4, 4);
impl_channel!(GPIOTE_CH5, 5);
impl_channel!(GPIOTE_CH6, 6);
impl_channel!(GPIOTE_CH7, 7);