diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs
index 0908cd7b..3a1e7f17 100644
--- a/embassy-nrf/src/ppi/dppi.rs
+++ b/embassy-nrf/src/ppi/dppi.rs
@@ -6,7 +6,7 @@ use crate::{pac, Peripheral};
const DPPI_ENABLE_BIT: u32 = 0x8000_0000;
const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF;
-fn regs() -> &'static pac::dppic::RegisterBlock {
+pub(crate) fn regs() -> &'static pac::dppic::RegisterBlock {
unsafe { &*pac::DPPIC::ptr() }
}
diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs
index b76eccf0..7c18da6e 100644
--- a/embassy-nrf/src/ppi/mod.rs
+++ b/embassy-nrf/src/ppi/mod.rs
@@ -17,16 +17,16 @@
use core::ptr::NonNull;
-use embassy_hal_common::{impl_peripheral, PeripheralRef};
+use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
use crate::{peripherals, Peripheral};
-#[cfg(feature = "_dppi")]
-mod dppi;
-#[cfg(feature = "_ppi")]
-mod ppi;
+#[cfg_attr(feature = "_dppi", path = "dppi.rs")]
+#[cfg_attr(feature = "_ppi", path = "ppi.rs")]
+mod _version;
+pub(crate) use _version::*;
-/// An instance of the Programmable peripheral interconnect on nRF devices.
+/// PPI channel driver.
pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> {
ch: PeripheralRef<'d, C>,
#[cfg(feature = "_dppi")]
@@ -35,6 +35,88 @@ pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize
tasks: [Task; TASK_COUNT],
}
+/// PPI channel group driver.
+pub struct PpiGroup<'d, G: Group> {
+ g: PeripheralRef<'d, G>,
+}
+
+impl<'d, G: Group> PpiGroup<'d, G> {
+ /// Create a new PPI group driver.
+ ///
+ /// The group is initialized as containing no channels.
+ pub fn new(g: impl Peripheral
+ 'd) -> Self {
+ into_ref!(g);
+
+ let r = regs();
+ let n = g.number();
+ r.chg[n].write(|w| unsafe { w.bits(0) });
+
+ Self { g }
+ }
+
+ /// Add a PPI channel to this group.
+ ///
+ /// If the channel is already in the group, this is a no-op.
+ pub fn add_channel(
+ &mut self,
+ ch: &Ppi<'_, C, EVENT_COUNT, TASK_COUNT>,
+ ) {
+ let r = regs();
+ let ng = self.g.number();
+ let nc = ch.ch.number();
+ r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() | 1 << nc) });
+ }
+
+ /// Remove a PPI channel from this group.
+ ///
+ /// If the channel is already not in the group, this is a no-op.
+ pub fn remove_channel(
+ &mut self,
+ ch: &Ppi<'_, C, EVENT_COUNT, TASK_COUNT>,
+ ) {
+ let r = regs();
+ let ng = self.g.number();
+ let nc = ch.ch.number();
+ r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() & !(1 << nc)) });
+ }
+
+ /// Enable all the channels in this group.
+ pub fn enable_all(&mut self) {
+ let n = self.g.number();
+ regs().tasks_chg[n].en.write(|w| unsafe { w.bits(1) });
+ }
+
+ /// Disable all the channels in this group.
+ pub fn disable_all(&mut self) {
+ let n = self.g.number();
+ regs().tasks_chg[n].dis.write(|w| unsafe { w.bits(1) });
+ }
+
+ /// Get a reference to the "enable all" task.
+ ///
+ /// When triggered, it will enable all the channels in this group.
+ pub fn task_enable_all(&self) -> Task {
+ let n = self.g.number();
+ Task::from_reg(®s().tasks_chg[n].en)
+ }
+
+ /// Get a reference to the "disable all" task.
+ ///
+ /// When triggered, it will disable all the channels in this group.
+ pub fn task_disable_all(&self) -> Task {
+ let n = self.g.number();
+ Task::from_reg(®s().tasks_chg[n].dis)
+ }
+}
+
+impl<'d, G: Group> Drop for PpiGroup<'d, G> {
+ fn drop(&mut self) {
+ let r = regs();
+ let n = self.g.number();
+ r.chg[n].write(|w| unsafe { w.bits(0) });
+ }
+}
+
#[cfg(feature = "_dppi")]
const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::();
@@ -112,7 +194,7 @@ pub(crate) mod sealed {
}
/// Interface for PPI channels.
-pub trait Channel: sealed::Channel + Peripheral + Sized {
+pub trait Channel: sealed::Channel + Peripheral
+ Sized + 'static {
/// Returns the number of the channel
fn number(&self) -> usize;
}
@@ -130,7 +212,7 @@ pub trait StaticChannel: Channel + Into {
}
/// Interface for a group of PPI channels.
-pub trait Group: sealed::Group + Sized {
+pub trait Group: sealed::Group + Peripheral + Into + Sized + 'static {
/// Returns the number of the group.
fn number(&self) -> usize;
/// Convert into a type erased group.
@@ -248,6 +330,12 @@ macro_rules! impl_group {
$number
}
}
+
+ impl From for crate::ppi::AnyGroup {
+ fn from(val: peripherals::$type) -> Self {
+ crate::ppi::Group::degrade(val)
+ }
+ }
};
}
diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs
index a96ab50b..f1eeaee1 100644
--- a/embassy-nrf/src/ppi/ppi.rs
+++ b/embassy-nrf/src/ppi/ppi.rs
@@ -14,7 +14,7 @@ impl Event {
}
}
-fn regs() -> &'static pac::ppi::RegisterBlock {
+pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock {
unsafe { &*pac::PPI::ptr() }
}