nrf: add PPI channel group driver.

This commit is contained in:
Dario Nieuwenhuis 2023-03-04 05:24:38 +01:00
parent 78d733fc73
commit 4314b823aa
3 changed files with 98 additions and 10 deletions

View File

@ -6,7 +6,7 @@ use crate::{pac, Peripheral};
const DPPI_ENABLE_BIT: u32 = 0x8000_0000; const DPPI_ENABLE_BIT: u32 = 0x8000_0000;
const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF; 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() } unsafe { &*pac::DPPIC::ptr() }
} }

View File

@ -17,16 +17,16 @@
use core::ptr::NonNull; use core::ptr::NonNull;
use embassy_hal_common::{impl_peripheral, PeripheralRef}; use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
use crate::{peripherals, Peripheral}; use crate::{peripherals, Peripheral};
#[cfg(feature = "_dppi")] #[cfg_attr(feature = "_dppi", path = "dppi.rs")]
mod dppi; #[cfg_attr(feature = "_ppi", path = "ppi.rs")]
#[cfg(feature = "_ppi")] mod _version;
mod ppi; 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> { pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> {
ch: PeripheralRef<'d, C>, ch: PeripheralRef<'d, C>,
#[cfg(feature = "_dppi")] #[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], 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<P = G> + '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<C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize>(
&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<C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize>(
&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(&regs().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(&regs().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")] #[cfg(feature = "_dppi")]
const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>(); const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>();
@ -112,7 +194,7 @@ pub(crate) mod sealed {
} }
/// Interface for PPI channels. /// Interface for PPI channels.
pub trait Channel: sealed::Channel + Peripheral<P = Self> + Sized { pub trait Channel: sealed::Channel + Peripheral<P = Self> + Sized + 'static {
/// Returns the number of the channel /// Returns the number of the channel
fn number(&self) -> usize; fn number(&self) -> usize;
} }
@ -130,7 +212,7 @@ pub trait StaticChannel: Channel + Into<AnyStaticChannel> {
} }
/// Interface for a group of PPI channels. /// Interface for a group of PPI channels.
pub trait Group: sealed::Group + Sized { pub trait Group: sealed::Group + Peripheral<P = Self> + Into<AnyGroup> + Sized + 'static {
/// Returns the number of the group. /// Returns the number of the group.
fn number(&self) -> usize; fn number(&self) -> usize;
/// Convert into a type erased group. /// Convert into a type erased group.
@ -248,6 +330,12 @@ macro_rules! impl_group {
$number $number
} }
} }
impl From<peripherals::$type> for crate::ppi::AnyGroup {
fn from(val: peripherals::$type) -> Self {
crate::ppi::Group::degrade(val)
}
}
}; };
} }

View File

@ -14,7 +14,7 @@ impl Event {
} }
} }
fn regs() -> &'static pac::ppi::RegisterBlock { pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock {
unsafe { &*pac::PPI::ptr() } unsafe { &*pac::PPI::ptr() }
} }