Another redo using the feedback.

PPI is now split up into PPI and DPPI under the name 'interconnect'.
The tasks and events are tracked and reset in the drop function.
This commit is contained in:
Dion Dokter 2021-10-18 16:23:39 +02:00 committed by Dario Nieuwenhuis
parent e6ec81b999
commit 11655af034
20 changed files with 729 additions and 880 deletions

View file

@ -14,28 +14,15 @@ use embassy_hal_common::{low_power_wait_until, unborrow};
use crate::gpio::sealed::Pin as _; use crate::gpio::sealed::Pin as _;
use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin}; use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin};
use crate::ppi::{AnyChannel, Channel, Event, Ppi, Task}; use crate::interconnect::{AnyChannel, Event, OneToOneChannel, OneToTwoChannel, Ppi, Task};
use crate::pac;
use crate::timer::Instance as TimerInstance; use crate::timer::Instance as TimerInstance;
use crate::timer::{Frequency, Timer}; use crate::timer::{Frequency, Timer};
use crate::uarte::{Config, Instance as UarteInstance}; use crate::uarte::{Config, Instance as UarteInstance};
use crate::{pac, ppi};
// Re-export SVD variants to allow user to directly set values // Re-export SVD variants to allow user to directly set values
pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
#[non_exhaustive]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
PpiError(ppi::Error),
}
impl From<ppi::Error> for Error {
fn from(e: ppi::Error) -> Self {
Self::PpiError(e)
}
}
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
enum RxState { enum RxState {
Idle, Idle,
@ -58,8 +45,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> State<'d, U, T> {
struct StateInner<'d, U: UarteInstance, T: TimerInstance> { struct StateInner<'d, U: UarteInstance, T: TimerInstance> {
phantom: PhantomData<&'d mut U>, phantom: PhantomData<&'d mut U>,
timer: Timer<'d, T>, timer: Timer<'d, T>,
_ppi_ch1: Ppi<'d, AnyChannel>, _ppi_ch1: Ppi<'d, AnyChannel, 1, 2>,
_ppi_ch2: Ppi<'d, AnyChannel>, _ppi_ch2: Ppi<'d, AnyChannel, 1, 1>,
rx: RingBuffer<'d>, rx: RingBuffer<'d>,
rx_state: RxState, rx_state: RxState,
@ -79,15 +66,12 @@ impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {
impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
/// unsafe: may not leak self or futures /// unsafe: may not leak self or futures
///
/// - *Note:* ppi_ch1 must have at least 1 free event and 2 free tasks or a PPI error is returned
/// - *Note:* ppi_ch2 must have at least 1 free event and 1 free tasks or a PPI error is returned
pub unsafe fn new( pub unsafe fn new(
state: &'d mut State<'d, U, T>, state: &'d mut State<'d, U, T>,
_uarte: impl Unborrow<Target = U> + 'd, _uarte: impl Unborrow<Target = U> + 'd,
timer: impl Unborrow<Target = T> + 'd, timer: impl Unborrow<Target = T> + 'd,
ppi_ch1: impl Unborrow<Target = impl Channel> + 'd, ppi_ch1: impl Unborrow<Target = impl OneToTwoChannel + 'd> + 'd,
ppi_ch2: impl Unborrow<Target = impl Channel> + 'd, ppi_ch2: impl Unborrow<Target = impl OneToOneChannel + 'd> + 'd,
irq: impl Unborrow<Target = U::Interrupt> + 'd, irq: impl Unborrow<Target = U::Interrupt> + 'd,
rxd: impl Unborrow<Target = impl GpioPin> + 'd, rxd: impl Unborrow<Target = impl GpioPin> + 'd,
txd: impl Unborrow<Target = impl GpioPin> + 'd, txd: impl Unborrow<Target = impl GpioPin> + 'd,
@ -96,7 +80,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
config: Config, config: Config,
rx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8],
tx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8],
) -> Result<Self, Error> { ) -> Self {
unborrow!(ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts); unborrow!(ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts);
let r = U::regs(); let r = U::regs();
@ -160,18 +144,24 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
timer.cc(0).short_compare_clear(); timer.cc(0).short_compare_clear();
timer.cc(0).short_compare_stop(); timer.cc(0).short_compare_stop();
let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade()); let mut ppi_ch1 = Ppi::new_one_to_two(
ppi_ch1.publish(Event::from_reg(&r.events_rxdrdy))?; ppi_ch1,
ppi_ch1.subscribe(timer.task_clear())?; Event::from_reg(&r.events_rxdrdy),
ppi_ch1.subscribe(timer.task_start())?; timer.task_clear(),
timer.task_start(),
)
.degrade();
ppi_ch1.enable(); ppi_ch1.enable();
let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade()); let mut ppi_ch2 = Ppi::new_one_to_one(
ppi_ch2.publish(timer.cc(0).event_compare())?; ppi_ch2,
ppi_ch2.subscribe(Task::from_reg(&r.tasks_stoprx))?; timer.cc(0).event_compare(),
Task::from_reg(&r.tasks_stoprx),
)
.degrade();
ppi_ch2.enable(); ppi_ch2.enable();
Ok(Self { Self {
inner: PeripheralMutex::new_unchecked(irq, &mut state.0, move || StateInner { inner: PeripheralMutex::new_unchecked(irq, &mut state.0, move || StateInner {
phantom: PhantomData, phantom: PhantomData,
timer, timer,
@ -186,7 +176,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
tx_state: TxState::Idle, tx_state: TxState::Idle,
tx_waker: WakerRegistration::new(), tx_waker: WakerRegistration::new(),
}), }),
}) }
} }
pub fn set_baudrate(&mut self, baudrate: Baudrate) { pub fn set_baudrate(&mut self, baudrate: Baudrate) {

View file

@ -167,28 +167,28 @@ impl_pin!(P0_29, 0, 29);
impl_pin!(P0_30, 0, 30); impl_pin!(P0_30, 0, 30);
impl_pin!(P0_31, 0, 31); impl_pin!(P0_31, 0, 31);
impl_ppi_channel!(PPI_CH0, 0, 2, 1); impl_ppi_channel!(PPI_CH0, 0, true, 1, 2);
impl_ppi_channel!(PPI_CH1, 1, 2, 1); impl_ppi_channel!(PPI_CH1, 1, true, 1, 2);
impl_ppi_channel!(PPI_CH2, 2, 2, 1); impl_ppi_channel!(PPI_CH2, 2, true, 1, 2);
impl_ppi_channel!(PPI_CH3, 3, 2, 1); impl_ppi_channel!(PPI_CH3, 3, true, 1, 2);
impl_ppi_channel!(PPI_CH4, 4, 2, 1); impl_ppi_channel!(PPI_CH4, 4, true, 1, 2);
impl_ppi_channel!(PPI_CH5, 5, 2, 1); impl_ppi_channel!(PPI_CH5, 5, true, 1, 2);
impl_ppi_channel!(PPI_CH6, 6, 2, 1); impl_ppi_channel!(PPI_CH6, 6, true, 1, 2);
impl_ppi_channel!(PPI_CH7, 7, 2, 1); impl_ppi_channel!(PPI_CH7, 7, true, 1, 2);
impl_ppi_channel!(PPI_CH8, 8, 2, 1); impl_ppi_channel!(PPI_CH8, 8, true, 1, 2);
impl_ppi_channel!(PPI_CH9, 9, 2, 1); impl_ppi_channel!(PPI_CH9, 9, true, 1, 2);
impl_ppi_channel!(PPI_CH20, 20, 1, 0); impl_ppi_channel!(PPI_CH20, 20, false, 0, 1);
impl_ppi_channel!(PPI_CH21, 21, 1, 0); impl_ppi_channel!(PPI_CH21, 21, false, 0, 1);
impl_ppi_channel!(PPI_CH22, 22, 1, 0); impl_ppi_channel!(PPI_CH22, 22, false, 0, 1);
impl_ppi_channel!(PPI_CH23, 23, 1, 0); impl_ppi_channel!(PPI_CH23, 23, false, 0, 1);
impl_ppi_channel!(PPI_CH24, 24, 1, 0); impl_ppi_channel!(PPI_CH24, 24, false, 0, 1);
impl_ppi_channel!(PPI_CH25, 25, 1, 0); impl_ppi_channel!(PPI_CH25, 25, false, 0, 1);
impl_ppi_channel!(PPI_CH26, 26, 1, 0); impl_ppi_channel!(PPI_CH26, 26, false, 0, 1);
impl_ppi_channel!(PPI_CH27, 27, 1, 0); impl_ppi_channel!(PPI_CH27, 27, false, 0, 1);
impl_ppi_channel!(PPI_CH28, 28, 1, 0); impl_ppi_channel!(PPI_CH28, 28, false, 0, 1);
impl_ppi_channel!(PPI_CH29, 29, 1, 0); impl_ppi_channel!(PPI_CH29, 29, false, 0, 1);
impl_ppi_channel!(PPI_CH30, 30, 1, 0); impl_ppi_channel!(PPI_CH30, 30, false, 0, 1);
impl_ppi_channel!(PPI_CH31, 31, 1, 0); impl_ppi_channel!(PPI_CH31, 31, false, 0, 1);
impl_saadc_input!(P0_04, ANALOGINPUT2); impl_saadc_input!(P0_04, ANALOGINPUT2);
impl_saadc_input!(P0_05, ANALOGINPUT3); impl_saadc_input!(P0_05, ANALOGINPUT3);

View file

@ -172,38 +172,38 @@ impl_pin!(P0_29, 0, 29);
impl_pin!(P0_30, 0, 30); impl_pin!(P0_30, 0, 30);
impl_pin!(P0_31, 0, 31); impl_pin!(P0_31, 0, 31);
impl_ppi_channel!(PPI_CH0, 0, 2, 1); impl_ppi_channel!(PPI_CH0, 0, true, 1, 2);
impl_ppi_channel!(PPI_CH1, 1, 2, 1); impl_ppi_channel!(PPI_CH1, 1, true, 1, 2);
impl_ppi_channel!(PPI_CH2, 2, 2, 1); impl_ppi_channel!(PPI_CH2, 2, true, 1, 2);
impl_ppi_channel!(PPI_CH3, 3, 2, 1); impl_ppi_channel!(PPI_CH3, 3, true, 1, 2);
impl_ppi_channel!(PPI_CH4, 4, 2, 1); impl_ppi_channel!(PPI_CH4, 4, true, 1, 2);
impl_ppi_channel!(PPI_CH5, 5, 2, 1); impl_ppi_channel!(PPI_CH5, 5, true, 1, 2);
impl_ppi_channel!(PPI_CH6, 6, 2, 1); impl_ppi_channel!(PPI_CH6, 6, true, 1, 2);
impl_ppi_channel!(PPI_CH7, 7, 2, 1); impl_ppi_channel!(PPI_CH7, 7, true, 1, 2);
impl_ppi_channel!(PPI_CH8, 8, 2, 1); impl_ppi_channel!(PPI_CH8, 8, true, 1, 2);
impl_ppi_channel!(PPI_CH9, 9, 2, 1); impl_ppi_channel!(PPI_CH9, 9, true, 1, 2);
impl_ppi_channel!(PPI_CH10, 10, 2, 1); impl_ppi_channel!(PPI_CH10, 10, true, 1, 2);
impl_ppi_channel!(PPI_CH11, 11, 2, 1); impl_ppi_channel!(PPI_CH11, 11, true, 1, 2);
impl_ppi_channel!(PPI_CH12, 12, 2, 1); impl_ppi_channel!(PPI_CH12, 12, true, 1, 2);
impl_ppi_channel!(PPI_CH13, 13, 2, 1); impl_ppi_channel!(PPI_CH13, 13, true, 1, 2);
impl_ppi_channel!(PPI_CH14, 14, 2, 1); impl_ppi_channel!(PPI_CH14, 14, true, 1, 2);
impl_ppi_channel!(PPI_CH15, 15, 2, 1); impl_ppi_channel!(PPI_CH15, 15, true, 1, 2);
impl_ppi_channel!(PPI_CH16, 16, 2, 1); impl_ppi_channel!(PPI_CH16, 16, true, 1, 2);
impl_ppi_channel!(PPI_CH17, 17, 2, 1); impl_ppi_channel!(PPI_CH17, 17, true, 1, 2);
impl_ppi_channel!(PPI_CH18, 18, 2, 1); impl_ppi_channel!(PPI_CH18, 18, true, 1, 2);
impl_ppi_channel!(PPI_CH19, 19, 2, 1); impl_ppi_channel!(PPI_CH19, 19, true, 1, 2);
impl_ppi_channel!(PPI_CH20, 20, 1, 0); impl_ppi_channel!(PPI_CH20, 20, false, 0, 1);
impl_ppi_channel!(PPI_CH21, 21, 1, 0); impl_ppi_channel!(PPI_CH21, 21, false, 0, 1);
impl_ppi_channel!(PPI_CH22, 22, 1, 0); impl_ppi_channel!(PPI_CH22, 22, false, 0, 1);
impl_ppi_channel!(PPI_CH23, 23, 1, 0); impl_ppi_channel!(PPI_CH23, 23, false, 0, 1);
impl_ppi_channel!(PPI_CH24, 24, 1, 0); impl_ppi_channel!(PPI_CH24, 24, false, 0, 1);
impl_ppi_channel!(PPI_CH25, 25, 1, 0); impl_ppi_channel!(PPI_CH25, 25, false, 0, 1);
impl_ppi_channel!(PPI_CH26, 26, 1, 0); impl_ppi_channel!(PPI_CH26, 26, false, 0, 1);
impl_ppi_channel!(PPI_CH27, 27, 1, 0); impl_ppi_channel!(PPI_CH27, 27, false, 0, 1);
impl_ppi_channel!(PPI_CH28, 28, 1, 0); impl_ppi_channel!(PPI_CH28, 28, false, 0, 1);
impl_ppi_channel!(PPI_CH29, 29, 1, 0); impl_ppi_channel!(PPI_CH29, 29, false, 0, 1);
impl_ppi_channel!(PPI_CH30, 30, 1, 0); impl_ppi_channel!(PPI_CH30, 30, false, 0, 1);
impl_ppi_channel!(PPI_CH31, 31, 1, 0); impl_ppi_channel!(PPI_CH31, 31, false, 0, 1);
impl_saadc_input!(P0_02, ANALOGINPUT0); impl_saadc_input!(P0_02, ANALOGINPUT0);
impl_saadc_input!(P0_03, ANALOGINPUT1); impl_saadc_input!(P0_03, ANALOGINPUT1);

View file

@ -173,38 +173,38 @@ impl_pin!(P0_29, 0, 29);
impl_pin!(P0_30, 0, 30); impl_pin!(P0_30, 0, 30);
impl_pin!(P0_31, 0, 31); impl_pin!(P0_31, 0, 31);
impl_ppi_channel!(PPI_CH0, 0, 2, 1); impl_ppi_channel!(PPI_CH0, 0, true, 1, 2);
impl_ppi_channel!(PPI_CH1, 1, 2, 1); impl_ppi_channel!(PPI_CH1, 1, true, 1, 2);
impl_ppi_channel!(PPI_CH2, 2, 2, 1); impl_ppi_channel!(PPI_CH2, 2, true, 1, 2);
impl_ppi_channel!(PPI_CH3, 3, 2, 1); impl_ppi_channel!(PPI_CH3, 3, true, 1, 2);
impl_ppi_channel!(PPI_CH4, 4, 2, 1); impl_ppi_channel!(PPI_CH4, 4, true, 1, 2);
impl_ppi_channel!(PPI_CH5, 5, 2, 1); impl_ppi_channel!(PPI_CH5, 5, true, 1, 2);
impl_ppi_channel!(PPI_CH6, 6, 2, 1); impl_ppi_channel!(PPI_CH6, 6, true, 1, 2);
impl_ppi_channel!(PPI_CH7, 7, 2, 1); impl_ppi_channel!(PPI_CH7, 7, true, 1, 2);
impl_ppi_channel!(PPI_CH8, 8, 2, 1); impl_ppi_channel!(PPI_CH8, 8, true, 1, 2);
impl_ppi_channel!(PPI_CH9, 9, 2, 1); impl_ppi_channel!(PPI_CH9, 9, true, 1, 2);
impl_ppi_channel!(PPI_CH10, 10, 2, 1); impl_ppi_channel!(PPI_CH10, 10, true, 1, 2);
impl_ppi_channel!(PPI_CH11, 11, 2, 1); impl_ppi_channel!(PPI_CH11, 11, true, 1, 2);
impl_ppi_channel!(PPI_CH12, 12, 2, 1); impl_ppi_channel!(PPI_CH12, 12, true, 1, 2);
impl_ppi_channel!(PPI_CH13, 13, 2, 1); impl_ppi_channel!(PPI_CH13, 13, true, 1, 2);
impl_ppi_channel!(PPI_CH14, 14, 2, 1); impl_ppi_channel!(PPI_CH14, 14, true, 1, 2);
impl_ppi_channel!(PPI_CH15, 15, 2, 1); impl_ppi_channel!(PPI_CH15, 15, true, 1, 2);
impl_ppi_channel!(PPI_CH16, 16, 2, 1); impl_ppi_channel!(PPI_CH16, 16, true, 1, 2);
impl_ppi_channel!(PPI_CH17, 17, 2, 1); impl_ppi_channel!(PPI_CH17, 17, true, 1, 2);
impl_ppi_channel!(PPI_CH18, 18, 2, 1); impl_ppi_channel!(PPI_CH18, 18, true, 1, 2);
impl_ppi_channel!(PPI_CH19, 19, 2, 1); impl_ppi_channel!(PPI_CH19, 19, true, 1, 2);
impl_ppi_channel!(PPI_CH20, 20, 1, 0); impl_ppi_channel!(PPI_CH20, 20, false, 0, 1);
impl_ppi_channel!(PPI_CH21, 21, 1, 0); impl_ppi_channel!(PPI_CH21, 21, false, 0, 1);
impl_ppi_channel!(PPI_CH22, 22, 1, 0); impl_ppi_channel!(PPI_CH22, 22, false, 0, 1);
impl_ppi_channel!(PPI_CH23, 23, 1, 0); impl_ppi_channel!(PPI_CH23, 23, false, 0, 1);
impl_ppi_channel!(PPI_CH24, 24, 1, 0); impl_ppi_channel!(PPI_CH24, 24, false, 0, 1);
impl_ppi_channel!(PPI_CH25, 25, 1, 0); impl_ppi_channel!(PPI_CH25, 25, false, 0, 1);
impl_ppi_channel!(PPI_CH26, 26, 1, 0); impl_ppi_channel!(PPI_CH26, 26, false, 0, 1);
impl_ppi_channel!(PPI_CH27, 27, 1, 0); impl_ppi_channel!(PPI_CH27, 27, false, 0, 1);
impl_ppi_channel!(PPI_CH28, 28, 1, 0); impl_ppi_channel!(PPI_CH28, 28, false, 0, 1);
impl_ppi_channel!(PPI_CH29, 29, 1, 0); impl_ppi_channel!(PPI_CH29, 29, false, 0, 1);
impl_ppi_channel!(PPI_CH30, 30, 1, 0); impl_ppi_channel!(PPI_CH30, 30, false, 0, 1);
impl_ppi_channel!(PPI_CH31, 31, 1, 0); impl_ppi_channel!(PPI_CH31, 31, false, 0, 1);
impl_saadc_input!(P0_02, ANALOGINPUT0); impl_saadc_input!(P0_02, ANALOGINPUT0);
impl_saadc_input!(P0_03, ANALOGINPUT1); impl_saadc_input!(P0_03, ANALOGINPUT1);

View file

@ -168,38 +168,38 @@ impl_pin!(P0_29, 0, 29);
impl_pin!(P0_30, 0, 30); impl_pin!(P0_30, 0, 30);
impl_pin!(P0_31, 0, 31); impl_pin!(P0_31, 0, 31);
impl_ppi_channel!(PPI_CH0, 0, 2, 1); impl_ppi_channel!(PPI_CH0, 0, true, 1, 2);
impl_ppi_channel!(PPI_CH1, 1, 2, 1); impl_ppi_channel!(PPI_CH1, 1, true, 1, 2);
impl_ppi_channel!(PPI_CH2, 2, 2, 1); impl_ppi_channel!(PPI_CH2, 2, true, 1, 2);
impl_ppi_channel!(PPI_CH3, 3, 2, 1); impl_ppi_channel!(PPI_CH3, 3, true, 1, 2);
impl_ppi_channel!(PPI_CH4, 4, 2, 1); impl_ppi_channel!(PPI_CH4, 4, true, 1, 2);
impl_ppi_channel!(PPI_CH5, 5, 2, 1); impl_ppi_channel!(PPI_CH5, 5, true, 1, 2);
impl_ppi_channel!(PPI_CH6, 6, 2, 1); impl_ppi_channel!(PPI_CH6, 6, true, 1, 2);
impl_ppi_channel!(PPI_CH7, 7, 2, 1); impl_ppi_channel!(PPI_CH7, 7, true, 1, 2);
impl_ppi_channel!(PPI_CH8, 8, 2, 1); impl_ppi_channel!(PPI_CH8, 8, true, 1, 2);
impl_ppi_channel!(PPI_CH9, 9, 2, 1); impl_ppi_channel!(PPI_CH9, 9, true, 1, 2);
impl_ppi_channel!(PPI_CH10, 10, 2, 1); impl_ppi_channel!(PPI_CH10, 10, true, 1, 2);
impl_ppi_channel!(PPI_CH11, 11, 2, 1); impl_ppi_channel!(PPI_CH11, 11, true, 1, 2);
impl_ppi_channel!(PPI_CH12, 12, 2, 1); impl_ppi_channel!(PPI_CH12, 12, true, 1, 2);
impl_ppi_channel!(PPI_CH13, 13, 2, 1); impl_ppi_channel!(PPI_CH13, 13, true, 1, 2);
impl_ppi_channel!(PPI_CH14, 14, 2, 1); impl_ppi_channel!(PPI_CH14, 14, true, 1, 2);
impl_ppi_channel!(PPI_CH15, 15, 2, 1); impl_ppi_channel!(PPI_CH15, 15, true, 1, 2);
impl_ppi_channel!(PPI_CH16, 16, 2, 1); impl_ppi_channel!(PPI_CH16, 16, true, 1, 2);
impl_ppi_channel!(PPI_CH17, 17, 2, 1); impl_ppi_channel!(PPI_CH17, 17, true, 1, 2);
impl_ppi_channel!(PPI_CH18, 18, 2, 1); impl_ppi_channel!(PPI_CH18, 18, true, 1, 2);
impl_ppi_channel!(PPI_CH19, 19, 2, 1); impl_ppi_channel!(PPI_CH19, 19, true, 1, 2);
impl_ppi_channel!(PPI_CH20, 20, 1, 0); impl_ppi_channel!(PPI_CH20, 20, false, 0, 1);
impl_ppi_channel!(PPI_CH21, 21, 1, 0); impl_ppi_channel!(PPI_CH21, 21, false, 0, 1);
impl_ppi_channel!(PPI_CH22, 22, 1, 0); impl_ppi_channel!(PPI_CH22, 22, false, 0, 1);
impl_ppi_channel!(PPI_CH23, 23, 1, 0); impl_ppi_channel!(PPI_CH23, 23, false, 0, 1);
impl_ppi_channel!(PPI_CH24, 24, 1, 0); impl_ppi_channel!(PPI_CH24, 24, false, 0, 1);
impl_ppi_channel!(PPI_CH25, 25, 1, 0); impl_ppi_channel!(PPI_CH25, 25, false, 0, 1);
impl_ppi_channel!(PPI_CH26, 26, 1, 0); impl_ppi_channel!(PPI_CH26, 26, false, 0, 1);
impl_ppi_channel!(PPI_CH27, 27, 1, 0); impl_ppi_channel!(PPI_CH27, 27, false, 0, 1);
impl_ppi_channel!(PPI_CH28, 28, 1, 0); impl_ppi_channel!(PPI_CH28, 28, false, 0, 1);
impl_ppi_channel!(PPI_CH29, 29, 1, 0); impl_ppi_channel!(PPI_CH29, 29, false, 0, 1);
impl_ppi_channel!(PPI_CH30, 30, 1, 0); impl_ppi_channel!(PPI_CH30, 30, false, 0, 1);
impl_ppi_channel!(PPI_CH31, 31, 1, 0); impl_ppi_channel!(PPI_CH31, 31, false, 0, 1);
pub mod irqs { pub mod irqs {
use crate::pac::Interrupt as InterruptEnum; use crate::pac::Interrupt as InterruptEnum;

View file

@ -190,38 +190,38 @@ impl_pin!(P0_29, 0, 29);
impl_pin!(P0_30, 0, 30); impl_pin!(P0_30, 0, 30);
impl_pin!(P0_31, 0, 31); impl_pin!(P0_31, 0, 31);
impl_ppi_channel!(PPI_CH0, 0, 2, 1); impl_ppi_channel!(PPI_CH0, 0, true, 1, 2);
impl_ppi_channel!(PPI_CH1, 1, 2, 1); impl_ppi_channel!(PPI_CH1, 1, true, 1, 2);
impl_ppi_channel!(PPI_CH2, 2, 2, 1); impl_ppi_channel!(PPI_CH2, 2, true, 1, 2);
impl_ppi_channel!(PPI_CH3, 3, 2, 1); impl_ppi_channel!(PPI_CH3, 3, true, 1, 2);
impl_ppi_channel!(PPI_CH4, 4, 2, 1); impl_ppi_channel!(PPI_CH4, 4, true, 1, 2);
impl_ppi_channel!(PPI_CH5, 5, 2, 1); impl_ppi_channel!(PPI_CH5, 5, true, 1, 2);
impl_ppi_channel!(PPI_CH6, 6, 2, 1); impl_ppi_channel!(PPI_CH6, 6, true, 1, 2);
impl_ppi_channel!(PPI_CH7, 7, 2, 1); impl_ppi_channel!(PPI_CH7, 7, true, 1, 2);
impl_ppi_channel!(PPI_CH8, 8, 2, 1); impl_ppi_channel!(PPI_CH8, 8, true, 1, 2);
impl_ppi_channel!(PPI_CH9, 9, 2, 1); impl_ppi_channel!(PPI_CH9, 9, true, 1, 2);
impl_ppi_channel!(PPI_CH10, 10, 2, 1); impl_ppi_channel!(PPI_CH10, 10, true, 1, 2);
impl_ppi_channel!(PPI_CH11, 11, 2, 1); impl_ppi_channel!(PPI_CH11, 11, true, 1, 2);
impl_ppi_channel!(PPI_CH12, 12, 2, 1); impl_ppi_channel!(PPI_CH12, 12, true, 1, 2);
impl_ppi_channel!(PPI_CH13, 13, 2, 1); impl_ppi_channel!(PPI_CH13, 13, true, 1, 2);
impl_ppi_channel!(PPI_CH14, 14, 2, 1); impl_ppi_channel!(PPI_CH14, 14, true, 1, 2);
impl_ppi_channel!(PPI_CH15, 15, 2, 1); impl_ppi_channel!(PPI_CH15, 15, true, 1, 2);
impl_ppi_channel!(PPI_CH16, 16, 2, 1); impl_ppi_channel!(PPI_CH16, 16, true, 1, 2);
impl_ppi_channel!(PPI_CH17, 17, 2, 1); impl_ppi_channel!(PPI_CH17, 17, true, 1, 2);
impl_ppi_channel!(PPI_CH18, 18, 2, 1); impl_ppi_channel!(PPI_CH18, 18, true, 1, 2);
impl_ppi_channel!(PPI_CH19, 19, 2, 1); impl_ppi_channel!(PPI_CH19, 19, true, 1, 2);
impl_ppi_channel!(PPI_CH20, 20, 1, 0); impl_ppi_channel!(PPI_CH20, 20, false, 0, 1);
impl_ppi_channel!(PPI_CH21, 21, 1, 0); impl_ppi_channel!(PPI_CH21, 21, false, 0, 1);
impl_ppi_channel!(PPI_CH22, 22, 1, 0); impl_ppi_channel!(PPI_CH22, 22, false, 0, 1);
impl_ppi_channel!(PPI_CH23, 23, 1, 0); impl_ppi_channel!(PPI_CH23, 23, false, 0, 1);
impl_ppi_channel!(PPI_CH24, 24, 1, 0); impl_ppi_channel!(PPI_CH24, 24, false, 0, 1);
impl_ppi_channel!(PPI_CH25, 25, 1, 0); impl_ppi_channel!(PPI_CH25, 25, false, 0, 1);
impl_ppi_channel!(PPI_CH26, 26, 1, 0); impl_ppi_channel!(PPI_CH26, 26, false, 0, 1);
impl_ppi_channel!(PPI_CH27, 27, 1, 0); impl_ppi_channel!(PPI_CH27, 27, false, 0, 1);
impl_ppi_channel!(PPI_CH28, 28, 1, 0); impl_ppi_channel!(PPI_CH28, 28, false, 0, 1);
impl_ppi_channel!(PPI_CH29, 29, 1, 0); impl_ppi_channel!(PPI_CH29, 29, false, 0, 1);
impl_ppi_channel!(PPI_CH30, 30, 1, 0); impl_ppi_channel!(PPI_CH30, 30, false, 0, 1);
impl_ppi_channel!(PPI_CH31, 31, 1, 0); impl_ppi_channel!(PPI_CH31, 31, false, 0, 1);
impl_saadc_input!(P0_02, ANALOGINPUT0); impl_saadc_input!(P0_02, ANALOGINPUT0);
impl_saadc_input!(P0_03, ANALOGINPUT1); impl_saadc_input!(P0_03, ANALOGINPUT1);

View file

@ -226,38 +226,38 @@ impl_pin!(P1_13, 1, 13);
impl_pin!(P1_14, 1, 14); impl_pin!(P1_14, 1, 14);
impl_pin!(P1_15, 1, 15); impl_pin!(P1_15, 1, 15);
impl_ppi_channel!(PPI_CH0, 0, 2, 1); impl_ppi_channel!(PPI_CH0, 0, true, 1, 2);
impl_ppi_channel!(PPI_CH1, 1, 2, 1); impl_ppi_channel!(PPI_CH1, 1, true, 1, 2);
impl_ppi_channel!(PPI_CH2, 2, 2, 1); impl_ppi_channel!(PPI_CH2, 2, true, 1, 2);
impl_ppi_channel!(PPI_CH3, 3, 2, 1); impl_ppi_channel!(PPI_CH3, 3, true, 1, 2);
impl_ppi_channel!(PPI_CH4, 4, 2, 1); impl_ppi_channel!(PPI_CH4, 4, true, 1, 2);
impl_ppi_channel!(PPI_CH5, 5, 2, 1); impl_ppi_channel!(PPI_CH5, 5, true, 1, 2);
impl_ppi_channel!(PPI_CH6, 6, 2, 1); impl_ppi_channel!(PPI_CH6, 6, true, 1, 2);
impl_ppi_channel!(PPI_CH7, 7, 2, 1); impl_ppi_channel!(PPI_CH7, 7, true, 1, 2);
impl_ppi_channel!(PPI_CH8, 8, 2, 1); impl_ppi_channel!(PPI_CH8, 8, true, 1, 2);
impl_ppi_channel!(PPI_CH9, 9, 2, 1); impl_ppi_channel!(PPI_CH9, 9, true, 1, 2);
impl_ppi_channel!(PPI_CH10, 10, 2, 1); impl_ppi_channel!(PPI_CH10, 10, true, 1, 2);
impl_ppi_channel!(PPI_CH11, 11, 2, 1); impl_ppi_channel!(PPI_CH11, 11, true, 1, 2);
impl_ppi_channel!(PPI_CH12, 12, 2, 1); impl_ppi_channel!(PPI_CH12, 12, true, 1, 2);
impl_ppi_channel!(PPI_CH13, 13, 2, 1); impl_ppi_channel!(PPI_CH13, 13, true, 1, 2);
impl_ppi_channel!(PPI_CH14, 14, 2, 1); impl_ppi_channel!(PPI_CH14, 14, true, 1, 2);
impl_ppi_channel!(PPI_CH15, 15, 2, 1); impl_ppi_channel!(PPI_CH15, 15, true, 1, 2);
impl_ppi_channel!(PPI_CH16, 16, 2, 1); impl_ppi_channel!(PPI_CH16, 16, true, 1, 2);
impl_ppi_channel!(PPI_CH17, 17, 2, 1); impl_ppi_channel!(PPI_CH17, 17, true, 1, 2);
impl_ppi_channel!(PPI_CH18, 18, 2, 1); impl_ppi_channel!(PPI_CH18, 18, true, 1, 2);
impl_ppi_channel!(PPI_CH19, 19, 2, 1); impl_ppi_channel!(PPI_CH19, 19, true, 1, 2);
impl_ppi_channel!(PPI_CH20, 20, 1, 0); impl_ppi_channel!(PPI_CH20, 20, false, 0, 1);
impl_ppi_channel!(PPI_CH21, 21, 1, 0); impl_ppi_channel!(PPI_CH21, 21, false, 0, 1);
impl_ppi_channel!(PPI_CH22, 22, 1, 0); impl_ppi_channel!(PPI_CH22, 22, false, 0, 1);
impl_ppi_channel!(PPI_CH23, 23, 1, 0); impl_ppi_channel!(PPI_CH23, 23, false, 0, 1);
impl_ppi_channel!(PPI_CH24, 24, 1, 0); impl_ppi_channel!(PPI_CH24, 24, false, 0, 1);
impl_ppi_channel!(PPI_CH25, 25, 1, 0); impl_ppi_channel!(PPI_CH25, 25, false, 0, 1);
impl_ppi_channel!(PPI_CH26, 26, 1, 0); impl_ppi_channel!(PPI_CH26, 26, false, 0, 1);
impl_ppi_channel!(PPI_CH27, 27, 1, 0); impl_ppi_channel!(PPI_CH27, 27, false, 0, 1);
impl_ppi_channel!(PPI_CH28, 28, 1, 0); impl_ppi_channel!(PPI_CH28, 28, false, 0, 1);
impl_ppi_channel!(PPI_CH29, 29, 1, 0); impl_ppi_channel!(PPI_CH29, 29, false, 0, 1);
impl_ppi_channel!(PPI_CH30, 30, 1, 0); impl_ppi_channel!(PPI_CH30, 30, false, 0, 1);
impl_ppi_channel!(PPI_CH31, 31, 1, 0); impl_ppi_channel!(PPI_CH31, 31, false, 0, 1);
impl_saadc_input!(P0_02, ANALOGINPUT0); impl_saadc_input!(P0_02, ANALOGINPUT0);
impl_saadc_input!(P0_03, ANALOGINPUT1); impl_saadc_input!(P0_03, ANALOGINPUT1);

View file

@ -231,38 +231,38 @@ impl_pin!(P1_13, 1, 13);
impl_pin!(P1_14, 1, 14); impl_pin!(P1_14, 1, 14);
impl_pin!(P1_15, 1, 15); impl_pin!(P1_15, 1, 15);
impl_ppi_channel!(PPI_CH0, 0, 2, 1); impl_ppi_channel!(PPI_CH0, 0, true, 1, 2);
impl_ppi_channel!(PPI_CH1, 1, 2, 1); impl_ppi_channel!(PPI_CH1, 1, true, 1, 2);
impl_ppi_channel!(PPI_CH2, 2, 2, 1); impl_ppi_channel!(PPI_CH2, 2, true, 1, 2);
impl_ppi_channel!(PPI_CH3, 3, 2, 1); impl_ppi_channel!(PPI_CH3, 3, true, 1, 2);
impl_ppi_channel!(PPI_CH4, 4, 2, 1); impl_ppi_channel!(PPI_CH4, 4, true, 1, 2);
impl_ppi_channel!(PPI_CH5, 5, 2, 1); impl_ppi_channel!(PPI_CH5, 5, true, 1, 2);
impl_ppi_channel!(PPI_CH6, 6, 2, 1); impl_ppi_channel!(PPI_CH6, 6, true, 1, 2);
impl_ppi_channel!(PPI_CH7, 7, 2, 1); impl_ppi_channel!(PPI_CH7, 7, true, 1, 2);
impl_ppi_channel!(PPI_CH8, 8, 2, 1); impl_ppi_channel!(PPI_CH8, 8, true, 1, 2);
impl_ppi_channel!(PPI_CH9, 9, 2, 1); impl_ppi_channel!(PPI_CH9, 9, true, 1, 2);
impl_ppi_channel!(PPI_CH10, 10, 2, 1); impl_ppi_channel!(PPI_CH10, 10, true, 1, 2);
impl_ppi_channel!(PPI_CH11, 11, 2, 1); impl_ppi_channel!(PPI_CH11, 11, true, 1, 2);
impl_ppi_channel!(PPI_CH12, 12, 2, 1); impl_ppi_channel!(PPI_CH12, 12, true, 1, 2);
impl_ppi_channel!(PPI_CH13, 13, 2, 1); impl_ppi_channel!(PPI_CH13, 13, true, 1, 2);
impl_ppi_channel!(PPI_CH14, 14, 2, 1); impl_ppi_channel!(PPI_CH14, 14, true, 1, 2);
impl_ppi_channel!(PPI_CH15, 15, 2, 1); impl_ppi_channel!(PPI_CH15, 15, true, 1, 2);
impl_ppi_channel!(PPI_CH16, 16, 2, 1); impl_ppi_channel!(PPI_CH16, 16, true, 1, 2);
impl_ppi_channel!(PPI_CH17, 17, 2, 1); impl_ppi_channel!(PPI_CH17, 17, true, 1, 2);
impl_ppi_channel!(PPI_CH18, 18, 2, 1); impl_ppi_channel!(PPI_CH18, 18, true, 1, 2);
impl_ppi_channel!(PPI_CH19, 19, 2, 1); impl_ppi_channel!(PPI_CH19, 19, true, 1, 2);
impl_ppi_channel!(PPI_CH20, 20, 1, 0); impl_ppi_channel!(PPI_CH20, 20, false, 0, 1);
impl_ppi_channel!(PPI_CH21, 21, 1, 0); impl_ppi_channel!(PPI_CH21, 21, false, 0, 1);
impl_ppi_channel!(PPI_CH22, 22, 1, 0); impl_ppi_channel!(PPI_CH22, 22, false, 0, 1);
impl_ppi_channel!(PPI_CH23, 23, 1, 0); impl_ppi_channel!(PPI_CH23, 23, false, 0, 1);
impl_ppi_channel!(PPI_CH24, 24, 1, 0); impl_ppi_channel!(PPI_CH24, 24, false, 0, 1);
impl_ppi_channel!(PPI_CH25, 25, 1, 0); impl_ppi_channel!(PPI_CH25, 25, false, 0, 1);
impl_ppi_channel!(PPI_CH26, 26, 1, 0); impl_ppi_channel!(PPI_CH26, 26, false, 0, 1);
impl_ppi_channel!(PPI_CH27, 27, 1, 0); impl_ppi_channel!(PPI_CH27, 27, false, 0, 1);
impl_ppi_channel!(PPI_CH28, 28, 1, 0); impl_ppi_channel!(PPI_CH28, 28, false, 0, 1);
impl_ppi_channel!(PPI_CH29, 29, 1, 0); impl_ppi_channel!(PPI_CH29, 29, false, 0, 1);
impl_ppi_channel!(PPI_CH30, 30, 1, 0); impl_ppi_channel!(PPI_CH30, 30, false, 0, 1);
impl_ppi_channel!(PPI_CH31, 31, 1, 0); impl_ppi_channel!(PPI_CH31, 31, false, 0, 1);
impl_saadc_input!(P0_02, ANALOGINPUT0); impl_saadc_input!(P0_02, ANALOGINPUT0);
impl_saadc_input!(P0_03, ANALOGINPUT1); impl_saadc_input!(P0_03, ANALOGINPUT1);

View file

@ -184,22 +184,22 @@ impl_pin!(P0_29, 0, 29);
impl_pin!(P0_30, 0, 30); impl_pin!(P0_30, 0, 30);
impl_pin!(P0_31, 0, 31); impl_pin!(P0_31, 0, 31);
impl_ppi_channel!(PPI_CH0, 0); impl_ppi_channel!(PPI_CH0, 0, true, many, many);
impl_ppi_channel!(PPI_CH1, 1); impl_ppi_channel!(PPI_CH1, 1, true, many, many);
impl_ppi_channel!(PPI_CH2, 2); impl_ppi_channel!(PPI_CH2, 2, true, many, many);
impl_ppi_channel!(PPI_CH3, 3); impl_ppi_channel!(PPI_CH3, 3, true, many, many);
impl_ppi_channel!(PPI_CH4, 4); impl_ppi_channel!(PPI_CH4, 4, true, many, many);
impl_ppi_channel!(PPI_CH5, 5); impl_ppi_channel!(PPI_CH5, 5, true, many, many);
impl_ppi_channel!(PPI_CH6, 6); impl_ppi_channel!(PPI_CH6, 6, true, many, many);
impl_ppi_channel!(PPI_CH7, 7); impl_ppi_channel!(PPI_CH7, 7, true, many, many);
impl_ppi_channel!(PPI_CH8, 8); impl_ppi_channel!(PPI_CH8, 8, true, many, many);
impl_ppi_channel!(PPI_CH9, 9); impl_ppi_channel!(PPI_CH9, 9, true, many, many);
impl_ppi_channel!(PPI_CH10, 10); impl_ppi_channel!(PPI_CH10, 10, true, many, many);
impl_ppi_channel!(PPI_CH11, 11); impl_ppi_channel!(PPI_CH11, 11, true, many, many);
impl_ppi_channel!(PPI_CH12, 12); impl_ppi_channel!(PPI_CH12, 12, true, many, many);
impl_ppi_channel!(PPI_CH13, 13); impl_ppi_channel!(PPI_CH13, 13, true, many, many);
impl_ppi_channel!(PPI_CH14, 14); impl_ppi_channel!(PPI_CH14, 14, true, many, many);
impl_ppi_channel!(PPI_CH15, 15); impl_ppi_channel!(PPI_CH15, 15, true, many, many);
impl_saadc_input!(P0_13, ANALOGINPUT0); impl_saadc_input!(P0_13, ANALOGINPUT0);
impl_saadc_input!(P0_14, ANALOGINPUT1); impl_saadc_input!(P0_14, ANALOGINPUT1);

View file

@ -11,8 +11,8 @@ use futures::future::poll_fn;
use crate::gpio::sealed::Pin as _; use crate::gpio::sealed::Pin as _;
use crate::gpio::{AnyPin, Input, Output, Pin as GpioPin}; use crate::gpio::{AnyPin, Input, Output, Pin as GpioPin};
use crate::interconnect::{Event, Task};
use crate::pac; use crate::pac;
use crate::ppi::{Event, Task};
use crate::{interrupt, peripherals}; use crate::{interrupt, peripherals};
pub const CHANNEL_COUNT: usize = 8; pub const CHANNEL_COUNT: usize = 8;
@ -190,13 +190,7 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> {
/// Returns the IN event, for use with PPI. /// Returns the IN event, for use with PPI.
pub fn event_in(&self) -> Event { pub fn event_in(&self) -> Event {
let g = unsafe { &*pac::GPIOTE::ptr() }; let g = unsafe { &*pac::GPIOTE::ptr() };
Event::from_reg(&g.events_in[self.ch.number()])
#[cfg(feature = "_ppi")]
let reg = &g.events_in[self.ch.number()];
#[cfg(feature = "_dppi")]
let reg = &g.publish_in[self.ch.number()];
Event::from_reg(reg)
} }
} }
@ -277,33 +271,21 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> {
/// Returns the OUT task, for use with PPI. /// Returns the OUT task, for use with PPI.
pub fn task_out(&self) -> Task { pub fn task_out(&self) -> Task {
let g = unsafe { &*pac::GPIOTE::ptr() }; let g = unsafe { &*pac::GPIOTE::ptr() };
#[cfg(feature = "_ppi")] Task::from_reg(&g.tasks_out[self.ch.number()])
let reg = &g.tasks_out[self.ch.number()];
#[cfg(feature = "_dppi")]
let reg = &g.subscribe_out[self.ch.number()];
Task::from_reg(reg)
} }
/// Returns the CLR task, for use with PPI. /// Returns the CLR task, for use with PPI.
#[cfg(not(feature = "nrf51"))] #[cfg(not(feature = "nrf51"))]
pub fn task_clr(&self) -> Task { pub fn task_clr(&self) -> Task {
let g = unsafe { &*pac::GPIOTE::ptr() }; let g = unsafe { &*pac::GPIOTE::ptr() };
#[cfg(feature = "_ppi")] Task::from_reg(&g.tasks_clr[self.ch.number()])
let reg = &g.tasks_clr[self.ch.number()];
#[cfg(feature = "_dppi")]
let reg = &g.subscribe_clr[self.ch.number()];
Task::from_reg(reg)
} }
/// Returns the SET task, for use with PPI. /// Returns the SET task, for use with PPI.
#[cfg(not(feature = "nrf51"))] #[cfg(not(feature = "nrf51"))]
pub fn task_set(&self) -> Task { pub fn task_set(&self) -> Task {
let g = unsafe { &*pac::GPIOTE::ptr() }; let g = unsafe { &*pac::GPIOTE::ptr() };
#[cfg(feature = "_ppi")] Task::from_reg(&g.tasks_set[self.ch.number()])
let reg = &g.tasks_set[self.ch.number()];
#[cfg(feature = "_dppi")]
let reg = &g.subscribe_set[self.ch.number()];
Task::from_reg(reg)
} }
} }

View file

@ -0,0 +1,47 @@
use super::{Channel, Event, Ppi, Task};
const DPPI_ENABLE_BIT: u32 = 0x8000_0000;
const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF;
const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>();
impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize>
Ppi<'d, C, EVENT_COUNT, TASK_COUNT>
{
pub(super) fn enable_task(task: &Task, channel: &C, _index: usize) {
unsafe {
task.0
.as_ptr()
.add(REGISTER_DPPI_CONFIG_OFFSET)
.write_volatile(DPPI_ENABLE_BIT | (channel.number() as u32 & DPPI_CHANNEL_MASK));
}
}
pub(super) fn disable_task(task: &Task, _channel: &C, _index: usize) {
unsafe {
task.0
.as_ptr()
.add(REGISTER_DPPI_CONFIG_OFFSET)
.write_volatile(0);
}
}
pub(super) fn enable_event(event: &Event, channel: &C, _index: usize) {
unsafe {
event
.0
.as_ptr()
.add(REGISTER_DPPI_CONFIG_OFFSET)
.write_volatile(DPPI_ENABLE_BIT | (channel.number() as u32 & DPPI_CHANNEL_MASK));
}
}
pub(super) fn disable_event(event: &Event, _channel: &C, _index: usize) {
unsafe {
event
.0
.as_ptr()
.add(REGISTER_DPPI_CONFIG_OFFSET)
.write_volatile(0);
}
}
}

View file

@ -0,0 +1,318 @@
#![macro_use]
//! HAL interface for the PPI and DPPI peripheral.
//!
//! The (Distributed) 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.
//!
//! The DPPI for nRF53 and nRF91 devices works in a different way. Every channel can support infinitely
//! many tasks and events, but any single task or event can only be coupled with one channel.
//!
use crate::{pac, peripherals};
use core::marker::PhantomData;
use core::ptr::NonNull;
use embassy::util::Unborrow;
use embassy_hal_common::{unborrow, unsafe_impl_unborrow};
#[cfg(feature = "_dppi")]
mod dppi;
#[cfg(feature = "_ppi")]
mod ppi;
pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> {
ch: C,
events: [Event; EVENT_COUNT],
tasks: [Task; TASK_COUNT],
phantom: PhantomData<&'d mut C>,
}
impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize>
Ppi<'d, C, EVENT_COUNT, TASK_COUNT>
{
pub fn degrade(self) -> Ppi<'d, AnyChannel, EVENT_COUNT, TASK_COUNT> {
Ppi {
ch: AnyChannel {
number: self.ch.number() as u8,
#[cfg(feature = "_ppi")]
has_configurable_task: self.ch.is_task_configurable(),
},
events: self.events,
tasks: self.tasks,
phantom: PhantomData,
}
}
/// 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()) });
}
/// Enables all tasks and events
fn enable_all(&self) {
for (index, task) in self.tasks.iter().enumerate() {
Self::enable_task(task, &self.ch, index);
}
for (index, event) in self.events.iter().enumerate() {
Self::enable_event(event, &self.ch, index);
}
}
/// Disable all tasks and events
fn disable_all(&self) {
for (index, task) in self.tasks.iter().enumerate() {
Self::disable_task(task, &self.ch, index);
}
for (index, event) in self.events.iter().enumerate() {
Self::disable_event(event, &self.ch, index);
}
}
}
impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop
for Ppi<'d, C, EVENT_COUNT, TASK_COUNT>
{
fn drop(&mut self) {
self.disable();
self.disable_all();
}
}
impl<'d, C: StaticToOneChannel> Ppi<'d, C, 0, 1> {
pub fn new_static_to_one(ch: impl Unborrow<Target = C> + 'd, task: Task) -> Self {
unborrow!(ch);
let s = Self {
ch,
events: [],
tasks: [task],
phantom: PhantomData,
};
s.enable_all();
s
}
}
impl<'d, C: OneToOneChannel> Ppi<'d, C, 1, 1> {
pub fn new_one_to_one(ch: impl Unborrow<Target = C> + 'd, event: Event, task: Task) -> Self {
unborrow!(ch);
let s = Self {
ch,
events: [event],
tasks: [task],
phantom: PhantomData,
};
s.enable_all();
s
}
}
impl<'d, C: OneToTwoChannel> Ppi<'d, C, 1, 2> {
pub fn new_one_to_two(
ch: impl Unborrow<Target = C> + 'd,
event: Event,
task1: Task,
task2: Task,
) -> Self {
unborrow!(ch);
let s = Self {
ch,
events: [event],
tasks: [task1, task2],
phantom: PhantomData,
};
s.enable_all();
s
}
}
impl<'d, C: ManyToManyChannel, const EVENT_COUNT: usize, const TASK_COUNT: usize>
Ppi<'d, C, EVENT_COUNT, TASK_COUNT>
{
pub fn new_many_to_many(
ch: impl Unborrow<Target = C> + 'd,
events: [Event; EVENT_COUNT],
tasks: [Task; TASK_COUNT],
) -> Self {
unborrow!(ch);
let s = Self {
ch,
events,
tasks,
phantom: PhantomData,
};
s.enable_all();
s
}
}
/// Represents a task that a peripheral can do.
/// When a task is subscribed to a PPI channel it will run when the channel is triggered by
/// a published event.
///
/// The pointer is to a task register
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Task(pub NonNull<u32>);
impl Task {
pub(crate) fn from_reg<T>(reg: &T) -> Self {
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
}
}
/// # Safety
///
/// NonNull is not send, but this event is only allowed to point at registers and those exist in any context on the same core.
unsafe impl Send for Task {}
/// Represents an event that a peripheral can publish.
/// An event can be set to publish on a PPI channel when the event happens.
///
/// The pointer is to an event register
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Event(pub NonNull<u32>);
impl Event {
pub(crate) fn from_reg<T>(reg: &T) -> Self {
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
}
}
/// # Safety
///
/// NonNull is not send, but this event is only allowed to point at registers and those exist in any context on the same core.
unsafe impl Send for Event {}
// ======================
// traits
pub(crate) mod sealed {
pub trait Channel {}
pub trait Group {}
}
pub trait Channel: sealed::Channel + Unborrow<Target = Self> + Sized {
/// Returns the number of the channel
fn number(&self) -> usize;
#[cfg(feature = "_ppi")]
fn is_task_configurable(&self) -> bool;
}
pub trait StaticToOneChannel: Channel {}
pub trait OneToOneChannel: StaticToOneChannel {}
pub trait OneToTwoChannel: OneToOneChannel {}
pub trait ManyToManyChannel: OneToTwoChannel {}
pub trait Group: sealed::Group + Sized {
fn number(&self) -> usize;
}
// ======================
// channels
pub struct AnyChannel {
number: u8,
#[cfg(feature = "_ppi")]
has_configurable_task: bool,
}
unsafe_impl_unborrow!(AnyChannel);
impl sealed::Channel for AnyChannel {}
impl Channel for AnyChannel {
fn number(&self) -> usize {
self.number as usize
}
#[cfg(feature = "_ppi")]
fn is_task_configurable(&self) -> bool {
self.has_configurable_task
}
}
macro_rules! impl_ppi_channel {
($type:ident, $number:expr, $has_configurable_task:expr) => {
impl crate::interconnect::sealed::Channel for peripherals::$type {}
impl crate::interconnect::Channel for peripherals::$type {
fn number(&self) -> usize {
$number
}
#[cfg(feature = "_ppi")]
fn is_task_configurable(&self) -> bool {
$has_configurable_task
}
}
};
($type:ident, $number:expr, $has_configurable_task:expr, 0, 0) => {
impl_ppi_channel!($type, $number, $has_configurable_task);
};
($type:ident, $number:expr, $has_configurable_task:expr, 0, 1) => {
impl_ppi_channel!($type, $number, $has_configurable_task, 0, 0);
impl crate::interconnect::StaticToOneChannel for peripherals::$type {}
};
($type:ident, $number:expr, $has_configurable_task:expr, 1, 1) => {
impl_ppi_channel!($type, $number, $has_configurable_task, 0, 1);
impl crate::interconnect::OneToOneChannel for peripherals::$type {}
};
($type:ident, $number:expr, $has_configurable_task:expr, 1, 2) => {
impl_ppi_channel!($type, $number, $has_configurable_task, 1, 1);
impl crate::interconnect::OneToTwoChannel for peripherals::$type {}
};
($type:ident, $number:expr, $has_configurable_task:expr, many, many) => {
impl_ppi_channel!($type, $number, $has_configurable_task, 1, 2);
impl crate::interconnect::ManyToManyChannel for peripherals::$type {}
};
}
// ======================
// groups
pub struct AnyGroup {
number: u8,
}
unsafe_impl_unborrow!(AnyGroup);
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);
#[cfg(not(feature = "nrf51"))]
impl_group!(PPI_GROUP4, 4);
#[cfg(not(feature = "nrf51"))]
impl_group!(PPI_GROUP5, 5);

View file

@ -0,0 +1,65 @@
use super::{Channel, Event, Ppi, Task};
use crate::pac;
impl<'d, C: Channel + 'd, const EVENT_COUNT: usize, const TASK_COUNT: usize>
Ppi<'d, C, EVENT_COUNT, TASK_COUNT>
{
pub(super) fn enable_task(task: &Task, channel: &C, index: usize) {
match (index, channel.is_task_configurable()) {
(0, false) => Self::set_fork_task(Some(task), channel.number()), // Static channel with fork
(0, true) => Self::set_main_task(Some(task), channel.number()), // Configurable channel without fork
(1, true) => Self::set_fork_task(Some(task), channel.number()), // Configurable channel with fork
_ => unreachable!("{}, {}", index, channel.is_task_configurable()), // Not available with the PPI, so should not be constructable
}
}
pub(super) fn disable_task(_task: &Task, channel: &C, index: usize) {
match (index, channel.is_task_configurable()) {
(0, false) => Self::set_fork_task(None, channel.number()), // Static channel with fork
(0, true) => Self::set_main_task(None, channel.number()), // Configurable channel without fork
(1, true) => Self::set_fork_task(None, channel.number()), // Configurable channel with fork
_ => unreachable!(), // Not available with the PPI, so should not be constructable
}
}
pub(super) fn enable_event(event: &Event, channel: &C, _index: usize) {
Self::set_event(Some(event), channel.number())
}
pub(super) fn disable_event(_event: &Event, channel: &C, _index: usize) {
Self::set_event(None, channel.number())
}
fn set_main_task(task: Option<&Task>, channel: usize) {
let r = unsafe { &*pac::PPI::ptr() };
if let Some(task) = task {
r.ch[channel]
.tep
.write(|w| unsafe { w.bits(task.0.as_ptr() as u32) })
} else {
r.ch[channel].tep.write(|w| unsafe { w.bits(0) })
}
}
fn set_fork_task(task: Option<&Task>, channel: usize) {
let r = unsafe { &*pac::PPI::ptr() };
if let Some(task) = task {
r.fork[channel]
.tep
.write(|w| unsafe { w.bits(task.0.as_ptr() as u32) })
} else {
r.fork[channel].tep.write(|w| unsafe { w.bits(0) })
}
}
fn set_event(event: Option<&Event>, channel: usize) {
let r = unsafe { &*pac::PPI::ptr() };
if let Some(event) = event {
r.ch[channel]
.eep
.write(|w| unsafe { w.bits(event.0.as_ptr() as u32) })
} else {
r.ch[channel].eep.write(|w| unsafe { w.bits(0) })
}
}
}

View file

@ -31,7 +31,7 @@ pub mod gpio;
pub mod gpiote; pub mod gpiote;
#[cfg(not(feature = "nrf9160"))] #[cfg(not(feature = "nrf9160"))]
pub mod nvmc; pub mod nvmc;
pub mod ppi; pub mod interconnect;
#[cfg(not(any(feature = "nrf52805", feature = "nrf52820")))] #[cfg(not(any(feature = "nrf52805", feature = "nrf52820")))]
pub mod pwm; pub mod pwm;
#[cfg(feature = "nrf52840")] #[cfg(feature = "nrf52840")]

View file

@ -1,513 +0,0 @@
#![macro_use]
//! 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.
use crate::{pac, peripherals};
use core::marker::PhantomData;
use core::ptr::NonNull;
use embassy::util::Unborrow;
use embassy_hal_common::{unborrow, unsafe_impl_unborrow};
// ======================
// driver
/// Error type of the PPI driver
#[non_exhaustive]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
/// There is no capacity to enable this task or event (nRF51 & nRF52 only)
NoCapacityLeft,
/// This task or event is not in use by the current channel
NotInUseByChannel,
/// This task or event is already enabled on another channel (nRF53 & nRF91 only)
AlreadyInUse,
}
pub struct Ppi<'d, C: Channel> {
ch: C,
phantom: PhantomData<&'d mut C>,
}
impl<'d, C: Channel> Ppi<'d, C> {
pub fn new(ch: impl Unborrow<Target = C> + 'd) -> Self {
unborrow!(ch);
Self {
ch,
phantom: PhantomData,
}
}
/// 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()) });
}
}
#[cfg(feature = "_ppi")]
impl<'d, C: Channel> Ppi<'d, C> {
/// Makes it so that the given task is subscribed to this channel
pub fn subscribe(&mut self, task: Task) -> Result<(), Error> {
if self.is_main_task_free() {
self.set_main_task(Some(task));
Ok(())
} else if self.is_fork_task_free() {
self.set_fork_task(Some(task));
Ok(())
} else {
Err(Error::NoCapacityLeft)
}
}
/// Makes it so that the given task is not subscribed to this channel
pub fn unsubscribe(&mut self, task: Task) -> Result<(), Error> {
if self.get_main_task() == Some(task) {
// If there is a fork task, we move that to the main task for consistency
// If there is no fork task, then the main task is set to 0
let fork_task = self.get_fork_task();
self.set_main_task(fork_task);
if self.has_fork_task() {
// The fork task was copied to the main task, so reset the fork task
self.set_fork_task(None);
}
Ok(())
} else if self.get_fork_task() == Some(task) {
// Reset the fork task
self.set_fork_task(None);
Ok(())
} else {
Err(Error::NotInUseByChannel)
}
}
/// Makes it so that the given event is published on this channel
pub fn publish(&mut self, event: Event) -> Result<(), Error> {
if self.is_event_free() {
self.set_event(Some(event));
Ok(())
} else {
Err(Error::NoCapacityLeft)
}
}
/// Makes it so that the given event is not published on this channel
pub fn unpublish(&mut self, event: Event) -> Result<(), Error> {
if self.get_event() == Some(event) {
self.set_event(None);
Ok(())
} else {
Err(Error::NotInUseByChannel)
}
}
fn set_main_task(&mut self, task: Option<Task>) {
let r = unsafe { &*pac::PPI::ptr() };
if let Some(task) = task {
r.ch[self.ch.number()]
.tep
.write(|w| unsafe { w.bits(task.0.as_ptr() as u32) })
} else {
r.ch[self.ch.number()].tep.write(|w| unsafe { w.bits(0) })
}
}
fn get_main_task(&mut self) -> Option<Task> {
let r = unsafe { &*pac::PPI::ptr() };
if !self.has_main_task() {
return None;
}
let bits = r.ch[self.ch.number()].tep.read().tep().bits();
if bits == 0 {
None
} else {
unsafe { Some(Task(NonNull::new_unchecked(bits as *mut _))) }
}
}
fn set_fork_task(&mut self, task: Option<Task>) {
let r = unsafe { &*pac::PPI::ptr() };
if let Some(task) = task {
r.fork[self.ch.number()]
.tep
.write(|w| unsafe { w.bits(task.0.as_ptr() as u32) })
} else {
r.fork[self.ch.number()].tep.write(|w| unsafe { w.bits(0) })
}
}
fn get_fork_task(&mut self) -> Option<Task> {
let r = unsafe { &*pac::PPI::ptr() };
if !self.has_fork_task() {
return None;
}
let bits = r.fork[self.ch.number()].tep.read().tep().bits();
if bits == 0 {
None
} else {
unsafe { Some(Task(NonNull::new_unchecked(bits as *mut _))) }
}
}
fn has_main_task(&self) -> bool {
match (self.ch.task_capacity(), self.ch.event_capacity()) {
(0, 0) => false, // Static task
(1, 0) => false, // Static task with fork
(1 | 2, 1) => true, // Configurable task with possibly a fork
_ => unreachable!(), // Every PPI config is covered
}
}
fn has_fork_task(&self) -> bool {
match (self.ch.task_capacity(), self.ch.event_capacity()) {
(0, 0) => false, // Static task
(1, 0) => true, // Static task with fork
(1, 1) => false, // Configurable task without fork
(2, 1) => true, // Configurable task with fork
_ => unreachable!(), // Every PPI config is covered
}
}
fn is_main_task_free(&mut self) -> bool {
self.get_main_task().is_none()
}
fn is_fork_task_free(&mut self) -> bool {
self.get_fork_task().is_none()
}
fn set_event(&mut self, event: Option<Event>) {
let r = unsafe { &*pac::PPI::ptr() };
if let Some(event) = event {
r.ch[self.ch.number()]
.eep
.write(|w| unsafe { w.bits(event.0.as_ptr() as u32) })
} else {
r.ch[self.ch.number()].eep.write(|w| unsafe { w.bits(0) })
}
}
fn get_event(&mut self) -> Option<Event> {
let r = unsafe { &*pac::PPI::ptr() };
if !self.has_event() {
return None;
}
let bits = r.ch[self.ch.number()].eep.read().eep().bits();
if bits == 0 {
None
} else {
unsafe { Some(Event(NonNull::new_unchecked(bits as *mut _))) }
}
}
fn has_event(&self) -> bool {
match (self.ch.task_capacity(), self.ch.event_capacity()) {
(_, 0) => false, // Static event
(_, 1) => true, // Configurable event
_ => unreachable!(), // Every PPI config is covered
}
}
fn is_event_free(&mut self) -> bool {
self.get_event().is_none()
}
}
#[cfg(feature = "_dppi")]
const DPPI_ENABLE_BIT: u32 = 0x8000_0000;
#[cfg(feature = "_dppi")]
const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF;
#[cfg(feature = "_dppi")]
impl<'d, C: Channel> Ppi<'d, C> {
/// Makes it so that the given task is subscribed to this channel
pub fn subscribe(&mut self, task: Task) -> Result<(), Error> {
unsafe {
if Self::is_register_enabled(task.0) {
Err(Error::AlreadyInUse)
} else {
Self::set_register_active(task.0, self.ch.number() as u8);
Ok(())
}
}
}
/// Makes it so that the given task is not subscribed to this channel
pub fn unsubscribe(&mut self, task: Task) -> Result<(), Error> {
unsafe {
if Self::get_register_channel(task.0) != self.ch.number() as u8 {
Err(Error::NotInUseByChannel)
} else {
Self::set_register_inactive(task.0);
Ok(())
}
}
}
/// Makes it so that the given event is published on this channel
pub fn publish(&mut self, event: Event) -> Result<(), Error> {
unsafe {
if Self::is_register_enabled(event.0) {
Err(Error::AlreadyInUse)
} else {
Self::set_register_active(event.0, self.ch.number() as u8);
Ok(())
}
}
}
/// Makes it so that the given event is not published on this channel
pub fn unpublish(&mut self, event: Event) -> Result<(), Error> {
unsafe {
if Self::get_register_channel(event.0) != self.ch.number() as u8 {
Err(Error::NotInUseByChannel)
} else {
Self::set_register_inactive(event.0);
Ok(())
}
}
}
/// Checks if the DPPI_ENABLE_BIT is set in the register
///
/// # Safety
///
/// The register pointer must point at one of the many SUBSCRIBE_* or PUBLISH_* registers of the peripherals
unsafe fn is_register_enabled(register: NonNull<u32>) -> bool {
let bits = register.as_ptr().read_volatile();
bits & DPPI_ENABLE_BIT > 0
}
/// Sets the register to the given channel and enables it
///
/// # Safety
///
/// The register pointer must point at one of the many SUBSCRIBE_* or PUBLISH_* registers of the peripherals
unsafe fn set_register_active(register: NonNull<u32>, channel: u8) {
register
.as_ptr()
.write_volatile(DPPI_ENABLE_BIT | (channel as u32 & DPPI_CHANNEL_MASK));
}
/// Resets the channel number and disables the register
///
/// # Safety
///
/// The register pointer must point at one of the many SUBSCRIBE_* or PUBLISH_* registers of the peripherals
unsafe fn set_register_inactive(register: NonNull<u32>) {
register.as_ptr().write_volatile(0);
}
/// Gets the current configured channel number of the register
///
/// # Safety
///
/// The register pointer must point at one of the many SUBSCRIBE_* or PUBLISH_* registers of the peripherals
unsafe fn get_register_channel(register: NonNull<u32>) -> u8 {
let bits = register.as_ptr().read_volatile();
(bits & DPPI_CHANNEL_MASK) as u8
}
}
impl<'d, C: Channel> Drop for Ppi<'d, C> {
fn drop(&mut self) {
self.disable()
}
}
/// Represents a task that a peripheral can do.
/// When a task is subscribed to a PPI channel it will run when the channel is triggered by
/// a published event.
///
/// The pointer in the task can point to two different kinds of register:
/// - PPI *(nRF51 & nRF52)*: A pointer to a task register of the task of the peripheral that has
/// to be registered with the PPI to subscribe to a channel
/// - DPPI *(nRF53 & nRF91)*: A pointer to the subscribe register of the task of the peripheral
/// that has to have the channel number and enable bit written tp it to subscribe to a channel
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Task(pub NonNull<u32>);
impl Task {
pub(crate) fn from_reg<T>(reg: &T) -> Self {
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
}
}
/// Represents an event that a peripheral can publish.
/// An event can be set to publish on a PPI channel when the event happens.
///
/// The pointer in the event can point to two different kinds of register:
/// - PPI *(nRF51 & nRF52)*: A pointer to an event register of the event of the peripheral that has
/// to be registered with the PPI to publish to a channel
/// - DPPI *(nRF53 & nRF91)*: A pointer to the publish register of the event of the peripheral
/// that has to have the channel number and enable bit written tp it to publish to a channel
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Event(pub NonNull<u32>);
impl Event {
pub(crate) fn from_reg<T>(reg: &T) -> Self {
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
}
}
// ======================
// traits
pub(crate) mod sealed {
pub trait Channel {}
pub trait Group {}
}
pub trait Channel: sealed::Channel + Sized {
/// Returns the number of the channel
fn number(&self) -> usize;
/// Returns the amount of configurable tasks this channel has.
///
/// - MAX for DPPI with unlimited capacity (nRF53 & nRF91)
/// - 0 for static channel without fork (nRF51)
/// - 1 for static channel with fork (nRF52) or for configurable channel (nRF51)
/// - 2 for configurable channel with fork (nRF52)
fn task_capacity(&self) -> usize;
/// Returns the amount of configurable events this channels has
///
/// - MAX for DPPI with unlimited capacity (nRF53 & nRF91)
/// - 0 for static channel (nRF51 & nRF52)
/// - 1 for configurable channel (nRF51 & nRF52)
fn event_capacity(&self) -> usize;
fn degrade(self) -> AnyChannel {
pub trait ConfigurableChannel {}
AnyChannel {
number: self.number() as u8,
task_capacity: self.task_capacity() as _,
event_capacity: self.event_capacity() as _,
}
}
}
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,
task_capacity: u8,
event_capacity: u8,
}
unsafe_impl_unborrow!(AnyChannel);
impl sealed::Channel for AnyChannel {}
impl Channel for AnyChannel {
fn number(&self) -> usize {
self.number as usize
}
fn task_capacity(&self) -> usize {
self.task_capacity as _
}
fn event_capacity(&self) -> usize {
self.event_capacity as _
}
}
macro_rules! impl_ppi_channel {
($type:ident, $number:expr, $task_capacity:expr, $event_capacity:expr) => {
impl crate::ppi::sealed::Channel for peripherals::$type {}
impl crate::ppi::Channel for peripherals::$type {
fn number(&self) -> usize {
$number
}
fn task_capacity(&self) -> usize {
$task_capacity
}
fn event_capacity(&self) -> usize {
$event_capacity
}
}
};
($type:ident, $number:expr) => {
impl crate::ppi::sealed::Channel for peripherals::$type {}
impl crate::ppi::Channel for peripherals::$type {
fn number(&self) -> usize {
$number
}
fn task_capacity(&self) -> usize {
usize::MAX
}
fn event_capacity(&self) -> usize {
usize::MAX
}
}
};
}
// ======================
// groups
pub struct AnyGroup {
number: u8,
}
unsafe_impl_unborrow!(AnyGroup);
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);
#[cfg(not(feature = "nrf51"))]
impl_group!(PPI_GROUP4, 4);
#[cfg(not(feature = "nrf51"))]
impl_group!(PPI_GROUP5, 5);

View file

@ -11,9 +11,8 @@ use embassy_hal_common::drop::OnDrop;
use embassy_hal_common::unborrow; use embassy_hal_common::unborrow;
use futures::future::poll_fn; use futures::future::poll_fn;
use crate::interconnect::{Event, Task};
use crate::pac; use crate::pac;
use crate::ppi::Event;
use crate::ppi::Task;
pub(crate) mod sealed { pub(crate) mod sealed {
@ -184,36 +183,21 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
/// ///
/// When triggered, this task starts the timer. /// When triggered, this task starts the timer.
pub fn task_start(&self) -> Task { pub fn task_start(&self) -> Task {
#[cfg(feature = "_ppi")] Task::from_reg(&T::regs().tasks_start)
let reg = &T::regs().tasks_start;
#[cfg(feature = "_dppi")]
let reg = &T::regs().subscribe_start;
Task::from_reg(reg)
} }
/// Returns the STOP task, for use with PPI. /// Returns the STOP task, for use with PPI.
/// ///
/// When triggered, this task stops the timer. /// When triggered, this task stops the timer.
pub fn task_stop(&self) -> Task { pub fn task_stop(&self) -> Task {
#[cfg(feature = "_ppi")] Task::from_reg(&T::regs().tasks_stop)
let reg = &T::regs().tasks_stop;
#[cfg(feature = "_dppi")]
let reg = &T::regs().subscribe_stop;
Task::from_reg(reg)
} }
/// Returns the CLEAR task, for use with PPI. /// Returns the CLEAR task, for use with PPI.
/// ///
/// When triggered, this task resets the timer's counter to 0. /// When triggered, this task resets the timer's counter to 0.
pub fn task_clear(&self) -> Task { pub fn task_clear(&self) -> Task {
#[cfg(feature = "_ppi")] Task::from_reg(&T::regs().tasks_clear)
let reg = &T::regs().tasks_clear;
#[cfg(feature = "_dppi")]
let reg = &T::regs().subscribe_clear;
Task::from_reg(reg)
} }
/// Change the timer's frequency. /// Change the timer's frequency.
@ -334,24 +318,14 @@ impl<'a, T: Instance, I: TimerType> Cc<'a, T, I> {
/// ///
/// When triggered, this task will capture the current value of the timer's counter in this register. /// When triggered, this task will capture the current value of the timer's counter in this register.
pub fn task_capture(&self) -> Task { pub fn task_capture(&self) -> Task {
#[cfg(feature = "_ppi")] Task::from_reg(&T::regs().tasks_capture)
let reg = &T::regs().tasks_capture;
#[cfg(feature = "_dppi")]
let reg = &T::regs().subscribe_capture;
Task::from_reg(reg)
} }
/// Returns this CC register's COMPARE event, for use with PPI. /// Returns this CC register's COMPARE event, for use with PPI.
/// ///
/// This event will fire when the timer's counter reaches the value in this CC register. /// This event will fire when the timer's counter reaches the value in this CC register.
pub fn event_compare(&self) -> Event { pub fn event_compare(&self) -> Event {
#[cfg(feature = "_ppi")] Event::from_reg(&T::regs().events_compare[self.n])
let reg = &T::regs().events_compare[self.n];
#[cfg(feature = "_dppi")]
let reg = &T::regs().publish_compare[self.n];
Event::from_reg(reg)
} }
/// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. /// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task.

View file

@ -16,28 +16,15 @@ use futures::future::poll_fn;
use crate::chip::EASY_DMA_SIZE; use crate::chip::EASY_DMA_SIZE;
use crate::gpio::sealed::Pin as _; use crate::gpio::sealed::Pin as _;
use crate::gpio::{self, OptionalPin as GpioOptionalPin, Pin as GpioPin}; use crate::gpio::{self, OptionalPin as GpioOptionalPin, Pin as GpioPin};
use crate::interconnect::{AnyChannel, Event, OneToOneChannel, OneToTwoChannel, Ppi, Task};
use crate::interrupt::Interrupt; use crate::interrupt::Interrupt;
use crate::pac; use crate::pac;
use crate::ppi::{AnyChannel, Channel, Event, Ppi, Task};
use crate::timer::Instance as TimerInstance; use crate::timer::Instance as TimerInstance;
use crate::timer::{Frequency, Timer}; use crate::timer::{Frequency, Timer};
// Re-export SVD variants to allow user to directly set values. // Re-export SVD variants to allow user to directly set values.
pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
#[non_exhaustive]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
PpiError(crate::ppi::Error),
}
impl From<crate::ppi::Error> for Error {
fn from(e: crate::ppi::Error) -> Self {
Self::PpiError(e)
}
}
#[non_exhaustive] #[non_exhaustive]
pub struct Config { pub struct Config {
pub parity: Parity, pub parity: Parity,
@ -344,17 +331,14 @@ impl<'d, T: Instance> Write for Uarte<'d, T> {
pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> { pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> {
uarte: Uarte<'d, U>, uarte: Uarte<'d, U>,
timer: Timer<'d, T>, timer: Timer<'d, T>,
ppi_ch1: Ppi<'d, AnyChannel>, ppi_ch1: Ppi<'d, AnyChannel, 1, 2>,
_ppi_ch2: Ppi<'d, AnyChannel>, _ppi_ch2: Ppi<'d, AnyChannel, 1, 1>,
} }
impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> { impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> {
/// Creates the interface to a UARTE instance. /// Creates the interface to a UARTE instance.
/// Sets the baud rate, parity and assigns the pins to the UARTE peripheral. /// Sets the baud rate, parity and assigns the pins to the UARTE peripheral.
/// ///
/// - *Note:* ppi_ch1 must have at least 1 free event and 2 free tasks or a PPI error is returned
/// - *Note:* ppi_ch2 must have at least 1 free event and 1 free tasks or a PPI error is returned
///
/// # Safety /// # Safety
/// ///
/// The returned API is safe unless you use `mem::forget` (or similar safe mechanisms) /// The returned API is safe unless you use `mem::forget` (or similar safe mechanisms)
@ -364,15 +348,15 @@ impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> {
pub unsafe fn new( pub unsafe fn new(
uarte: impl Unborrow<Target = U> + 'd, uarte: impl Unborrow<Target = U> + 'd,
timer: impl Unborrow<Target = T> + 'd, timer: impl Unborrow<Target = T> + 'd,
ppi_ch1: impl Unborrow<Target = impl Channel> + 'd, ppi_ch1: impl Unborrow<Target = impl OneToTwoChannel + 'd> + 'd,
ppi_ch2: impl Unborrow<Target = impl Channel> + 'd, ppi_ch2: impl Unborrow<Target = impl OneToOneChannel + 'd> + 'd,
irq: impl Unborrow<Target = U::Interrupt> + 'd, irq: impl Unborrow<Target = U::Interrupt> + 'd,
rxd: impl Unborrow<Target = impl GpioPin> + 'd, rxd: impl Unborrow<Target = impl GpioPin> + 'd,
txd: impl Unborrow<Target = impl GpioPin> + 'd, txd: impl Unborrow<Target = impl GpioPin> + 'd,
cts: impl Unborrow<Target = impl GpioOptionalPin> + 'd, cts: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
rts: impl Unborrow<Target = impl GpioOptionalPin> + 'd, rts: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
config: Config, config: Config,
) -> Result<Self, Error> { ) -> Self {
let baudrate = config.baudrate; let baudrate = config.baudrate;
let uarte = Uarte::new(uarte, irq, rxd, txd, cts, rts, config); let uarte = Uarte::new(uarte, irq, rxd, txd, cts, rts, config);
let mut timer = Timer::new(timer); let mut timer = Timer::new(timer);
@ -394,23 +378,29 @@ impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> {
timer.cc(0).short_compare_clear(); timer.cc(0).short_compare_clear();
timer.cc(0).short_compare_stop(); timer.cc(0).short_compare_stop();
let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade()); let mut ppi_ch1 = Ppi::new_one_to_two(
ppi_ch1.publish(Event::from_reg(&r.events_rxdrdy))?; ppi_ch1,
ppi_ch1.subscribe(timer.task_clear())?; Event::from_reg(&r.events_rxdrdy),
ppi_ch1.subscribe(timer.task_start())?; timer.task_clear(),
timer.task_start(),
)
.degrade();
ppi_ch1.enable(); ppi_ch1.enable();
let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade()); let mut ppi_ch2 = Ppi::new_one_to_one(
ppi_ch2.publish(timer.cc(0).event_compare())?; ppi_ch2,
ppi_ch2.subscribe(Task::from_reg(&r.tasks_stoprx))?; timer.cc(0).event_compare(),
Task::from_reg(&r.tasks_stoprx),
)
.degrade();
ppi_ch2.enable(); ppi_ch2.enable();
Ok(Self { Self {
uarte, uarte,
timer, timer,
ppi_ch1: ppi_ch1, ppi_ch1: ppi_ch1,
_ppi_ch2: ppi_ch2, _ppi_ch2: ppi_ch2,
}) }
} }
} }

View file

@ -26,7 +26,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
let irq = interrupt::take!(UARTE0_UART0); let irq = interrupt::take!(UARTE0_UART0);
let mut state = State::new(); let mut state = State::new();
let u = unsafe { let u = unsafe {
unwrap!(BufferedUarte::new( BufferedUarte::new(
&mut state, &mut state,
p.UARTE0, p.UARTE0,
p.TIMER0, p.TIMER0,
@ -40,7 +40,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
config, config,
&mut rx_buffer, &mut rx_buffer,
&mut tx_buffer, &mut tx_buffer,
)) )
}; };
pin_mut!(u); pin_mut!(u);

View file

@ -10,7 +10,7 @@ use core::future::pending;
use embassy::executor::Spawner; use embassy::executor::Spawner;
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity};
use embassy_nrf::ppi::Ppi; use embassy_nrf::interconnect::Ppi;
use embassy_nrf::Peripherals; use embassy_nrf::Peripherals;
use gpiote::{OutputChannel, OutputChannelPolarity}; use gpiote::{OutputChannel, OutputChannelPolarity};
@ -51,25 +51,21 @@ async fn main(_spawner: Spawner, p: Peripherals) {
OutputChannelPolarity::Toggle, OutputChannelPolarity::Toggle,
); );
let mut ppi = Ppi::new(p.PPI_CH0); let mut ppi = Ppi::new_one_to_one(p.PPI_CH0, button1.event_in(), led1.task_out());
ppi.publish(button1.event_in()).unwrap();
ppi.subscribe(led1.task_out()).unwrap();
ppi.enable(); ppi.enable();
let mut ppi = Ppi::new(p.PPI_CH1); let mut ppi = Ppi::new_one_to_one(p.PPI_CH1, button2.event_in(), led1.task_clr());
ppi.publish(button2.event_in()).unwrap();
ppi.subscribe(led1.task_clr()).unwrap();
ppi.enable(); ppi.enable();
let mut ppi = Ppi::new(p.PPI_CH2); let mut ppi = Ppi::new_one_to_one(p.PPI_CH2, button3.event_in(), led1.task_set());
ppi.publish(button3.event_in()).unwrap();
ppi.subscribe(led1.task_set()).unwrap();
ppi.enable(); ppi.enable();
let mut ppi = Ppi::new(p.PPI_CH3); let mut ppi = Ppi::new_one_to_two(
ppi.publish(button4.event_in()).unwrap(); p.PPI_CH3,
ppi.subscribe(led1.task_out()).unwrap(); button4.event_in(),
ppi.subscribe(led2.task_out()).unwrap(); led1.task_out(),
led2.task_out(),
);
ppi.enable(); ppi.enable();
info!("PPI setup!"); info!("PPI setup!");

View file

@ -21,9 +21,9 @@ async fn main(_spawner: Spawner, p: Peripherals) {
let irq = interrupt::take!(UARTE0_UART0); let irq = interrupt::take!(UARTE0_UART0);
let mut uart = unsafe { let mut uart = unsafe {
unwrap!(uarte::UarteWithIdle::new( uarte::UarteWithIdle::new(
p.UARTE0, p.TIMER0, p.PPI_CH0, p.PPI_CH1, irq, p.P0_08, p.P0_06, NoPin, NoPin, config, p.UARTE0, p.TIMER0, p.PPI_CH0, p.PPI_CH1, irq, p.P0_08, p.P0_06, NoPin, NoPin, config,
)) )
}; };
info!("uarte initialized!"); info!("uarte initialized!");