diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-03-27 16:13:32 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-03-29 00:58:58 +0200 |
| commit | b6496a85d89beb0f9bc4d3db2f39d82e8768e5da (patch) | |
| tree | ebe3f634cd636dce23888397408eed5910e69db6 /embassy-nrf/src | |
| parent | 26705ec32862a00e79cf334019aa3fbd4596bf17 (diff) | |
nrf/ppi: implement and add example
Diffstat (limited to 'embassy-nrf/src')
| -rw-r--r-- | embassy-nrf/src/gpiote.rs | 44 | ||||
| -rw-r--r-- | embassy-nrf/src/ppi.rs | 97 |
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; | |||
| 7 | use embassy::traits::gpio::{WaitForHigh, WaitForLow}; | 7 | use embassy::traits::gpio::{WaitForHigh, WaitForLow}; |
| 8 | use embassy::util::AtomicWaker; | 8 | use embassy::util::AtomicWaker; |
| 9 | use embassy_extras::impl_unborrow; | 9 | use embassy_extras::impl_unborrow; |
| 10 | use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; | 10 | use embedded_hal::digital::v2::{InputPin, StatefulOutputPin}; |
| 11 | use futures::future::poll_fn; | 11 | use futures::future::poll_fn; |
| 12 | 12 | ||
| 13 | use crate::gpio::sealed::Pin as _; | 13 | use crate::gpio::sealed::Pin as _; |
| 14 | use crate::gpio::{AnyPin, Input, Output, Pin as GpioPin, Port, Pull}; | 14 | use crate::gpio::{AnyPin, Input, Output, Pin as GpioPin, Port}; |
| 15 | use crate::pac; | 15 | use crate::pac; |
| 16 | use crate::pac::generic::Reg; | 16 | use crate::ppi::{Event, Task}; |
| 17 | use crate::pac::gpiote::_TASKS_OUT; | ||
| 18 | use crate::{interrupt, peripherals}; | 17 | use crate::{interrupt, peripherals}; |
| 19 | 18 | ||
| 20 | #[cfg(not(feature = "51"))] | ||
| 21 | use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET}; | ||
| 22 | |||
| 23 | pub const CHANNEL_COUNT: usize = 8; | 19 | pub 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 | ||
| 56 | pub fn initialize(gpiote: peripherals::GPIOTE, irq: interrupt::GPIOTE) -> Initialized { | 52 | pub 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 | ||
| 125 | pub struct InputChannel<'d, C: Channel, T: GpioPin> { | 122 | pub 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 | ||
| 190 | impl<'d, C: Channel, T: GpioPin> InputPin for InputChannel<'d, C, T> { | 193 | impl<'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 | ||
| 202 | pub struct OutputChannel<'d, C: Channel, T: GpioPin> { | 206 | pub 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 | ||
| 207 | impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> { | 211 | impl<'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 |
| 290 | pub struct PortInput<'d, T: GpioPin> { | 294 | pub 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 | ||
| 12 | use embassy_extras::impl_unborrow; | 12 | use core::marker::PhantomData; |
| 13 | use core::ptr::NonNull; | ||
| 14 | use embassy::util::PeripheralBorrow; | ||
| 15 | use embassy_extras::{impl_unborrow, unborrow}; | ||
| 13 | 16 | ||
| 14 | use crate::peripherals; | 17 | use crate::{pac, peripherals}; |
| 18 | |||
| 19 | // ====================== | ||
| 20 | // driver | ||
| 21 | |||
| 22 | pub struct Ppi<'d, C: Channel> { | ||
| 23 | ch: C, | ||
| 24 | phantom: PhantomData<&'d mut C>, | ||
| 25 | } | ||
| 26 | |||
| 27 | impl<'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 | |||
| 71 | impl<'d, C: Channel> Drop for Ppi<'d, C> { | ||
| 72 | fn drop(&mut self) { | ||
| 73 | self.disable() | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | impl<'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 | ||
| 98 | pub struct Task(pub NonNull<()>); | ||
| 99 | impl 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 | |||
| 105 | pub struct Event(pub NonNull<()>); | ||
| 106 | impl 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 | |||
| 19 | mod sealed { | 112 | mod sealed { |
| 20 | pub trait ConfigurableChannel {} | 113 | pub trait ConfigurableChannel {} |
| 21 | pub trait Channel {} | 114 | pub trait Channel {} |
