nrf/gpiote: new api: switch to owned structs, implement WaitForHigh/WaitForLow.
This commit is contained in:
parent
1879703153
commit
a7797a918d
@ -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")
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user