aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf/src
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-03-27 16:13:32 +0100
committerDario Nieuwenhuis <[email protected]>2021-03-29 00:58:58 +0200
commitb6496a85d89beb0f9bc4d3db2f39d82e8768e5da (patch)
treeebe3f634cd636dce23888397408eed5910e69db6 /embassy-nrf/src
parent26705ec32862a00e79cf334019aa3fbd4596bf17 (diff)
nrf/ppi: implement and add example
Diffstat (limited to 'embassy-nrf/src')
-rw-r--r--embassy-nrf/src/gpiote.rs44
-rw-r--r--embassy-nrf/src/ppi.rs97
2 files changed, 119 insertions, 22 deletions
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index c321c0fd9..412eef1b5 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -7,19 +7,15 @@ use embassy::interrupt::InterruptExt;
7use embassy::traits::gpio::{WaitForHigh, WaitForLow}; 7use embassy::traits::gpio::{WaitForHigh, WaitForLow};
8use embassy::util::AtomicWaker; 8use embassy::util::AtomicWaker;
9use embassy_extras::impl_unborrow; 9use embassy_extras::impl_unborrow;
10use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; 10use embedded_hal::digital::v2::{InputPin, StatefulOutputPin};
11use futures::future::poll_fn; 11use futures::future::poll_fn;
12 12
13use crate::gpio::sealed::Pin as _; 13use crate::gpio::sealed::Pin as _;
14use crate::gpio::{AnyPin, Input, Output, Pin as GpioPin, Port, Pull}; 14use crate::gpio::{AnyPin, Input, Output, Pin as GpioPin, Port};
15use crate::pac; 15use crate::pac;
16use crate::pac::generic::Reg; 16use crate::ppi::{Event, Task};
17use crate::pac::gpiote::_TASKS_OUT;
18use crate::{interrupt, peripherals}; 17use crate::{interrupt, peripherals};
19 18
20#[cfg(not(feature = "51"))]
21use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET};
22
23pub const CHANNEL_COUNT: usize = 8; 19pub const CHANNEL_COUNT: usize = 8;
24 20
25#[cfg(any(feature = "52833", feature = "52840"))] 21#[cfg(any(feature = "52833", feature = "52840"))]
@@ -53,7 +49,7 @@ pub struct Initialized {
53 _private: (), 49 _private: (),
54} 50}
55 51
56pub fn initialize(gpiote: peripherals::GPIOTE, irq: interrupt::GPIOTE) -> Initialized { 52pub fn initialize(_gpiote: peripherals::GPIOTE, irq: interrupt::GPIOTE) -> Initialized {
57 #[cfg(any(feature = "52833", feature = "52840"))] 53 #[cfg(any(feature = "52833", feature = "52840"))]
58 let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; 54 let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] };
59 #[cfg(not(any(feature = "52833", feature = "52840")))] 55 #[cfg(not(any(feature = "52833", feature = "52840")))]
@@ -122,6 +118,7 @@ impl Iterator for BitIter {
122 } 118 }
123} 119}
124 120
121/// GPIOTE channel driver in input mode
125pub struct InputChannel<'d, C: Channel, T: GpioPin> { 122pub struct InputChannel<'d, C: Channel, T: GpioPin> {
126 ch: C, 123 ch: C,
127 pin: Input<'d, T>, 124 pin: Input<'d, T>,
@@ -185,6 +182,12 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> {
185 }) 182 })
186 .await; 183 .await;
187 } 184 }
185
186 /// Returns the IN event, for use with PPI.
187 pub fn event_in(&self) -> Event {
188 let g = unsafe { &*pac::GPIOTE::ptr() };
189 Event::from_reg(&g.events_in[self.ch.number()])
190 }
188} 191}
189 192
190impl<'d, C: Channel, T: GpioPin> InputPin for InputChannel<'d, C, T> { 193impl<'d, C: Channel, T: GpioPin> InputPin for InputChannel<'d, C, T> {
@@ -199,9 +202,10 @@ impl<'d, C: Channel, T: GpioPin> InputPin for InputChannel<'d, C, T> {
199 } 202 }
200} 203}
201 204
205/// GPIOTE channel driver in output mode
202pub struct OutputChannel<'d, C: Channel, T: GpioPin> { 206pub struct OutputChannel<'d, C: Channel, T: GpioPin> {
203 ch: C, 207 ch: C,
204 pin: Output<'d, T>, 208 _pin: Output<'d, T>,
205} 209}
206 210
207impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> { 211impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> {
@@ -242,7 +246,7 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> {
242 unsafe { w.psel().bits(pin.pin.pin()) } 246 unsafe { w.psel().bits(pin.pin.pin()) }
243 }); 247 });
244 248
245 OutputChannel { ch, pin } 249 OutputChannel { ch, _pin: pin }
246 } 250 }
247 251
248 /// Triggers `task out` (as configured with task_out_polarity, defaults to Toggle). 252 /// Triggers `task out` (as configured with task_out_polarity, defaults to Toggle).
@@ -265,28 +269,28 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> {
265 g.tasks_clr[self.ch.number()].write(|w| unsafe { w.bits(1) }); 269 g.tasks_clr[self.ch.number()].write(|w| unsafe { w.bits(1) });
266 } 270 }
267 271
268 /// Returns reference to task_out endpoint for PPI. 272 /// Returns the OUT task, for use with PPI.
269 pub fn task_out(&self) -> &Reg<u32, _TASKS_OUT> { 273 pub fn task_out(&self) -> Task {
270 let g = unsafe { &*pac::GPIOTE::ptr() }; 274 let g = unsafe { &*pac::GPIOTE::ptr() };
271 &g.tasks_out[self.ch.number()] 275 Task::from_reg(&g.tasks_out[self.ch.number()])
272 } 276 }
273 277
274 /// Returns reference to task_clr endpoint for PPI. 278 /// Returns the CLR task, for use with PPI.
275 #[cfg(not(feature = "51"))] 279 #[cfg(not(feature = "51"))]
276 pub fn task_clr(&self) -> &Reg<u32, _TASKS_CLR> { 280 pub fn task_clr(&self) -> Task {
277 let g = unsafe { &*pac::GPIOTE::ptr() }; 281 let g = unsafe { &*pac::GPIOTE::ptr() };
278 &g.tasks_clr[self.ch.number()] 282 Task::from_reg(&g.tasks_clr[self.ch.number()])
279 } 283 }
280 284
281 /// Returns reference to task_set endpoint for PPI. 285 /// Returns the SET task, for use with PPI.
282 #[cfg(not(feature = "51"))] 286 #[cfg(not(feature = "51"))]
283 pub fn task_set(&self) -> &Reg<u32, _TASKS_SET> { 287 pub fn task_set(&self) -> Task {
284 let g = unsafe { &*pac::GPIOTE::ptr() }; 288 let g = unsafe { &*pac::GPIOTE::ptr() };
285 &g.tasks_set[self.ch.number()] 289 Task::from_reg(&g.tasks_set[self.ch.number()])
286 } 290 }
287} 291}
288 292
289/// GPIO input driver with support 293/// GPIOTE port input driver
290pub struct PortInput<'d, T: GpioPin> { 294pub struct PortInput<'d, T: GpioPin> {
291 pin: Input<'d, T>, 295 pin: Input<'d, T>,
292} 296}
diff --git a/embassy-nrf/src/ppi.rs b/embassy-nrf/src/ppi.rs
index c06b212c1..0129a2a47 100644
--- a/embassy-nrf/src/ppi.rs
+++ b/embassy-nrf/src/ppi.rs
@@ -9,13 +9,106 @@
9//! On nRF52 devices, there is also a fork task endpoint, where the user can configure one more task 9//! On nRF52 devices, there is also a fork task endpoint, where the user can configure one more task
10//! to be triggered by the same event, even fixed PPI channels have a configurable fork task. 10//! to be triggered by the same event, even fixed PPI channels have a configurable fork task.
11 11
12use embassy_extras::impl_unborrow; 12use core::marker::PhantomData;
13use core::ptr::NonNull;
14use embassy::util::PeripheralBorrow;
15use embassy_extras::{impl_unborrow, unborrow};
13 16
14use crate::peripherals; 17use crate::{pac, peripherals};
18
19// ======================
20// driver
21
22pub struct Ppi<'d, C: Channel> {
23 ch: C,
24 phantom: PhantomData<&'d mut C>,
25}
26
27impl<'d, C: Channel> Ppi<'d, C> {
28 pub fn new(ch: impl PeripheralBorrow<Target = C> + 'd) -> Self {
29 unborrow!(ch);
30 let mut this = Self {
31 ch,
32 phantom: PhantomData,
33 };
34 #[cfg(not(feature = "51"))]
35 this.clear_fork_task();
36 this
37 }
38
39 /// Enables the channel.
40 pub fn enable(&mut self) {
41 let r = unsafe { &*pac::PPI::ptr() };
42 r.chenset
43 .write(|w| unsafe { w.bits(1 << self.ch.number()) });
44 }
45
46 /// Disables the channel.
47 pub fn disable(&mut self) {
48 let r = unsafe { &*pac::PPI::ptr() };
49 r.chenclr
50 .write(|w| unsafe { w.bits(1 << self.ch.number()) });
51 }
52
53 #[cfg(not(feature = "51"))]
54 /// Sets the fork task that must be triggered when the configured event occurs. The user must
55 /// provide a reference to the task.
56 pub fn set_fork_task(&mut self, task: Task) {
57 let r = unsafe { &*pac::PPI::ptr() };
58 r.fork[self.ch.number()]
59 .tep
60 .write(|w| unsafe { w.bits(task.0.as_ptr() as u32) })
61 }
62
63 #[cfg(not(feature = "51"))]
64 /// Clear the fork task endpoint. Previously set task will no longer be triggered.
65 pub fn clear_fork_task(&mut self) {
66 let r = unsafe { &*pac::PPI::ptr() };
67 r.fork[self.ch.number()].tep.write(|w| unsafe { w.bits(0) })
68 }
69}
70
71impl<'d, C: Channel> Drop for Ppi<'d, C> {
72 fn drop(&mut self) {
73 self.disable()
74 }
75}
76
77impl<'d, C: ConfigurableChannel> Ppi<'d, C> {
78 /// Sets the task to be triggered when the configured event occurs.
79 pub fn set_task(&mut self, task: Task) {
80 let r = unsafe { &*pac::PPI::ptr() };
81 r.ch[self.ch.number()]
82 .tep
83 .write(|w| unsafe { w.bits(task.0.as_ptr() as u32) })
84 }
85
86 /// Sets the event that will trigger the chosen task(s).
87 pub fn set_event(&mut self, event: Event) {
88 let r = unsafe { &*pac::PPI::ptr() };
89 r.ch[self.ch.number()]
90 .eep
91 .write(|w| unsafe { w.bits(event.0.as_ptr() as u32) })
92 }
93}
15 94
16// ====================== 95// ======================
17// traits 96// traits
18 97
98pub struct Task(pub NonNull<()>);
99impl Task {
100 pub(crate) fn from_reg<T>(reg: &T) -> Self {
101 Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut ()) })
102 }
103}
104
105pub struct Event(pub NonNull<()>);
106impl Event {
107 pub(crate) fn from_reg<T>(reg: &T) -> Self {
108 Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut ()) })
109 }
110}
111
19mod sealed { 112mod sealed {
20 pub trait ConfigurableChannel {} 113 pub trait ConfigurableChannel {}
21 pub trait Channel {} 114 pub trait Channel {}