nrf: add PPI channel group driver.
This commit is contained in:
parent
78d733fc73
commit
4314b823aa
3 changed files with 98 additions and 10 deletions
|
@ -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() }
|
||||
}
|
||||
|
||||
|
|
|
@ -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<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(®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::<u32>();
|
||||
|
||||
|
@ -112,7 +194,7 @@ pub(crate) mod sealed {
|
|||
}
|
||||
|
||||
/// 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
|
||||
fn number(&self) -> usize;
|
||||
}
|
||||
|
@ -130,7 +212,7 @@ pub trait StaticChannel: Channel + Into<AnyStaticChannel> {
|
|||
}
|
||||
|
||||
/// 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.
|
||||
fn number(&self) -> usize;
|
||||
/// Convert into a type erased group.
|
||||
|
@ -248,6 +330,12 @@ macro_rules! impl_group {
|
|||
$number
|
||||
}
|
||||
}
|
||||
|
||||
impl From<peripherals::$type> for crate::ppi::AnyGroup {
|
||||
fn from(val: peripherals::$type) -> Self {
|
||||
crate::ppi::Group::degrade(val)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ impl Event {
|
|||
}
|
||||
}
|
||||
|
||||
fn regs() -> &'static pac::ppi::RegisterBlock {
|
||||
pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock {
|
||||
unsafe { &*pac::PPI::ptr() }
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue