2021-10-11 01:19:06 +02:00
|
|
|
#![macro_use]
|
|
|
|
|
2021-03-27 04:40:05 +01:00
|
|
|
//! HAL interface for the PPI peripheral.
|
|
|
|
//!
|
|
|
|
//! The Programmable Peripheral Interconnect interface allows for an autonomous interoperability
|
|
|
|
//! between peripherals through their events and tasks. There are fixed PPI channels and fully
|
|
|
|
//! configurable ones, fixed channels can only connect specific events to specific tasks. For fully
|
|
|
|
//! configurable channels, it is possible to choose, via software, the event and the task that it
|
|
|
|
//! will triggered by the event.
|
|
|
|
//!
|
|
|
|
//! On nRF52 devices, there is also a fork task endpoint, where the user can configure one more task
|
|
|
|
//! to be triggered by the same event, even fixed PPI channels have a configurable fork task.
|
|
|
|
|
2021-03-27 16:13:32 +01:00
|
|
|
use core::marker::PhantomData;
|
|
|
|
use core::ptr::NonNull;
|
2021-04-14 19:59:52 +02:00
|
|
|
use embassy::util::Unborrow;
|
2021-07-29 13:44:51 +02:00
|
|
|
use embassy_hal_common::{unborrow, unsafe_impl_unborrow};
|
2021-03-27 04:40:05 +01:00
|
|
|
|
2021-03-27 16:13:32 +01:00
|
|
|
use crate::{pac, peripherals};
|
|
|
|
|
|
|
|
// ======================
|
|
|
|
// driver
|
|
|
|
|
|
|
|
pub struct Ppi<'d, C: Channel> {
|
|
|
|
ch: C,
|
|
|
|
phantom: PhantomData<&'d mut C>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'d, C: Channel> Ppi<'d, C> {
|
2021-04-14 19:59:52 +02:00
|
|
|
pub fn new(ch: impl Unborrow<Target = C> + 'd) -> Self {
|
2021-03-27 16:13:32 +01:00
|
|
|
unborrow!(ch);
|
|
|
|
let mut this = Self {
|
|
|
|
ch,
|
|
|
|
phantom: PhantomData,
|
|
|
|
};
|
2021-10-11 01:09:57 +02:00
|
|
|
#[cfg(not(feature = "nrf51"))]
|
2021-03-27 16:13:32 +01:00
|
|
|
this.clear_fork_task();
|
|
|
|
this
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Enables the channel.
|
|
|
|
pub fn enable(&mut self) {
|
|
|
|
let r = unsafe { &*pac::PPI::ptr() };
|
|
|
|
r.chenset
|
|
|
|
.write(|w| unsafe { w.bits(1 << self.ch.number()) });
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Disables the channel.
|
|
|
|
pub fn disable(&mut self) {
|
|
|
|
let r = unsafe { &*pac::PPI::ptr() };
|
|
|
|
r.chenclr
|
|
|
|
.write(|w| unsafe { w.bits(1 << self.ch.number()) });
|
|
|
|
}
|
|
|
|
|
2021-10-11 01:09:57 +02:00
|
|
|
#[cfg(not(feature = "nrf51"))]
|
2021-03-27 16:13:32 +01:00
|
|
|
/// Sets the fork task that must be triggered when the configured event occurs. The user must
|
|
|
|
/// provide a reference to the task.
|
|
|
|
pub fn set_fork_task(&mut self, task: Task) {
|
|
|
|
let r = unsafe { &*pac::PPI::ptr() };
|
|
|
|
r.fork[self.ch.number()]
|
|
|
|
.tep
|
|
|
|
.write(|w| unsafe { w.bits(task.0.as_ptr() as u32) })
|
|
|
|
}
|
|
|
|
|
2021-10-11 01:09:57 +02:00
|
|
|
#[cfg(not(feature = "nrf51"))]
|
2021-03-27 16:13:32 +01:00
|
|
|
/// Clear the fork task endpoint. Previously set task will no longer be triggered.
|
|
|
|
pub fn clear_fork_task(&mut self) {
|
|
|
|
let r = unsafe { &*pac::PPI::ptr() };
|
|
|
|
r.fork[self.ch.number()].tep.write(|w| unsafe { w.bits(0) })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'d, C: Channel> Drop for Ppi<'d, C> {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.disable()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'d, C: ConfigurableChannel> Ppi<'d, C> {
|
|
|
|
/// Sets the task to be triggered when the configured event occurs.
|
|
|
|
pub fn set_task(&mut self, task: Task) {
|
|
|
|
let r = unsafe { &*pac::PPI::ptr() };
|
|
|
|
r.ch[self.ch.number()]
|
|
|
|
.tep
|
|
|
|
.write(|w| unsafe { w.bits(task.0.as_ptr() as u32) })
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the event that will trigger the chosen task(s).
|
|
|
|
pub fn set_event(&mut self, event: Event) {
|
|
|
|
let r = unsafe { &*pac::PPI::ptr() };
|
|
|
|
r.ch[self.ch.number()]
|
|
|
|
.eep
|
|
|
|
.write(|w| unsafe { w.bits(event.0.as_ptr() as u32) })
|
|
|
|
}
|
|
|
|
}
|
2021-03-27 04:40:05 +01:00
|
|
|
|
|
|
|
// ======================
|
|
|
|
// traits
|
|
|
|
|
2021-03-27 16:13:32 +01:00
|
|
|
pub struct Task(pub NonNull<()>);
|
|
|
|
impl Task {
|
|
|
|
pub(crate) fn from_reg<T>(reg: &T) -> Self {
|
|
|
|
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut ()) })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Event(pub NonNull<()>);
|
|
|
|
impl Event {
|
|
|
|
pub(crate) fn from_reg<T>(reg: &T) -> Self {
|
|
|
|
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut ()) })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 01:19:06 +02:00
|
|
|
pub(crate) mod sealed {
|
2021-03-27 04:40:05 +01:00
|
|
|
pub trait ConfigurableChannel {}
|
|
|
|
pub trait Channel {}
|
|
|
|
pub trait Group {}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait Channel: sealed::Channel + Sized {
|
|
|
|
fn number(&self) -> usize;
|
|
|
|
fn degrade(self) -> AnyChannel {
|
|
|
|
AnyChannel {
|
|
|
|
number: self.number() as u8,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-03-28 22:41:07 +02:00
|
|
|
pub trait ConfigurableChannel: Channel + sealed::ConfigurableChannel {
|
|
|
|
fn degrade_configurable(self) -> AnyConfigurableChannel {
|
|
|
|
AnyConfigurableChannel {
|
|
|
|
number: self.number() as u8,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-03-27 04:40:05 +01:00
|
|
|
|
|
|
|
pub trait Group: sealed::Group + Sized {
|
|
|
|
fn number(&self) -> usize;
|
|
|
|
fn degrade(self) -> AnyGroup {
|
|
|
|
AnyGroup {
|
|
|
|
number: self.number() as u8,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ======================
|
|
|
|
// channels
|
|
|
|
|
|
|
|
pub struct AnyChannel {
|
|
|
|
number: u8,
|
|
|
|
}
|
2021-05-19 23:21:31 +02:00
|
|
|
unsafe_impl_unborrow!(AnyChannel);
|
2021-03-27 04:40:05 +01:00
|
|
|
impl sealed::Channel for AnyChannel {}
|
|
|
|
impl Channel for AnyChannel {
|
|
|
|
fn number(&self) -> usize {
|
|
|
|
self.number as usize
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-28 22:41:07 +02:00
|
|
|
pub struct AnyConfigurableChannel {
|
|
|
|
number: u8,
|
|
|
|
}
|
2021-05-19 23:21:31 +02:00
|
|
|
unsafe_impl_unborrow!(AnyConfigurableChannel);
|
2021-03-28 22:41:07 +02:00
|
|
|
impl sealed::Channel for AnyConfigurableChannel {}
|
|
|
|
impl sealed::ConfigurableChannel for AnyConfigurableChannel {}
|
|
|
|
impl ConfigurableChannel for AnyConfigurableChannel {}
|
|
|
|
impl Channel for AnyConfigurableChannel {
|
|
|
|
fn number(&self) -> usize {
|
|
|
|
self.number as usize
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 01:19:06 +02:00
|
|
|
macro_rules! impl_ppi_channel {
|
2021-03-27 04:40:05 +01:00
|
|
|
($type:ident, $number:expr, configurable) => {
|
2021-10-11 01:19:06 +02:00
|
|
|
impl_ppi_channel!($type, $number);
|
|
|
|
impl crate::ppi::sealed::ConfigurableChannel for peripherals::$type {}
|
|
|
|
impl crate::ppi::ConfigurableChannel for peripherals::$type {}
|
2021-03-27 04:40:05 +01:00
|
|
|
};
|
|
|
|
($type:ident, $number:expr) => {
|
2021-10-11 01:19:06 +02:00
|
|
|
impl crate::ppi::sealed::Channel for peripherals::$type {}
|
|
|
|
impl crate::ppi::Channel for peripherals::$type {
|
2021-03-27 04:40:05 +01:00
|
|
|
fn number(&self) -> usize {
|
|
|
|
$number
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// ======================
|
|
|
|
// groups
|
|
|
|
|
|
|
|
pub struct AnyGroup {
|
|
|
|
number: u8,
|
|
|
|
}
|
2021-05-19 23:21:31 +02:00
|
|
|
unsafe_impl_unborrow!(AnyGroup);
|
2021-03-27 04:40:05 +01:00
|
|
|
impl sealed::Group for AnyGroup {}
|
|
|
|
impl Group for AnyGroup {
|
|
|
|
fn number(&self) -> usize {
|
|
|
|
self.number as usize
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! impl_group {
|
|
|
|
($type:ident, $number:expr) => {
|
|
|
|
impl sealed::Group for peripherals::$type {}
|
|
|
|
impl Group for peripherals::$type {
|
|
|
|
fn number(&self) -> usize {
|
|
|
|
$number
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_group!(PPI_GROUP0, 0);
|
|
|
|
impl_group!(PPI_GROUP1, 1);
|
|
|
|
impl_group!(PPI_GROUP2, 2);
|
|
|
|
impl_group!(PPI_GROUP3, 3);
|
2021-10-11 01:09:57 +02:00
|
|
|
#[cfg(not(feature = "nrf51"))]
|
2021-03-27 04:40:05 +01:00
|
|
|
impl_group!(PPI_GROUP4, 4);
|
2021-10-11 01:09:57 +02:00
|
|
|
#[cfg(not(feature = "nrf51"))]
|
2021-03-27 04:40:05 +01:00
|
|
|
impl_group!(PPI_GROUP5, 5);
|