diff --git a/embassy-hal-common/src/peripheral.rs b/embassy-hal-common/src/peripheral.rs index 99df4b894..038cebb5e 100644 --- a/embassy-hal-common/src/peripheral.rs +++ b/embassy-hal-common/src/peripheral.rs @@ -27,6 +27,36 @@ impl<'a, T> PeripheralRef<'a, T> { } } + /// Unsafely clone (duplicate) a peripheral singleton. + /// + /// # Safety + /// + /// This returns an owned clone of the peripheral. You must manually ensure + /// only one copy of the peripheral is in use at a time. For example, don't + /// create two SPI drivers on `SPI1`, because they will "fight" each other. + /// + /// You should strongly prefer using `reborrow()` instead. It returns a + /// `PeripheralRef` that borrows `self`, which allows the borrow checker + /// to enforce this at compile time. + pub unsafe fn clone_unchecked(&mut self) -> PeripheralRef<'a, T> + where + T: Peripheral
, + { + PeripheralRef::new(self.inner.clone_unchecked()) + } + + /// Reborrow into a "child" PeripheralRef. + /// + /// `self` will stay borrowed until the child PeripheralRef is dropped. + pub fn reborrow(&mut self) -> PeripheralRef<'_, T> + where + T: Peripheral
, + { + // safety: we're returning the clone inside a new PeripheralRef that borrows + // self, so user code can't use both at the same time. + PeripheralRef::new(unsafe { self.inner.clone_unchecked() }) + } + /// Map the inner peripheral using `Into`. /// /// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`, using an diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 036af3804..89c1ba908 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -15,14 +15,13 @@ use core::cmp::min; use core::future::Future; -use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy::waitqueue::WakerRegistration; use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; use embassy_hal_common::ring_buffer::RingBuffer; -use embassy_hal_common::{into_ref, low_power_wait_until}; +use embassy_hal_common::{into_ref, low_power_wait_until, PeripheralRef}; use futures::future::poll_fn; // 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}; @@ -54,7 +53,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> State<'d, U, T> { } struct StateInner<'d, U: UarteInstance, T: TimerInstance> { - phantom: PhantomData<&'d mut U>, + _peri: PeripheralRef<'d, U>, timer: Timer<'d, T>, _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>, _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>, @@ -78,7 +77,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> { impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { pub fn new( state: &'d mut State<'d, U, T>, - _uarte: impl Peripheral
+ 'd, + peri: impl Peripheral
+ 'd, timer: impl Peripheral
+ 'd, ppi_ch1: impl Peripheral
+ 'd, ppi_ch2: impl Peripheral
+ 'd, @@ -91,7 +90,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { rx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8], ) -> Self { - into_ref!(ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts); + into_ref!(peri, ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts); let r = U::regs(); @@ -163,7 +162,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { Self { inner: PeripheralMutex::new(irq, &mut state.0, move || StateInner { - phantom: PhantomData, + _peri: peri, timer, _ppi_ch1: ppi_ch1, _ppi_ch2: ppi_ch2, diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index e89d01685..cef80ae0a 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -1,10 +1,9 @@ use core::convert::Infallible; use core::future::Future; -use core::marker::PhantomData; use core::task::{Context, Poll}; use embassy::waitqueue::AtomicWaker; -use embassy_hal_common::impl_peripheral; +use embassy_hal_common::{impl_peripheral, Peripheral, PeripheralRef}; use futures::future::poll_fn; use crate::gpio::sealed::Pin as _; @@ -301,16 +300,22 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { // ======================= pub(crate) struct PortInputFuture<'a> { - pin_port: u8, - phantom: PhantomData<&'a mut AnyPin>, + pin: PeripheralRef<'a, AnyPin>, +} + +impl<'a> PortInputFuture<'a> { + fn new(pin: impl Peripheral
+ 'a) -> Self {
+ Self {
+ pin: pin.into_ref().map_into(),
+ }
+ }
}
impl<'a> Unpin for PortInputFuture<'a> {}
impl<'a> Drop for PortInputFuture<'a> {
fn drop(&mut self) {
- let pin = unsafe { AnyPin::steal(self.pin_port) };
- pin.conf().modify(|_, w| w.sense().disabled());
+ self.pin.conf().modify(|_, w| w.sense().disabled());
}
}
@@ -318,10 +323,9 @@ impl<'a> Future for PortInputFuture<'a> {
type Output = ();
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll + 'd) -> Self {
into_ref!(_p);
-
- Self { _p: PhantomData }
+ Self { _p }
}
fn regs() -> &'static pac::nvmc::RegisterBlock {
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index ecc674ce0..5f750a91e 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -1,6 +1,5 @@
#![macro_use]
-use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use embassy_hal_common::{into_ref, PeripheralRef};
@@ -15,7 +14,7 @@ use crate::{pac, Peripheral};
/// SimplePwm is the traditional pwm interface you're probably used to, allowing
/// to simply set a duty cycle across up to four channels.
pub struct SimplePwm<'d, T: Instance> {
- phantom: PhantomData<&'d mut T>,
+ _peri: PeripheralRef<'d, T>,
duty: [u16; 4],
ch0: Option + 'd,
+ p: impl Peripheral + 'd,
irq: impl Peripheral + 'd,
a: PeripheralRef<'d, AnyPin>,
b: PeripheralRef<'d, AnyPin>,
led: Option + 'd) -> Self {
@@ -132,9 +80,8 @@ impl<'d> ChannelConfig<'d> {
gain: Gain::GAIN1_6,
resistor: Resistor::BYPASS,
time: Time::_10US,
- p_channel: input.channel(),
+ p_channel: input.map_into(),
n_channel: None,
- phantom: PhantomData,
}
}
/// Default configuration for differential channel sampling.
@@ -148,9 +95,8 @@ impl<'d> ChannelConfig<'d> {
gain: Gain::GAIN1_6,
resistor: Resistor::BYPASS,
time: Time::_10US,
- p_channel: p_input.channel(),
- n_channel: Some(n_input.channel()),
- phantom: PhantomData,
+ p_channel: p_input.map_into(),
+ n_channel: Some(n_input.map_into()),
}
}
}
@@ -167,12 +113,12 @@ pub enum SamplerState {
impl<'d, const N: usize> Saadc<'d, N> {
pub fn new(
- _saadc: impl Peripheral + 'd,
+ saadc: impl Peripheral + 'd,
irq: impl Peripheral + 'd,
config: Config,
channel_configs: [ChannelConfig; N],
) -> Self {
- into_ref!(irq);
+ into_ref!(saadc, irq);
let r = unsafe { &*SAADC::ptr() };
@@ -184,9 +130,11 @@ impl<'d, const N: usize> Saadc<'d, N> {
r.oversample.write(|w| w.oversample().variant(oversample.into()));
for (i, cc) in channel_configs.iter().enumerate() {
- r.ch[i].pselp.write(|w| w.pselp().variant(cc.p_channel));
- if let Some(n_channel) = cc.n_channel {
- r.ch[i].pseln.write(|w| unsafe { w.pseln().bits(n_channel as u8) });
+ r.ch[i].pselp.write(|w| w.pselp().variant(cc.p_channel.channel()));
+ if let Some(n_channel) = &cc.n_channel {
+ r.ch[i]
+ .pseln
+ .write(|w| unsafe { w.pseln().bits(n_channel.channel() as u8) });
}
r.ch[i].config.write(|w| {
w.refsel().variant(cc.reference.into());
@@ -215,7 +163,7 @@ impl<'d, const N: usize> Saadc<'d, N> {
irq.unpend();
irq.enable();
- Self { phantom: PhantomData }
+ Self { _p: saadc }
}
fn on_interrupt(_ctx: *mut ()) {
@@ -674,7 +622,7 @@ pub(crate) mod sealed {
}
/// An input that can be used as either or negative end of a ADC differential in the SAADC periperhal.
-pub trait Input: sealed::Input + Peripheral + Sized {
+pub trait Input: sealed::Input + Into + Sized + 'static {
fn degrade_saadc(self) -> AnyInput {
AnyInput {
channel: self.channel(),
@@ -682,13 +630,57 @@ pub trait Input: sealed::Input + Peripheral + Sized {
}
}
+pub struct AnyInput {
+ channel: InputChannel,
+}
+
+impl_peripheral!(AnyInput);
+
+impl sealed::Input for AnyInput {
+ fn channel(&self) -> InputChannel {
+ self.channel
+ }
+}
+
+impl Input for AnyInput {}
+
macro_rules! impl_saadc_input {
($pin:ident, $ch:ident) => {
- impl crate::saadc::sealed::Input for crate::peripherals::$pin {
+ impl_saadc_input!(@local, crate::peripherals::$pin, $ch);
+ };
+ (@local, $pin:ty, $ch:ident) => {
+ impl crate::saadc::sealed::Input for $pin {
fn channel(&self) -> crate::saadc::InputChannel {
crate::saadc::InputChannel::$ch
}
}
- impl crate::saadc::Input for crate::peripherals::$pin {}
+ impl crate::saadc::Input for $pin {}
+
+ impl From<$pin> for crate::saadc::AnyInput {
+ fn from(val: $pin) -> Self {
+ crate::saadc::Input::degrade_saadc(val)
+ }
+ }
};
}
+
+/// A dummy `Input` pin implementation for SAADC peripheral sampling from the
+/// internal voltage.
+pub struct VddInput;
+
+impl_peripheral!(VddInput);
+#[cfg(not(feature = "_nrf9160"))]
+impl_saadc_input!(@local, VddInput, VDD);
+#[cfg(feature = "_nrf9160")]
+impl_saadc_input!(@local, VddInput, VDDGPIO);
+
+/// A dummy `Input` pin implementation for SAADC peripheral sampling from the
+/// VDDH / 5 voltage.
+#[cfg(any(feature = "_nrf5340-app", feature = "nrf52833", feature = "nrf52840"))]
+pub struct VddhDiv5Input;
+
+#[cfg(any(feature = "_nrf5340-app", feature = "nrf52833", feature = "nrf52840"))]
+impl_peripheral!(VddhDiv5Input);
+
+#[cfg(any(feature = "_nrf5340-app", feature = "nrf52833", feature = "nrf52840"))]
+impl_saadc_input!(@local, VddhDiv5Input, VDDHDIV5);
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index a6b0be076..a512b4813 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -1,6 +1,5 @@
#![macro_use]
-use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
@@ -31,7 +30,7 @@ pub enum Error {
///
/// For more details about EasyDMA, consult the module documentation.
pub struct Spim<'d, T: Instance> {
- phantom: PhantomData<&'d mut T>,
+ _p: PeripheralRef<'d, T>,
}
#[non_exhaustive]
@@ -94,14 +93,14 @@ impl<'d, T: Instance> Spim<'d, T> {
}
fn new_inner(
- _spim: impl Peripheral + 'd,
+ spim: impl Peripheral + 'd,
irq: impl Peripheral + 'd,
sck: PeripheralRef<'d, AnyPin>,
miso: Option + 'd) -> Self {
+ fn new_irqless(timer: impl Peripheral + 'd) -> Self {
+ into_ref!(timer);
+
let regs = T::regs();
- let mut this = Self { phantom: PhantomData };
+ let mut this = Self {
+ _p: timer,
+ _i: PhantomData,
+ };
// Stop the timer before doing anything else,
// since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
@@ -230,7 +236,8 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
}
Cc {
n,
- phantom: PhantomData,
+ _p: self._p.reborrow(),
+ _i: PhantomData,
}
}
}
@@ -242,12 +249,13 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
///
/// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register.
/// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register
-pub struct Cc<'a, T: Instance, I: TimerType = NotAwaitable> {
+pub struct Cc<'d, T: Instance, I: TimerType = NotAwaitable> {
n: usize,
- phantom: PhantomData<(&'a mut T, I)>,
+ _p: PeripheralRef<'d, T>,
+ _i: PhantomData,
}
-impl<'a, T: Instance> Cc<'a, T, Awaitable> {
+impl<'d, T: Instance> Cc<'d, T, Awaitable> {
/// Wait until the timer's counter reaches the value stored in this register.
///
/// This requires a mutable reference so that this task's waker cannot be overwritten by a second call to `wait`.
@@ -281,9 +289,9 @@ impl<'a, T: Instance> Cc<'a, T, Awaitable> {
on_drop.defuse();
}
}
-impl<'a, T: Instance> Cc<'a, T, NotAwaitable> {}
+impl<'d, T: Instance> Cc<'d, T, NotAwaitable> {}
-impl<'a, T: Instance, I: TimerType> Cc<'a, T, I> {
+impl<'d, T: Instance, I: TimerType> Cc<'d, T, I> {
/// Get the current value stored in the register.
pub fn read(&self) -> u32 {
T::regs().cc[self.n].read().cc().bits()
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index 7699d2a71..6d6eb84e7 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -7,7 +7,6 @@
//! - nRF52832: Section 33
//! - nRF52840: Section 6.31
use core::future::Future;
-use core::marker::PhantomData;
use core::sync::atomic::compiler_fence;
use core::sync::atomic::Ordering::SeqCst;
use core::task::Poll;
@@ -16,7 +15,7 @@ use core::task::Poll;
use embassy::time::{Duration, Instant};
use embassy::waitqueue::AtomicWaker;
use embassy_embedded_hal::SetConfig;
-use embassy_hal_common::into_ref;
+use embassy_hal_common::{into_ref, PeripheralRef};
use futures::future::poll_fn;
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
@@ -75,18 +74,18 @@ pub enum Error {
///
/// For more details about EasyDMA, consult the module documentation.
pub struct Twim<'d, T: Instance> {
- phantom: PhantomData<&'d mut T>,
+ _p: PeripheralRef<'d, T>,
}
impl<'d, T: Instance> Twim<'d, T> {
pub fn new(
- _twim: impl Peripheral + 'd,
+ twim: impl Peripheral + 'd,
irq: impl Peripheral + 'd,
sda: impl Peripheral + 'd,
scl: impl Peripheral + 'd,
config: Config,
) -> Self {
- into_ref!(irq, sda, scl);
+ into_ref!(twim, irq, sda, scl);
let r = T::regs();
@@ -136,7 +135,7 @@ impl<'d, T: Instance> Twim<'d, T> {
irq.unpend();
irq.enable();
- Self { phantom: PhantomData }
+ Self { _p: twim }
}
fn on_interrupt(_: *mut ()) {
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index e23525563..792b8ecca 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -13,7 +13,6 @@
//! memory may be used given that buffers are passed in directly to its read and write
//! methods.
-use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
@@ -63,7 +62,6 @@ pub enum Error {
///
/// For more details about EasyDMA, consult the module documentation.
pub struct Uarte<'d, T: Instance> {
- phantom: PhantomData<&'d mut T>,
tx: UarteTx<'d, T>,
rx: UarteRx<'d, T>,
}
@@ -71,13 +69,13 @@ pub struct Uarte<'d, T: Instance> {
/// Transmitter interface to the UARTE peripheral obtained
/// via [Uarte]::split.
pub struct UarteTx<'d, T: Instance> {
- phantom: PhantomData<&'d mut T>,
+ _p: PeripheralRef<'d, T>,
}
/// Receiver interface to the UARTE peripheral obtained
/// via [Uarte]::split.
pub struct UarteRx<'d, T: Instance> {
- phantom: PhantomData<&'d mut T>,
+ _p: PeripheralRef<'d, T>,
}
impl<'d, T: Instance> Uarte<'d, T> {
@@ -116,7 +114,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
}
fn new_inner(
- _uarte: impl Peripheral + 'd,
+ uarte: impl Peripheral + 'd,
irq: impl Peripheral + 'd,
rxd: PeripheralRef<'d, AnyPin>,
txd: PeripheralRef<'d, AnyPin>,
@@ -124,7 +122,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
rts: Option + 'd,
+ uarte: impl Peripheral + 'd,
irq: impl Peripheral + 'd,
txd: PeripheralRef<'d, AnyPin>,
cts: Option + 'd,
+ uarte: impl Peripheral + 'd,
irq: impl Peripheral + 'd,
rxd: PeripheralRef<'d, AnyPin>,
rts: Option + 'd, irq: impl Peripheral + 'd, usb_supply: P) -> Self {
- into_ref!(irq);
+ pub fn new(usb: impl Peripheral + 'd, irq: impl Peripheral + 'd, usb_supply: P) -> Self {
+ into_ref!(usb, irq);
irq.set_handler(Self::on_interrupt);
irq.unpend();
irq.enable();
Self {
- phantom: PhantomData,
+ _p: usb,
alloc_in: Allocator::new(),
alloc_out: Allocator::new(),
usb_supply,
@@ -269,15 +269,15 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P>
}))
}
- fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
+ fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
(
Bus {
- phantom: PhantomData,
+ _p: unsafe { self._p.clone_unchecked() },
power_available: false,
usb_supply: self.usb_supply,
},
ControlPipe {
- _phantom: PhantomData,
+ _p: self._p,
max_packet_size: control_max_packet_size,
},
)
@@ -285,7 +285,7 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P>
}
pub struct Bus<'d, T: Instance, P: UsbSupply> {
- phantom: PhantomData<&'d mut T>,
+ _p: PeripheralRef<'d, T>,
power_available: bool,
usb_supply: P,
}
@@ -746,7 +746,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
}
pub struct ControlPipe<'d, T: Instance> {
- _phantom: PhantomData<&'d mut T>,
+ _p: PeripheralRef<'d, T>,
max_packet_size: u16,
}