diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index fc1ec6b01..c083978c3 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -18,18 +18,20 @@ defmt-info = [ ] defmt-warn = [ ] defmt-error = [ ] -nrf52805 = ["nrf52805-pac"] -nrf52810 = ["nrf52810-pac"] -nrf52811 = ["nrf52811-pac"] -nrf52820 = ["nrf52820-pac"] -nrf52832 = ["nrf52832-pac"] -nrf52833 = ["nrf52833-pac"] -nrf52840 = ["nrf52840-pac"] -nrf9160 = ["nrf9160-pac"] +nrf52805 = ["nrf52805-pac", "_ppi"] +nrf52810 = ["nrf52810-pac", "_ppi"] +nrf52811 = ["nrf52811-pac", "_ppi"] +nrf52820 = ["nrf52820-pac", "_ppi"] +nrf52832 = ["nrf52832-pac", "_ppi"] +nrf52833 = ["nrf52833-pac", "_ppi"] +nrf52840 = ["nrf52840-pac", "_ppi"] +nrf9160 = ["nrf9160-pac", "_dppi"] # Features starting with `_` are for internal use only. They're not intended # to be enabled by other crates, and are not covered by semver guarantees. _time-driver = ["embassy/time-tick-32768hz"] +_ppi = [] +_dppi = [] gpiote = [] time-driver-rtc1 = ["_time-driver"] diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index cd08875cd..f7e55e428 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -5,7 +5,7 @@ use core::pin::Pin; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::{Context, Poll}; use embassy::interrupt::InterruptExt; -use embassy::io::{AsyncBufRead, AsyncWrite, Result}; +use embassy::io::{AsyncBufRead, AsyncWrite}; use embassy::util::Unborrow; use embassy::waitqueue::WakerRegistration; use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; @@ -14,15 +14,27 @@ use embassy_hal_common::{low_power_wait_until, unborrow}; use crate::gpio::sealed::Pin as _; use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin}; -use crate::pac; -use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; +use crate::ppi::{AnyChannel, Channel, Event, Ppi, Task}; use crate::timer::Instance as TimerInstance; use crate::timer::{Frequency, Timer}; use crate::uarte::{Config, Instance as UarteInstance}; +use crate::{pac, ppi}; // 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}; +#[non_exhaustive] +#[derive(Clone, Debug)] +pub enum Error { + PpiError(ppi::Error), +} + +impl From for Error { + fn from(e: ppi::Error) -> Self { + Self::PpiError(e) + } +} + #[derive(Copy, Clone, Debug, PartialEq)] enum RxState { Idle, @@ -45,8 +57,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> State<'d, U, T> { struct StateInner<'d, U: UarteInstance, T: TimerInstance> { phantom: PhantomData<&'d mut U>, timer: Timer<'d, T>, - _ppi_ch1: Ppi<'d, AnyConfigurableChannel>, - _ppi_ch2: Ppi<'d, AnyConfigurableChannel>, + _ppi_ch1: Ppi<'d, AnyChannel>, + _ppi_ch2: Ppi<'d, AnyChannel>, rx: RingBuffer<'d>, rx_state: RxState, @@ -66,12 +78,15 @@ impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> { impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { /// 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( state: &'d mut State<'d, U, T>, _uarte: impl Unborrow + 'd, timer: impl Unborrow + 'd, - ppi_ch1: impl Unborrow + 'd, - ppi_ch2: impl Unborrow + 'd, + ppi_ch1: impl Unborrow + 'd, + ppi_ch2: impl Unborrow + 'd, irq: impl Unborrow + 'd, rxd: impl Unborrow + 'd, txd: impl Unborrow + 'd, @@ -80,7 +95,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { config: Config, rx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8], - ) -> Self { + ) -> Result { unborrow!(ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts); let r = U::regs(); @@ -144,18 +159,18 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { timer.cc(0).short_compare_clear(); timer.cc(0).short_compare_stop(); - let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade_configurable()); - ppi_ch1.set_event(Event::from_reg(&r.events_rxdrdy)); - ppi_ch1.set_task(timer.task_clear()); - ppi_ch1.set_fork_task(timer.task_start()); + let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade()); + ppi_ch1.publish(Event::from_reg(&r.events_rxdrdy))?; + ppi_ch1.subscribe(timer.task_clear())?; + ppi_ch1.subscribe(timer.task_start())?; ppi_ch1.enable(); - let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade_configurable()); - ppi_ch2.set_event(timer.cc(0).event_compare()); - ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx)); + let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade()); + ppi_ch2.publish(timer.cc(0).event_compare())?; + ppi_ch2.subscribe(Task::from_reg(&r.tasks_stoprx))?; ppi_ch2.enable(); - Self { + Ok(Self { inner: PeripheralMutex::new_unchecked(irq, &mut state.0, move || StateInner { phantom: PhantomData, timer, @@ -170,7 +185,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { tx_state: TxState::Idle, tx_waker: WakerRegistration::new(), }), - } + }) } pub fn set_baudrate(&mut self, baudrate: Baudrate) { @@ -187,7 +202,10 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { } impl<'d, U: UarteInstance, T: TimerInstance> AsyncBufRead for BufferedUarte<'d, U, T> { - fn poll_fill_buf(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll_fill_buf( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { self.inner.with(|state| { // Conservative compiler fence to prevent optimizations that do not // take in to account actions by DMA. The fence has been placed here, @@ -206,7 +224,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> AsyncBufRead for BufferedUarte<'d, trace!(" empty"); state.rx_waker.register(cx.waker()); - Poll::>::Pending + Poll::>::Pending }) } @@ -224,7 +242,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> AsyncWrite for BufferedUarte<'d, U, mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], - ) -> Poll> { + ) -> Poll> { let poll = self.inner.with(|state| { trace!("poll_write: {:?}", buf.len()); diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index d68697936..03fc5f307 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -167,28 +167,28 @@ impl_pin!(P0_29, 0, 29); impl_pin!(P0_30, 0, 30); impl_pin!(P0_31, 0, 31); -impl_ppi_channel!(PPI_CH0, 0, configurable); -impl_ppi_channel!(PPI_CH1, 1, configurable); -impl_ppi_channel!(PPI_CH2, 2, configurable); -impl_ppi_channel!(PPI_CH3, 3, configurable); -impl_ppi_channel!(PPI_CH4, 4, configurable); -impl_ppi_channel!(PPI_CH5, 5, configurable); -impl_ppi_channel!(PPI_CH6, 6, configurable); -impl_ppi_channel!(PPI_CH7, 7, configurable); -impl_ppi_channel!(PPI_CH8, 8, configurable); -impl_ppi_channel!(PPI_CH9, 9, configurable); -impl_ppi_channel!(PPI_CH20, 20); -impl_ppi_channel!(PPI_CH21, 21); -impl_ppi_channel!(PPI_CH22, 22); -impl_ppi_channel!(PPI_CH23, 23); -impl_ppi_channel!(PPI_CH24, 24); -impl_ppi_channel!(PPI_CH25, 25); -impl_ppi_channel!(PPI_CH26, 26); -impl_ppi_channel!(PPI_CH27, 27); -impl_ppi_channel!(PPI_CH28, 28); -impl_ppi_channel!(PPI_CH29, 29); -impl_ppi_channel!(PPI_CH30, 30); -impl_ppi_channel!(PPI_CH31, 31); +impl_ppi_channel!(PPI_CH0, 0, 2, 1); +impl_ppi_channel!(PPI_CH1, 1, 2, 1); +impl_ppi_channel!(PPI_CH2, 2, 2, 1); +impl_ppi_channel!(PPI_CH3, 3, 2, 1); +impl_ppi_channel!(PPI_CH4, 4, 2, 1); +impl_ppi_channel!(PPI_CH5, 5, 2, 1); +impl_ppi_channel!(PPI_CH6, 6, 2, 1); +impl_ppi_channel!(PPI_CH7, 7, 2, 1); +impl_ppi_channel!(PPI_CH8, 8, 2, 1); +impl_ppi_channel!(PPI_CH9, 9, 2, 1); +impl_ppi_channel!(PPI_CH20, 20, 1, 0); +impl_ppi_channel!(PPI_CH21, 21, 1, 0); +impl_ppi_channel!(PPI_CH22, 22, 1, 0); +impl_ppi_channel!(PPI_CH23, 23, 1, 0); +impl_ppi_channel!(PPI_CH24, 24, 1, 0); +impl_ppi_channel!(PPI_CH25, 25, 1, 0); +impl_ppi_channel!(PPI_CH26, 26, 1, 0); +impl_ppi_channel!(PPI_CH27, 27, 1, 0); +impl_ppi_channel!(PPI_CH28, 28, 1, 0); +impl_ppi_channel!(PPI_CH29, 29, 1, 0); +impl_ppi_channel!(PPI_CH30, 30, 1, 0); +impl_ppi_channel!(PPI_CH31, 31, 1, 0); impl_saadc_input!(P0_04, ANALOGINPUT2); impl_saadc_input!(P0_05, ANALOGINPUT3); diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index c119e7cdb..e317e4c54 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -172,38 +172,38 @@ impl_pin!(P0_29, 0, 29); impl_pin!(P0_30, 0, 30); impl_pin!(P0_31, 0, 31); -impl_ppi_channel!(PPI_CH0, 0, configurable); -impl_ppi_channel!(PPI_CH1, 1, configurable); -impl_ppi_channel!(PPI_CH2, 2, configurable); -impl_ppi_channel!(PPI_CH3, 3, configurable); -impl_ppi_channel!(PPI_CH4, 4, configurable); -impl_ppi_channel!(PPI_CH5, 5, configurable); -impl_ppi_channel!(PPI_CH6, 6, configurable); -impl_ppi_channel!(PPI_CH7, 7, configurable); -impl_ppi_channel!(PPI_CH8, 8, configurable); -impl_ppi_channel!(PPI_CH9, 9, configurable); -impl_ppi_channel!(PPI_CH10, 10, configurable); -impl_ppi_channel!(PPI_CH11, 11, configurable); -impl_ppi_channel!(PPI_CH12, 12, configurable); -impl_ppi_channel!(PPI_CH13, 13, configurable); -impl_ppi_channel!(PPI_CH14, 14, configurable); -impl_ppi_channel!(PPI_CH15, 15, configurable); -impl_ppi_channel!(PPI_CH16, 16, configurable); -impl_ppi_channel!(PPI_CH17, 17, configurable); -impl_ppi_channel!(PPI_CH18, 18, configurable); -impl_ppi_channel!(PPI_CH19, 19, configurable); -impl_ppi_channel!(PPI_CH20, 20); -impl_ppi_channel!(PPI_CH21, 21); -impl_ppi_channel!(PPI_CH22, 22); -impl_ppi_channel!(PPI_CH23, 23); -impl_ppi_channel!(PPI_CH24, 24); -impl_ppi_channel!(PPI_CH25, 25); -impl_ppi_channel!(PPI_CH26, 26); -impl_ppi_channel!(PPI_CH27, 27); -impl_ppi_channel!(PPI_CH28, 28); -impl_ppi_channel!(PPI_CH29, 29); -impl_ppi_channel!(PPI_CH30, 30); -impl_ppi_channel!(PPI_CH31, 31); +impl_ppi_channel!(PPI_CH0, 0, 2, 1); +impl_ppi_channel!(PPI_CH1, 1, 2, 1); +impl_ppi_channel!(PPI_CH2, 2, 2, 1); +impl_ppi_channel!(PPI_CH3, 3, 2, 1); +impl_ppi_channel!(PPI_CH4, 4, 2, 1); +impl_ppi_channel!(PPI_CH5, 5, 2, 1); +impl_ppi_channel!(PPI_CH6, 6, 2, 1); +impl_ppi_channel!(PPI_CH7, 7, 2, 1); +impl_ppi_channel!(PPI_CH8, 8, 2, 1); +impl_ppi_channel!(PPI_CH9, 9, 2, 1); +impl_ppi_channel!(PPI_CH10, 10, 2, 1); +impl_ppi_channel!(PPI_CH11, 11, 2, 1); +impl_ppi_channel!(PPI_CH12, 12, 2, 1); +impl_ppi_channel!(PPI_CH13, 13, 2, 1); +impl_ppi_channel!(PPI_CH14, 14, 2, 1); +impl_ppi_channel!(PPI_CH15, 15, 2, 1); +impl_ppi_channel!(PPI_CH16, 16, 2, 1); +impl_ppi_channel!(PPI_CH17, 17, 2, 1); +impl_ppi_channel!(PPI_CH18, 18, 2, 1); +impl_ppi_channel!(PPI_CH19, 19, 2, 1); +impl_ppi_channel!(PPI_CH20, 20, 1, 0); +impl_ppi_channel!(PPI_CH21, 21, 1, 0); +impl_ppi_channel!(PPI_CH22, 22, 1, 0); +impl_ppi_channel!(PPI_CH23, 23, 1, 0); +impl_ppi_channel!(PPI_CH24, 24, 1, 0); +impl_ppi_channel!(PPI_CH25, 25, 1, 0); +impl_ppi_channel!(PPI_CH26, 26, 1, 0); +impl_ppi_channel!(PPI_CH27, 27, 1, 0); +impl_ppi_channel!(PPI_CH28, 28, 1, 0); +impl_ppi_channel!(PPI_CH29, 29, 1, 0); +impl_ppi_channel!(PPI_CH30, 30, 1, 0); +impl_ppi_channel!(PPI_CH31, 31, 1, 0); impl_saadc_input!(P0_02, ANALOGINPUT0); impl_saadc_input!(P0_03, ANALOGINPUT1); diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 3c9df40fe..748f5f4ba 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -173,38 +173,38 @@ impl_pin!(P0_29, 0, 29); impl_pin!(P0_30, 0, 30); impl_pin!(P0_31, 0, 31); -impl_ppi_channel!(PPI_CH0, 0, configurable); -impl_ppi_channel!(PPI_CH1, 1, configurable); -impl_ppi_channel!(PPI_CH2, 2, configurable); -impl_ppi_channel!(PPI_CH3, 3, configurable); -impl_ppi_channel!(PPI_CH4, 4, configurable); -impl_ppi_channel!(PPI_CH5, 5, configurable); -impl_ppi_channel!(PPI_CH6, 6, configurable); -impl_ppi_channel!(PPI_CH7, 7, configurable); -impl_ppi_channel!(PPI_CH8, 8, configurable); -impl_ppi_channel!(PPI_CH9, 9, configurable); -impl_ppi_channel!(PPI_CH10, 10, configurable); -impl_ppi_channel!(PPI_CH11, 11, configurable); -impl_ppi_channel!(PPI_CH12, 12, configurable); -impl_ppi_channel!(PPI_CH13, 13, configurable); -impl_ppi_channel!(PPI_CH14, 14, configurable); -impl_ppi_channel!(PPI_CH15, 15, configurable); -impl_ppi_channel!(PPI_CH16, 16, configurable); -impl_ppi_channel!(PPI_CH17, 17, configurable); -impl_ppi_channel!(PPI_CH18, 18, configurable); -impl_ppi_channel!(PPI_CH19, 19, configurable); -impl_ppi_channel!(PPI_CH20, 20); -impl_ppi_channel!(PPI_CH21, 21); -impl_ppi_channel!(PPI_CH22, 22); -impl_ppi_channel!(PPI_CH23, 23); -impl_ppi_channel!(PPI_CH24, 24); -impl_ppi_channel!(PPI_CH25, 25); -impl_ppi_channel!(PPI_CH26, 26); -impl_ppi_channel!(PPI_CH27, 27); -impl_ppi_channel!(PPI_CH28, 28); -impl_ppi_channel!(PPI_CH29, 29); -impl_ppi_channel!(PPI_CH30, 30); -impl_ppi_channel!(PPI_CH31, 31); +impl_ppi_channel!(PPI_CH0, 0, 2, 1); +impl_ppi_channel!(PPI_CH1, 1, 2, 1); +impl_ppi_channel!(PPI_CH2, 2, 2, 1); +impl_ppi_channel!(PPI_CH3, 3, 2, 1); +impl_ppi_channel!(PPI_CH4, 4, 2, 1); +impl_ppi_channel!(PPI_CH5, 5, 2, 1); +impl_ppi_channel!(PPI_CH6, 6, 2, 1); +impl_ppi_channel!(PPI_CH7, 7, 2, 1); +impl_ppi_channel!(PPI_CH8, 8, 2, 1); +impl_ppi_channel!(PPI_CH9, 9, 2, 1); +impl_ppi_channel!(PPI_CH10, 10, 2, 1); +impl_ppi_channel!(PPI_CH11, 11, 2, 1); +impl_ppi_channel!(PPI_CH12, 12, 2, 1); +impl_ppi_channel!(PPI_CH13, 13, 2, 1); +impl_ppi_channel!(PPI_CH14, 14, 2, 1); +impl_ppi_channel!(PPI_CH15, 15, 2, 1); +impl_ppi_channel!(PPI_CH16, 16, 2, 1); +impl_ppi_channel!(PPI_CH17, 17, 2, 1); +impl_ppi_channel!(PPI_CH18, 18, 2, 1); +impl_ppi_channel!(PPI_CH19, 19, 2, 1); +impl_ppi_channel!(PPI_CH20, 20, 1, 0); +impl_ppi_channel!(PPI_CH21, 21, 1, 0); +impl_ppi_channel!(PPI_CH22, 22, 1, 0); +impl_ppi_channel!(PPI_CH23, 23, 1, 0); +impl_ppi_channel!(PPI_CH24, 24, 1, 0); +impl_ppi_channel!(PPI_CH25, 25, 1, 0); +impl_ppi_channel!(PPI_CH26, 26, 1, 0); +impl_ppi_channel!(PPI_CH27, 27, 1, 0); +impl_ppi_channel!(PPI_CH28, 28, 1, 0); +impl_ppi_channel!(PPI_CH29, 29, 1, 0); +impl_ppi_channel!(PPI_CH30, 30, 1, 0); +impl_ppi_channel!(PPI_CH31, 31, 1, 0); impl_saadc_input!(P0_02, ANALOGINPUT0); impl_saadc_input!(P0_03, ANALOGINPUT1); diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 8a8e23a9e..02d2c6103 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -168,38 +168,38 @@ impl_pin!(P0_29, 0, 29); impl_pin!(P0_30, 0, 30); impl_pin!(P0_31, 0, 31); -impl_ppi_channel!(PPI_CH0, 0, configurable); -impl_ppi_channel!(PPI_CH1, 1, configurable); -impl_ppi_channel!(PPI_CH2, 2, configurable); -impl_ppi_channel!(PPI_CH3, 3, configurable); -impl_ppi_channel!(PPI_CH4, 4, configurable); -impl_ppi_channel!(PPI_CH5, 5, configurable); -impl_ppi_channel!(PPI_CH6, 6, configurable); -impl_ppi_channel!(PPI_CH7, 7, configurable); -impl_ppi_channel!(PPI_CH8, 8, configurable); -impl_ppi_channel!(PPI_CH9, 9, configurable); -impl_ppi_channel!(PPI_CH10, 10, configurable); -impl_ppi_channel!(PPI_CH11, 11, configurable); -impl_ppi_channel!(PPI_CH12, 12, configurable); -impl_ppi_channel!(PPI_CH13, 13, configurable); -impl_ppi_channel!(PPI_CH14, 14, configurable); -impl_ppi_channel!(PPI_CH15, 15, configurable); -impl_ppi_channel!(PPI_CH16, 16, configurable); -impl_ppi_channel!(PPI_CH17, 17, configurable); -impl_ppi_channel!(PPI_CH18, 18, configurable); -impl_ppi_channel!(PPI_CH19, 19, configurable); -impl_ppi_channel!(PPI_CH20, 20); -impl_ppi_channel!(PPI_CH21, 21); -impl_ppi_channel!(PPI_CH22, 22); -impl_ppi_channel!(PPI_CH23, 23); -impl_ppi_channel!(PPI_CH24, 24); -impl_ppi_channel!(PPI_CH25, 25); -impl_ppi_channel!(PPI_CH26, 26); -impl_ppi_channel!(PPI_CH27, 27); -impl_ppi_channel!(PPI_CH28, 28); -impl_ppi_channel!(PPI_CH29, 29); -impl_ppi_channel!(PPI_CH30, 30); -impl_ppi_channel!(PPI_CH31, 31); +impl_ppi_channel!(PPI_CH0, 0, 2, 1); +impl_ppi_channel!(PPI_CH1, 1, 2, 1); +impl_ppi_channel!(PPI_CH2, 2, 2, 1); +impl_ppi_channel!(PPI_CH3, 3, 2, 1); +impl_ppi_channel!(PPI_CH4, 4, 2, 1); +impl_ppi_channel!(PPI_CH5, 5, 2, 1); +impl_ppi_channel!(PPI_CH6, 6, 2, 1); +impl_ppi_channel!(PPI_CH7, 7, 2, 1); +impl_ppi_channel!(PPI_CH8, 8, 2, 1); +impl_ppi_channel!(PPI_CH9, 9, 2, 1); +impl_ppi_channel!(PPI_CH10, 10, 2, 1); +impl_ppi_channel!(PPI_CH11, 11, 2, 1); +impl_ppi_channel!(PPI_CH12, 12, 2, 1); +impl_ppi_channel!(PPI_CH13, 13, 2, 1); +impl_ppi_channel!(PPI_CH14, 14, 2, 1); +impl_ppi_channel!(PPI_CH15, 15, 2, 1); +impl_ppi_channel!(PPI_CH16, 16, 2, 1); +impl_ppi_channel!(PPI_CH17, 17, 2, 1); +impl_ppi_channel!(PPI_CH18, 18, 2, 1); +impl_ppi_channel!(PPI_CH19, 19, 2, 1); +impl_ppi_channel!(PPI_CH20, 20, 1, 0); +impl_ppi_channel!(PPI_CH21, 21, 1, 0); +impl_ppi_channel!(PPI_CH22, 22, 1, 0); +impl_ppi_channel!(PPI_CH23, 23, 1, 0); +impl_ppi_channel!(PPI_CH24, 24, 1, 0); +impl_ppi_channel!(PPI_CH25, 25, 1, 0); +impl_ppi_channel!(PPI_CH26, 26, 1, 0); +impl_ppi_channel!(PPI_CH27, 27, 1, 0); +impl_ppi_channel!(PPI_CH28, 28, 1, 0); +impl_ppi_channel!(PPI_CH29, 29, 1, 0); +impl_ppi_channel!(PPI_CH30, 30, 1, 0); +impl_ppi_channel!(PPI_CH31, 31, 1, 0); pub mod irqs { use crate::pac::Interrupt as InterruptEnum; diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index c1b02a0bf..611dbbd50 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -190,38 +190,38 @@ impl_pin!(P0_29, 0, 29); impl_pin!(P0_30, 0, 30); impl_pin!(P0_31, 0, 31); -impl_ppi_channel!(PPI_CH0, 0, configurable); -impl_ppi_channel!(PPI_CH1, 1, configurable); -impl_ppi_channel!(PPI_CH2, 2, configurable); -impl_ppi_channel!(PPI_CH3, 3, configurable); -impl_ppi_channel!(PPI_CH4, 4, configurable); -impl_ppi_channel!(PPI_CH5, 5, configurable); -impl_ppi_channel!(PPI_CH6, 6, configurable); -impl_ppi_channel!(PPI_CH7, 7, configurable); -impl_ppi_channel!(PPI_CH8, 8, configurable); -impl_ppi_channel!(PPI_CH9, 9, configurable); -impl_ppi_channel!(PPI_CH10, 10, configurable); -impl_ppi_channel!(PPI_CH11, 11, configurable); -impl_ppi_channel!(PPI_CH12, 12, configurable); -impl_ppi_channel!(PPI_CH13, 13, configurable); -impl_ppi_channel!(PPI_CH14, 14, configurable); -impl_ppi_channel!(PPI_CH15, 15, configurable); -impl_ppi_channel!(PPI_CH16, 16, configurable); -impl_ppi_channel!(PPI_CH17, 17, configurable); -impl_ppi_channel!(PPI_CH18, 18, configurable); -impl_ppi_channel!(PPI_CH19, 19, configurable); -impl_ppi_channel!(PPI_CH20, 20); -impl_ppi_channel!(PPI_CH21, 21); -impl_ppi_channel!(PPI_CH22, 22); -impl_ppi_channel!(PPI_CH23, 23); -impl_ppi_channel!(PPI_CH24, 24); -impl_ppi_channel!(PPI_CH25, 25); -impl_ppi_channel!(PPI_CH26, 26); -impl_ppi_channel!(PPI_CH27, 27); -impl_ppi_channel!(PPI_CH28, 28); -impl_ppi_channel!(PPI_CH29, 29); -impl_ppi_channel!(PPI_CH30, 30); -impl_ppi_channel!(PPI_CH31, 31); +impl_ppi_channel!(PPI_CH0, 0, 2, 1); +impl_ppi_channel!(PPI_CH1, 1, 2, 1); +impl_ppi_channel!(PPI_CH2, 2, 2, 1); +impl_ppi_channel!(PPI_CH3, 3, 2, 1); +impl_ppi_channel!(PPI_CH4, 4, 2, 1); +impl_ppi_channel!(PPI_CH5, 5, 2, 1); +impl_ppi_channel!(PPI_CH6, 6, 2, 1); +impl_ppi_channel!(PPI_CH7, 7, 2, 1); +impl_ppi_channel!(PPI_CH8, 8, 2, 1); +impl_ppi_channel!(PPI_CH9, 9, 2, 1); +impl_ppi_channel!(PPI_CH10, 10, 2, 1); +impl_ppi_channel!(PPI_CH11, 11, 2, 1); +impl_ppi_channel!(PPI_CH12, 12, 2, 1); +impl_ppi_channel!(PPI_CH13, 13, 2, 1); +impl_ppi_channel!(PPI_CH14, 14, 2, 1); +impl_ppi_channel!(PPI_CH15, 15, 2, 1); +impl_ppi_channel!(PPI_CH16, 16, 2, 1); +impl_ppi_channel!(PPI_CH17, 17, 2, 1); +impl_ppi_channel!(PPI_CH18, 18, 2, 1); +impl_ppi_channel!(PPI_CH19, 19, 2, 1); +impl_ppi_channel!(PPI_CH20, 20, 1, 0); +impl_ppi_channel!(PPI_CH21, 21, 1, 0); +impl_ppi_channel!(PPI_CH22, 22, 1, 0); +impl_ppi_channel!(PPI_CH23, 23, 1, 0); +impl_ppi_channel!(PPI_CH24, 24, 1, 0); +impl_ppi_channel!(PPI_CH25, 25, 1, 0); +impl_ppi_channel!(PPI_CH26, 26, 1, 0); +impl_ppi_channel!(PPI_CH27, 27, 1, 0); +impl_ppi_channel!(PPI_CH28, 28, 1, 0); +impl_ppi_channel!(PPI_CH29, 29, 1, 0); +impl_ppi_channel!(PPI_CH30, 30, 1, 0); +impl_ppi_channel!(PPI_CH31, 31, 1, 0); impl_saadc_input!(P0_02, ANALOGINPUT0); impl_saadc_input!(P0_03, ANALOGINPUT1); diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 4f5c26002..6f70f2a47 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -226,38 +226,38 @@ impl_pin!(P1_13, 1, 13); impl_pin!(P1_14, 1, 14); impl_pin!(P1_15, 1, 15); -impl_ppi_channel!(PPI_CH0, 0, configurable); -impl_ppi_channel!(PPI_CH1, 1, configurable); -impl_ppi_channel!(PPI_CH2, 2, configurable); -impl_ppi_channel!(PPI_CH3, 3, configurable); -impl_ppi_channel!(PPI_CH4, 4, configurable); -impl_ppi_channel!(PPI_CH5, 5, configurable); -impl_ppi_channel!(PPI_CH6, 6, configurable); -impl_ppi_channel!(PPI_CH7, 7, configurable); -impl_ppi_channel!(PPI_CH8, 8, configurable); -impl_ppi_channel!(PPI_CH9, 9, configurable); -impl_ppi_channel!(PPI_CH10, 10, configurable); -impl_ppi_channel!(PPI_CH11, 11, configurable); -impl_ppi_channel!(PPI_CH12, 12, configurable); -impl_ppi_channel!(PPI_CH13, 13, configurable); -impl_ppi_channel!(PPI_CH14, 14, configurable); -impl_ppi_channel!(PPI_CH15, 15, configurable); -impl_ppi_channel!(PPI_CH16, 16, configurable); -impl_ppi_channel!(PPI_CH17, 17, configurable); -impl_ppi_channel!(PPI_CH18, 18, configurable); -impl_ppi_channel!(PPI_CH19, 19, configurable); -impl_ppi_channel!(PPI_CH20, 20); -impl_ppi_channel!(PPI_CH21, 21); -impl_ppi_channel!(PPI_CH22, 22); -impl_ppi_channel!(PPI_CH23, 23); -impl_ppi_channel!(PPI_CH24, 24); -impl_ppi_channel!(PPI_CH25, 25); -impl_ppi_channel!(PPI_CH26, 26); -impl_ppi_channel!(PPI_CH27, 27); -impl_ppi_channel!(PPI_CH28, 28); -impl_ppi_channel!(PPI_CH29, 29); -impl_ppi_channel!(PPI_CH30, 30); -impl_ppi_channel!(PPI_CH31, 31); +impl_ppi_channel!(PPI_CH0, 0, 2, 1); +impl_ppi_channel!(PPI_CH1, 1, 2, 1); +impl_ppi_channel!(PPI_CH2, 2, 2, 1); +impl_ppi_channel!(PPI_CH3, 3, 2, 1); +impl_ppi_channel!(PPI_CH4, 4, 2, 1); +impl_ppi_channel!(PPI_CH5, 5, 2, 1); +impl_ppi_channel!(PPI_CH6, 6, 2, 1); +impl_ppi_channel!(PPI_CH7, 7, 2, 1); +impl_ppi_channel!(PPI_CH8, 8, 2, 1); +impl_ppi_channel!(PPI_CH9, 9, 2, 1); +impl_ppi_channel!(PPI_CH10, 10, 2, 1); +impl_ppi_channel!(PPI_CH11, 11, 2, 1); +impl_ppi_channel!(PPI_CH12, 12, 2, 1); +impl_ppi_channel!(PPI_CH13, 13, 2, 1); +impl_ppi_channel!(PPI_CH14, 14, 2, 1); +impl_ppi_channel!(PPI_CH15, 15, 2, 1); +impl_ppi_channel!(PPI_CH16, 16, 2, 1); +impl_ppi_channel!(PPI_CH17, 17, 2, 1); +impl_ppi_channel!(PPI_CH18, 18, 2, 1); +impl_ppi_channel!(PPI_CH19, 19, 2, 1); +impl_ppi_channel!(PPI_CH20, 20, 1, 0); +impl_ppi_channel!(PPI_CH21, 21, 1, 0); +impl_ppi_channel!(PPI_CH22, 22, 1, 0); +impl_ppi_channel!(PPI_CH23, 23, 1, 0); +impl_ppi_channel!(PPI_CH24, 24, 1, 0); +impl_ppi_channel!(PPI_CH25, 25, 1, 0); +impl_ppi_channel!(PPI_CH26, 26, 1, 0); +impl_ppi_channel!(PPI_CH27, 27, 1, 0); +impl_ppi_channel!(PPI_CH28, 28, 1, 0); +impl_ppi_channel!(PPI_CH29, 29, 1, 0); +impl_ppi_channel!(PPI_CH30, 30, 1, 0); +impl_ppi_channel!(PPI_CH31, 31, 1, 0); impl_saadc_input!(P0_02, ANALOGINPUT0); impl_saadc_input!(P0_03, ANALOGINPUT1); diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index 1006acd95..1b9824151 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -231,38 +231,38 @@ impl_pin!(P1_13, 1, 13); impl_pin!(P1_14, 1, 14); impl_pin!(P1_15, 1, 15); -impl_ppi_channel!(PPI_CH0, 0, configurable); -impl_ppi_channel!(PPI_CH1, 1, configurable); -impl_ppi_channel!(PPI_CH2, 2, configurable); -impl_ppi_channel!(PPI_CH3, 3, configurable); -impl_ppi_channel!(PPI_CH4, 4, configurable); -impl_ppi_channel!(PPI_CH5, 5, configurable); -impl_ppi_channel!(PPI_CH6, 6, configurable); -impl_ppi_channel!(PPI_CH7, 7, configurable); -impl_ppi_channel!(PPI_CH8, 8, configurable); -impl_ppi_channel!(PPI_CH9, 9, configurable); -impl_ppi_channel!(PPI_CH10, 10, configurable); -impl_ppi_channel!(PPI_CH11, 11, configurable); -impl_ppi_channel!(PPI_CH12, 12, configurable); -impl_ppi_channel!(PPI_CH13, 13, configurable); -impl_ppi_channel!(PPI_CH14, 14, configurable); -impl_ppi_channel!(PPI_CH15, 15, configurable); -impl_ppi_channel!(PPI_CH16, 16, configurable); -impl_ppi_channel!(PPI_CH17, 17, configurable); -impl_ppi_channel!(PPI_CH18, 18, configurable); -impl_ppi_channel!(PPI_CH19, 19, configurable); -impl_ppi_channel!(PPI_CH20, 20); -impl_ppi_channel!(PPI_CH21, 21); -impl_ppi_channel!(PPI_CH22, 22); -impl_ppi_channel!(PPI_CH23, 23); -impl_ppi_channel!(PPI_CH24, 24); -impl_ppi_channel!(PPI_CH25, 25); -impl_ppi_channel!(PPI_CH26, 26); -impl_ppi_channel!(PPI_CH27, 27); -impl_ppi_channel!(PPI_CH28, 28); -impl_ppi_channel!(PPI_CH29, 29); -impl_ppi_channel!(PPI_CH30, 30); -impl_ppi_channel!(PPI_CH31, 31); +impl_ppi_channel!(PPI_CH0, 0, 2, 1); +impl_ppi_channel!(PPI_CH1, 1, 2, 1); +impl_ppi_channel!(PPI_CH2, 2, 2, 1); +impl_ppi_channel!(PPI_CH3, 3, 2, 1); +impl_ppi_channel!(PPI_CH4, 4, 2, 1); +impl_ppi_channel!(PPI_CH5, 5, 2, 1); +impl_ppi_channel!(PPI_CH6, 6, 2, 1); +impl_ppi_channel!(PPI_CH7, 7, 2, 1); +impl_ppi_channel!(PPI_CH8, 8, 2, 1); +impl_ppi_channel!(PPI_CH9, 9, 2, 1); +impl_ppi_channel!(PPI_CH10, 10, 2, 1); +impl_ppi_channel!(PPI_CH11, 11, 2, 1); +impl_ppi_channel!(PPI_CH12, 12, 2, 1); +impl_ppi_channel!(PPI_CH13, 13, 2, 1); +impl_ppi_channel!(PPI_CH14, 14, 2, 1); +impl_ppi_channel!(PPI_CH15, 15, 2, 1); +impl_ppi_channel!(PPI_CH16, 16, 2, 1); +impl_ppi_channel!(PPI_CH17, 17, 2, 1); +impl_ppi_channel!(PPI_CH18, 18, 2, 1); +impl_ppi_channel!(PPI_CH19, 19, 2, 1); +impl_ppi_channel!(PPI_CH20, 20, 1, 0); +impl_ppi_channel!(PPI_CH21, 21, 1, 0); +impl_ppi_channel!(PPI_CH22, 22, 1, 0); +impl_ppi_channel!(PPI_CH23, 23, 1, 0); +impl_ppi_channel!(PPI_CH24, 24, 1, 0); +impl_ppi_channel!(PPI_CH25, 25, 1, 0); +impl_ppi_channel!(PPI_CH26, 26, 1, 0); +impl_ppi_channel!(PPI_CH27, 27, 1, 0); +impl_ppi_channel!(PPI_CH28, 28, 1, 0); +impl_ppi_channel!(PPI_CH29, 29, 1, 0); +impl_ppi_channel!(PPI_CH30, 30, 1, 0); +impl_ppi_channel!(PPI_CH31, 31, 1, 0); impl_saadc_input!(P0_02, ANALOGINPUT0); impl_saadc_input!(P0_03, ANALOGINPUT1); diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 7ec072ac8..943ff530b 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -190,7 +190,13 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { /// Returns the IN event, for use with PPI. pub fn event_in(&self) -> Event { 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) } } @@ -271,21 +277,33 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { /// Returns the OUT task, for use with PPI. pub fn task_out(&self) -> Task { let g = unsafe { &*pac::GPIOTE::ptr() }; - Task::from_reg(&g.tasks_out[self.ch.number()]) + #[cfg(feature = "_ppi")] + 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. #[cfg(not(feature = "nrf51"))] pub fn task_clr(&self) -> Task { let g = unsafe { &*pac::GPIOTE::ptr() }; - Task::from_reg(&g.tasks_clr[self.ch.number()]) + #[cfg(feature = "_ppi")] + 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. #[cfg(not(feature = "nrf51"))] pub fn task_set(&self) -> Task { let g = unsafe { &*pac::GPIOTE::ptr() }; - Task::from_reg(&g.tasks_set[self.ch.number()]) + #[cfg(feature = "_ppi")] + let reg = &g.tasks_set[self.ch.number()]; + #[cfg(feature = "_dppi")] + let reg = &g.subscribe_set[self.ch.number()]; + Task::from_reg(reg) } } diff --git a/embassy-nrf/src/ppi.rs b/embassy-nrf/src/ppi.rs index f5e06c69f..822663ea2 100644 --- a/embassy-nrf/src/ppi.rs +++ b/embassy-nrf/src/ppi.rs @@ -20,6 +20,16 @@ use embassy_hal_common::{unborrow, unsafe_impl_unborrow}; // ====================== // driver +#[non_exhaustive] +#[derive(Clone, Debug)] +pub enum Error { + NoCapacityLeft, + UnknownTask, + TaskAlreadyInUse, + UnknownEvent, + EventAlreadyInUse, +} + pub struct Ppi<'d, C: Channel> { ch: C, phantom: PhantomData<&'d mut C>, @@ -29,14 +39,10 @@ impl<'d, C: Channel> Ppi<'d, C> { pub fn new(ch: impl Unborrow + 'd) -> Self { unborrow!(ch); - #[allow(unused_mut)] - let mut this = Self { + Self { ch, phantom: PhantomData, - }; - #[cfg(not(any(feature = "nrf51", feature = "nrf9160")))] - this.clear_fork_task(); - this + } } /// Enables the channel. @@ -52,35 +58,279 @@ impl<'d, C: Channel> Ppi<'d, C> { r.chenclr .write(|w| unsafe { w.bits(1 << self.ch.number()) }); } +} - #[cfg(not(any(feature = "nrf51", feature = "nrf9160")))] - /// 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) { +#[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::UnknownTask) + } + } + + /// 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::UnknownEvent) + } + } + + fn set_main_task(&mut self, task: Option) { let r = unsafe { &*pac::PPI::ptr() }; - r.fork[self.ch.number()] - .tep - .write(|w| unsafe { w.bits(task.0.as_ptr() as u32) }) + 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) }) + } } - #[cfg(not(any(feature = "nrf51", feature = "nrf9160")))] - /// Clear the fork task endpoint. Previously set task will no longer be triggered. - pub fn clear_fork_task(&mut self) { + fn get_main_task(&mut self) -> Option { let r = unsafe { &*pac::PPI::ptr() }; - r.fork[self.ch.number()].tep.write(|w| unsafe { w.bits(0) }) + + 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 _))) } + } } - #[cfg(feature = "nrf9160")] - /// 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) { - todo!("Tasks not yet implemented for nrf9160"); + fn set_fork_task(&mut self, task: Option) { + 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) }) + } } - #[cfg(feature = "nrf9160")] - /// Clear the fork task endpoint. Previously set task will no longer be triggered. - pub fn clear_fork_task(&mut self) { - todo!("Tasks not yet implemented for nrf9160"); + fn get_fork_task(&mut self) -> Option { + 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) { + 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 { + 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::TaskAlreadyInUse) + } 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::UnknownTask) + } 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::TaskAlreadyInUse) + } 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::UnknownTask) + } 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) -> 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, 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) { + 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) -> u8 { + let bits = register.as_ptr().read_volatile(); + (bits & DPPI_CHANNEL_MASK) as u8 } } @@ -90,73 +340,59 @@ impl<'d, C: Channel> Drop for Ppi<'d, C> { } } -#[cfg(not(feature = "nrf9160"))] -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) }) +/// 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); +impl Task { + pub(crate) fn from_reg(reg: &T) -> Self { + Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }) } } -#[cfg(feature = "nrf9160")] -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) { - todo!("Tasks not yet implemented for nrf9160") - } - - /// Sets the event that will trigger the chosen task(s). - pub fn set_event(&mut self, _event: Event) { - todo!("Events not yet implemented for nrf9160") +/// 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); +impl Event { + pub(crate) fn from_reg(reg: &T) -> Self { + Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }) } } // ====================== // traits -pub struct Task(pub NonNull<()>); -impl Task { - pub(crate) fn from_reg(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(reg: &T) -> Self { - Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut ()) }) - } -} - pub(crate) mod sealed { - pub trait ConfigurableChannel {} pub trait Channel {} pub trait Group {} } pub trait Channel: sealed::Channel + Sized { fn number(&self) -> usize; + fn task_capacity(&self) -> usize; + fn event_capacity(&self) -> usize; + fn degrade(self) -> AnyChannel { + pub trait ConfigurableChannel {} + AnyChannel { number: self.number() as u8, - } - } -} -pub trait ConfigurableChannel: Channel + sealed::ConfigurableChannel { - fn degrade_configurable(self) -> AnyConfigurableChannel { - AnyConfigurableChannel { - number: self.number() as u8, + task_capacity: self.task_capacity() as _, + event_capacity: self.event_capacity() as _, } } } @@ -175,6 +411,8 @@ pub trait Group: sealed::Group + Sized { pub struct AnyChannel { number: u8, + task_capacity: u8, + event_capacity: u8, } unsafe_impl_unborrow!(AnyChannel); impl sealed::Channel for AnyChannel {} @@ -182,26 +420,30 @@ impl Channel for AnyChannel { fn number(&self) -> usize { self.number as usize } -} -pub struct AnyConfigurableChannel { - number: u8, -} -unsafe_impl_unborrow!(AnyConfigurableChannel); -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 + 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, configurable) => { - impl_ppi_channel!($type, $number); - impl crate::ppi::sealed::ConfigurableChannel for peripherals::$type {} - impl crate::ppi::ConfigurableChannel for peripherals::$type {} + ($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 {} @@ -209,6 +451,12 @@ macro_rules! impl_ppi_channel { fn number(&self) -> usize { $number } + fn task_capacity(&self) -> usize { + usize::MAX + } + fn event_capacity(&self) -> usize { + usize::MAX + } } }; } diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 5690ff0d8..e62120aef 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -184,21 +184,36 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { /// /// When triggered, this task starts the timer. pub fn task_start(&self) -> Task { - Task::from_reg(&T::regs().tasks_start) + #[cfg(feature = "_ppi")] + 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. /// /// When triggered, this task stops the timer. pub fn task_stop(&self) -> Task { - Task::from_reg(&T::regs().tasks_stop) + #[cfg(feature = "_ppi")] + 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. /// /// When triggered, this task resets the timer's counter to 0. pub fn task_clear(&self) -> Task { - Task::from_reg(&T::regs().tasks_clear) + #[cfg(feature = "_ppi")] + let reg = &T::regs().tasks_clear; + #[cfg(feature = "_dppi")] + let reg = &T::regs().subscribe_clear; + + Task::from_reg(reg) } /// Change the timer's frequency. @@ -319,14 +334,24 @@ 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. pub fn task_capture(&self) -> Task { - Task::from_reg(&T::regs().tasks_capture[self.n]) + #[cfg(feature = "_ppi")] + 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. /// /// This event will fire when the timer's counter reaches the value in this CC register. pub fn event_compare(&self) -> Event { - Event::from_reg(&T::regs().events_compare[self.n]) + #[cfg(feature = "_ppi")] + 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. diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 63bbe5a77..f2bf01f1f 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -7,7 +7,7 @@ use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy::interrupt::InterruptExt; -use embassy::traits::uart::{Error, Read, ReadUntilIdle, Write}; +use embassy::traits::uart::{Error as TraitError, Read, ReadUntilIdle, Write}; use embassy::util::Unborrow; use embassy_hal_common::drop::OnDrop; use embassy_hal_common::unborrow; @@ -18,13 +18,25 @@ use crate::gpio::sealed::Pin as _; use crate::gpio::{self, OptionalPin as GpioOptionalPin, Pin as GpioPin}; use crate::interrupt::Interrupt; use crate::pac; -use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; +use crate::ppi::{AnyChannel, Channel, Event, Ppi, Task}; use crate::timer::Instance as TimerInstance; use crate::timer::{Frequency, Timer}; // 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}; +#[non_exhaustive] +#[derive(Clone, Debug)] +pub enum Error { + PpiError(crate::ppi::Error), +} + +impl From for Error { + fn from(e: crate::ppi::Error) -> Self { + Self::PpiError(e) + } +} + #[non_exhaustive] pub struct Config { pub parity: Parity, @@ -219,7 +231,7 @@ impl<'a, T: Instance> Drop for Uarte<'a, T> { impl<'d, T: Instance> Read for Uarte<'d, T> { #[rustfmt::skip] - type ReadFuture<'a> where Self: 'a = impl Future> + 'a; + type ReadFuture<'a> where Self: 'a = impl Future> + 'a; fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { async move { @@ -273,7 +285,7 @@ impl<'d, T: Instance> Read for Uarte<'d, T> { impl<'d, T: Instance> Write for Uarte<'d, T> { #[rustfmt::skip] - type WriteFuture<'a> where Self: 'a = impl Future> + 'a; + type WriteFuture<'a> where Self: 'a = impl Future> + 'a; fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { async move { @@ -331,14 +343,17 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> { uarte: Uarte<'d, U>, timer: Timer<'d, T>, - ppi_ch1: Ppi<'d, AnyConfigurableChannel>, - _ppi_ch2: Ppi<'d, AnyConfigurableChannel>, + ppi_ch1: Ppi<'d, AnyChannel>, + _ppi_ch2: Ppi<'d, AnyChannel>, } impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> { /// Creates the interface to a UARTE instance. /// 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 /// /// The returned API is safe unless you use `mem::forget` (or similar safe mechanisms) @@ -348,15 +363,15 @@ impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> { pub unsafe fn new( uarte: impl Unborrow + 'd, timer: impl Unborrow + 'd, - ppi_ch1: impl Unborrow + 'd, - ppi_ch2: impl Unborrow + 'd, + ppi_ch1: impl Unborrow + 'd, + ppi_ch2: impl Unborrow + 'd, irq: impl Unborrow + 'd, rxd: impl Unborrow + 'd, txd: impl Unborrow + 'd, cts: impl Unborrow + 'd, rts: impl Unborrow + 'd, config: Config, - ) -> Self { + ) -> Result { let baudrate = config.baudrate; let uarte = Uarte::new(uarte, irq, rxd, txd, cts, rts, config); let mut timer = Timer::new(timer); @@ -378,29 +393,29 @@ impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> { timer.cc(0).short_compare_clear(); timer.cc(0).short_compare_stop(); - let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade_configurable()); - ppi_ch1.set_event(Event::from_reg(&r.events_rxdrdy)); - ppi_ch1.set_task(timer.task_clear()); - ppi_ch1.set_fork_task(timer.task_start()); + let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade()); + ppi_ch1.publish(Event::from_reg(&r.events_rxdrdy))?; + ppi_ch1.subscribe(timer.task_clear())?; + ppi_ch1.subscribe(timer.task_start())?; ppi_ch1.enable(); - let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade_configurable()); - ppi_ch2.set_event(timer.cc(0).event_compare()); - ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx)); + let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade()); + ppi_ch2.publish(timer.cc(0).event_compare())?; + ppi_ch2.subscribe(Task::from_reg(&r.tasks_stoprx))?; ppi_ch2.enable(); - Self { + Ok(Self { uarte, timer, ppi_ch1: ppi_ch1, _ppi_ch2: ppi_ch2, - } + }) } } impl<'d, U: Instance, T: TimerInstance> ReadUntilIdle for UarteWithIdle<'d, U, T> { #[rustfmt::skip] - type ReadUntilIdleFuture<'a> where Self: 'a = impl Future> + 'a; + type ReadUntilIdleFuture<'a> where Self: 'a = impl Future> + 'a; fn read_until_idle<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadUntilIdleFuture<'a> { async move { let ptr = rx_buffer.as_ptr(); @@ -460,7 +475,7 @@ impl<'d, U: Instance, T: TimerInstance> ReadUntilIdle for UarteWithIdle<'d, U, T impl<'d, U: Instance, T: TimerInstance> Read for UarteWithIdle<'d, U, T> { #[rustfmt::skip] - type ReadFuture<'a> where Self: 'a = impl Future> + 'a; + type ReadFuture<'a> where Self: 'a = impl Future> + 'a; fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { async move { self.ppi_ch1.disable(); @@ -473,7 +488,7 @@ impl<'d, U: Instance, T: TimerInstance> Read for UarteWithIdle<'d, U, T> { impl<'d, U: Instance, T: TimerInstance> Write for UarteWithIdle<'d, U, T> { #[rustfmt::skip] - type WriteFuture<'a> where Self: 'a = impl Future> + 'a; + type WriteFuture<'a> where Self: 'a = impl Future> + 'a; fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { self.uarte.write(tx_buffer) diff --git a/examples/nrf/src/bin/ppi.rs b/examples/nrf/src/bin/ppi.rs index 6ea03ebd0..550893968 100644 --- a/examples/nrf/src/bin/ppi.rs +++ b/examples/nrf/src/bin/ppi.rs @@ -52,24 +52,24 @@ async fn main(_spawner: Spawner, p: Peripherals) { ); let mut ppi = Ppi::new(p.PPI_CH0); - ppi.set_event(button1.event_in()); - ppi.set_task(led1.task_out()); + ppi.publish(button1.event_in()).unwrap(); + ppi.subscribe(led1.task_out()).unwrap(); ppi.enable(); let mut ppi = Ppi::new(p.PPI_CH1); - ppi.set_event(button2.event_in()); - ppi.set_task(led1.task_clr()); + ppi.publish(button2.event_in()).unwrap(); + ppi.subscribe(led1.task_clr()).unwrap(); ppi.enable(); let mut ppi = Ppi::new(p.PPI_CH2); - ppi.set_event(button3.event_in()); - ppi.set_task(led1.task_set()); + ppi.publish(button3.event_in()).unwrap(); + ppi.subscribe(led1.task_set()).unwrap(); ppi.enable(); let mut ppi = Ppi::new(p.PPI_CH3); - ppi.set_event(button4.event_in()); - ppi.set_task(led1.task_out()); - ppi.set_fork_task(led2.task_out()); + ppi.publish(button4.event_in()).unwrap(); + ppi.subscribe(led1.task_out()).unwrap(); + ppi.subscribe(led2.task_out()).unwrap(); ppi.enable(); info!("PPI setup!");