aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/gpiote.rs136
-rw-r--r--embassy-nrf/src/lib.rs2
-rw-r--r--examples/src/bin/gpiote.rs84
3 files changed, 222 insertions, 0 deletions
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
new file mode 100644
index 000000000..e6479b5e8
--- /dev/null
+++ b/embassy-nrf/src/gpiote.rs
@@ -0,0 +1,136 @@
1use core::cell::Cell;
2use core::pin::Pin;
3use core::ptr;
4use defmt::trace;
5use embassy::util::Signal;
6use nrf52840_hal::gpio::{Floating, Input, Pin as GpioPin, Port};
7
8use crate::interrupt;
9use crate::pac::GPIOTE;
10
11pub struct Gpiote {
12 inner: GPIOTE,
13 free_channels: Cell<u8>, // 0 = used, 1 = free. 8 bits for 8 channelself.
14 signals: [Signal<()>; 8],
15}
16
17static mut INSTANCE: *const Gpiote = ptr::null_mut();
18
19pub enum EventPolarity {
20 None,
21 HiToLo,
22 LoToHi,
23 Toggle,
24}
25
26#[derive(defmt::Format)]
27pub enum NewChannelError {
28 NoFreeChannels,
29}
30
31impl Gpiote {
32 pub fn new(gpiote: GPIOTE) -> Self {
33 let signal: Signal<()> = Signal::new();
34
35 interrupt::unpend(interrupt::GPIOTE);
36 interrupt::enable(interrupt::GPIOTE);
37
38 Self {
39 inner: gpiote,
40 free_channels: Cell::new(0xFF), // all 8 channels free
41 signals: [
42 Signal::new(),
43 Signal::new(),
44 Signal::new(),
45 Signal::new(),
46 Signal::new(),
47 Signal::new(),
48 Signal::new(),
49 Signal::new(),
50 ],
51 }
52 }
53
54 pub fn new_input_channel<T>(
55 &self,
56 pin: GpioPin<Input<T>>,
57 trigger_mode: EventPolarity,
58 ) -> Result<Channel<'_>, NewChannelError> {
59 interrupt::free(|_| {
60 unsafe { INSTANCE = self };
61
62 let chs = self.free_channels.get();
63 let index = chs.trailing_zeros() as usize;
64 if index == 8 {
65 return Err(NewChannelError::NoFreeChannels);
66 }
67 self.free_channels.set(chs & !(1 << index));
68
69 trace!("allocated ch {:u8}", index as u8);
70
71 self.inner.config[index].write(|w| {
72 match trigger_mode {
73 EventPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(),
74 EventPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(),
75 EventPolarity::None => w.mode().event().polarity().none(),
76 EventPolarity::Toggle => w.mode().event().polarity().toggle(),
77 };
78 w.port().bit(match pin.port() {
79 Port::Port0 => false,
80 Port::Port1 => true,
81 });
82 unsafe { w.psel().bits(pin.pin()) }
83 });
84
85 // Enable interrupt
86 self.inner.intenset.write(|w| unsafe { w.bits(1 << index) });
87
88 Ok(Channel {
89 gpiote: self,
90 index: index as u8,
91 })
92 })
93 }
94}
95
96pub struct Channel<'a> {
97 gpiote: &'a Gpiote,
98 index: u8,
99}
100
101impl<'a> Drop for Channel<'a> {
102 fn drop(&mut self) {
103 let g = unsafe { Pin::new_unchecked(self.gpiote) };
104
105 interrupt::free(|_| {
106 self.gpiote.inner.config[self.index as usize].write(|w| w.mode().disabled());
107 self.gpiote
108 .inner
109 .intenclr
110 .write(|w| unsafe { w.bits(1 << self.index) });
111
112 self.gpiote
113 .free_channels
114 .set(self.gpiote.free_channels.get() | 1 << self.index);
115 trace!("freed ch {:u8}", self.index);
116 })
117 }
118}
119
120impl<'a> Channel<'a> {
121 pub async fn wait(&self) -> () {
122 self.gpiote.signals[self.index as usize].wait().await;
123 }
124}
125
126#[interrupt]
127unsafe fn GPIOTE() {
128 let s = &(*INSTANCE);
129
130 for i in 0..8 {
131 if s.inner.events_in[i].read().bits() != 0 {
132 s.inner.events_in[i].write(|w| w);
133 s.signals[i].signal(());
134 }
135 }
136}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index f1ce0cbf9..edc2778b8 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -37,7 +37,9 @@ pub use nrf52833_pac as pac;
37#[cfg(feature = "nrf52840")] 37#[cfg(feature = "nrf52840")]
38pub use nrf52840_pac as pac; 38pub use nrf52840_pac as pac;
39 39
40pub mod gpiote;
40pub mod interrupt; 41pub mod interrupt;
41pub mod qspi; 42pub mod qspi;
42pub mod uarte; 43pub mod uarte;
44
43pub use cortex_m_rt::interrupt; 45pub use cortex_m_rt::interrupt;
diff --git a/examples/src/bin/gpiote.rs b/examples/src/bin/gpiote.rs
new file mode 100644
index 000000000..f55b0386d
--- /dev/null
+++ b/examples/src/bin/gpiote.rs
@@ -0,0 +1,84 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7use example_common::*;
8
9use core::pin::Pin;
10use cortex_m_rt::entry;
11use embassy::io::{AsyncBufRead, AsyncBufReadExt, AsyncWrite, AsyncWriteExt};
12use embassy_nrf::gpiote;
13use futures::pin_mut;
14use nrf52840_hal::gpio;
15
16#[static_executor::task]
17async fn run() {
18 let p = embassy_nrf::pac::Peripherals::take().dewrap();
19 let port0 = gpio::p0::Parts::new(p.P0);
20
21 let g = gpiote::Gpiote::new(p.GPIOTE);
22
23 info!("Starting!");
24
25 let pin1 = port0.p0_11.into_pullup_input().degrade();
26 let button1 = async {
27 let ch = g
28 .new_input_channel(pin1, gpiote::EventPolarity::HiToLo)
29 .dewrap();
30
31 loop {
32 ch.wait().await;
33 info!("Button 1 pressed")
34 }
35 };
36
37 let pin2 = port0.p0_12.into_pullup_input().degrade();
38 let button2 = async {
39 let ch = g
40 .new_input_channel(pin2, gpiote::EventPolarity::LoToHi)
41 .dewrap();
42
43 loop {
44 ch.wait().await;
45 info!("Button 2 released")
46 }
47 };
48
49 let pin3 = port0.p0_24.into_pullup_input().degrade();
50 let button3 = async {
51 let ch = g
52 .new_input_channel(pin3, gpiote::EventPolarity::Toggle)
53 .dewrap();
54
55 loop {
56 ch.wait().await;
57 info!("Button 3 toggled")
58 }
59 };
60
61 let pin4 = port0.p0_25.into_pullup_input().degrade();
62 let button4 = async {
63 let ch = g
64 .new_input_channel(pin4, gpiote::EventPolarity::Toggle)
65 .dewrap();
66
67 loop {
68 ch.wait().await;
69 info!("Button 4 toggled")
70 }
71 };
72
73 futures::join!(button1, button2, button3, button4);
74}
75
76#[entry]
77fn main() -> ! {
78 info!("Hello World!");
79
80 unsafe {
81 run.spawn().dewrap();
82 static_executor::run();
83 }
84}