From 9c4087ac5cc39c0799d25a70834b61899069b7c3 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 19 Mar 2021 04:02:42 +0100 Subject: [PATCH 01/45] Introduce PeripheralBorrow trait --- embassy/src/util/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs index 6917e999..18b61246 100644 --- a/embassy/src/util/mod.rs +++ b/embassy/src/util/mod.rs @@ -14,3 +14,8 @@ pub use mutex::*; pub use portal::*; pub use signal::*; pub use waker::*; + +pub trait PeripheralBorrow { + type Target; + unsafe fn unborrow(self) -> Self::Target; +} From d9aaa0edf88e822b9e5d6deb5f4a133dd32449fa Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 19 Mar 2021 04:02:56 +0100 Subject: [PATCH 02/45] Implement PeripheralBorrow for interrupts. --- embassy-macros/src/lib.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs index 450edbe4..bcf9dd4e 100644 --- a/embassy-macros/src/lib.rs +++ b/embassy-macros/src/lib.rs @@ -137,6 +137,20 @@ pub fn interrupt_declare(item: TokenStream) -> TokenStream { &HANDLER } } + + impl ::embassy::util::PeripheralBorrow for #name_interrupt { + type Target = #name_interrupt; + unsafe fn unborrow(self) -> #name_interrupt { + self + } + } + + impl ::embassy::util::PeripheralBorrow for &mut #name_interrupt { + type Target = #name_interrupt; + unsafe fn unborrow(self) -> #name_interrupt { + ::core::ptr::read(self) + } + } }; result.into() } From fcf6a63b5cf1d1505ec01ea42a1a75f33794b038 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 19 Mar 2021 04:08:44 +0100 Subject: [PATCH 03/45] nrf: add owned Peripherals struct, migrate gpio and spim --- embassy-nrf-examples/src/bin/spim.rs | 18 +- embassy-nrf/src/gpio.rs | 307 +++++++++++++++++++++++++++ embassy-nrf/src/lib.rs | 2 + embassy-nrf/src/peripherals.rs | 144 +++++++++++++ embassy-nrf/src/spim.rs | 88 +++++--- 5 files changed, 516 insertions(+), 43 deletions(-) create mode 100644 embassy-nrf/src/gpio.rs create mode 100644 embassy-nrf/src/peripherals.rs diff --git a/embassy-nrf-examples/src/bin/spim.rs b/embassy-nrf-examples/src/bin/spim.rs index d3d942e4..8eaac5e1 100644 --- a/embassy-nrf-examples/src/bin/spim.rs +++ b/embassy-nrf-examples/src/bin/spim.rs @@ -6,6 +6,8 @@ #[path = "../example_common.rs"] mod example_common; +use embassy_nrf::gpio::{Level, Output}; +use embassy_nrf::peripherals::Peripherals; use embassy_traits::spi::FullDuplex; use example_common::*; @@ -16,7 +18,6 @@ use embassy::util::Forever; use embedded_hal::digital::v2::*; use futures::pin_mut; use nrf52840_hal::clocks; -use nrf52840_hal::gpio; use embassy_nrf::{interrupt, pac, rtc, spim}; @@ -24,25 +25,20 @@ use embassy_nrf::{interrupt, pac, rtc, spim}; async fn run() { info!("running!"); - let p = unsafe { embassy_nrf::pac::Peripherals::steal() }; - let p0 = gpio::p0::Parts::new(p.P0); + let mut p = unsafe { Peripherals::steal() }; - let pins = spim::Pins { - sck: p0.p0_29.into_push_pull_output(gpio::Level::Low).degrade(), - miso: Some(p0.p0_28.into_floating_input().degrade()), - mosi: Some(p0.p0_30.into_push_pull_output(gpio::Level::Low).degrade()), - }; let config = spim::Config { - pins, frequency: spim::Frequency::M16, mode: spim::MODE_0, orc: 0x00, }; - let mut ncs = p0.p0_31.into_push_pull_output(gpio::Level::High); - let spim = spim::Spim::new(p.SPIM3, interrupt::take!(SPIM3), config); + let mut irq = interrupt::take!(SPIM3); + let spim = spim::Spim::new(p.spim3, irq, p.p0_29, p.p0_28, p.p0_30, config); pin_mut!(spim); + let mut ncs = Output::new(p.p0_31, Level::High); + // Example on how to talk to an ENC28J60 chip // softreset diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs new file mode 100644 index 00000000..9f4604b0 --- /dev/null +++ b/embassy-nrf/src/gpio.rs @@ -0,0 +1,307 @@ +use core::convert::Infallible; +use core::hint::unreachable_unchecked; + +use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; + +use crate::pac; +use crate::pac::p0 as gpio; +use crate::peripherals; + +/// Represents a digital input or output level. +#[derive(Debug, Eq, PartialEq)] +pub enum Level { + Low, + High, +} + +/// Represents a pull setting for an input. +#[derive(Debug, Eq, PartialEq)] +pub enum Pull { + None, + Up, + Down, +} + +/// A GPIO port with up to 32 pins. +#[derive(Debug, Eq, PartialEq)] +pub enum Port { + /// Port 0, available on all nRF52 and nRF51 MCUs. + Port0, + + /// Port 1, only available on some nRF52 MCUs. + #[cfg(any(feature = "52833", feature = "52840"))] + Port1, +} + +pub struct Input { + pin: T, +} + +impl Input { + pub fn new(pin: T, pull: Pull) -> Self { + pin.conf().write(|w| { + w.dir().input(); + w.input().connect(); + match pull { + Pull::None => { + w.pull().disabled(); + } + Pull::Up => { + w.pull().pullup(); + } + Pull::Down => { + w.pull().pulldown(); + } + } + w.drive().s0s1(); + w.sense().disabled(); + w + }); + + Self { pin } + } +} + +impl Drop for Input { + fn drop(&mut self) { + self.pin.conf().reset(); + } +} + +impl InputPin for Input { + type Error = Infallible; + + fn is_high(&self) -> Result { + self.is_low().map(|v| !v) + } + + fn is_low(&self) -> Result { + Ok(self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0) + } +} + +pub struct Output { + pin: T, +} + +impl Output { + // TODO opendrain + pub fn new(pin: T, initial_output: Level) -> Self { + pin.conf().write(|w| { + w.dir().output(); + w.input().disconnect(); + w.pull().disabled(); + w.drive().s0s1(); + w.sense().disabled(); + w + }); + + Self { pin } + } +} + +impl Drop for Output { + fn drop(&mut self) { + self.pin.conf().reset(); + } +} + +impl OutputPin for Output { + type Error = Infallible; + + /// Set the output as high. + fn set_high(&mut self) -> Result<(), Self::Error> { + unsafe { + self.pin + .block() + .outset + .write(|w| w.bits(1u32 << self.pin.pin())); + } + Ok(()) + } + + /// Set the output as low. + fn set_low(&mut self) -> Result<(), Self::Error> { + unsafe { + self.pin + .block() + .outclr + .write(|w| w.bits(1u32 << self.pin.pin())); + } + Ok(()) + } +} + +impl StatefulOutputPin for Output { + /// Is the output pin set as high? + fn is_set_high(&self) -> Result { + self.is_set_low().map(|v| !v) + } + + /// Is the output pin set as low? + fn is_set_low(&self) -> Result { + Ok(self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0) + } +} + +pub(crate) mod sealed { + use super::*; + + pub trait Pin { + fn pin_port(&self) -> u8; + + #[inline] + fn _pin(&self) -> u8 { + #[cfg(any(feature = "52833", feature = "52840"))] + { + self.pin_port() % 32 + } + + #[cfg(not(any(feature = "52833", feature = "52840")))] + { + self.pin_port() + } + } + + fn block(&self) -> &gpio::RegisterBlock { + unsafe { + match self.pin_port() / 32 { + 0 => &*pac::P0::ptr(), + #[cfg(any(feature = "52833", feature = "52840"))] + 1 => &*pac::P1::ptr(), + _ => unreachable_unchecked(), + } + } + } + + fn conf(&self) -> &gpio::PIN_CNF { + &self.block().pin_cnf[self._pin() as usize] + } + + /// Set the output as high. + fn set_high(&self) { + unsafe { + self.block().outset.write(|w| w.bits(1u32 << self._pin())); + } + } + + /// Set the output as low. + fn set_low(&self) { + unsafe { + self.block().outclr.write(|w| w.bits(1u32 << self._pin())); + } + } + } +} + +pub trait Pin: sealed::Pin + Sized { + #[inline] + fn pin(&self) -> u8 { + self._pin() + } + + #[inline] + fn port(&self) -> Port { + match self.pin_port() / 32 { + 1 => Port::Port0, + #[cfg(any(feature = "52833", feature = "52840"))] + 1 => Port::Port1, + _ => unsafe { unreachable_unchecked() }, + } + } + + #[inline] + fn psel_bits(&self) -> u32 { + self.pin_port() as u32 + } + + fn degrade(self) -> AnyPin { + AnyPin { + pin_port: self.pin_port(), + } + } +} + +pub struct AnyPin { + pin_port: u8, +} + +impl AnyPin { + pub unsafe fn from_psel_bits(psel_bits: u32) -> Self { + Self { + pin_port: psel_bits as u8, + } + } +} + +impl Pin for AnyPin {} +impl sealed::Pin for AnyPin { + fn pin_port(&self) -> u8 { + self.pin_port + } +} + +macro_rules! make_impl { + ($type:ident, $port_num:expr, $pin_num:expr) => { + impl Pin for peripherals::$type {} + impl sealed::Pin for peripherals::$type { + fn pin_port(&self) -> u8 { + $port_num * 32 + $pin_num + } + } + }; +} + +make_impl!(P0_00, 0, 0); +make_impl!(P0_01, 0, 1); +make_impl!(P0_02, 0, 2); +make_impl!(P0_03, 0, 3); +make_impl!(P0_04, 0, 4); +make_impl!(P0_05, 0, 5); +make_impl!(P0_06, 0, 6); +make_impl!(P0_07, 0, 7); +make_impl!(P0_08, 0, 8); +make_impl!(P0_09, 0, 9); +make_impl!(P0_10, 0, 10); +make_impl!(P0_11, 0, 11); +make_impl!(P0_12, 0, 12); +make_impl!(P0_13, 0, 13); +make_impl!(P0_14, 0, 14); +make_impl!(P0_15, 0, 15); +make_impl!(P0_16, 0, 16); +make_impl!(P0_17, 0, 17); +make_impl!(P0_18, 0, 18); +make_impl!(P0_19, 0, 19); +make_impl!(P0_20, 0, 20); +make_impl!(P0_21, 0, 21); +make_impl!(P0_22, 0, 22); +make_impl!(P0_23, 0, 23); +make_impl!(P0_24, 0, 24); +make_impl!(P0_25, 0, 25); +make_impl!(P0_26, 0, 26); +make_impl!(P0_27, 0, 27); +make_impl!(P0_28, 0, 28); +make_impl!(P0_29, 0, 29); +make_impl!(P0_30, 0, 30); +make_impl!(P0_31, 0, 31); + +#[cfg(any(feature = "52833", feature = "52840"))] +mod _p1 { + use super::*; + make_impl!(P1_00, 1, 0); + make_impl!(P1_01, 1, 1); + make_impl!(P1_02, 1, 2); + make_impl!(P1_03, 1, 3); + make_impl!(P1_04, 1, 4); + make_impl!(P1_05, 1, 5); + make_impl!(P1_06, 1, 6); + make_impl!(P1_07, 1, 7); + make_impl!(P1_08, 1, 8); + make_impl!(P1_09, 1, 9); + make_impl!(P1_10, 1, 10); + make_impl!(P1_11, 1, 11); + make_impl!(P1_12, 1, 12); + make_impl!(P1_13, 1, 13); + make_impl!(P1_14, 1, 14); + make_impl!(P1_15, 1, 15); +} diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 2c72b912..07759996 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -94,8 +94,10 @@ pub(crate) fn slice_in_ram_or(slice: &[u8], err: T) -> Result<(), T> { pub(crate) mod fmt; pub mod buffered_uarte; +pub mod gpio; pub mod gpiote; pub mod interrupt; +pub mod peripherals; #[cfg(feature = "52840")] pub mod qspi; pub mod rtc; diff --git a/embassy-nrf/src/peripherals.rs b/embassy-nrf/src/peripherals.rs new file mode 100644 index 00000000..bc2ed881 --- /dev/null +++ b/embassy-nrf/src/peripherals.rs @@ -0,0 +1,144 @@ +use embassy::util::PeripheralBorrow; + +macro_rules! peripherals { + ($($(#[$cfg:meta])? $name:ident: $type:ident),*$(,)?) => { + $( + $(#[$cfg])? + pub struct $type { _private: () } + + $(#[$cfg])? + impl PeripheralBorrow for $type { + type Target = $type; + unsafe fn unborrow(self) -> $type { + self + } + } + + $(#[$cfg])? + impl PeripheralBorrow for &mut $type { + type Target = $type; + unsafe fn unborrow(self) -> $type { + ::core::ptr::read(self) + } + } + )* + + pub struct Peripherals { + $( + $(#[$cfg])? + pub $name: $type, + )* + } + + impl Peripherals { + pub unsafe fn steal() -> Self { + Self { + $( + $(#[$cfg])? + $name: $type { _private: () }, + )* + } + } + } + + }; +} + +peripherals! { + // RTC + rtc0: RTC0, + rtc1: RTC1, + #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] + rtc2: RTC2, + + // QSPI + #[cfg(feature = "52840")] + qspi: QSPI, + + // UARTE + uarte0: UARTE0, + #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] + uarte1: UARTE1, + + // SPIM + // TODO this is actually shared with SPI, SPIM, SPIS, TWI, TWIS, TWIS. + // When they're all implemented, they should be only one peripheral here. + spim0: SPIM0, + #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] + spim1: SPIM1, + #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] + spim2: SPIM2, + #[cfg(any(feature = "52833", feature = "52840"))] + spim3: SPIM3, + + // GPIOTE + gpiote: GPIOTE, + + // GPIO port 0 + p0_00: P0_00, + p0_01: P0_01, + p0_02: P0_02, + p0_03: P0_03, + p0_04: P0_04, + p0_05: P0_05, + p0_06: P0_06, + p0_07: P0_07, + p0_08: P0_08, + p0_09: P0_09, + p0_10: P0_10, + p0_11: P0_11, + p0_12: P0_12, + p0_13: P0_13, + p0_14: P0_14, + p0_15: P0_15, + p0_16: P0_16, + p0_17: P0_17, + p0_18: P0_18, + p0_19: P0_19, + p0_20: P0_20, + p0_21: P0_21, + p0_22: P0_22, + p0_23: P0_23, + p0_24: P0_24, + p0_25: P0_25, + p0_26: P0_26, + p0_27: P0_27, + p0_28: P0_28, + p0_29: P0_29, + p0_30: P0_30, + p0_31: P0_31, + + // GPIO port 1 + #[cfg(any(feature = "52833", feature = "52840"))] + p1_00: P1_00, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_01: P1_01, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_02: P1_02, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_03: P1_03, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_04: P1_04, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_05: P1_05, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_06: P1_06, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_07: P1_07, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_08: P1_08, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_09: P1_09, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_10: P1_10, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_11: P1_11, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_12: P1_12, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_13: P1_13, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_14: P1_14, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_15: P1_15, +} diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index b236f538..38cfa005 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -1,19 +1,20 @@ use core::future::Future; +use core::marker::PhantomData; use core::pin::Pin; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy::traits; -use embassy::util::WakerRegistration; +use embassy::util::{PeripheralBorrow, WakerRegistration}; use embassy_extras::peripheral::{PeripheralMutex, PeripheralState}; use futures::future::poll_fn; use traits::spi::FullDuplex; +use crate::gpio::Pin as GpioPin; use crate::interrupt::{self, Interrupt}; -use crate::{pac, slice_in_ram_or}; +use crate::{pac, peripherals, slice_in_ram_or}; -pub use crate::hal::spim::{ - Frequency, Mode, Phase, Pins, Polarity, MODE_0, MODE_1, MODE_2, MODE_3, -}; +pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +pub use pac::spim0::frequency::FREQUENCY_A as Frequency; #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -30,41 +31,63 @@ struct State { waker: WakerRegistration, } -pub struct Spim { +pub struct Spim<'d, T: Instance> { inner: PeripheralMutex>, + phantom: PhantomData<&'d mut T>, } pub struct Config { - pub pins: Pins, pub frequency: Frequency, pub mode: Mode, pub orc: u8, } -impl Spim { - pub fn new(mut spim: T, irq: T::Interrupt, config: Config) -> Self { +impl<'d, T: Instance> Spim<'d, T> { + pub fn new( + spim: impl PeripheralBorrow + 'd, + irq: impl PeripheralBorrow + 'd, + sck: impl PeripheralBorrow + 'd, + miso: impl PeripheralBorrow + 'd, + mosi: impl PeripheralBorrow + 'd, + config: Config, + ) -> Self { + let mut spim = unsafe { spim.unborrow() }; + let irq = unsafe { irq.unborrow() }; + let sck = unsafe { sck.unborrow() }; + let miso = unsafe { miso.unborrow() }; + let mosi = unsafe { mosi.unborrow() }; + let r = spim.regs(); + // Configure pins + sck.conf().write(|w| w.dir().output()); + mosi.conf().write(|w| w.dir().output()); + miso.conf().write(|w| w.input().connect()); + + match config.mode.polarity { + Polarity::IdleHigh => { + sck.set_high(); + mosi.set_high(); + } + Polarity::IdleLow => { + sck.set_low(); + mosi.set_low(); + } + } + // Select pins. r.psel.sck.write(|w| { - unsafe { w.bits(config.pins.sck.psel_bits()) }; + unsafe { w.bits(sck.psel_bits()) }; + w.connect().connected() + }); + r.psel.mosi.write(|w| { + unsafe { w.bits(mosi.psel_bits()) }; + w.connect().connected() + }); + r.psel.miso.write(|w| { + unsafe { w.bits(miso.psel_bits()) }; w.connect().connected() }); - - match config.pins.mosi { - Some(mosi) => r.psel.mosi.write(|w| { - unsafe { w.bits(mosi.psel_bits()) }; - w.connect().connected() - }), - None => r.psel.mosi.write(|w| w.connect().disconnected()), - } - match config.pins.miso { - Some(miso) => r.psel.miso.write(|w| { - unsafe { w.bits(miso.psel_bits()) }; - w.connect().connected() - }), - None => r.psel.miso.write(|w| w.connect().disconnected()), - } // Enable SPIM instance. r.enable.write(|w| w.enable().enabled()); @@ -114,6 +137,7 @@ impl Spim { }, irq, ), + phantom: PhantomData, } } @@ -122,7 +146,7 @@ impl Spim { } } -impl FullDuplex for Spim { +impl<'d, T: Instance> FullDuplex for Spim<'d, T> { type Error = Error; #[rustfmt::skip] @@ -222,19 +246,19 @@ mod sealed { } } -pub trait Instance: sealed::Instance { +pub trait Instance: sealed::Instance + 'static { type Interrupt: Interrupt; } macro_rules! make_impl { - ($SPIMx:ident, $IRQ:ident) => { - impl sealed::Instance for pac::$SPIMx { + ($type:ident, $irq:ident) => { + impl sealed::Instance for peripherals::$type { fn regs(&mut self) -> &pac::spim0::RegisterBlock { - self + unsafe { &*pac::$type::ptr() } } } - impl Instance for pac::$SPIMx { - type Interrupt = interrupt::$IRQ; + impl Instance for peripherals::$type { + type Interrupt = interrupt::$irq; } }; } From 3d3e770b8dca9adb50b02f14d0087fe40ee1ce35 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 20 Mar 2021 01:36:00 +0100 Subject: [PATCH 04/45] nrf/gpio: add output drive config. --- embassy-nrf/src/gpio.rs | 84 +++++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 19 deletions(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 9f4604b0..52cb5731 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -2,26 +2,12 @@ use core::convert::Infallible; use core::hint::unreachable_unchecked; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; +use gpio::pin_cnf::DRIVE_A; use crate::pac; use crate::pac::p0 as gpio; use crate::peripherals; -/// Represents a digital input or output level. -#[derive(Debug, Eq, PartialEq)] -pub enum Level { - Low, - High, -} - -/// Represents a pull setting for an input. -#[derive(Debug, Eq, PartialEq)] -pub enum Pull { - None, - Up, - Down, -} - /// A GPIO port with up to 32 pins. #[derive(Debug, Eq, PartialEq)] pub enum Port { @@ -33,6 +19,16 @@ pub enum Port { Port1, } +/// Pull setting for an input. +#[derive(Debug, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Pull { + None, + Up, + Down, +} + +/// GPIO input driver. pub struct Input { pin: T, } @@ -80,18 +76,64 @@ impl InputPin for Input { } } +/// Digital input or output level. +#[derive(Debug, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Level { + Low, + High, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum OutputDrive { + /// Standard '0', standard '1' + Standard = 0, + /// High drive '0', standard '1' + HighDrive0Standard1 = 1, + /// Standard '0', high drive '1' + Standard0HighDrive1 = 2, + /// High drive '0', high 'drive '1' + HighDrive = 3, + /// Disconnect '0' standard '1' (normally used for wired-or connections) + Disconnect0Standard1 = 4, + /// Disconnect '0', high drive '1' (normally used for wired-or connections) + Disconnect0HighDrive1 = 5, + /// Standard '0'. disconnect '1' (also known as "open drain", normally used for wired-and connections) + Standard0Disconnect1 = 6, + /// High drive '0', disconnect '1' (also known as "open drain", normally used for wired-and connections) + HighDrive0Disconnect1 = 7, +} + +/// GPIO output driver. pub struct Output { pin: T, } impl Output { - // TODO opendrain - pub fn new(pin: T, initial_output: Level) -> Self { + pub fn new(pin: T, initial_output: Level, drive: OutputDrive) -> Self { + match initial_output { + Level::High => pin.set_high(), + Level::Low => pin.set_low(), + } + + let drive = match drive { + OutputDrive::Standard => DRIVE_A::S0S1, + OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1, + OutputDrive::Standard0HighDrive1 => DRIVE_A::S0H1, + OutputDrive::HighDrive => DRIVE_A::H0H1, + OutputDrive::Disconnect0Standard1 => DRIVE_A::D0S1, + OutputDrive::Disconnect0HighDrive1 => DRIVE_A::D0H1, + OutputDrive::Standard0Disconnect1 => DRIVE_A::S0D1, + OutputDrive::HighDrive0Disconnect1 => DRIVE_A::H0D1, + }; + pin.conf().write(|w| { w.dir().output(); w.input().disconnect(); w.pull().disabled(); - w.drive().s0s1(); + w.drive().variant(drive); w.sense().disabled(); w }); @@ -195,11 +237,13 @@ pub(crate) mod sealed { } pub trait Pin: sealed::Pin + Sized { + /// Number of the pin within the port (0..31) #[inline] fn pin(&self) -> u8 { self._pin() } + /// Port of the pin #[inline] fn port(&self) -> Port { match self.pin_port() / 32 { @@ -215,6 +259,7 @@ pub trait Pin: sealed::Pin + Sized { self.pin_port() as u32 } + /// Convert from concrete pin type PX_XX to type erased `AnyPin`. fn degrade(self) -> AnyPin { AnyPin { pin_port: self.pin_port(), @@ -222,12 +267,13 @@ pub trait Pin: sealed::Pin + Sized { } } +// Type-erased GPIO pin pub struct AnyPin { pin_port: u8, } impl AnyPin { - pub unsafe fn from_psel_bits(psel_bits: u32) -> Self { + pub unsafe fn steal_from_psel_bits(psel_bits: u32) -> Self { Self { pin_port: psel_bits as u8, } From ba7b3974bb0092f0a9d3bf5e02fb5d4c41c53083 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 20 Mar 2021 03:09:42 +0100 Subject: [PATCH 05/45] nrf/gpiote: update to new gpio --- embassy-nrf-examples/src/bin/gpiote_port.rs | 19 +- embassy-nrf/src/gpio.rs | 8 +- embassy-nrf/src/gpiote.rs | 291 +++++++++----------- 3 files changed, 142 insertions(+), 176 deletions(-) diff --git a/embassy-nrf-examples/src/bin/gpiote_port.rs b/embassy-nrf-examples/src/bin/gpiote_port.rs index 36ee1c8e..273cd124 100644 --- a/embassy-nrf-examples/src/bin/gpiote_port.rs +++ b/embassy-nrf-examples/src/bin/gpiote_port.rs @@ -6,7 +6,9 @@ #[path = "../example_common.rs"] mod example_common; +use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; use example_common::*; +use gpiote::GpioteInput; use core::pin::Pin; use cortex_m_rt::entry; @@ -16,10 +18,10 @@ use nrf52840_hal::gpio; use embassy::executor::{task, Executor}; use embassy::traits::gpio::{WaitForHigh, WaitForLow}; use embassy::util::Forever; -use embassy_nrf::gpiote::{Gpiote, GpiotePin}; +use embassy_nrf::gpiote; use embassy_nrf::interrupt; -async fn button(n: usize, mut pin: GpiotePin) { +async fn button(n: usize, mut pin: GpioteInput) { loop { Pin::new(&mut pin).wait_for_low().await; info!("Button {:?} pressed!", n); @@ -30,26 +32,25 @@ async fn button(n: usize, mut pin: GpiotePin) { #[task] async fn run() { - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - let port0 = gpio::p0::Parts::new(p.P0); + let p = unsafe { embassy_nrf::peripherals::Peripherals::steal() }; - let (g, _) = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); + let g = gpiote::initialize(p.gpiote, interrupt::take!(GPIOTE)); let button1 = button( 1, - GpiotePin::new(g, port0.p0_11.into_pullup_input().degrade()), + GpioteInput::new(g, Input::new(p.p0_11.degrade(), Pull::Up)), ); let button2 = button( 2, - GpiotePin::new(g, port0.p0_12.into_pullup_input().degrade()), + GpioteInput::new(g, Input::new(p.p0_12.degrade(), Pull::Up)), ); let button3 = button( 3, - GpiotePin::new(g, port0.p0_24.into_pullup_input().degrade()), + GpioteInput::new(g, Input::new(p.p0_24.degrade(), Pull::Up)), ); let button4 = button( 4, - GpiotePin::new(g, port0.p0_25.into_pullup_input().degrade()), + GpioteInput::new(g, Input::new(p.p0_25.degrade(), Pull::Up)), ); futures::join!(button1, button2, button3, button4); } diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 52cb5731..dd334c63 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -30,7 +30,7 @@ pub enum Pull { /// GPIO input driver. pub struct Input { - pin: T, + pub(crate) pin: T, } impl Input { @@ -273,10 +273,8 @@ pub struct AnyPin { } impl AnyPin { - pub unsafe fn steal_from_psel_bits(psel_bits: u32) -> Self { - Self { - pin_port: psel_bits as u8, - } + pub unsafe fn steal(pin_port: u8) -> Self { + Self { pin_port } } } diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 5dc80a63..2b603c4c 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -1,19 +1,24 @@ +use core::convert::Infallible; use core::future::Future; -use core::mem::ManuallyDrop; +use core::intrinsics::transmute; +use core::marker::PhantomData; +use core::mem::{self, ManuallyDrop}; use core::ops::Deref; use core::pin::Pin; use core::ptr; use core::task::{Context, Poll}; use embassy::interrupt::InterruptExt; use embassy::traits::gpio::{WaitForHigh, WaitForLow}; -use embassy::util::Signal; +use embassy::util::{AtomicWakerRegistration, Signal}; +use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; -use crate::hal::gpio::{Input, Level, Output, Pin as GpioPin, Port}; -use crate::interrupt; +use crate::gpio::sealed::Pin as _; +use crate::gpio::{AnyPin, Input, Pin as GpioPin, Pull}; use crate::pac; use crate::pac::generic::Reg; use crate::pac::gpiote::_TASKS_OUT; -use crate::pac::{p0 as pac_gpio, GPIOTE}; +use crate::pac::p0 as pac_gpio; +use crate::{interrupt, peripherals}; #[cfg(not(feature = "51"))] use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET}; @@ -63,12 +68,9 @@ impl ChannelID for ChAny { } } -#[derive(Clone, Copy)] -pub struct Gpiote(()); - -const NEW_SIGNAL: Signal<()> = Signal::new(); -static CHANNEL_SIGNALS: [Signal<()>; CHANNEL_COUNT] = [NEW_SIGNAL; CHANNEL_COUNT]; -static PORT_SIGNALS: [Signal<()>; PIN_COUNT] = [NEW_SIGNAL; PIN_COUNT]; +const NEW_AWR: AtomicWakerRegistration = AtomicWakerRegistration::new(); +static CHANNEL_WAKERS: [AtomicWakerRegistration; CHANNEL_COUNT] = [NEW_AWR; CHANNEL_COUNT]; +static PORT_WAKERS: [AtomicWakerRegistration; PIN_COUNT] = [NEW_AWR; PIN_COUNT]; pub enum InputChannelPolarity { None, @@ -84,117 +86,84 @@ pub enum OutputChannelPolarity { Toggle, } -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum NewChannelError { - NoFreeChannels, +/// Token indicating GPIOTE has been correctly initialized. +/// +/// This is not an owned singleton, it is Copy. Drivers that make use of GPIOTE require it. +#[derive(Clone, Copy)] +pub struct Initialized { + _private: (), } -pub struct Channels { - pub ch0: Ch0, - pub ch1: Ch1, - pub ch2: Ch2, - pub ch3: Ch3, - pub ch4: Ch4, - pub ch5: Ch5, - pub ch6: Ch6, - pub ch7: Ch7, +pub fn initialize(gpiote: peripherals::GPIOTE, irq: interrupt::GPIOTE) -> Initialized { + #[cfg(any(feature = "52833", feature = "52840"))] + let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; + #[cfg(not(any(feature = "52833", feature = "52840")))] + let ports = unsafe { &[&*pac::P0::ptr()] }; + + for &p in ports { + // Enable latched detection + p.detectmode.write(|w| w.detectmode().ldetect()); + // Clear latch + p.latch.write(|w| unsafe { w.bits(0xFFFFFFFF) }) + } + + // Enable interrupts + let g = unsafe { &*pac::GPIOTE::ptr() }; + g.events_port.write(|w| w); + g.intenset.write(|w| w.port().set()); + irq.set_handler(on_irq); + irq.unpend(); + irq.enable(); + + Initialized { _private: () } } -impl Gpiote { - pub fn new(gpiote: GPIOTE, irq: interrupt::GPIOTE) -> (Self, Channels) { +unsafe fn on_irq(_ctx: *mut ()) { + let g = &*pac::GPIOTE::ptr(); + + for i in 0..CHANNEL_COUNT { + if g.events_in[i].read().bits() != 0 { + g.events_in[i].write(|w| w); + CHANNEL_WAKERS[i].wake(); + } + } + + if g.events_port.read().bits() != 0 { + g.events_port.write(|w| w); + #[cfg(any(feature = "52833", feature = "52840"))] - let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; + let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()]; #[cfg(not(any(feature = "52833", feature = "52840")))] - let ports = unsafe { &[&*pac::P0::ptr()] }; + let ports = &[&*pac::P0::ptr()]; - for &p in ports { - // Enable latched detection - p.detectmode.write(|w| w.detectmode().ldetect()); - // Clear latch - p.latch.write(|w| unsafe { w.bits(0xFFFFFFFF) }) - } - - // Enable interrupts - gpiote.events_port.write(|w| w); - gpiote.intenset.write(|w| w.port().set()); - irq.set_handler(Self::on_irq); - irq.unpend(); - irq.enable(); - - ( - Self(()), - Channels { - ch0: Ch0(()), - ch1: Ch1(()), - ch2: Ch2(()), - ch3: Ch3(()), - ch4: Ch4(()), - ch5: Ch5(()), - ch6: Ch6(()), - ch7: Ch7(()), - }, - ) - } - - unsafe fn on_irq(_ctx: *mut ()) { - let g = &*GPIOTE::ptr(); - - for (event_in, signal) in g.events_in.iter().zip(CHANNEL_SIGNALS.iter()) { - if event_in.read().bits() != 0 { - event_in.write(|w| w); - signal.signal(()); + for (port, &p) in ports.iter().enumerate() { + let bits = p.latch.read().bits(); + for pin in BitIter(bits) { + p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled()); + PORT_WAKERS[port * 32 + pin as usize].wake(); } + p.latch.write(|w| w.bits(bits)); } + } +} - if g.events_port.read().bits() != 0 { - g.events_port.write(|w| w); +struct BitIter(u32); - #[cfg(any(feature = "52833", feature = "52840"))] - let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()]; - #[cfg(not(any(feature = "52833", feature = "52840")))] - let ports = &[&*pac::P0::ptr()]; +impl Iterator for BitIter { + type Item = u32; - let mut work = true; - while work { - work = false; - for (port, &p) in ports.iter().enumerate() { - for pin in BitIter(p.latch.read().bits()) { - work = true; - p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled()); - p.latch.write(|w| w.bits(1 << pin)); - PORT_SIGNALS[port * 32 + pin as usize].signal(()); - } - } + fn next(&mut self) -> Option { + match self.0.trailing_zeros() { + 32 => None, + b => { + self.0 &= !(1 << b); + Some(b) } } } } -fn pin_num(pin: &GpioPin) -> usize { - let port = match pin.port() { - Port::Port0 => 0, - #[cfg(any(feature = "52833", feature = "52840"))] - Port::Port1 => 32, - }; - - port + pin.pin() as usize -} - -fn pin_block(pin: &GpioPin) -> &pac_gpio::RegisterBlock { - let ptr = match pin.port() { - Port::Port0 => pac::P0::ptr(), - #[cfg(any(feature = "52833", feature = "52840"))] - Port::Port1 => pac::P1::ptr(), - }; - - unsafe { &*ptr } -} - -fn pin_conf(pin: &GpioPin) -> &pac_gpio::PIN_CNF { - &pin_block(pin).pin_cnf[pin.pin() as usize] -} - +/* pub struct InputChannel { ch: C, pin: GpioPin>, @@ -211,7 +180,7 @@ impl Drop for InputChannel { impl InputChannel { pub fn new( - _gpiote: Gpiote, + _init: Initialized, ch: C, pin: GpioPin>, polarity: InputChannelPolarity, @@ -234,7 +203,7 @@ impl InputChannel { unsafe { w.psel().bits(pin.pin()) } }); - CHANNEL_SIGNALS[index].reset(); + CHANNEL_WAKERS[index].reset(); // Enable interrupt g.intenset.write(|w| unsafe { w.bits(1 << index) }); @@ -251,7 +220,7 @@ impl InputChannel { pub async fn wait(&self) { let index = self.ch.number(); - CHANNEL_SIGNALS[index].wait().await; + CHANNEL_WAKERS[index].wait().await; } pub fn pin(&self) -> &GpioPin> { @@ -366,89 +335,87 @@ impl OutputChannel { &g.tasks_set[index] } } + */ -struct BitIter(u32); - -impl Iterator for BitIter { - type Item = u32; - - fn next(&mut self) -> Option { - match self.0.trailing_zeros() { - 32 => None, - b => { - self.0 &= !(1 << b); - Some(b) - } - } - } +/// GPIO input driver with support +pub struct GpioteInput { + pin: Input, } +impl Unpin for GpioteInput {} -pub struct GpiotePin { - pin: GpioPin>, -} - -impl Unpin for GpiotePin {} - -impl GpiotePin { - pub fn new(_gpiote: Gpiote, pin: GpioPin>) -> Self { +impl GpioteInput { + pub fn new(_init: Initialized, pin: Input) -> Self { Self { pin } } } -impl WaitForHigh for GpiotePin { - type Future<'a> = PortInputFuture<'a, T>; +impl InputPin for GpioteInput { + type Error = Infallible; + + fn is_high(&self) -> Result { + self.pin.is_high() + } + + fn is_low(&self) -> Result { + self.pin.is_low() + } +} + +impl WaitForHigh for GpioteInput { + type Future<'a> = PortInputFuture<'a>; fn wait_for_high<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> { + self.pin.pin.conf().modify(|_, w| w.sense().high()); + PortInputFuture { - pin: &self.get_mut().pin, - polarity: PortInputPolarity::High, + pin_port: self.pin.pin.pin_port(), + phantom: PhantomData, } } } -impl WaitForLow for GpiotePin { - type Future<'a> = PortInputFuture<'a, T>; +impl WaitForLow for GpioteInput { + type Future<'a> = PortInputFuture<'a>; fn wait_for_low<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> { + self.pin.pin.conf().modify(|_, w| w.sense().low()); + PortInputFuture { - pin: &self.get_mut().pin, - polarity: PortInputPolarity::Low, + pin_port: self.pin.pin.pin_port(), + phantom: PhantomData, } } } -impl Deref for GpiotePin { - type Target = GpioPin>; - fn deref(&self) -> &Self::Target { - &self.pin - } +pub struct PortInputFuture<'a> { + pin_port: u8, + phantom: PhantomData<&'a mut AnyPin>, } -enum PortInputPolarity { - High, - Low, -} - -pub struct PortInputFuture<'a, T> { - pin: &'a GpioPin>, - polarity: PortInputPolarity, -} - -impl<'a, T> Drop for PortInputFuture<'a, T> { +impl<'a> Drop for PortInputFuture<'a> { fn drop(&mut self) { - pin_conf(&self.pin).modify(|_, w| w.sense().disabled()); - PORT_SIGNALS[pin_num(&self.pin)].reset(); + unsafe { AnyPin::steal(self.pin_port) } + .conf() + .modify(|_, w| w.sense().disabled()); } } -impl<'a, T> Future for PortInputFuture<'a, T> { +impl<'a> Future for PortInputFuture<'a> { type Output = (); fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - pin_conf(&self.pin).modify(|_, w| match self.polarity { - PortInputPolarity::Low => w.sense().low(), - PortInputPolarity::High => w.sense().high(), - }); - PORT_SIGNALS[pin_num(&self.pin)].poll_wait(cx) + let dis = unsafe { AnyPin::steal(self.pin_port) } + .conf() + .read() + .sense() + .is_disabled(); + + if dis { + return Poll::Ready(()); + } + + PORT_WAKERS[self.pin_port as usize].register(cx.waker()); + + Poll::Pending } } From 15eb46ec714beaf443577f2f7bef4610d22f54f5 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 20 Mar 2021 03:09:56 +0100 Subject: [PATCH 06/45] wip gpiote changels --- embassy-nrf/src/peripherals.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/embassy-nrf/src/peripherals.rs b/embassy-nrf/src/peripherals.rs index bc2ed881..1f449e91 100644 --- a/embassy-nrf/src/peripherals.rs +++ b/embassy-nrf/src/peripherals.rs @@ -4,6 +4,7 @@ macro_rules! peripherals { ($($(#[$cfg:meta])? $name:ident: $type:ident),*$(,)?) => { $( $(#[$cfg])? + #[allow(non_camel_case_types)] pub struct $type { _private: () } $(#[$cfg])? @@ -73,6 +74,14 @@ peripherals! { // GPIOTE gpiote: GPIOTE, + gpiote_ch_0: GPIOTE_CH0, + gpiote_ch_1: GPIOTE_CH1, + gpiote_ch_2: GPIOTE_CH2, + gpiote_ch_3: GPIOTE_CH3, + gpiote_ch_4: GPIOTE_CH4, + gpiote_ch_5: GPIOTE_CH5, + gpiote_ch_6: GPIOTE_CH6, + gpiote_ch_7: GPIOTE_CH7, // GPIO port 0 p0_00: P0_00, From ba6e0a405831793ab1e5acaa4694171199012df0 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 20 Mar 2021 03:37:48 +0100 Subject: [PATCH 07/45] util: add wake_on_interrupt. This is a lighter version of InterruptFuture. --- embassy/src/util/signal.rs | 42 ++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/embassy/src/util/signal.rs b/embassy/src/util/signal.rs index 0fd5c927..749b3224 100644 --- a/embassy/src/util/signal.rs +++ b/embassy/src/util/signal.rs @@ -5,6 +5,8 @@ use core::ptr; use core::task::{Context, Poll, Waker}; use cortex_m::peripheral::NVIC; use cortex_m::peripheral::{scb, SCB}; +use executor::raw::TaskHeader; +use ptr::NonNull; use crate::executor; use crate::fmt::panic; @@ -79,6 +81,30 @@ impl Signal { } } +// ========== + +pub fn wake_on_interrupt(interrupt: &mut impl Interrupt, waker: &Waker) { + interrupt.disable(); + interrupt.set_handler(irq_wake_handler); + interrupt.set_handler_context(unsafe { executor::raw::task_from_waker(waker) }.as_ptr() as _); + interrupt.enable(); +} + +unsafe fn irq_wake_handler(ctx: *mut ()) { + if let Some(task) = NonNull::new(ctx as *mut TaskHeader) { + executor::raw::wake_task(task); + } + + let irq = match SCB::vect_active() { + scb::VectActive::Interrupt { irqn } => irqn, + _ => unreachable!(), + }; + + NVIC::mask(crate::interrupt::NrWrap(irq as u16)); +} + +// ========== + struct NrWrap(u8); unsafe impl cortex_m::interrupt::Nr for NrWrap { fn nr(&self) -> u8 { @@ -119,26 +145,13 @@ impl<'a, I: Interrupt> Drop for InterruptFuture<'a, I> { impl<'a, I: Interrupt> InterruptFuture<'a, I> { pub fn new(interrupt: &'a mut I) -> Self { interrupt.disable(); - interrupt.set_handler(Self::interrupt_handler); + interrupt.set_handler(irq_wake_handler); interrupt.set_handler_context(ptr::null_mut()); interrupt.unpend(); interrupt.enable(); Self { interrupt } } - - unsafe fn interrupt_handler(ctx: *mut ()) { - let irq = match SCB::vect_active() { - scb::VectActive::Interrupt { irqn } => irqn, - _ => unreachable!(), - }; - - if !ctx.is_null() { - executor::raw::wake_task(ptr::NonNull::new_unchecked(ctx as _)); - } - - NVIC::mask(crate::interrupt::NrWrap(irq as u16)); - } } impl<'a, I: Interrupt> Unpin for InterruptFuture<'a, I> {} @@ -148,7 +161,6 @@ impl<'a, I: Interrupt> Future for InterruptFuture<'a, I> { fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { let s = unsafe { self.get_unchecked_mut() }; - s.interrupt.set_handler(Self::interrupt_handler); s.interrupt.set_handler_context(unsafe { executor::raw::task_from_waker(&cx.waker()).cast().as_ptr() }); From f36cbe5e0cfa0a791d53ae6ddde40d69982867f4 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 20 Mar 2021 03:38:21 +0100 Subject: [PATCH 08/45] nrf/spim: do not use PeripheralMutex --- embassy-nrf-examples/src/bin/spim.rs | 4 +- embassy-nrf/src/spim.rs | 118 +++++++++++---------------- 2 files changed, 49 insertions(+), 73 deletions(-) diff --git a/embassy-nrf-examples/src/bin/spim.rs b/embassy-nrf-examples/src/bin/spim.rs index 8eaac5e1..b7436332 100644 --- a/embassy-nrf-examples/src/bin/spim.rs +++ b/embassy-nrf-examples/src/bin/spim.rs @@ -6,7 +6,7 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_nrf::gpio::{Level, Output}; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::peripherals::Peripherals; use embassy_traits::spi::FullDuplex; use example_common::*; @@ -37,7 +37,7 @@ async fn run() { let spim = spim::Spim::new(p.spim3, irq, p.p0_29, p.p0_28, p.p0_30, config); pin_mut!(spim); - let mut ncs = Output::new(p.p0_31, Level::High); + let mut ncs = Output::new(p.p0_31, Level::High, OutputDrive::Standard); // Example on how to talk to an ENC28J60 chip diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 38cfa005..33005188 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -4,8 +4,7 @@ use core::pin::Pin; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy::traits; -use embassy::util::{PeripheralBorrow, WakerRegistration}; -use embassy_extras::peripheral::{PeripheralMutex, PeripheralState}; +use embassy::util::{wake_on_interrupt, PeripheralBorrow}; use futures::future::poll_fn; use traits::spi::FullDuplex; @@ -26,13 +25,9 @@ pub enum Error { DMABufferNotInDataMemory, } -struct State { - spim: T, - waker: WakerRegistration, -} - pub struct Spim<'d, T: Instance> { - inner: PeripheralMutex>, + spim: T, + irq: T::Interrupt, phantom: PhantomData<&'d mut T>, } @@ -130,20 +125,11 @@ impl<'d, T: Instance> Spim<'d, T> { r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); Self { - inner: PeripheralMutex::new( - State { - spim, - waker: WakerRegistration::new(), - }, - irq, - ), + spim, + irq, phantom: PhantomData, } } - - fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex>> { - unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } - } } impl<'d, T: Instance> FullDuplex for Spim<'d, T> { @@ -157,69 +143,69 @@ impl<'d, T: Instance> FullDuplex for Spim<'d, T> { type WriteReadFuture<'a> where Self: 'a = impl Future> + 'a; fn read<'a>(self: Pin<&'a mut Self>, data: &'a mut [u8]) -> Self::ReadFuture<'a> { - async move { todo!() } + self.read_write(data, &[]) } fn write<'a>(self: Pin<&'a mut Self>, data: &'a [u8]) -> Self::WriteFuture<'a> { - async move { todo!() } + self.read_write(&mut [], data) } fn read_write<'a>( - mut self: Pin<&'a mut Self>, + self: Pin<&'a mut Self>, rx: &'a mut [u8], tx: &'a [u8], ) -> Self::WriteReadFuture<'a> { async move { + let this = unsafe { self.get_unchecked_mut() }; slice_in_ram_or(rx, Error::DMABufferNotInDataMemory)?; slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?; - self.as_mut().inner().register_interrupt(); - self.as_mut().inner().with(|s, _irq| { - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // before any DMA action has started. - compiler_fence(Ordering::SeqCst); + // Conservative compiler fence to prevent optimizations that do not + // take in to account actions by DMA. The fence has been placed here, + // before any DMA action has started. + compiler_fence(Ordering::SeqCst); - let r = s.spim.regs(); + let r = this.spim.regs(); - // Set up the DMA write. - r.txd - .ptr - .write(|w| unsafe { w.ptr().bits(tx.as_ptr() as u32) }); - r.txd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(tx.len() as _) }); + // Set up the DMA write. + r.txd + .ptr + .write(|w| unsafe { w.ptr().bits(tx.as_ptr() as u32) }); + r.txd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(tx.len() as _) }); - // Set up the DMA read. - r.rxd - .ptr - .write(|w| unsafe { w.ptr().bits(rx.as_mut_ptr() as u32) }); - r.rxd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(rx.len() as _) }); + // Set up the DMA read. + r.rxd + .ptr + .write(|w| unsafe { w.ptr().bits(rx.as_mut_ptr() as u32) }); + r.rxd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(rx.len() as _) }); - // Reset and enable the event - r.events_end.reset(); - r.intenset.write(|w| w.end().set()); + // Reset and enable the event + r.events_end.reset(); + r.intenset.write(|w| w.end().set()); - // Start SPI transaction. - r.tasks_start.write(|w| unsafe { w.bits(1) }); + // Start SPI transaction. + r.tasks_start.write(|w| unsafe { w.bits(1) }); - // Conservative compiler fence to prevent optimizations that do not - // take in to account actions by DMA. The fence has been placed here, - // after all possible DMA actions have completed. - compiler_fence(Ordering::SeqCst); - }); + // Conservative compiler fence to prevent optimizations that do not + // take in to account actions by DMA. The fence has been placed here, + // after all possible DMA actions have completed. + compiler_fence(Ordering::SeqCst); // Wait for 'end' event. poll_fn(|cx| { - self.as_mut().inner().with(|s, _irq| { - let r = s.spim.regs(); - if r.events_end.read().bits() != 0 { - return Poll::Ready(()); - } - s.waker.register(cx.waker()); - Poll::Pending - }) + let r = this.spim.regs(); + + if r.events_end.read().bits() != 0 { + r.events_end.reset(); + return Poll::Ready(()); + } + + wake_on_interrupt(&mut this.irq, cx.waker()); + + Poll::Pending }) .await; @@ -228,16 +214,6 @@ impl<'d, T: Instance> FullDuplex for Spim<'d, T> { } } -impl PeripheralState for State { - type Interrupt = U::Interrupt; - fn on_interrupt(&mut self) { - if self.spim.regs().events_end.read().bits() != 0 { - self.spim.regs().intenclr.write(|w| w.end().clear()); - self.waker.wake() - } - } -} - mod sealed { use super::*; From 16bb6fd6ac34646f498424459b8eb6863635b119 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 21 Mar 2021 20:52:20 +0100 Subject: [PATCH 09/45] nrf: Specify `connected` bit in psel_bits --- embassy-nrf/src/spim.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 33005188..f0c6ebe1 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -55,9 +55,9 @@ impl<'d, T: Instance> Spim<'d, T> { let r = spim.regs(); // Configure pins - sck.conf().write(|w| w.dir().output()); - mosi.conf().write(|w| w.dir().output()); - miso.conf().write(|w| w.input().connect()); + sck.conf().write(|w| w.dir().output().drive().h0h1()); + mosi.conf().write(|w| w.dir().output().drive().h0h1()); + miso.conf().write(|w| w.input().connect().drive().h0h1()); match config.mode.polarity { Polarity::IdleHigh => { @@ -71,18 +71,9 @@ impl<'d, T: Instance> Spim<'d, T> { } // Select pins. - r.psel.sck.write(|w| { - unsafe { w.bits(sck.psel_bits()) }; - w.connect().connected() - }); - r.psel.mosi.write(|w| { - unsafe { w.bits(mosi.psel_bits()) }; - w.connect().connected() - }); - r.psel.miso.write(|w| { - unsafe { w.bits(miso.psel_bits()) }; - w.connect().connected() - }); + r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) }); + r.psel.mosi.write(|w| unsafe { w.bits(mosi.psel_bits()) }); + r.psel.miso.write(|w| unsafe { w.bits(miso.psel_bits()) }); // Enable SPIM instance. r.enable.write(|w| w.enable().enabled()); From ec7309962a8f427732a0c6fc7c29713923b39028 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 21 Mar 2021 20:54:09 +0100 Subject: [PATCH 10/45] nrf/qspi: update to new api --- embassy-nrf-examples/src/bin/qspi.rs | 47 +--- embassy-nrf/src/qspi.rs | 368 +++++++++++++-------------- embassy-traits/src/flash.rs | 14 +- 3 files changed, 200 insertions(+), 229 deletions(-) diff --git a/embassy-nrf-examples/src/bin/qspi.rs b/embassy-nrf-examples/src/bin/qspi.rs index 7d8a45f7..a0896988 100644 --- a/embassy-nrf-examples/src/bin/qspi.rs +++ b/embassy-nrf-examples/src/bin/qspi.rs @@ -6,12 +6,12 @@ #[path = "../example_common.rs"] mod example_common; +use embassy_nrf::peripherals::Peripherals; use example_common::*; use cortex_m_rt::entry; use defmt::{assert_eq, panic}; use futures::pin_mut; -use nrf52840_hal::gpio; use embassy::executor::{task, Executor}; use embassy::traits::flash::Flash; @@ -27,43 +27,16 @@ struct AlignedBuf([u8; 4096]); #[task] async fn run() { - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + let p = unsafe { Peripherals::steal() }; - let port0 = gpio::p0::Parts::new(p.P0); - - let pins = qspi::Pins { - csn: port0 - .p0_17 - .into_push_pull_output(gpio::Level::High) - .degrade(), - sck: port0 - .p0_19 - .into_push_pull_output(gpio::Level::High) - .degrade(), - io0: port0 - .p0_20 - .into_push_pull_output(gpio::Level::High) - .degrade(), - io1: port0 - .p0_21 - .into_push_pull_output(gpio::Level::High) - .degrade(), - io2: Some( - port0 - .p0_22 - .into_push_pull_output(gpio::Level::High) - .degrade(), - ), - io3: Some( - port0 - .p0_23 - .into_push_pull_output(gpio::Level::High) - .degrade(), - ), - }; + let csn = p.p0_17; + let sck = p.p0_19; + let io0 = p.p0_20; + let io1 = p.p0_21; + let io2 = p.p0_22; + let io3 = p.p0_23; let config = qspi::Config { - pins, read_opcode: qspi::ReadOpcode::READ4IO, write_opcode: qspi::WriteOpcode::PP4IO, xip_offset: 0, @@ -72,7 +45,7 @@ async fn run() { }; let irq = interrupt::take!(QSPI); - let q = qspi::Qspi::new(p.QSPI, irq, config); + let q = qspi::Qspi::new(p.qspi, irq, sck, csn, io0, io1, io2, io3, config); pin_mut!(q); let mut id = [1; 3]; @@ -83,7 +56,7 @@ async fn run() { info!("id: {}", id); // Read status register - let mut status = [0; 1]; + let mut status = [4; 1]; q.as_mut() .custom_instruction(0x05, &[], &mut status) .await diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 026660cb..39428c62 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -1,13 +1,15 @@ use core::future::Future; +use core::marker::PhantomData; use core::pin::Pin; use core::task::Poll; +use embassy::interrupt::Interrupt; use embassy_extras::peripheral::{PeripheralMutex, PeripheralState}; use crate::fmt::{assert, assert_eq, *}; -use crate::hal::gpio::{Output, Pin as GpioPin, PushPull}; +use crate::gpio::Pin as GpioPin; use crate::interrupt::{self}; -use crate::pac::QSPI; +use crate::{pac, peripherals}; pub use crate::pac::qspi::ifconfig0::ADDRMODE_A as AddressMode; pub use crate::pac::qspi::ifconfig0::PPSIZE_A as WritePageSize; @@ -25,25 +27,15 @@ pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode; // - set gpio in high drive use embassy::traits::flash::{Error, Flash}; -use embassy::util::{DropBomb, WakerRegistration}; +use embassy::util::{wake_on_interrupt, DropBomb, PeripheralBorrow, WakerRegistration}; use futures::future::poll_fn; -pub struct Pins { - pub sck: GpioPin>, - pub csn: GpioPin>, - pub io0: GpioPin>, - pub io1: GpioPin>, - pub io2: Option>>, - pub io3: Option>>, -} - pub struct DeepPowerDownConfig { pub enter_time: u16, pub exit_time: u16, } pub struct Config { - pub pins: Pins, pub xip_offset: u32, pub read_opcode: ReadOpcode, pub write_opcode: WriteOpcode, @@ -51,55 +43,54 @@ pub struct Config { pub deep_power_down: Option, } -struct State { - inner: QSPI, - waker: WakerRegistration, +pub struct Qspi<'d, T: Instance> { + qspi: T, + irq: T::Interrupt, + phantom: PhantomData<&'d mut T>, } -pub struct Qspi { - inner: PeripheralMutex, -} +impl<'d, T: Instance> Qspi<'d, T> { + pub fn new( + qspi: impl PeripheralBorrow + 'd, + irq: impl PeripheralBorrow + 'd, + sck: impl PeripheralBorrow + 'd, + csn: impl PeripheralBorrow + 'd, + io0: impl PeripheralBorrow + 'd, + io1: impl PeripheralBorrow + 'd, + io2: impl PeripheralBorrow + 'd, + io3: impl PeripheralBorrow + 'd, + config: Config, + ) -> Self { + let mut qspi = unsafe { qspi.unborrow() }; + let irq = unsafe { irq.unborrow() }; + let sck = unsafe { sck.unborrow() }; + let csn = unsafe { csn.unborrow() }; + let io0 = unsafe { io0.unborrow() }; + let io1 = unsafe { io1.unborrow() }; + let io2 = unsafe { io2.unborrow() }; + let io3 = unsafe { io3.unborrow() }; -impl Qspi { - pub fn new(qspi: QSPI, irq: interrupt::QSPI, config: Config) -> Self { - qspi.psel.sck.write(|w| { - let pin = &config.pins.sck; - unsafe { w.bits(pin.psel_bits()) }; - w.connect().connected() - }); - qspi.psel.csn.write(|w| { - let pin = &config.pins.csn; - unsafe { w.bits(pin.psel_bits()) }; - w.connect().connected() - }); - qspi.psel.io0.write(|w| { - let pin = &config.pins.io0; - unsafe { w.bits(pin.psel_bits()) }; - w.connect().connected() - }); - qspi.psel.io1.write(|w| { - let pin = &config.pins.io1; - unsafe { w.bits(pin.psel_bits()) }; - w.connect().connected() - }); - qspi.psel.io2.write(|w| { - if let Some(ref pin) = config.pins.io2 { - unsafe { w.bits(pin.psel_bits()) }; - w.connect().connected() - } else { - w.connect().disconnected() - } - }); - qspi.psel.io3.write(|w| { - if let Some(ref pin) = config.pins.io3 { - unsafe { w.bits(pin.psel_bits()) }; - w.connect().connected() - } else { - w.connect().disconnected() - } - }); + let r = qspi.regs(); - qspi.ifconfig0.write(|mut w| { + for cnf in &[ + sck.conf(), + csn.conf(), + io0.conf(), + io1.conf(), + io2.conf(), + io3.conf(), + ] { + cnf.write(|w| w.dir().output().drive().h0h1()); + } + + r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) }); + r.psel.csn.write(|w| unsafe { w.bits(csn.psel_bits()) }); + r.psel.io0.write(|w| unsafe { w.bits(io0.psel_bits()) }); + r.psel.io1.write(|w| unsafe { w.bits(io1.psel_bits()) }); + r.psel.io2.write(|w| unsafe { w.bits(io2.psel_bits()) }); + r.psel.io3.write(|w| unsafe { w.bits(io3.psel_bits()) }); + + r.ifconfig0.write(|mut w| { w = w.addrmode().variant(AddressMode::_24BIT); if config.deep_power_down.is_some() { w = w.dpmenable().enable(); @@ -113,14 +104,14 @@ impl Qspi { }); if let Some(dpd) = &config.deep_power_down { - qspi.dpmdur.write(|mut w| unsafe { + r.dpmdur.write(|mut w| unsafe { w = w.enter().bits(dpd.enter_time); w = w.exit().bits(dpd.exit_time); w }) } - qspi.ifconfig1.write(|w| { + r.ifconfig1.write(|w| { let w = unsafe { w.sckdelay().bits(80) }; let w = w.dpmen().exit(); let w = w.spimode().mode0(); @@ -128,48 +119,42 @@ impl Qspi { w }); - qspi.xipoffset + r.xipoffset .write(|w| unsafe { w.xipoffset().bits(config.xip_offset) }); // Enable it - qspi.enable.write(|w| w.enable().enabled()); + r.enable.write(|w| w.enable().enabled()); - qspi.events_ready.reset(); - qspi.tasks_activate.write(|w| w.tasks_activate().bit(true)); - while qspi.events_ready.read().bits() == 0 {} - qspi.events_ready.reset(); + r.events_ready.reset(); + r.tasks_activate.write(|w| w.tasks_activate().bit(true)); + while r.events_ready.read().bits() == 0 {} + r.events_ready.reset(); Self { - inner: PeripheralMutex::new( - State { - inner: qspi, - waker: WakerRegistration::new(), - }, - irq, - ), + qspi, + irq, + phantom: PhantomData, } } - pub fn sleep(self: Pin<&mut Self>) { - self.inner().with(|s, _| { - info!("flash: sleeping"); - info!("flash: state = {:?}", s.inner.status.read().bits()); - s.inner.ifconfig1.modify(|_, w| w.dpmen().enter()); - info!("flash: state = {:?}", s.inner.status.read().bits()); - cortex_m::asm::delay(1000000); - info!("flash: state = {:?}", s.inner.status.read().bits()); + pub fn sleep(mut self: Pin<&mut Self>) { + let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs(); - s.inner - .tasks_deactivate - .write(|w| w.tasks_deactivate().set_bit()); - }); + info!("flash: sleeping"); + info!("flash: state = {:?}", r.status.read().bits()); + r.ifconfig1.modify(|_, w| w.dpmen().enter()); + info!("flash: state = {:?}", r.status.read().bits()); + cortex_m::asm::delay(1000000); + info!("flash: state = {:?}", r.status.read().bits()); + + r.tasks_deactivate.write(|w| w.tasks_deactivate().set_bit()); } - pub async fn custom_instruction<'a>( - mut self: Pin<&'a mut Self>, + pub async fn custom_instruction( + mut self: Pin<&mut Self>, opcode: u8, - req: &'a [u8], - resp: &'a mut [u8], + req: &[u8], + resp: &mut [u8], ) -> Result<(), Error> { let bomb = DropBomb::new(); @@ -192,69 +177,73 @@ impl Qspi { let len = core::cmp::max(req.len(), resp.len()) as u8; - self.as_mut().inner().with(|s, _| { - s.inner.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); - s.inner.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); + let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs(); + r.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); + r.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); - s.inner.events_ready.reset(); - s.inner.intenset.write(|w| w.ready().set()); + r.events_ready.reset(); + r.intenset.write(|w| w.ready().set()); - s.inner.cinstrconf.write(|w| { - let w = unsafe { w.opcode().bits(opcode) }; - let w = unsafe { w.length().bits(len + 1) }; - let w = w.lio2().bit(true); - let w = w.lio3().bit(true); - let w = w.wipwait().bit(true); - let w = w.wren().bit(true); - let w = w.lfen().bit(false); - let w = w.lfstop().bit(false); - w - }); + r.cinstrconf.write(|w| { + let w = unsafe { w.opcode().bits(opcode) }; + let w = unsafe { w.length().bits(len + 1) }; + let w = w.lio2().bit(true); + let w = w.lio3().bit(true); + let w = w.wipwait().bit(true); + let w = w.wren().bit(true); + let w = w.lfen().bit(false); + let w = w.lfstop().bit(false); + w }); self.as_mut().wait_ready().await; - self.as_mut().inner().with(|s, _| { - let dat0 = s.inner.cinstrdat0.read().bits(); - let dat1 = s.inner.cinstrdat1.read().bits(); - for i in 0..4 { - if i < resp.len() { - resp[i] = (dat0 >> (i * 8)) as u8; - } + let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs(); + + let dat0 = r.cinstrdat0.read().bits(); + let dat1 = r.cinstrdat1.read().bits(); + for i in 0..4 { + if i < resp.len() { + resp[i] = (dat0 >> (i * 8)) as u8; } - for i in 0..4 { - if i + 4 < resp.len() { - resp[i] = (dat1 >> (i * 8)) as u8; - } + } + for i in 0..4 { + if i + 4 < resp.len() { + resp[i] = (dat1 >> (i * 8)) as u8; } - }); + } bomb.defuse(); Ok(()) } - fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex> { - unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } - } + async fn wait_ready(self: Pin<&mut Self>) { + let this = unsafe { self.get_unchecked_mut() }; - fn wait_ready<'a>(mut self: Pin<&'a mut Self>) -> impl Future + 'a { poll_fn(move |cx| { - self.as_mut().inner().with(|s, _irq| { - if s.inner.events_ready.read().bits() != 0 { - return Poll::Ready(()); - } - s.waker.register(cx.waker()); - Poll::Pending - }) + let r = this.qspi.regs(); + + if r.events_ready.read().bits() != 0 { + r.events_ready.reset(); + return Poll::Ready(()); + } + + wake_on_interrupt(&mut this.irq, cx.waker()); + + Poll::Pending }) + .await } } -impl Flash for Qspi { - type ReadFuture<'a> = impl Future> + 'a; - type WriteFuture<'a> = impl Future> + 'a; - type ErasePageFuture<'a> = impl Future> + 'a; +impl<'d, T: Instance> Flash for Qspi<'d, T> { + #[rustfmt::skip] + type ReadFuture<'a> where Self: 'a = impl Future> + 'a; + #[rustfmt::skip] + type WriteFuture<'a> where Self: 'a = impl Future> + 'a; + #[rustfmt::skip] + type ErasePageFuture<'a> where Self: 'a = impl Future> + 'a; fn read<'a>( mut self: Pin<&'a mut Self>, @@ -268,26 +257,21 @@ impl Flash for Qspi { assert_eq!(data.len() as u32 % 4, 0); assert_eq!(address as u32 % 4, 0); - self.as_mut().inner().with(|s, _| { - s.inner - .read - .src - .write(|w| unsafe { w.src().bits(address as u32) }); - s.inner - .read - .dst - .write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); - s.inner - .read - .cnt - .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); + let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs(); - s.inner.events_ready.reset(); - s.inner.intenset.write(|w| w.ready().set()); - s.inner - .tasks_readstart - .write(|w| w.tasks_readstart().bit(true)); - }); + r.read + .src + .write(|w| unsafe { w.src().bits(address as u32) }); + r.read + .dst + .write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); + r.read + .cnt + .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); + + r.events_ready.reset(); + r.intenset.write(|w| w.ready().set()); + r.tasks_readstart.write(|w| w.tasks_readstart().bit(true)); self.as_mut().wait_ready().await; @@ -309,26 +293,20 @@ impl Flash for Qspi { assert_eq!(data.len() as u32 % 4, 0); assert_eq!(address as u32 % 4, 0); - self.as_mut().inner().with(|s, _| { - s.inner - .write - .src - .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); - s.inner - .write - .dst - .write(|w| unsafe { w.dst().bits(address as u32) }); - s.inner - .write - .cnt - .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); + let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs(); + r.write + .src + .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); + r.write + .dst + .write(|w| unsafe { w.dst().bits(address as u32) }); + r.write + .cnt + .write(|w| unsafe { w.cnt().bits(data.len() as u32) }); - s.inner.events_ready.reset(); - s.inner.intenset.write(|w| w.ready().set()); - s.inner - .tasks_writestart - .write(|w| w.tasks_writestart().bit(true)); - }); + r.events_ready.reset(); + r.intenset.write(|w| w.ready().set()); + r.tasks_writestart.write(|w| w.tasks_writestart().bit(true)); self.as_mut().wait_ready().await; @@ -344,19 +322,15 @@ impl Flash for Qspi { assert_eq!(address as u32 % 4096, 0); - self.as_mut().inner().with(|s, _| { - s.inner - .erase - .ptr - .write(|w| unsafe { w.ptr().bits(address as u32) }); - s.inner.erase.len.write(|w| w.len()._4kb()); + let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs(); + r.erase + .ptr + .write(|w| unsafe { w.ptr().bits(address as u32) }); + r.erase.len.write(|w| w.len()._4kb()); - s.inner.events_ready.reset(); - s.inner.intenset.write(|w| w.ready().set()); - s.inner - .tasks_erasestart - .write(|w| w.tasks_erasestart().bit(true)); - }); + r.events_ready.reset(); + r.intenset.write(|w| w.ready().set()); + r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true)); self.as_mut().wait_ready().await; @@ -383,13 +357,29 @@ impl Flash for Qspi { } } -impl PeripheralState for State { - type Interrupt = interrupt::QSPI; +mod sealed { + use super::*; - fn on_interrupt(&mut self) { - if self.inner.events_ready.read().bits() != 0 { - self.inner.intenclr.write(|w| w.ready().clear()); - self.waker.wake() - } + pub trait Instance { + fn regs(&mut self) -> &pac::qspi::RegisterBlock; } } + +pub trait Instance: sealed::Instance + 'static { + type Interrupt: Interrupt; +} + +macro_rules! make_impl { + ($type:ident, $irq:ident) => { + impl sealed::Instance for peripherals::$type { + fn regs(&mut self) -> &pac::qspi::RegisterBlock { + unsafe { &*pac::$type::ptr() } + } + } + impl Instance for peripherals::$type { + type Interrupt = interrupt::$irq; + } + }; +} + +make_impl!(QSPI, QSPI); diff --git a/embassy-traits/src/flash.rs b/embassy-traits/src/flash.rs index 145cc768..3adaa3a0 100644 --- a/embassy-traits/src/flash.rs +++ b/embassy-traits/src/flash.rs @@ -11,9 +11,17 @@ pub enum Error { } pub trait Flash { - type ReadFuture<'a>: Future>; - type WriteFuture<'a>: Future>; - type ErasePageFuture<'a>: Future>; + type ReadFuture<'a>: Future> + where + Self: 'a; + + type WriteFuture<'a>: Future> + where + Self: 'a; + + type ErasePageFuture<'a>: Future> + where + Self: 'a; /// Reads data from the flash device. /// From c0876187dd16d4a391a9b11a4eb5f91689c7d6ff Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 21 Mar 2021 20:57:49 +0100 Subject: [PATCH 11/45] extras: move peripherals from nrf to extras --- embassy-extras/src/lib.rs | 1 + embassy-extras/src/macros.rs | 45 +++++++++++++++++++++++++++++++ embassy-nrf/src/peripherals.rs | 49 +--------------------------------- 3 files changed, 47 insertions(+), 48 deletions(-) create mode 100644 embassy-extras/src/macros.rs diff --git a/embassy-extras/src/lib.rs b/embassy-extras/src/lib.rs index 536e86c6..5dafba70 100644 --- a/embassy-extras/src/lib.rs +++ b/embassy-extras/src/lib.rs @@ -3,6 +3,7 @@ // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; +mod macros; pub mod peripheral; pub mod ring_buffer; pub mod usb; diff --git a/embassy-extras/src/macros.rs b/embassy-extras/src/macros.rs new file mode 100644 index 00000000..151f410a --- /dev/null +++ b/embassy-extras/src/macros.rs @@ -0,0 +1,45 @@ +#[macro_export] +macro_rules! peripherals { + ($($(#[$cfg:meta])? $name:ident: $type:ident),*$(,)?) => { + $( + $(#[$cfg])? + #[allow(non_camel_case_types)] + pub struct $type { _private: () } + + $(#[$cfg])? + impl embassy::util::PeripheralBorrow for $type { + type Target = $type; + unsafe fn unborrow(self) -> $type { + self + } + } + + $(#[$cfg])? + impl embassy::util::PeripheralBorrow for &mut $type { + type Target = $type; + unsafe fn unborrow(self) -> $type { + ::core::ptr::read(self) + } + } + )* + + pub struct Peripherals { + $( + $(#[$cfg])? + pub $name: $type, + )* + } + + impl Peripherals { + pub unsafe fn steal() -> Self { + Self { + $( + $(#[$cfg])? + $name: $type { _private: () }, + )* + } + } + } + + }; +} diff --git a/embassy-nrf/src/peripherals.rs b/embassy-nrf/src/peripherals.rs index 1f449e91..ea76c809 100644 --- a/embassy-nrf/src/peripherals.rs +++ b/embassy-nrf/src/peripherals.rs @@ -1,51 +1,4 @@ -use embassy::util::PeripheralBorrow; - -macro_rules! peripherals { - ($($(#[$cfg:meta])? $name:ident: $type:ident),*$(,)?) => { - $( - $(#[$cfg])? - #[allow(non_camel_case_types)] - pub struct $type { _private: () } - - $(#[$cfg])? - impl PeripheralBorrow for $type { - type Target = $type; - unsafe fn unborrow(self) -> $type { - self - } - } - - $(#[$cfg])? - impl PeripheralBorrow for &mut $type { - type Target = $type; - unsafe fn unborrow(self) -> $type { - ::core::ptr::read(self) - } - } - )* - - pub struct Peripherals { - $( - $(#[$cfg])? - pub $name: $type, - )* - } - - impl Peripherals { - pub unsafe fn steal() -> Self { - Self { - $( - $(#[$cfg])? - $name: $type { _private: () }, - )* - } - } - } - - }; -} - -peripherals! { +embassy_extras::peripherals! { // RTC rtc0: RTC0, rtc1: RTC1, From 95218bf8d4a49121e94d6290b8cdb4129a9ea0b8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 21 Mar 2021 21:01:06 +0100 Subject: [PATCH 12/45] Rename GpioteInput -> PortInput --- embassy-nrf-examples/src/bin/gpiote_port.rs | 12 ++++++------ embassy-nrf/src/gpiote.rs | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/embassy-nrf-examples/src/bin/gpiote_port.rs b/embassy-nrf-examples/src/bin/gpiote_port.rs index 273cd124..b0e59ccc 100644 --- a/embassy-nrf-examples/src/bin/gpiote_port.rs +++ b/embassy-nrf-examples/src/bin/gpiote_port.rs @@ -8,7 +8,7 @@ mod example_common; use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; use example_common::*; -use gpiote::GpioteInput; +use gpiote::PortInput; use core::pin::Pin; use cortex_m_rt::entry; @@ -21,7 +21,7 @@ use embassy::util::Forever; use embassy_nrf::gpiote; use embassy_nrf::interrupt; -async fn button(n: usize, mut pin: GpioteInput) { +async fn button(n: usize, mut pin: PortInput) { loop { Pin::new(&mut pin).wait_for_low().await; info!("Button {:?} pressed!", n); @@ -38,19 +38,19 @@ async fn run() { let button1 = button( 1, - GpioteInput::new(g, Input::new(p.p0_11.degrade(), Pull::Up)), + PortInput::new(g, Input::new(p.p0_11.degrade(), Pull::Up)), ); let button2 = button( 2, - GpioteInput::new(g, Input::new(p.p0_12.degrade(), Pull::Up)), + PortInput::new(g, Input::new(p.p0_12.degrade(), Pull::Up)), ); let button3 = button( 3, - GpioteInput::new(g, Input::new(p.p0_24.degrade(), Pull::Up)), + PortInput::new(g, Input::new(p.p0_24.degrade(), Pull::Up)), ); let button4 = button( 4, - GpioteInput::new(g, Input::new(p.p0_25.degrade(), Pull::Up)), + PortInput::new(g, Input::new(p.p0_25.degrade(), Pull::Up)), ); futures::join!(button1, button2, button3, button4); } diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 2b603c4c..dc96a7eb 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -338,18 +338,18 @@ impl OutputChannel { */ /// GPIO input driver with support -pub struct GpioteInput { +pub struct PortInput { pin: Input, } -impl Unpin for GpioteInput {} +impl Unpin for PortInput {} -impl GpioteInput { +impl PortInput { pub fn new(_init: Initialized, pin: Input) -> Self { Self { pin } } } -impl InputPin for GpioteInput { +impl InputPin for PortInput { type Error = Infallible; fn is_high(&self) -> Result { @@ -361,7 +361,7 @@ impl InputPin for GpioteInput { } } -impl WaitForHigh for GpioteInput { +impl WaitForHigh for PortInput { type Future<'a> = PortInputFuture<'a>; fn wait_for_high<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> { @@ -374,7 +374,7 @@ impl WaitForHigh for GpioteInput { } } -impl WaitForLow for GpioteInput { +impl WaitForLow for PortInput { type Future<'a> = PortInputFuture<'a>; fn wait_for_low<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> { From 90a2b823a4da6ff71b835e97eee8b4f7a91d3758 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 21 Mar 2021 21:03:02 +0100 Subject: [PATCH 13/45] nrf/gpiote: cleanup imports --- embassy-nrf-examples/src/bin/gpiote_port.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/embassy-nrf-examples/src/bin/gpiote_port.rs b/embassy-nrf-examples/src/bin/gpiote_port.rs index b0e59ccc..0ec9e5d3 100644 --- a/embassy-nrf-examples/src/bin/gpiote_port.rs +++ b/embassy-nrf-examples/src/bin/gpiote_port.rs @@ -6,19 +6,17 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; use example_common::*; -use gpiote::PortInput; use core::pin::Pin; use cortex_m_rt::entry; use defmt::panic; -use nrf52840_hal::gpio; use embassy::executor::{task, Executor}; use embassy::traits::gpio::{WaitForHigh, WaitForLow}; use embassy::util::Forever; -use embassy_nrf::gpiote; +use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; +use embassy_nrf::gpiote::{self, PortInput}; use embassy_nrf::interrupt; async fn button(n: usize, mut pin: PortInput) { From d5ff1a0ae30db8963eec1b7f23b90991e4f47c3d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 21 Mar 2021 21:57:04 +0100 Subject: [PATCH 14/45] nrf: rename inner peripheral to `peri` for consistence --- embassy-nrf/src/qspi.rs | 18 +++++++++--------- embassy-nrf/src/spim.rs | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 39428c62..39cefa0a 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -44,7 +44,7 @@ pub struct Config { } pub struct Qspi<'d, T: Instance> { - qspi: T, + peri: T, irq: T::Interrupt, phantom: PhantomData<&'d mut T>, } @@ -131,14 +131,14 @@ impl<'d, T: Instance> Qspi<'d, T> { r.events_ready.reset(); Self { - qspi, + peri: qspi, irq, phantom: PhantomData, } } pub fn sleep(mut self: Pin<&mut Self>) { - let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs(); + let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs(); info!("flash: sleeping"); info!("flash: state = {:?}", r.status.read().bits()); @@ -177,7 +177,7 @@ impl<'d, T: Instance> Qspi<'d, T> { let len = core::cmp::max(req.len(), resp.len()) as u8; - let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs(); + let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs(); r.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); r.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); @@ -198,7 +198,7 @@ impl<'d, T: Instance> Qspi<'d, T> { self.as_mut().wait_ready().await; - let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs(); + let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs(); let dat0 = r.cinstrdat0.read().bits(); let dat1 = r.cinstrdat1.read().bits(); @@ -222,7 +222,7 @@ impl<'d, T: Instance> Qspi<'d, T> { let this = unsafe { self.get_unchecked_mut() }; poll_fn(move |cx| { - let r = this.qspi.regs(); + let r = this.peri.regs(); if r.events_ready.read().bits() != 0 { r.events_ready.reset(); @@ -257,7 +257,7 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { assert_eq!(data.len() as u32 % 4, 0); assert_eq!(address as u32 % 4, 0); - let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs(); + let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs(); r.read .src @@ -293,7 +293,7 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { assert_eq!(data.len() as u32 % 4, 0); assert_eq!(address as u32 % 4, 0); - let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs(); + let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs(); r.write .src .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); @@ -322,7 +322,7 @@ impl<'d, T: Instance> Flash for Qspi<'d, T> { assert_eq!(address as u32 % 4096, 0); - let r = unsafe { self.as_mut().get_unchecked_mut() }.qspi.regs(); + let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs(); r.erase .ptr .write(|w| unsafe { w.ptr().bits(address as u32) }); diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index f0c6ebe1..214868b6 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -26,7 +26,7 @@ pub enum Error { } pub struct Spim<'d, T: Instance> { - spim: T, + peri: T, irq: T::Interrupt, phantom: PhantomData<&'d mut T>, } @@ -116,7 +116,7 @@ impl<'d, T: Instance> Spim<'d, T> { r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); Self { - spim, + peri: spim, irq, phantom: PhantomData, } @@ -155,7 +155,7 @@ impl<'d, T: Instance> FullDuplex for Spim<'d, T> { // before any DMA action has started. compiler_fence(Ordering::SeqCst); - let r = this.spim.regs(); + let r = this.peri.regs(); // Set up the DMA write. r.txd @@ -187,7 +187,7 @@ impl<'d, T: Instance> FullDuplex for Spim<'d, T> { // Wait for 'end' event. poll_fn(|cx| { - let r = this.spim.regs(); + let r = this.peri.regs(); if r.events_end.read().bits() != 0 { r.events_end.reset(); From a134fce122d570cfcd3837944554fff6c35e4039 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 21 Mar 2021 21:58:59 +0100 Subject: [PATCH 15/45] nrf: nicer Peripherals api, add take() --- embassy-extras/src/macros.rs | 70 +++++++++---- embassy-nrf-examples/src/bin/gpiote_port.rs | 6 +- embassy-nrf-examples/src/bin/qspi.rs | 9 +- embassy-nrf-examples/src/bin/spim.rs | 15 ++- embassy-nrf/src/lib.rs | 108 +++++++++++++++++++- embassy-nrf/src/peripherals.rs | 106 ------------------- embassy/src/util/mod.rs | 4 + 7 files changed, 175 insertions(+), 143 deletions(-) delete mode 100644 embassy-nrf/src/peripherals.rs diff --git a/embassy-extras/src/macros.rs b/embassy-extras/src/macros.rs index 151f410a..478549ac 100644 --- a/embassy-extras/src/macros.rs +++ b/embassy-extras/src/macros.rs @@ -1,41 +1,71 @@ #[macro_export] macro_rules! peripherals { ($($(#[$cfg:meta])? $name:ident: $type:ident),*$(,)?) => { - $( - $(#[$cfg])? - #[allow(non_camel_case_types)] - pub struct $type { _private: () } + pub mod peripherals { + $( + $(#[$cfg])? + #[allow(non_camel_case_types)] + pub struct $type { _private: () } - $(#[$cfg])? - impl embassy::util::PeripheralBorrow for $type { - type Target = $type; - unsafe fn unborrow(self) -> $type { - self + impl embassy::util::Steal for $type { + #[inline] + unsafe fn steal() -> Self { + Self{ _private: ()} + } } - } - $(#[$cfg])? - impl embassy::util::PeripheralBorrow for &mut $type { - type Target = $type; - unsafe fn unborrow(self) -> $type { - ::core::ptr::read(self) + $(#[$cfg])? + impl embassy::util::PeripheralBorrow for $type { + type Target = $type; + #[inline] + unsafe fn unborrow(self) -> $type { + self + } } - } - )* + + $(#[$cfg])? + impl embassy::util::PeripheralBorrow for &mut $type { + type Target = $type; + #[inline] + unsafe fn unborrow(self) -> $type { + ::core::ptr::read(self) + } + } + )* + } pub struct Peripherals { $( $(#[$cfg])? - pub $name: $type, + pub $name: peripherals::$type, )* } impl Peripherals { - pub unsafe fn steal() -> Self { + ///Returns all the peripherals *once* + #[inline] + pub fn take() -> Option { + + #[no_mangle] + static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false; + + cortex_m::interrupt::free(|_| { + if unsafe { _EMBASSY_DEVICE_PERIPHERALS } { + None + } else { + Some(unsafe { ::steal() }) + } + }) + } + } + + impl embassy::util::Steal for Peripherals { + #[inline] + unsafe fn steal() -> Self { Self { $( $(#[$cfg])? - $name: $type { _private: () }, + $name: ::steal(), )* } } diff --git a/embassy-nrf-examples/src/bin/gpiote_port.rs b/embassy-nrf-examples/src/bin/gpiote_port.rs index 0ec9e5d3..593261ae 100644 --- a/embassy-nrf-examples/src/bin/gpiote_port.rs +++ b/embassy-nrf-examples/src/bin/gpiote_port.rs @@ -6,18 +6,18 @@ #[path = "../example_common.rs"] mod example_common; -use example_common::*; use core::pin::Pin; use cortex_m_rt::entry; use defmt::panic; - use embassy::executor::{task, Executor}; use embassy::traits::gpio::{WaitForHigh, WaitForLow}; use embassy::util::Forever; use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; use embassy_nrf::gpiote::{self, PortInput}; use embassy_nrf::interrupt; +use embassy_nrf::Peripherals; +use example_common::*; async fn button(n: usize, mut pin: PortInput) { loop { @@ -30,7 +30,7 @@ async fn button(n: usize, mut pin: PortInput) { #[task] async fn run() { - let p = unsafe { embassy_nrf::peripherals::Peripherals::steal() }; + let p = Peripherals::take().unwrap(); let g = gpiote::initialize(p.gpiote, interrupt::take!(GPIOTE)); diff --git a/embassy-nrf-examples/src/bin/qspi.rs b/embassy-nrf-examples/src/bin/qspi.rs index a0896988..1637b397 100644 --- a/embassy-nrf-examples/src/bin/qspi.rs +++ b/embassy-nrf-examples/src/bin/qspi.rs @@ -6,17 +6,16 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_nrf::peripherals::Peripherals; -use example_common::*; use cortex_m_rt::entry; use defmt::{assert_eq, panic}; -use futures::pin_mut; - use embassy::executor::{task, Executor}; use embassy::traits::flash::Flash; use embassy::util::Forever; +use embassy_nrf::Peripherals; use embassy_nrf::{interrupt, qspi}; +use example_common::*; +use futures::pin_mut; const PAGE_SIZE: usize = 4096; @@ -27,7 +26,7 @@ struct AlignedBuf([u8; 4096]); #[task] async fn run() { - let p = unsafe { Peripherals::steal() }; + let p = Peripherals::take().unwrap(); let csn = p.p0_17; let sck = p.p0_19; diff --git a/embassy-nrf-examples/src/bin/spim.rs b/embassy-nrf-examples/src/bin/spim.rs index b7436332..f4fb22ba 100644 --- a/embassy-nrf-examples/src/bin/spim.rs +++ b/embassy-nrf-examples/src/bin/spim.rs @@ -6,26 +6,25 @@ #[path = "../example_common.rs"] mod example_common; -use embassy_nrf::gpio::{Level, Output, OutputDrive}; -use embassy_nrf::peripherals::Peripherals; -use embassy_traits::spi::FullDuplex; -use example_common::*; use cortex_m_rt::entry; use defmt::panic; use embassy::executor::{task, Executor}; use embassy::util::Forever; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::Peripherals; +use embassy_nrf::{interrupt, pac, rtc, spim}; +use embassy_traits::spi::FullDuplex; use embedded_hal::digital::v2::*; +use example_common::*; use futures::pin_mut; use nrf52840_hal::clocks; -use embassy_nrf::{interrupt, pac, rtc, spim}; - #[task] async fn run() { info!("running!"); - let mut p = unsafe { Peripherals::steal() }; + let p = Peripherals::take().unwrap(); let config = spim::Config { frequency: spim::Frequency::M16, @@ -33,7 +32,7 @@ async fn run() { orc: 0x00, }; - let mut irq = interrupt::take!(SPIM3); + let irq = interrupt::take!(SPIM3); let spim = spim::Spim::new(p.spim3, irq, p.p0_29, p.p0_28, p.p0_30, config); pin_mut!(spim); diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 07759996..22c71e7f 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -97,9 +97,115 @@ pub mod buffered_uarte; pub mod gpio; pub mod gpiote; pub mod interrupt; -pub mod peripherals; #[cfg(feature = "52840")] pub mod qspi; pub mod rtc; pub mod spim; pub mod uarte; + +embassy_extras::peripherals! { + // RTC + rtc0: RTC0, + rtc1: RTC1, + #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] + rtc2: RTC2, + + // QSPI + #[cfg(feature = "52840")] + qspi: QSPI, + + // UARTE + uarte0: UARTE0, + #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] + uarte1: UARTE1, + + // SPIM + // TODO this is actually shared with SPI, SPIM, SPIS, TWI, TWIS, TWIS. + // When they're all implemented, they should be only one peripheral here. + spim0: SPIM0, + #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] + spim1: SPIM1, + #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] + spim2: SPIM2, + #[cfg(any(feature = "52833", feature = "52840"))] + spim3: SPIM3, + + // GPIOTE + gpiote: GPIOTE, + gpiote_ch_0: GPIOTE_CH0, + gpiote_ch_1: GPIOTE_CH1, + gpiote_ch_2: GPIOTE_CH2, + gpiote_ch_3: GPIOTE_CH3, + gpiote_ch_4: GPIOTE_CH4, + gpiote_ch_5: GPIOTE_CH5, + gpiote_ch_6: GPIOTE_CH6, + gpiote_ch_7: GPIOTE_CH7, + + // GPIO port 0 + p0_00: P0_00, + p0_01: P0_01, + p0_02: P0_02, + p0_03: P0_03, + p0_04: P0_04, + p0_05: P0_05, + p0_06: P0_06, + p0_07: P0_07, + p0_08: P0_08, + p0_09: P0_09, + p0_10: P0_10, + p0_11: P0_11, + p0_12: P0_12, + p0_13: P0_13, + p0_14: P0_14, + p0_15: P0_15, + p0_16: P0_16, + p0_17: P0_17, + p0_18: P0_18, + p0_19: P0_19, + p0_20: P0_20, + p0_21: P0_21, + p0_22: P0_22, + p0_23: P0_23, + p0_24: P0_24, + p0_25: P0_25, + p0_26: P0_26, + p0_27: P0_27, + p0_28: P0_28, + p0_29: P0_29, + p0_30: P0_30, + p0_31: P0_31, + + // GPIO port 1 + #[cfg(any(feature = "52833", feature = "52840"))] + p1_00: P1_00, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_01: P1_01, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_02: P1_02, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_03: P1_03, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_04: P1_04, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_05: P1_05, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_06: P1_06, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_07: P1_07, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_08: P1_08, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_09: P1_09, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_10: P1_10, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_11: P1_11, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_12: P1_12, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_13: P1_13, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_14: P1_14, + #[cfg(any(feature = "52833", feature = "52840"))] + p1_15: P1_15, +} diff --git a/embassy-nrf/src/peripherals.rs b/embassy-nrf/src/peripherals.rs deleted file mode 100644 index ea76c809..00000000 --- a/embassy-nrf/src/peripherals.rs +++ /dev/null @@ -1,106 +0,0 @@ -embassy_extras::peripherals! { - // RTC - rtc0: RTC0, - rtc1: RTC1, - #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] - rtc2: RTC2, - - // QSPI - #[cfg(feature = "52840")] - qspi: QSPI, - - // UARTE - uarte0: UARTE0, - #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] - uarte1: UARTE1, - - // SPIM - // TODO this is actually shared with SPI, SPIM, SPIS, TWI, TWIS, TWIS. - // When they're all implemented, they should be only one peripheral here. - spim0: SPIM0, - #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] - spim1: SPIM1, - #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] - spim2: SPIM2, - #[cfg(any(feature = "52833", feature = "52840"))] - spim3: SPIM3, - - // GPIOTE - gpiote: GPIOTE, - gpiote_ch_0: GPIOTE_CH0, - gpiote_ch_1: GPIOTE_CH1, - gpiote_ch_2: GPIOTE_CH2, - gpiote_ch_3: GPIOTE_CH3, - gpiote_ch_4: GPIOTE_CH4, - gpiote_ch_5: GPIOTE_CH5, - gpiote_ch_6: GPIOTE_CH6, - gpiote_ch_7: GPIOTE_CH7, - - // GPIO port 0 - p0_00: P0_00, - p0_01: P0_01, - p0_02: P0_02, - p0_03: P0_03, - p0_04: P0_04, - p0_05: P0_05, - p0_06: P0_06, - p0_07: P0_07, - p0_08: P0_08, - p0_09: P0_09, - p0_10: P0_10, - p0_11: P0_11, - p0_12: P0_12, - p0_13: P0_13, - p0_14: P0_14, - p0_15: P0_15, - p0_16: P0_16, - p0_17: P0_17, - p0_18: P0_18, - p0_19: P0_19, - p0_20: P0_20, - p0_21: P0_21, - p0_22: P0_22, - p0_23: P0_23, - p0_24: P0_24, - p0_25: P0_25, - p0_26: P0_26, - p0_27: P0_27, - p0_28: P0_28, - p0_29: P0_29, - p0_30: P0_30, - p0_31: P0_31, - - // GPIO port 1 - #[cfg(any(feature = "52833", feature = "52840"))] - p1_00: P1_00, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_01: P1_01, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_02: P1_02, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_03: P1_03, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_04: P1_04, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_05: P1_05, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_06: P1_06, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_07: P1_07, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_08: P1_08, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_09: P1_09, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_10: P1_10, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_11: P1_11, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_12: P1_12, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_13: P1_13, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_14: P1_14, - #[cfg(any(feature = "52833", feature = "52840"))] - p1_15: P1_15, -} diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs index 18b61246..3166c65d 100644 --- a/embassy/src/util/mod.rs +++ b/embassy/src/util/mod.rs @@ -19,3 +19,7 @@ pub trait PeripheralBorrow { type Target; unsafe fn unborrow(self) -> Self::Target; } + +pub trait Steal { + unsafe fn steal() -> Self; +} From 7b6086d19eca2d51c7cddf9dbbbc47eacf371472 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 21 Mar 2021 22:09:06 +0100 Subject: [PATCH 16/45] nrf: add unborrow! macro --- embassy-extras/src/macros.rs | 9 +++++++++ embassy-nrf/src/qspi.rs | 14 ++++---------- embassy-nrf/src/spim.rs | 11 ++++------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/embassy-extras/src/macros.rs b/embassy-extras/src/macros.rs index 478549ac..5c50f5d9 100644 --- a/embassy-extras/src/macros.rs +++ b/embassy-extras/src/macros.rs @@ -73,3 +73,12 @@ macro_rules! peripherals { }; } + +#[macro_export] +macro_rules! unborrow { + ($($name:ident),*) => { + $( + let $name = unsafe { $name.unborrow() }; + )* + } +} diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 39cefa0a..10564ba5 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -5,6 +5,7 @@ use core::task::Poll; use embassy::interrupt::Interrupt; use embassy_extras::peripheral::{PeripheralMutex, PeripheralState}; +use embassy_extras::unborrow; use crate::fmt::{assert, assert_eq, *}; use crate::gpio::Pin as GpioPin; @@ -61,14 +62,7 @@ impl<'d, T: Instance> Qspi<'d, T> { io3: impl PeripheralBorrow + 'd, config: Config, ) -> Self { - let mut qspi = unsafe { qspi.unborrow() }; - let irq = unsafe { irq.unborrow() }; - let sck = unsafe { sck.unborrow() }; - let csn = unsafe { csn.unborrow() }; - let io0 = unsafe { io0.unborrow() }; - let io1 = unsafe { io1.unborrow() }; - let io2 = unsafe { io2.unborrow() }; - let io3 = unsafe { io3.unborrow() }; + unborrow!(qspi, irq, sck, csn, io0, io1, io2, io3); let r = qspi.regs(); @@ -361,7 +355,7 @@ mod sealed { use super::*; pub trait Instance { - fn regs(&mut self) -> &pac::qspi::RegisterBlock; + fn regs(&self) -> &pac::qspi::RegisterBlock; } } @@ -372,7 +366,7 @@ pub trait Instance: sealed::Instance + 'static { macro_rules! make_impl { ($type:ident, $irq:ident) => { impl sealed::Instance for peripherals::$type { - fn regs(&mut self) -> &pac::qspi::RegisterBlock { + fn regs(&self) -> &pac::qspi::RegisterBlock { unsafe { &*pac::$type::ptr() } } } diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 214868b6..c84861f3 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -5,6 +5,7 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy::traits; use embassy::util::{wake_on_interrupt, PeripheralBorrow}; +use embassy_extras::unborrow; use futures::future::poll_fn; use traits::spi::FullDuplex; @@ -46,11 +47,7 @@ impl<'d, T: Instance> Spim<'d, T> { mosi: impl PeripheralBorrow + 'd, config: Config, ) -> Self { - let mut spim = unsafe { spim.unborrow() }; - let irq = unsafe { irq.unborrow() }; - let sck = unsafe { sck.unborrow() }; - let miso = unsafe { miso.unborrow() }; - let mosi = unsafe { mosi.unborrow() }; + unborrow!(spim, irq, sck, miso, mosi); let r = spim.regs(); @@ -209,7 +206,7 @@ mod sealed { use super::*; pub trait Instance { - fn regs(&mut self) -> &pac::spim0::RegisterBlock; + fn regs(&self) -> &pac::spim0::RegisterBlock; } } @@ -220,7 +217,7 @@ pub trait Instance: sealed::Instance + 'static { macro_rules! make_impl { ($type:ident, $irq:ident) => { impl sealed::Instance for peripherals::$type { - fn regs(&mut self) -> &pac::spim0::RegisterBlock { + fn regs(&self) -> &pac::spim0::RegisterBlock { unsafe { &*pac::$type::ptr() } } } From df42c384923579c449a13511b0fdb8de3b2a4773 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Mar 2021 01:15:44 +0100 Subject: [PATCH 17/45] nrf/uarte: update to new api --- embassy-nrf-examples/src/bin/uart.rs | 52 ++-- embassy-nrf/src/uarte.rs | 419 +++++++++++++-------------- embassy-traits/src/uart.rs | 34 ++- embassy/src/util/mod.rs | 2 + embassy/src/util/on_drop.rs | 24 ++ 5 files changed, 267 insertions(+), 264 deletions(-) create mode 100644 embassy/src/util/on_drop.rs diff --git a/embassy-nrf-examples/src/bin/uart.rs b/embassy-nrf-examples/src/bin/uart.rs index 0acd6fde..c39e70d5 100644 --- a/embassy-nrf-examples/src/bin/uart.rs +++ b/embassy-nrf-examples/src/bin/uart.rs @@ -12,38 +12,26 @@ use cortex_m_rt::entry; use defmt::panic; use embassy::executor::{task, Executor}; use embassy::time::{Duration, Timer}; -use embassy::traits::uart::Uart; +use embassy::traits::uart::{Read, Write}; use embassy::util::Forever; -use embassy_nrf::{interrupt, pac, rtc, uarte}; +use embassy_nrf::{interrupt, pac, rtc, uarte, Peripherals}; use futures::future::{select, Either}; +use futures::pin_mut; use nrf52840_hal::clocks; use nrf52840_hal::gpio; #[task] -async fn run(uart: pac::UARTE0, port: pac::P0) { - // Init UART - let port0 = gpio::p0::Parts::new(port); +async fn run() { + let p = Peripherals::take().unwrap(); - let pins = uarte::Pins { - rxd: port0.p0_08.into_floating_input().degrade(), - txd: port0 - .p0_06 - .into_push_pull_output(gpio::Level::Low) - .degrade(), - cts: None, - rts: None, - }; + let mut config = uarte::Config::default(); + config.parity = uarte::Parity::EXCLUDED; + config.baudrate = uarte::Baudrate::BAUD115200; - // NOTE(unsafe): Safe becasue we do not use `mem::forget` anywhere. - let mut uart = unsafe { - uarte::Uarte::new( - uart, - interrupt::take!(UARTE0_UART0), - pins, - uarte::Parity::EXCLUDED, - uarte::Baudrate::BAUD115200, - ) - }; + let irq = interrupt::take!(UARTE0_UART0); + let uart = + unsafe { uarte::Uarte::new(p.uarte0, irq, p.p0_08, p.p0_06, p.p0_07, p.p0_05, config) }; + pin_mut!(uart); info!("uarte initialized!"); @@ -51,19 +39,22 @@ async fn run(uart: pac::UARTE0, port: pac::P0) { let mut buf = [0; 8]; buf.copy_from_slice(b"Hello!\r\n"); - unwrap!(uart.send(&buf).await); + unwrap!(uart.as_mut().write(&buf).await); info!("wrote hello in uart!"); loop { - let buf_len = buf.len(); info!("reading..."); + unwrap!(uart.as_mut().read(&mut buf).await); + info!("writing..."); + unwrap!(uart.as_mut().write(&buf).await); + /* // `receive()` doesn't return until the buffer has been completely filled with // incoming data, which in this case is 8 bytes. // // This example shows how to use `select` to run an uart receive concurrently with a // 1 second timer, effectively adding a timeout to the receive operation. - let recv_fut = uart.receive(&mut buf); + let recv_fut = uart.read(&mut buf); let timer_fut = Timer::after(Duration::from_millis(1000)); let received_len = match select(recv_fut, timer_fut).await { // recv_fut completed first, so we've received `buf_len` bytes. @@ -81,8 +72,9 @@ async fn run(uart: pac::UARTE0, port: pac::P0) { info!("read done, got {}", received); // Echo back received data - unwrap!(uart.send(received).await); + unwrap!(uart.write(received).await); } + */ } } @@ -110,9 +102,7 @@ fn main() -> ! { let executor = EXECUTOR.put(Executor::new()); executor.set_alarm(alarm); - let uarte0 = p.UARTE0; - let p0 = p.P0; executor.run(|spawner| { - unwrap!(spawner.spawn(run(uarte0, p0))); + unwrap!(spawner.spawn(run())); }); } diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index b5e4da86..fc57f406 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -5,43 +5,49 @@ //! are dropped correctly (e.g. not using `mem::forget()`). use core::future::Future; -use core::ops::Deref; +use core::marker::PhantomData; +use core::pin::Pin; use core::sync::atomic::{compiler_fence, Ordering}; -use core::task::{Context, Poll}; - -use embassy::interrupt::InterruptExt; -use embassy::util::Signal; +use core::task::Poll; +use embassy::traits::uart::{Error, Read, Write}; +use embassy::util::{wake_on_interrupt, OnDrop, PeripheralBorrow, Signal}; +use embassy_extras::unborrow; +use futures::future::poll_fn; use crate::fmt::{assert, *}; +use crate::gpio::Pin as GpioPin; use crate::hal::pac; -use crate::hal::prelude::*; use crate::hal::target_constants::EASY_DMA_SIZE; use crate::interrupt; use crate::interrupt::Interrupt; +use crate::peripherals; -pub use crate::hal::uarte::Pins; // 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] +pub struct Config { + pub parity: Parity, + pub baudrate: Baudrate, +} + +impl Default for Config { + fn default() -> Self { + Self { + parity: Parity::EXCLUDED, + baudrate: Baudrate::BAUD115200, + } + } +} + /// Interface to the UARTE peripheral -pub struct Uarte -where - T: Instance, -{ - instance: T, +pub struct Uarte<'d, T: Instance> { + peri: T, irq: T::Interrupt, - pins: Pins, + phantom: PhantomData<&'d mut T>, } -pub struct State { - tx_done: Signal<()>, - rx_done: Signal, -} - -impl Uarte -where - T: Instance, -{ +impl<'d, T: Instance> Uarte<'d, T> { /// Creates the interface to a UARTE instance. /// Sets the baud rate, parity and assigns the pins to the UARTE peripheral. /// @@ -52,85 +58,48 @@ where /// or [`receive`](Uarte::receive). #[allow(unused_unsafe)] pub unsafe fn new( - uarte: T, - irq: T::Interrupt, - mut pins: Pins, - parity: Parity, - baudrate: Baudrate, + uarte: impl PeripheralBorrow + 'd, + irq: impl PeripheralBorrow + 'd, + rxd: impl PeripheralBorrow + 'd, + txd: impl PeripheralBorrow + 'd, + cts: impl PeripheralBorrow + 'd, + rts: impl PeripheralBorrow + 'd, + config: Config, ) -> Self { - assert!(uarte.enable.read().enable().is_disabled()); + unborrow!(uarte, irq, rxd, txd, cts, rts); - uarte.psel.rxd.write(|w| { - unsafe { w.bits(pins.rxd.psel_bits()) }; - w.connect().connected() - }); + let r = uarte.regs(); - pins.txd.set_high().unwrap(); - uarte.psel.txd.write(|w| { - unsafe { w.bits(pins.txd.psel_bits()) }; - w.connect().connected() - }); + assert!(r.enable.read().enable().is_disabled()); - // Optional pins - uarte.psel.cts.write(|w| { - if let Some(ref pin) = pins.cts { - unsafe { w.bits(pin.psel_bits()) }; - w.connect().connected() - } else { - w.connect().disconnected() - } - }); + // TODO OptionalPin for RTS/CTS. - uarte.psel.rts.write(|w| { - if let Some(ref pin) = pins.rts { - unsafe { w.bits(pin.psel_bits()) }; - w.connect().connected() - } else { - w.connect().disconnected() - } - }); + txd.set_high(); + rts.set_high(); + rxd.conf().write(|w| w.input().connect().drive().h0h1()); + txd.conf().write(|w| w.dir().output().drive().h0h1()); + //cts.conf().write(|w| w.input().connect().drive().h0h1()); + //rts.conf().write(|w| w.dir().output().drive().h0h1()); - uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); - uarte.config.write(|w| w.parity().variant(parity)); + r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); + r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); + //r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); + //r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); - // Enable interrupts - uarte.events_endtx.reset(); - uarte.events_endrx.reset(); - uarte - .intenset - .write(|w| w.endtx().set().txstopped().set().endrx().set().rxto().set()); + r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); + r.config.write(|w| w.parity().variant(config.parity)); - // Register ISR - irq.set_handler(Self::on_irq); - irq.unpend(); - irq.enable(); + // Enable + r.enable.write(|w| w.enable().enabled()); - Uarte { - instance: uarte, + Self { + peri: uarte, irq, - pins, + phantom: PhantomData, } } - pub fn free(self) -> (T, T::Interrupt, Pins) { - // Wait for the peripheral to be disabled from the ISR. - while self.instance.enable.read().enable().is_enabled() {} - (self.instance, self.irq, self.pins) - } - - fn enable(&mut self) { - trace!("enable"); - self.instance.enable.write(|w| w.enable().enabled()); - } - - fn tx_started(&self) -> bool { - self.instance.events_txstarted.read().bits() != 0 - } - - fn rx_started(&self) -> bool { - self.instance.events_rxstarted.read().bits() != 0 - } - + /* unsafe fn on_irq(_ctx: *mut ()) { let uarte = &*pac::UARTE0::ptr(); @@ -186,54 +155,127 @@ where uarte.enable.write(|w| w.enable().disabled()); } } + */ } -impl embassy::traits::uart::Uart for Uarte { - type ReceiveFuture<'a> = ReceiveFuture<'a, T>; - type SendFuture<'a> = SendFuture<'a, T>; +impl<'d, T: Instance> Read for Uarte<'d, T> { + #[rustfmt::skip] + type ReadFuture<'a> where Self: 'a = impl Future> + 'a; - /// Sends serial data. - /// - /// `tx_buffer` is marked as static as per `embedded-dma` requirements. - /// It it safe to use a buffer with a non static lifetime if memory is not - /// reused until the future has finished. - fn send<'a>(&'a mut self, tx_buffer: &'a [u8]) -> SendFuture<'a, T> { - // Panic if TX is running which can happen if the user has called - // `mem::forget()` on a previous future after polling it once. - assert!(!self.tx_started()); + fn read<'a>(self: Pin<&'a mut Self>, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { + async move { + let this = unsafe { self.get_unchecked_mut() }; - T::state().tx_done.reset(); + let ptr = rx_buffer.as_ptr(); + let len = rx_buffer.len(); + assert!(len <= EASY_DMA_SIZE); - SendFuture { - uarte: self, - buf: tx_buffer, - } - } + let r = this.peri.regs(); - /// Receives serial data. - /// - /// The future is pending until the buffer is completely filled. - /// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel - /// unfinished transfers after a timeout to prevent lockup when no more data - /// is incoming. - /// - /// `rx_buffer` is marked as static as per `embedded-dma` requirements. - /// It it safe to use a buffer with a non static lifetime if memory is not - /// reused until the future has finished. - fn receive<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> ReceiveFuture<'a, T> { - // Panic if RX is running which can happen if the user has called - // `mem::forget()` on a previous future after polling it once. - assert!(!self.rx_started()); + let drop = OnDrop::new(move || { + info!("read drop: stopping"); - T::state().rx_done.reset(); + r.intenclr.write(|w| w.endrx().clear()); + r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); - ReceiveFuture { - uarte: self, - buf: rx_buffer, + // TX is stopped almost instantly, spinning is fine. + while r.events_endrx.read().bits() == 0 {} + info!("read drop: stopped"); + }); + + r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); + r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + + r.events_endrx.reset(); + r.intenset.write(|w| w.endrx().set()); + + compiler_fence(Ordering::SeqCst); + + trace!("startrx"); + r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + + let irq = &mut this.irq; + poll_fn(|cx| { + if r.events_endrx.read().bits() != 0 { + r.events_endrx.reset(); + return Poll::Ready(()); + } + + wake_on_interrupt(irq, cx.waker()); + + Poll::Pending + }) + .await; + + compiler_fence(Ordering::SeqCst); + r.intenclr.write(|w| w.endrx().clear()); + drop.defuse(); + + Ok(()) } } } +impl<'d, T: Instance> Write for Uarte<'d, T> { + #[rustfmt::skip] + type WriteFuture<'a> where Self: 'a = impl Future> + 'a; + + fn write<'a>(self: Pin<&'a mut Self>, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { + async move { + let this = unsafe { self.get_unchecked_mut() }; + + let ptr = tx_buffer.as_ptr(); + let len = tx_buffer.len(); + assert!(len <= EASY_DMA_SIZE); + // TODO: panic if buffer is not in SRAM + + let r = this.peri.regs(); + + let drop = OnDrop::new(move || { + info!("write drop: stopping"); + + r.intenclr.write(|w| w.endtx().clear()); + r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); + + // TX is stopped almost instantly, spinning is fine. + while r.events_endtx.read().bits() == 0 {} + info!("write drop: stopped"); + }); + + r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); + r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + + r.events_endtx.reset(); + r.intenset.write(|w| w.endtx().set()); + + compiler_fence(Ordering::SeqCst); + + trace!("starttx"); + r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + + let irq = &mut this.irq; + poll_fn(|cx| { + if r.events_endtx.read().bits() != 0 { + r.events_endtx.reset(); + return Poll::Ready(()); + } + + wake_on_interrupt(irq, cx.waker()); + + Poll::Pending + }) + .await; + + compiler_fence(Ordering::SeqCst); + r.intenclr.write(|w| w.endtx().clear()); + drop.defuse(); + + Ok(()) + } + } +} + +/* /// Future for the [`Uarte::send()`] method. pub struct SendFuture<'a, T> where @@ -252,11 +294,8 @@ where trace!("stoptx"); // Stop the transmitter to minimize the current consumption. - self.uarte.instance.events_txstarted.reset(); - self.uarte - .instance - .tasks_stoptx - .write(|w| unsafe { w.bits(1) }); + self.uarte.peri.events_txstarted.reset(); + self.uarte.peri.tasks_stoptx.write(|w| unsafe { w.bits(1) }); // TX is stopped almost instantly, spinning is fine. while !T::state().tx_done.signaled() {} @@ -264,46 +303,6 @@ where } } -impl<'a, T> Future for SendFuture<'a, T> -where - T: Instance, -{ - type Output = Result<(), embassy::traits::uart::Error>; - - fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; - - if T::state().tx_done.poll_wait(cx).is_pending() { - let ptr = buf.as_ptr(); - let len = buf.len(); - assert!(len <= EASY_DMA_SIZE); - // TODO: panic if buffer is not in SRAM - - uarte.enable(); - - compiler_fence(Ordering::SeqCst); - uarte - .instance - .txd - .ptr - .write(|w| unsafe { w.ptr().bits(ptr as u32) }); - uarte - .instance - .txd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(len as _) }); - - trace!("starttx"); - uarte.instance.tasks_starttx.write(|w| unsafe { w.bits(1) }); - while !uarte.tx_started() {} // Make sure transmission has started - - Poll::Pending - } else { - Poll::Ready(Ok(())) - } - } -} - /// Future for the [`Uarte::receive()`] method. pub struct ReceiveFuture<'a, T> where @@ -321,11 +320,8 @@ where if self.uarte.rx_started() { trace!("stoprx (drop)"); - self.uarte.instance.events_rxstarted.reset(); - self.uarte - .instance - .tasks_stoprx - .write(|w| unsafe { w.bits(1) }); + self.uarte.peri.events_rxstarted.reset(); + self.uarte.peri.tasks_stoprx.write(|w| unsafe { w.bits(1) }); embassy_extras::low_power_wait_until(|| T::state().rx_done.signaled()) } @@ -350,19 +346,11 @@ where uarte.enable(); compiler_fence(Ordering::SeqCst); - uarte - .instance - .rxd - .ptr - .write(|w| unsafe { w.ptr().bits(ptr as u32) }); - uarte - .instance - .rxd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(len as _) }); + r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); + r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); trace!("startrx"); - uarte.instance.tasks_startrx.write(|w| unsafe { w.bits(1) }); + uarte.peri.tasks_startrx.write(|w| unsafe { w.bits(1) }); while !uarte.rx_started() {} // Make sure reception has started Poll::Pending @@ -383,11 +371,8 @@ where let len = if self.uarte.rx_started() { trace!("stoprx (stop)"); - self.uarte.instance.events_rxstarted.reset(); - self.uarte - .instance - .tasks_stoprx - .write(|w| unsafe { w.bits(1) }); + self.uarte.peri.events_rxstarted.reset(); + self.uarte.peri.tasks_stoprx.write(|w| unsafe { w.bits(1) }); T::state().rx_done.wait().await } else { // Transfer was stopped before it even started. No bytes were sent. @@ -396,45 +381,33 @@ where len as _ } } + */ -mod private { - pub trait Sealed {} +mod sealed { + use super::*; + + pub trait Instance { + fn regs(&self) -> &pac::uarte0::RegisterBlock; + } } -pub trait Instance: - Deref + Sized + private::Sealed + 'static -{ +pub trait Instance: sealed::Instance + 'static { type Interrupt: Interrupt; - - #[doc(hidden)] - fn state() -> &'static State; } -static UARTE0_STATE: State = State { - tx_done: Signal::new(), - rx_done: Signal::new(), -}; -impl private::Sealed for pac::UARTE0 {} -impl Instance for pac::UARTE0 { - type Interrupt = interrupt::UARTE0_UART0; - - fn state() -> &'static State { - &UARTE0_STATE - } +macro_rules! make_impl { + ($type:ident, $irq:ident) => { + impl sealed::Instance for peripherals::$type { + fn regs(&self) -> &pac::uarte0::RegisterBlock { + unsafe { &*pac::$type::ptr() } + } + } + impl Instance for peripherals::$type { + type Interrupt = interrupt::$irq; + } + }; } +make_impl!(UARTE0, UARTE0_UART0); #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] -static UARTE1_STATE: State = State { - tx_done: Signal::new(), - rx_done: Signal::new(), -}; -#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] -impl private::Sealed for pac::UARTE1 {} -#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] -impl Instance for pac::UARTE1 { - type Interrupt = interrupt::UARTE1; - - fn state() -> &'static State { - &UARTE1_STATE - } -} +make_impl!(UARTE1, UARTE1); diff --git a/embassy-traits/src/uart.rs b/embassy-traits/src/uart.rs index 44174718..5676e3fc 100644 --- a/embassy-traits/src/uart.rs +++ b/embassy-traits/src/uart.rs @@ -1,4 +1,5 @@ use core::future::Future; +use core::pin::Pin; #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -7,18 +8,31 @@ pub enum Error { Other, } -pub trait Uart { - type ReceiveFuture<'a>: Future>; - type SendFuture<'a>: Future>; - /// Receive into the buffer until the buffer is full - fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a>; - /// Send the specified buffer, and return when the transmission has completed - fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a>; +pub trait Read { + type ReadFuture<'a>: Future> + where + Self: 'a; + + fn read<'a>(self: Pin<&'a mut Self>, buf: &'a mut [u8]) -> Self::ReadFuture<'a>; } -pub trait IdleUart { - type ReceiveFuture<'a>: Future>; +pub trait ReadUntilIdle { + type ReadUntilIdleFuture<'a>: Future> + where + Self: 'a; + /// Receive into the buffer until the buffer is full or the line is idle after some bytes are received /// Return the number of bytes received - fn receive_until_idle<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a>; + fn read_until_idle<'a>( + self: Pin<&'a mut Self>, + buf: &'a mut [u8], + ) -> Self::ReadUntilIdleFuture<'a>; +} + +pub trait Write { + type WriteFuture<'a>: Future> + where + Self: 'a; + + fn write<'a>(self: Pin<&'a mut Self>, buf: &'a [u8]) -> Self::WriteFuture<'a>; } diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs index 3166c65d..9f82422d 100644 --- a/embassy/src/util/mod.rs +++ b/embassy/src/util/mod.rs @@ -2,6 +2,7 @@ mod drop_bomb; mod forever; mod mutex; +mod on_drop; mod portal; mod signal; @@ -11,6 +12,7 @@ mod waker; pub use drop_bomb::*; pub use forever::*; pub use mutex::*; +pub use on_drop::*; pub use portal::*; pub use signal::*; pub use waker::*; diff --git a/embassy/src/util/on_drop.rs b/embassy/src/util/on_drop.rs new file mode 100644 index 00000000..10f3407f --- /dev/null +++ b/embassy/src/util/on_drop.rs @@ -0,0 +1,24 @@ +use core::mem; +use core::mem::MaybeUninit; + +pub struct OnDrop { + f: MaybeUninit, +} + +impl OnDrop { + pub fn new(f: F) -> Self { + Self { + f: MaybeUninit::new(f), + } + } + + pub fn defuse(self) { + mem::forget(self) + } +} + +impl Drop for OnDrop { + fn drop(&mut self) { + unsafe { self.f.as_ptr().read()() } + } +} From e7e34cb8c21517eb9e23dab8df719580eaa1bc3a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Mar 2021 02:10:15 +0100 Subject: [PATCH 18/45] nrf/gpio: add OptionalPin --- embassy-nrf/src/gpio.rs | 104 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index dd334c63..d48ad3d0 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -1,6 +1,7 @@ use core::convert::Infallible; use core::hint::unreachable_unchecked; +use embassy::util::PeripheralBorrow; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; use gpio::pin_cnf::DRIVE_A; @@ -205,6 +206,7 @@ pub(crate) mod sealed { } } + #[inline] fn block(&self) -> &gpio::RegisterBlock { unsafe { match self.pin_port() / 32 { @@ -216,11 +218,13 @@ pub(crate) mod sealed { } } + #[inline] fn conf(&self) -> &gpio::PIN_CNF { &self.block().pin_cnf[self._pin() as usize] } /// Set the output as high. + #[inline] fn set_high(&self) { unsafe { self.block().outset.write(|w| w.bits(1u32 << self._pin())); @@ -228,12 +232,15 @@ pub(crate) mod sealed { } /// Set the output as low. + #[inline] fn set_low(&self) { unsafe { self.block().outclr.write(|w| w.bits(1u32 << self._pin())); } } } + + pub trait OptionalPin {} } pub trait Pin: sealed::Pin + Sized { @@ -247,7 +254,7 @@ pub trait Pin: sealed::Pin + Sized { #[inline] fn port(&self) -> Port { match self.pin_port() / 32 { - 1 => Port::Port0, + 0 => Port::Port0, #[cfg(any(feature = "52833", feature = "52840"))] 1 => Port::Port1, _ => unsafe { unreachable_unchecked() }, @@ -260,6 +267,7 @@ pub trait Pin: sealed::Pin + Sized { } /// Convert from concrete pin type PX_XX to type erased `AnyPin`. + #[inline] fn degrade(self) -> AnyPin { AnyPin { pin_port: self.pin_port(), @@ -273,6 +281,7 @@ pub struct AnyPin { } impl AnyPin { + #[inline] pub unsafe fn steal(pin_port: u8) -> Self { Self { pin_port } } @@ -280,15 +289,108 @@ impl AnyPin { impl Pin for AnyPin {} impl sealed::Pin for AnyPin { + #[inline] fn pin_port(&self) -> u8 { self.pin_port } } +impl PeripheralBorrow for AnyPin { + type Target = AnyPin; + #[inline] + unsafe fn unborrow(self) -> Self::Target { + self + } +} + +impl<'a> PeripheralBorrow for &'a mut AnyPin { + type Target = AnyPin; + #[inline] + unsafe fn unborrow(self) -> Self::Target { + AnyPin { + pin_port: self.pin_port, + } + } +} + +// ==================== + +pub trait OptionalPin: sealed::OptionalPin + Sized { + type Pin: Pin; + fn pin(&self) -> Option<&Self::Pin>; + fn pin_mut(&mut self) -> Option<&mut Self::Pin>; + + #[inline] + fn psel_bits(&self) -> u32 { + self.pin().map_or(1u32 << 31, |pin| Pin::psel_bits(pin)) + } + + /// Convert from concrete pin type PX_XX to type erased `Option`. + #[inline] + fn degrade_optional(mut self) -> Option { + self.pin_mut() + .map(|pin| unsafe { core::ptr::read(pin) }.degrade()) + } +} + +impl sealed::OptionalPin for T {} +impl OptionalPin for T { + type Pin = T; + + #[inline] + fn pin(&self) -> Option<&T> { + Some(self) + } + + #[inline] + fn pin_mut(&mut self) -> Option<&mut T> { + Some(self) + } +} + +// Uninhabited enum, so it's actually impossible to create a DummyPin value. +#[doc(hidden)] +pub enum DummyPin {} +impl Pin for DummyPin {} +impl sealed::Pin for DummyPin { + #[inline] + fn pin_port(&self) -> u8 { + unreachable!() + } +} + +#[derive(Clone, Copy, Debug)] +pub struct NoPin; +impl sealed::OptionalPin for NoPin {} +impl OptionalPin for NoPin { + type Pin = DummyPin; + + #[inline] + fn pin(&self) -> Option<&DummyPin> { + None + } + + #[inline] + fn pin_mut(&mut self) -> Option<&mut DummyPin> { + None + } +} + +impl PeripheralBorrow for NoPin { + type Target = NoPin; + #[inline] + unsafe fn unborrow(self) -> Self::Target { + self + } +} + +// ==================== + macro_rules! make_impl { ($type:ident, $port_num:expr, $pin_num:expr) => { impl Pin for peripherals::$type {} impl sealed::Pin for peripherals::$type { + #[inline] fn pin_port(&self) -> u8 { $port_num * 32 + $pin_num } From a0511e6caad8bbb4e41bed40283a92aaee7714bd Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Mar 2021 02:10:59 +0100 Subject: [PATCH 19/45] nrf/uart: make rts/cts optional. --- embassy-extras/src/macros.rs | 2 +- embassy-nrf-examples/src/bin/uart.rs | 4 +- embassy-nrf/src/uarte.rs | 98 +++++++--------------------- 3 files changed, 28 insertions(+), 76 deletions(-) diff --git a/embassy-extras/src/macros.rs b/embassy-extras/src/macros.rs index 5c50f5d9..22f93a1d 100644 --- a/embassy-extras/src/macros.rs +++ b/embassy-extras/src/macros.rs @@ -78,7 +78,7 @@ macro_rules! peripherals { macro_rules! unborrow { ($($name:ident),*) => { $( - let $name = unsafe { $name.unborrow() }; + let mut $name = unsafe { $name.unborrow() }; )* } } diff --git a/embassy-nrf-examples/src/bin/uart.rs b/embassy-nrf-examples/src/bin/uart.rs index c39e70d5..7efb3ebe 100644 --- a/embassy-nrf-examples/src/bin/uart.rs +++ b/embassy-nrf-examples/src/bin/uart.rs @@ -6,6 +6,7 @@ #[path = "../example_common.rs"] mod example_common; +use embassy_nrf::gpio::NoPin; use example_common::*; use cortex_m_rt::entry; @@ -29,8 +30,7 @@ async fn run() { config.baudrate = uarte::Baudrate::BAUD115200; let irq = interrupt::take!(UARTE0_UART0); - let uart = - unsafe { uarte::Uarte::new(p.uarte0, irq, p.p0_08, p.p0_06, p.p0_07, p.p0_05, config) }; + let uart = unsafe { uarte::Uarte::new(p.uarte0, irq, p.p0_08, p.p0_06, NoPin, NoPin, config) }; pin_mut!(uart); info!("uarte initialized!"); diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index fc57f406..9a6e4990 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -1,8 +1,4 @@ -//! Async low power UARTE. -//! -//! The peripheral is automatically enabled and disabled as required to save power. -//! Lowest power consumption can only be guaranteed if the send receive futures -//! are dropped correctly (e.g. not using `mem::forget()`). +//! Async UART use core::future::Future; use core::marker::PhantomData; @@ -10,12 +6,13 @@ use core::pin::Pin; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy::traits::uart::{Error, Read, Write}; -use embassy::util::{wake_on_interrupt, OnDrop, PeripheralBorrow, Signal}; +use embassy::util::{wake_on_interrupt, OnDrop, PeripheralBorrow}; use embassy_extras::unborrow; use futures::future::poll_fn; use crate::fmt::{assert, *}; -use crate::gpio::Pin as GpioPin; +use crate::gpio::sealed::Pin as _; +use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin}; use crate::hal::pac; use crate::hal::target_constants::EASY_DMA_SIZE; use crate::interrupt; @@ -62,8 +59,8 @@ impl<'d, T: Instance> Uarte<'d, T> { irq: impl PeripheralBorrow + 'd, rxd: impl PeripheralBorrow + 'd, txd: impl PeripheralBorrow + 'd, - cts: impl PeripheralBorrow + 'd, - rts: impl PeripheralBorrow + 'd, + cts: impl PeripheralBorrow + 'd, + rts: impl PeripheralBorrow + 'd, config: Config, ) -> Self { unborrow!(uarte, irq, rxd, txd, cts, rts); @@ -72,19 +69,23 @@ impl<'d, T: Instance> Uarte<'d, T> { assert!(r.enable.read().enable().is_disabled()); - // TODO OptionalPin for RTS/CTS. + rxd.conf().write(|w| w.input().connect().drive().h0h1()); + r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); txd.set_high(); - rts.set_high(); - rxd.conf().write(|w| w.input().connect().drive().h0h1()); txd.conf().write(|w| w.dir().output().drive().h0h1()); - //cts.conf().write(|w| w.input().connect().drive().h0h1()); - //rts.conf().write(|w| w.dir().output().drive().h0h1()); - - r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); - //r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); - //r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); + + if let Some(pin) = rts.pin_mut() { + pin.set_high(); + pin.conf().write(|w| w.dir().output().drive().h0h1()); + } + r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); + + if let Some(pin) = cts.pin_mut() { + pin.conf().write(|w| w.input().connect().drive().h0h1()); + } + r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); r.config.write(|w| w.parity().variant(config.parity)); @@ -98,64 +99,15 @@ impl<'d, T: Instance> Uarte<'d, T> { phantom: PhantomData, } } +} - /* - unsafe fn on_irq(_ctx: *mut ()) { - let uarte = &*pac::UARTE0::ptr(); +impl<'d, T: Instance> Drop for Uarte<'d, T> { + fn drop(&mut self) { + let r = self.peri.regs(); + r.enable.write(|w| w.enable().disabled()); - let mut try_disable = false; - - if uarte.events_endtx.read().bits() != 0 { - uarte.events_endtx.reset(); - trace!("endtx"); - compiler_fence(Ordering::SeqCst); - - if uarte.events_txstarted.read().bits() != 0 { - // The ENDTX was signal triggered because DMA has finished. - uarte.events_txstarted.reset(); - try_disable = true; - } - - T::state().tx_done.signal(()); - } - - if uarte.events_txstopped.read().bits() != 0 { - uarte.events_txstopped.reset(); - trace!("txstopped"); - try_disable = true; - } - - if uarte.events_endrx.read().bits() != 0 { - uarte.events_endrx.reset(); - trace!("endrx"); - let len = uarte.rxd.amount.read().bits(); - compiler_fence(Ordering::SeqCst); - - if uarte.events_rxstarted.read().bits() != 0 { - // The ENDRX was signal triggered because DMA buffer is full. - uarte.events_rxstarted.reset(); - try_disable = true; - } - - T::state().rx_done.signal(len); - } - - if uarte.events_rxto.read().bits() != 0 { - uarte.events_rxto.reset(); - trace!("rxto"); - try_disable = true; - } - - // Disable the peripheral if not active. - if try_disable - && uarte.events_txstarted.read().bits() == 0 - && uarte.events_rxstarted.read().bits() == 0 - { - trace!("disable"); - uarte.enable.write(|w| w.enable().disabled()); - } + // todo disable pins } - */ } impl<'d, T: Instance> Read for Uarte<'d, T> { From 806ee120ba4186d3cefbcaf39b84b727089d9268 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 22 Mar 2021 14:55:27 +0100 Subject: [PATCH 20/45] extras: add missing cfg to peripherals macro --- embassy-extras/src/macros.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-extras/src/macros.rs b/embassy-extras/src/macros.rs index 22f93a1d..a0464378 100644 --- a/embassy-extras/src/macros.rs +++ b/embassy-extras/src/macros.rs @@ -7,6 +7,7 @@ macro_rules! peripherals { #[allow(non_camel_case_types)] pub struct $type { _private: () } + $(#[$cfg])? impl embassy::util::Steal for $type { #[inline] unsafe fn steal() -> Self { From a08d7814420ed575ead6744f4254bfbb431bbc27 Mon Sep 17 00:00:00 2001 From: Richard Dodd Date: Wed, 24 Mar 2021 18:31:11 +0100 Subject: [PATCH 21/45] nrf/gpio: allow borrowed pins. --- embassy-nrf-examples/src/bin/gpiote_port.rs | 2 +- embassy-nrf/src/gpio.rs | 44 +++++++++++++++------ embassy-nrf/src/gpiote.rs | 19 ++++----- 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/embassy-nrf-examples/src/bin/gpiote_port.rs b/embassy-nrf-examples/src/bin/gpiote_port.rs index 593261ae..556a199f 100644 --- a/embassy-nrf-examples/src/bin/gpiote_port.rs +++ b/embassy-nrf-examples/src/bin/gpiote_port.rs @@ -19,7 +19,7 @@ use embassy_nrf::interrupt; use embassy_nrf::Peripherals; use example_common::*; -async fn button(n: usize, mut pin: PortInput) { +async fn button(n: usize, mut pin: PortInput<'static, AnyPin>) { loop { Pin::new(&mut pin).wait_for_low().await; info!("Button {:?} pressed!", n); diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index d48ad3d0..0d566ff3 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -1,7 +1,9 @@ use core::convert::Infallible; use core::hint::unreachable_unchecked; +use core::marker::PhantomData; use embassy::util::PeripheralBorrow; +use embassy_extras::unborrow; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; use gpio::pin_cnf::DRIVE_A; @@ -30,12 +32,15 @@ pub enum Pull { } /// GPIO input driver. -pub struct Input { +pub struct Input<'d, T: Pin> { pub(crate) pin: T, + phantom: PhantomData<&'d mut T>, } -impl Input { - pub fn new(pin: T, pull: Pull) -> Self { +impl<'d, T: Pin> Input<'d, T> { + pub fn new(pin: impl PeripheralBorrow + 'd, pull: Pull) -> Self { + unborrow!(pin); + pin.conf().write(|w| { w.dir().input(); w.input().connect(); @@ -55,17 +60,20 @@ impl Input { w }); - Self { pin } + Self { + pin, + phantom: PhantomData, + } } } -impl Drop for Input { +impl<'d, T: Pin> Drop for Input<'d, T> { fn drop(&mut self) { self.pin.conf().reset(); } } -impl InputPin for Input { +impl<'d, T: Pin> InputPin for Input<'d, T> { type Error = Infallible; fn is_high(&self) -> Result { @@ -108,12 +116,19 @@ pub enum OutputDrive { } /// GPIO output driver. -pub struct Output { +pub struct Output<'d, T: Pin> { pin: T, + phantom: PhantomData<&'d mut T>, } -impl Output { - pub fn new(pin: T, initial_output: Level, drive: OutputDrive) -> Self { +impl<'d, T: Pin> Output<'d, T> { + pub fn new( + pin: impl PeripheralBorrow + 'd, + initial_output: Level, + drive: OutputDrive, + ) -> Self { + unborrow!(pin); + match initial_output { Level::High => pin.set_high(), Level::Low => pin.set_low(), @@ -139,17 +154,20 @@ impl Output { w }); - Self { pin } + Self { + pin, + phantom: PhantomData, + } } } -impl Drop for Output { +impl<'d, T: Pin> Drop for Output<'d, T> { fn drop(&mut self) { self.pin.conf().reset(); } } -impl OutputPin for Output { +impl<'d, T: Pin> OutputPin for Output<'d, T> { type Error = Infallible; /// Set the output as high. @@ -175,7 +193,7 @@ impl OutputPin for Output { } } -impl StatefulOutputPin for Output { +impl<'d, T: Pin> StatefulOutputPin for Output<'d, T> { /// Is the output pin set as high? fn is_set_high(&self) -> Result { self.is_set_low().map(|v| !v) diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index dc96a7eb..9a7642c5 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -9,7 +9,7 @@ use core::ptr; use core::task::{Context, Poll}; use embassy::interrupt::InterruptExt; use embassy::traits::gpio::{WaitForHigh, WaitForLow}; -use embassy::util::{AtomicWakerRegistration, Signal}; +use embassy::util::{AtomicWakerRegistration, PeripheralBorrow, Signal}; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; use crate::gpio::sealed::Pin as _; @@ -338,18 +338,19 @@ impl OutputChannel { */ /// GPIO input driver with support -pub struct PortInput { - pin: Input, +pub struct PortInput<'d, T: GpioPin> { + pin: Input<'d, T>, } -impl Unpin for PortInput {} -impl PortInput { - pub fn new(_init: Initialized, pin: Input) -> Self { +impl<'d, T: GpioPin> Unpin for PortInput<'d, T> {} + +impl<'d, T: GpioPin> PortInput<'d, T> { + pub fn new(_init: Initialized, pin: Input<'d, T>) -> Self { Self { pin } } } -impl InputPin for PortInput { +impl<'d, T: GpioPin> InputPin for PortInput<'d, T> { type Error = Infallible; fn is_high(&self) -> Result { @@ -361,7 +362,7 @@ impl InputPin for PortInput { } } -impl WaitForHigh for PortInput { +impl<'d, T: GpioPin> WaitForHigh for PortInput<'d, T> { type Future<'a> = PortInputFuture<'a>; fn wait_for_high<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> { @@ -374,7 +375,7 @@ impl WaitForHigh for PortInput { } } -impl WaitForLow for PortInput { +impl<'d, T: GpioPin> WaitForLow for PortInput<'d, T> { type Future<'a> = PortInputFuture<'a>; fn wait_for_low<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> { From 53645d9d38bcb5904f1deba2cfa4e6719da2bc58 Mon Sep 17 00:00:00 2001 From: Richard Dodd Date: Wed, 24 Mar 2021 18:33:17 +0100 Subject: [PATCH 22/45] nrf/saadc: initial implementation --- embassy-nrf/src/lib.rs | 4 + embassy-nrf/src/saadc.rs | 242 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 246 insertions(+) create mode 100644 embassy-nrf/src/saadc.rs diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 22c71e7f..009cb99b 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -100,6 +100,7 @@ pub mod interrupt; #[cfg(feature = "52840")] pub mod qspi; pub mod rtc; +pub mod saadc; pub mod spim; pub mod uarte; @@ -130,6 +131,9 @@ embassy_extras::peripherals! { #[cfg(any(feature = "52833", feature = "52840"))] spim3: SPIM3, + // SAADC + saadc: SAADC, + // GPIOTE gpiote: GPIOTE, gpiote_ch_0: GPIOTE_CH0, diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs new file mode 100644 index 00000000..b854ce78 --- /dev/null +++ b/embassy-nrf/src/saadc.rs @@ -0,0 +1,242 @@ +use core::future::Future; +use core::marker::PhantomData; +use core::pin::Pin; +use core::sync::atomic::{compiler_fence, Ordering}; +use core::task::Poll; +use embassy::traits; +use embassy::util::{wake_on_interrupt, PeripheralBorrow}; +use embassy_extras::unborrow; +use futures::future::poll_fn; +use traits::spi::FullDuplex; + +use crate::gpio::Pin as GpioPin; +use crate::interrupt::{self, Interrupt}; +use crate::{pac, peripherals, slice_in_ram_or}; + +#[cfg(feature = "9160")] +use pac::{saadc_ns as saadc, SAADC_NS as SAADC}; + +#[cfg(not(feature = "9160"))] +use pac::{saadc, SAADC}; + +pub use saadc::{ + ch::{ + config::{GAIN_A as Gain, REFSEL_A as Reference, RESP_A as Resistor, TACQ_A as Time}, + pselp::PSELP_A as PositiveChannel, + }, + oversample::OVERSAMPLE_A as Oversample, + resolution::VAL_A as Resolution, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error {} + +/// One-shot saadc. Continuous sample mode TODO. +pub struct OneShot<'d, T: PositivePin> { + peri: peripherals::SAADC, + positive_pin: T, + irq: interrupt::SAADC, + phantom: PhantomData<(&'d mut peripherals::SAADC, &'d mut T)>, +} + +/// Used to configure the SAADC peripheral. +/// +/// See the `Default` impl for suitable default values. +pub struct Config { + /// Output resolution in bits. + pub resolution: Resolution, + /// Average 2^`oversample` input samples before transferring the result into memory. + pub oversample: Oversample, + /// Reference voltage of the SAADC input. + pub reference: Reference, + /// Gain used to control the effective input range of the SAADC. + pub gain: Gain, + /// Positive channel resistor control. + pub resistor: Resistor, + /// Acquisition time in microseconds. + pub time: Time, +} + +impl Default for Config { + fn default() -> Self { + Self { + resolution: Resolution::_14BIT, + oversample: Oversample::OVER8X, + reference: Reference::VDD1_4, + gain: Gain::GAIN1_4, + resistor: Resistor::BYPASS, + time: Time::_20US, + } + } +} + +impl<'d, T: PositivePin> OneShot<'d, T> { + pub fn new( + saadc: impl PeripheralBorrow + 'd, + irq: impl PeripheralBorrow + 'd, + positive_pin: impl PeripheralBorrow + 'd, + config: Config, + ) -> Self { + unborrow!(saadc, irq, positive_pin); + + let r = unsafe { &*SAADC::ptr() }; + + let Config { + resolution, + oversample, + reference, + gain, + resistor, + time, + } = config; + + // Configure pins + r.enable.write(|w| w.enable().enabled()); + r.resolution.write(|w| w.val().variant(resolution)); + r.oversample.write(|w| w.oversample().variant(oversample)); + + r.ch[0].config.write(|w| { + w.refsel().variant(reference); + w.gain().variant(gain); + w.tacq().variant(time); + w.mode().se(); + w.resp().variant(resistor); + w.resn().bypass(); + if !matches!(oversample, Oversample::BYPASS) { + w.burst().enabled(); + } else { + w.burst().disabled(); + } + w + }); + + // Set positive channel + r.ch[0] + .pselp + .write(|w| w.pselp().variant(positive_pin.channel())); + + // Disable all events interrupts + r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); + + Self { + peri: saadc, + positive_pin, + irq, + phantom: PhantomData, + } + } + + fn regs(&self) -> &saadc::RegisterBlock { + unsafe { &*SAADC::ptr() } + } +} + +impl<'d, T: PositivePin> Drop for OneShot<'d, T> { + fn drop(&mut self) { + let r = self.regs(); + r.enable.write(|w| w.enable().disabled()); + } +} + +pub trait Sample { + type SampleFuture<'a>: Future + 'a + where + Self: 'a; + + fn sample<'a>(self: Pin<&'a mut Self>) -> Self::SampleFuture<'a>; +} + +impl<'d, T: PositivePin> Sample for OneShot<'d, T> { + #[rustfmt::skip] + type SampleFuture<'a> where Self: 'a = impl Future + 'a; + + fn sample<'a>(self: Pin<&'a mut Self>) -> Self::SampleFuture<'a> { + async move { + let this = unsafe { self.get_unchecked_mut() }; + let r = this.regs(); + + // Set up the DMA + let mut val: i16 = 0; + r.result + .ptr + .write(|w| unsafe { w.ptr().bits(((&mut val) as *mut _) as u32) }); + r.result.maxcnt.write(|w| unsafe { w.maxcnt().bits(1) }); + + // Reset and enable the end event + r.events_end.reset(); + r.intenset.write(|w| w.end().set()); + + // Don't reorder the ADC start event before the previous writes. Hopefully this + // wouldn't happen anyway. + compiler_fence(Ordering::SeqCst); + + r.tasks_start.write(|w| unsafe { w.bits(1) }); + r.tasks_sample.write(|w| unsafe { w.bits(1) }); + + // Wait for 'end' event. + poll_fn(|cx| { + let r = this.regs(); + + if r.events_end.read().bits() != 0 { + r.events_end.reset(); + return Poll::Ready(()); + } + + wake_on_interrupt(&mut this.irq, cx.waker()); + + Poll::Pending + }) + .await; + + // The DMA wrote the sampled value to `val`. + val + } + } +} + +/// A pin that can be used as the positive end of a ADC differential in the SAADC periperhal. +/// +/// Currently negative is always shorted to ground (0V). +pub trait PositivePin { + fn channel(&self) -> PositiveChannel; +} + +macro_rules! positive_pin_mappings { + ( $($ch:ident => $pin:ident,)*) => { + $( + impl PositivePin for crate::peripherals::$pin { + fn channel(&self) -> PositiveChannel { + PositiveChannel::$ch + } + } + )* + }; +} + +// TODO the variant names are unchecked +// the pins are copied from nrf hal +#[cfg(feature = "9160")] +positive_pin_mappings! { + ANALOGINPUT0 => P0_13, + ANALOGINPUT1 => P0_14, + ANALOGINPUT2 => P0_15, + ANALOGINPUT3 => P0_16, + ANALOGINPUT4 => P0_17, + ANALOGINPUT5 => P0_18, + ANALOGINPUT6 => P0_19, + ANALOGINPUT7 => P0_20, +} + +#[cfg(not(feature = "9160"))] +positive_pin_mappings! { + ANALOGINPUT0 => P0_02, + ANALOGINPUT1 => P0_03, + ANALOGINPUT2 => P0_04, + ANALOGINPUT3 => P0_05, + ANALOGINPUT4 => P0_28, + ANALOGINPUT5 => P0_29, + ANALOGINPUT6 => P0_30, + ANALOGINPUT7 => P0_31, +} From eedb51bbb63677f53cfdfb4d0e342981a4866df7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 26 Mar 2021 23:20:27 +0100 Subject: [PATCH 23/45] extras: add Peripheral with shared state (like PeripheralMutex but without mutex) --- embassy-extras/src/lib.rs | 1 + embassy-extras/src/peripheral_shared.rs | 68 +++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 embassy-extras/src/peripheral_shared.rs diff --git a/embassy-extras/src/lib.rs b/embassy-extras/src/lib.rs index 5dafba70..be08ddf1 100644 --- a/embassy-extras/src/lib.rs +++ b/embassy-extras/src/lib.rs @@ -5,6 +5,7 @@ pub(crate) mod fmt; mod macros; pub mod peripheral; +pub mod peripheral_shared; pub mod ring_buffer; pub mod usb; diff --git a/embassy-extras/src/peripheral_shared.rs b/embassy-extras/src/peripheral_shared.rs new file mode 100644 index 00000000..73906698 --- /dev/null +++ b/embassy-extras/src/peripheral_shared.rs @@ -0,0 +1,68 @@ +use core::cell::UnsafeCell; +use core::marker::{PhantomData, PhantomPinned}; +use core::pin::Pin; +use core::sync::atomic::{compiler_fence, Ordering}; + +use embassy::interrupt::{Interrupt, InterruptExt}; + +pub trait PeripheralState { + type Interrupt: Interrupt; + fn on_interrupt(&self); +} + +pub struct Peripheral { + state: UnsafeCell, + + irq_setup_done: bool, + irq: S::Interrupt, + + _not_send: PhantomData<*mut ()>, + _pinned: PhantomPinned, +} + +impl Peripheral { + pub fn new(irq: S::Interrupt, state: S) -> Self { + Self { + irq, + irq_setup_done: false, + + state: UnsafeCell::new(state), + _not_send: PhantomData, + _pinned: PhantomPinned, + } + } + + pub fn register_interrupt(self: Pin<&mut Self>) { + let this = unsafe { self.get_unchecked_mut() }; + if this.irq_setup_done { + return; + } + + this.irq.disable(); + compiler_fence(Ordering::SeqCst); + + this.irq.set_handler(|p| { + let state = unsafe { &*(p as *const S) }; + state.on_interrupt(); + }); + this.irq + .set_handler_context((&this.state) as *const _ as *mut ()); + + compiler_fence(Ordering::SeqCst); + this.irq.enable(); + + this.irq_setup_done = true; + } + + pub fn state(self: Pin<&mut Self>) -> &S { + let this = unsafe { self.get_unchecked_mut() }; + unsafe { &*this.state.get() } + } +} + +impl Drop for Peripheral { + fn drop(&mut self) { + self.irq.disable(); + self.irq.remove_handler(); + } +} From 0e8bb5dc0b59a490f679f82c3efc6c2994c2d1d9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 26 Mar 2021 23:20:53 +0100 Subject: [PATCH 24/45] util: Do not unregister waker on wake in AtomicWaker. --- embassy-nrf/src/gpiote.rs | 8 ++++---- embassy/src/util/waker.rs | 15 ++++++--------- embassy/src/util/waker_agnostic.rs | 13 +++++-------- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 9a7642c5..920d6923 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -9,7 +9,7 @@ use core::ptr; use core::task::{Context, Poll}; use embassy::interrupt::InterruptExt; use embassy::traits::gpio::{WaitForHigh, WaitForLow}; -use embassy::util::{AtomicWakerRegistration, PeripheralBorrow, Signal}; +use embassy::util::{AtomicWaker, PeripheralBorrow, Signal}; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; use crate::gpio::sealed::Pin as _; @@ -68,9 +68,9 @@ impl ChannelID for ChAny { } } -const NEW_AWR: AtomicWakerRegistration = AtomicWakerRegistration::new(); -static CHANNEL_WAKERS: [AtomicWakerRegistration; CHANNEL_COUNT] = [NEW_AWR; CHANNEL_COUNT]; -static PORT_WAKERS: [AtomicWakerRegistration; PIN_COUNT] = [NEW_AWR; PIN_COUNT]; +const NEW_AWR: AtomicWaker = AtomicWaker::new(); +static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AWR; CHANNEL_COUNT]; +static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AWR; PIN_COUNT]; pub enum InputChannelPolarity { None, diff --git a/embassy/src/util/waker.rs b/embassy/src/util/waker.rs index 2b72fd56..cd53cca6 100644 --- a/embassy/src/util/waker.rs +++ b/embassy/src/util/waker.rs @@ -48,11 +48,11 @@ impl WakerRegistration { } } -pub struct AtomicWakerRegistration { +pub struct AtomicWaker { waker: AtomicPtr, } -impl AtomicWakerRegistration { +impl AtomicWaker { pub const fn new() -> Self { Self { waker: AtomicPtr::new(ptr::null_mut()), @@ -62,17 +62,14 @@ impl AtomicWakerRegistration { /// Register a waker. Overwrites the previous waker, if any. pub fn register(&self, w: &Waker) { let w = unsafe { task_from_waker(w) }; - let w2 = self.waker.swap(w.as_ptr(), Ordering::Relaxed); - if !w2.is_null() && w2 != w.as_ptr() { - unsafe { wake_task(NonNull::new_unchecked(w2)) }; - } + self.waker.store(w.as_ptr(), Ordering::Relaxed); } /// Wake the registered waker, if any. pub fn wake(&self) { - let w2 = self.waker.swap(ptr::null_mut(), Ordering::Relaxed); - if !w2.is_null() { - unsafe { wake_task(NonNull::new_unchecked(w2)) }; + let w2 = self.waker.load(Ordering::Relaxed); + if let Some(w2) = NonNull::new(w2) { + unsafe { wake_task(w2) }; } } } diff --git a/embassy/src/util/waker_agnostic.rs b/embassy/src/util/waker_agnostic.rs index b4234c0f..3f6ad373 100644 --- a/embassy/src/util/waker_agnostic.rs +++ b/embassy/src/util/waker_agnostic.rs @@ -49,11 +49,11 @@ impl WakerRegistration { } /// Utility struct to register and wake a waker. -pub struct AtomicWakerRegistration { +pub struct AtomicWaker { waker: Mutex>>, } -impl AtomicWakerRegistration { +impl AtomicWaker { pub const fn new() -> Self { Self { waker: Mutex::new(Cell::new(None)), @@ -66,11 +66,7 @@ impl AtomicWakerRegistration { let cell = self.waker.borrow(cs); cell.set(match cell.replace(None) { Some(w2) if (w2.will_wake(w)) => Some(w2), - Some(w2) => { - w2.wake(); - Some(w.clone()) - } - None => Some(w.clone()), + _ => Some(w.clone()), }) }) } @@ -80,7 +76,8 @@ impl AtomicWakerRegistration { cortex_m::interrupt::free(|cs| { let cell = self.waker.borrow(cs); if let Some(w) = cell.replace(None) { - w.wake() + w.wake_by_ref(); + cell.set(Some(w)); } }) } From 7a41541ab279e200b7bda93704e8ba66df52f5b4 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 26 Mar 2021 23:22:06 +0100 Subject: [PATCH 25/45] nrf/uarte: use Peripheral, wait for stop on drop. --- embassy-nrf/src/uarte.rs | 239 +++++++++++++++++---------------------- 1 file changed, 101 insertions(+), 138 deletions(-) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 9a6e4990..06493da6 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -3,10 +3,11 @@ use core::future::Future; use core::marker::PhantomData; use core::pin::Pin; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; use core::task::Poll; use embassy::traits::uart::{Error, Read, Write}; -use embassy::util::{wake_on_interrupt, OnDrop, PeripheralBorrow}; +use embassy::util::{AtomicWaker, OnDrop, PeripheralBorrow}; +use embassy_extras::peripheral_shared::{Peripheral, PeripheralState}; use embassy_extras::unborrow; use futures::future::poll_fn; @@ -37,10 +38,18 @@ impl Default for Config { } } +struct State { + peri: T, + did_stoprx: AtomicBool, + did_stoptx: AtomicBool, + + endrx_waker: AtomicWaker, + endtx_waker: AtomicWaker, +} + /// Interface to the UARTE peripheral pub struct Uarte<'d, T: Instance> { - peri: T, - irq: T::Interrupt, + inner: Peripheral>, phantom: PhantomData<&'d mut T>, } @@ -90,23 +99,85 @@ impl<'d, T: Instance> Uarte<'d, T> { r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); r.config.write(|w| w.parity().variant(config.parity)); + // Disable all interrupts + r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); + // Enable r.enable.write(|w| w.enable().enabled()); Self { - peri: uarte, - irq, + inner: Peripheral::new( + irq, + State { + did_stoprx: AtomicBool::new(false), + did_stoptx: AtomicBool::new(false), + peri: uarte, + endrx_waker: AtomicWaker::new(), + endtx_waker: AtomicWaker::new(), + }, + ), phantom: PhantomData, } } + + fn inner(self: Pin<&mut Self>) -> Pin<&mut Peripheral>> { + unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } + } +} + +impl PeripheralState for State { + type Interrupt = T::Interrupt; + + fn on_interrupt(&self) { + info!("irq"); + + let r = self.peri.regs(); + if r.events_endrx.read().bits() != 0 { + self.endrx_waker.wake(); + r.intenclr.write(|w| w.endrx().clear()); + } + if r.events_endtx.read().bits() != 0 { + self.endtx_waker.wake(); + r.intenclr.write(|w| w.endtx().clear()); + } + + if r.events_rxto.read().bits() != 0 { + r.intenclr.write(|w| w.rxto().clear()); + } + if r.events_txstopped.read().bits() != 0 { + r.intenclr.write(|w| w.txstopped().clear()); + } + } } -impl<'d, T: Instance> Drop for Uarte<'d, T> { +impl<'a, T: Instance> Drop for Uarte<'a, T> { fn drop(&mut self) { - let r = self.peri.regs(); + info!("uarte drop"); + + let s = unsafe { Pin::new_unchecked(&mut self.inner) }.state(); + let r = s.peri.regs(); + + let did_stoprx = s.did_stoprx.load(Ordering::Relaxed); + let did_stoptx = s.did_stoptx.load(Ordering::Relaxed); + info!("did_stoprx {} did_stoptx {}", did_stoprx, did_stoptx); + + // Wait for rxto or txstopped, if needed. + r.intenset.write(|w| w.rxto().set().txstopped().set()); + while (did_stoprx && r.events_rxto.read().bits() == 0) + || (did_stoptx && r.events_txstopped.read().bits() == 0) + { + info!("uarte drop: wfe"); + cortex_m::asm::wfe(); + } + + cortex_m::asm::sev(); + + // Finally we can disable! r.enable.write(|w| w.enable().disabled()); - // todo disable pins + info!("uarte drop: done"); + + // TODO: disable pins } } @@ -114,25 +185,29 @@ impl<'d, T: Instance> Read for Uarte<'d, T> { #[rustfmt::skip] type ReadFuture<'a> where Self: 'a = impl Future> + 'a; - fn read<'a>(self: Pin<&'a mut Self>, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { - async move { - let this = unsafe { self.get_unchecked_mut() }; + fn read<'a>(mut self: Pin<&'a mut Self>, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { + self.as_mut().inner().register_interrupt(); + async move { let ptr = rx_buffer.as_ptr(); let len = rx_buffer.len(); assert!(len <= EASY_DMA_SIZE); - let r = this.peri.regs(); + let s = self.inner().state(); + let r = s.peri.regs(); + let did_stoprx = &s.did_stoprx; let drop = OnDrop::new(move || { info!("read drop: stopping"); r.intenclr.write(|w| w.endrx().clear()); + r.events_rxto.reset(); r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); - // TX is stopped almost instantly, spinning is fine. while r.events_endrx.read().bits() == 0 {} + info!("read drop: stopped"); + did_stoprx.store(true, Ordering::Relaxed); }); r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); @@ -146,21 +221,17 @@ impl<'d, T: Instance> Read for Uarte<'d, T> { trace!("startrx"); r.tasks_startrx.write(|w| unsafe { w.bits(1) }); - let irq = &mut this.irq; poll_fn(|cx| { + s.endrx_waker.register(cx.waker()); if r.events_endrx.read().bits() != 0 { - r.events_endrx.reset(); return Poll::Ready(()); } - - wake_on_interrupt(irq, cx.waker()); - Poll::Pending }) .await; compiler_fence(Ordering::SeqCst); - r.intenclr.write(|w| w.endrx().clear()); + s.did_stoprx.store(false, Ordering::Relaxed); drop.defuse(); Ok(()) @@ -172,26 +243,30 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { #[rustfmt::skip] type WriteFuture<'a> where Self: 'a = impl Future> + 'a; - fn write<'a>(self: Pin<&'a mut Self>, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { - async move { - let this = unsafe { self.get_unchecked_mut() }; + fn write<'a>(mut self: Pin<&'a mut Self>, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { + self.as_mut().inner().register_interrupt(); + async move { let ptr = tx_buffer.as_ptr(); let len = tx_buffer.len(); assert!(len <= EASY_DMA_SIZE); // TODO: panic if buffer is not in SRAM - let r = this.peri.regs(); + let s = self.inner().state(); + let r = s.peri.regs(); + let did_stoptx = &s.did_stoptx; let drop = OnDrop::new(move || { info!("write drop: stopping"); r.intenclr.write(|w| w.endtx().clear()); + r.events_txstopped.reset(); r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); // TX is stopped almost instantly, spinning is fine. while r.events_endtx.read().bits() == 0 {} info!("write drop: stopped"); + did_stoptx.store(true, Ordering::Relaxed); }); r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); @@ -205,21 +280,17 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { trace!("starttx"); r.tasks_starttx.write(|w| unsafe { w.bits(1) }); - let irq = &mut this.irq; poll_fn(|cx| { + s.endtx_waker.register(cx.waker()); if r.events_endtx.read().bits() != 0 { - r.events_endtx.reset(); return Poll::Ready(()); } - - wake_on_interrupt(irq, cx.waker()); - Poll::Pending }) .await; compiler_fence(Ordering::SeqCst); - r.intenclr.write(|w| w.endtx().clear()); + s.did_stoptx.store(false, Ordering::Relaxed); drop.defuse(); Ok(()) @@ -227,114 +298,6 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { } } -/* -/// Future for the [`Uarte::send()`] method. -pub struct SendFuture<'a, T> -where - T: Instance, -{ - uarte: &'a mut Uarte, - buf: &'a [u8], -} - -impl<'a, T> Drop for SendFuture<'a, T> -where - T: Instance, -{ - fn drop(self: &mut Self) { - if self.uarte.tx_started() { - trace!("stoptx"); - - // Stop the transmitter to minimize the current consumption. - self.uarte.peri.events_txstarted.reset(); - self.uarte.peri.tasks_stoptx.write(|w| unsafe { w.bits(1) }); - - // TX is stopped almost instantly, spinning is fine. - while !T::state().tx_done.signaled() {} - } - } -} - -/// Future for the [`Uarte::receive()`] method. -pub struct ReceiveFuture<'a, T> -where - T: Instance, -{ - uarte: &'a mut Uarte, - buf: &'a mut [u8], -} - -impl<'a, T> Drop for ReceiveFuture<'a, T> -where - T: Instance, -{ - fn drop(self: &mut Self) { - if self.uarte.rx_started() { - trace!("stoprx (drop)"); - - self.uarte.peri.events_rxstarted.reset(); - self.uarte.peri.tasks_stoprx.write(|w| unsafe { w.bits(1) }); - - embassy_extras::low_power_wait_until(|| T::state().rx_done.signaled()) - } - } -} - -impl<'a, T> Future for ReceiveFuture<'a, T> -where - T: Instance, -{ - type Output = Result<(), embassy::traits::uart::Error>; - - fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; - - match T::state().rx_done.poll_wait(cx) { - Poll::Pending if !uarte.rx_started() => { - let ptr = buf.as_ptr(); - let len = buf.len(); - assert!(len <= EASY_DMA_SIZE); - - uarte.enable(); - - compiler_fence(Ordering::SeqCst); - r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); - - trace!("startrx"); - uarte.peri.tasks_startrx.write(|w| unsafe { w.bits(1) }); - while !uarte.rx_started() {} // Make sure reception has started - - Poll::Pending - } - Poll::Pending => Poll::Pending, - Poll::Ready(_) => Poll::Ready(Ok(())), - } - } -} - -/// Future for the [`receive()`] method. -impl<'a, T> ReceiveFuture<'a, T> -where - T: Instance, -{ - /// Stops the ongoing reception and returns the number of bytes received. - pub async fn stop(self) -> usize { - let len = if self.uarte.rx_started() { - trace!("stoprx (stop)"); - - self.uarte.peri.events_rxstarted.reset(); - self.uarte.peri.tasks_stoprx.write(|w| unsafe { w.bits(1) }); - T::state().rx_done.wait().await - } else { - // Transfer was stopped before it even started. No bytes were sent. - 0 - }; - len as _ - } -} - */ - mod sealed { use super::*; From 4ce46df1603697b14f2446b33663a122dda4a468 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Mar 2021 01:43:38 +0100 Subject: [PATCH 26/45] Code size optimizations. --- embassy-extras/src/peripheral.rs | 8 -------- embassy-extras/src/peripheral_shared.rs | 5 ----- embassy-macros/src/lib.rs | 10 ++++------ embassy/src/executor/raw.rs | 6 +++++- embassy/src/interrupt.rs | 14 ++++++++++---- embassy/src/util/forever.rs | 23 ++++++++++++++++++++++- 6 files changed, 41 insertions(+), 25 deletions(-) diff --git a/embassy-extras/src/peripheral.rs b/embassy-extras/src/peripheral.rs index e2435d63..68972c54 100644 --- a/embassy-extras/src/peripheral.rs +++ b/embassy-extras/src/peripheral.rs @@ -1,7 +1,6 @@ use core::cell::UnsafeCell; use core::marker::{PhantomData, PhantomPinned}; use core::pin::Pin; -use core::sync::atomic::{compiler_fence, Ordering}; use embassy::interrupt::{Interrupt, InterruptExt}; @@ -39,8 +38,6 @@ impl PeripheralMutex { } this.irq.disable(); - compiler_fence(Ordering::SeqCst); - this.irq.set_handler(|p| { // Safety: it's OK to get a &mut to the state, since // - We're in the IRQ, no one else can't preempt us @@ -50,8 +47,6 @@ impl PeripheralMutex { }); this.irq .set_handler_context((&mut this.state) as *mut _ as *mut ()); - - compiler_fence(Ordering::SeqCst); this.irq.enable(); this.irq_setup_done = true; @@ -61,14 +56,11 @@ impl PeripheralMutex { let this = unsafe { self.get_unchecked_mut() }; this.irq.disable(); - compiler_fence(Ordering::SeqCst); // Safety: it's OK to get a &mut to the state, since the irq is disabled. let state = unsafe { &mut *this.state.get() }; - let r = f(state, &mut this.irq); - compiler_fence(Ordering::SeqCst); this.irq.enable(); r diff --git a/embassy-extras/src/peripheral_shared.rs b/embassy-extras/src/peripheral_shared.rs index 73906698..c6211339 100644 --- a/embassy-extras/src/peripheral_shared.rs +++ b/embassy-extras/src/peripheral_shared.rs @@ -1,7 +1,6 @@ use core::cell::UnsafeCell; use core::marker::{PhantomData, PhantomPinned}; use core::pin::Pin; -use core::sync::atomic::{compiler_fence, Ordering}; use embassy::interrupt::{Interrupt, InterruptExt}; @@ -39,16 +38,12 @@ impl Peripheral { } this.irq.disable(); - compiler_fence(Ordering::SeqCst); - this.irq.set_handler(|p| { let state = unsafe { &*(p as *const S) }; state.on_interrupt(); }); this.irq .set_handler_context((&this.state) as *const _ as *mut ()); - - compiler_fence(Ordering::SeqCst); this.irq.enable(); this.irq_setup_done = true; diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs index bcf9dd4e..a14c374f 100644 --- a/embassy-macros/src/lib.rs +++ b/embassy-macros/src/lib.rs @@ -172,12 +172,10 @@ pub fn interrupt_take(item: TokenStream) -> TokenStream { static HANDLER: ::embassy::interrupt::Handler; } - let func = HANDLER.func.load(::embassy::export::atomic::Ordering::Acquire); - let ctx = HANDLER.ctx.load(::embassy::export::atomic::Ordering::Acquire); - if !func.is_null() { - let func: fn(*mut ()) = ::core::mem::transmute(func); - func(ctx) - } + let func = HANDLER.func.load(::embassy::export::atomic::Ordering::Relaxed); + let ctx = HANDLER.ctx.load(::embassy::export::atomic::Ordering::Relaxed); + let func: fn(*mut ()) = ::core::mem::transmute(func); + func(ctx) } static TAKEN: ::embassy::export::atomic::AtomicBool = ::embassy::export::atomic::AtomicBool::new(false); diff --git a/embassy/src/executor/raw.rs b/embassy/src/executor/raw.rs index 7e981b08..52512c53 100644 --- a/embassy/src/executor/raw.rs +++ b/embassy/src/executor/raw.rs @@ -4,9 +4,9 @@ use core::cmp::min; use core::future::Future; use core::marker::PhantomData; use core::pin::Pin; -use core::ptr; use core::ptr::NonNull; use core::task::{Context, Poll, Waker}; +use core::{mem, ptr}; use super::run_queue::{RunQueue, RunQueueItem}; use super::timer_queue::{TimerQueue, TimerQueueItem}; @@ -143,6 +143,10 @@ impl Task { } Poll::Pending => {} } + + // the compiler is emitting a virtual call for waker drop, but we know + // it's a noop for our waker. + mem::forget(waker); } } diff --git a/embassy/src/interrupt.rs b/embassy/src/interrupt.rs index a4285a9f..99d7af75 100644 --- a/embassy/src/interrupt.rs +++ b/embassy/src/interrupt.rs @@ -1,7 +1,7 @@ use core::ptr; use cortex_m::peripheral::NVIC; -use atomic_polyfill::{AtomicPtr, Ordering}; +use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering}; pub use embassy_macros::interrupt_declare as declare; pub use embassy_macros::interrupt_take as take; @@ -58,22 +58,27 @@ pub trait InterruptExt: Interrupt { impl InterruptExt for T { fn set_handler(&self, func: unsafe fn(*mut ())) { + compiler_fence(Ordering::SeqCst); let handler = unsafe { self.__handler() }; - handler.func.store(func as *mut (), Ordering::Release); + handler.func.store(func as *mut (), Ordering::Relaxed); + compiler_fence(Ordering::SeqCst); } fn remove_handler(&self) { + compiler_fence(Ordering::SeqCst); let handler = unsafe { self.__handler() }; - handler.func.store(ptr::null_mut(), Ordering::Release); + handler.func.store(ptr::null_mut(), Ordering::Relaxed); + compiler_fence(Ordering::SeqCst); } fn set_handler_context(&self, ctx: *mut ()) { let handler = unsafe { self.__handler() }; - handler.ctx.store(ctx, Ordering::Release); + handler.ctx.store(ctx, Ordering::Relaxed); } #[inline] fn enable(&self) { + compiler_fence(Ordering::SeqCst); unsafe { NVIC::unmask(NrWrap(self.number())); } @@ -82,6 +87,7 @@ impl InterruptExt for T { #[inline] fn disable(&self) { NVIC::mask(NrWrap(self.number())); + compiler_fence(Ordering::SeqCst); } #[inline] diff --git a/embassy/src/util/forever.rs b/embassy/src/util/forever.rs index efa96f30..0432fa51 100644 --- a/embassy/src/util/forever.rs +++ b/embassy/src/util/forever.rs @@ -31,6 +31,7 @@ unsafe impl Send for Forever {} unsafe impl Sync for Forever {} impl Forever { + #[inline(always)] pub const fn new() -> Self { Self { used: AtomicBool::new(false), @@ -43,10 +44,11 @@ impl Forever { /// Panics if this `Forever` already has a value. /// /// Returns a mutable reference to the stored value. + #[inline(always)] pub fn put(&'static self, val: T) -> &'static mut T { if self .used - .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) + .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) .is_err() { panic!("Forever.put() called multiple times"); @@ -60,6 +62,25 @@ impl Forever { } } + #[inline(always)] + pub fn put_with(&'static self, val: impl FnOnce() -> T) -> &'static mut T { + if self + .used + .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) + .is_err() + { + panic!("Forever.put() called multiple times"); + } + + unsafe { + let p = self.t.get(); + let p = (&mut *p).as_mut_ptr(); + p.write(val()); + &mut *p + } + } + + #[inline(always)] pub unsafe fn steal(&'static self) -> &'static mut T { let p = self.t.get(); let p = (&mut *p).as_mut_ptr(); From 1c9f98e1b63296602da2aac0103bea917dcbdcd9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Mar 2021 02:08:01 +0100 Subject: [PATCH 27/45] nrf/gpiote: fix irq race condition The interrupt could fire between checking if sense=disabled and registering the waker, in which case the future would get stuck. --- embassy-nrf/src/gpiote.rs | 22 ++++++++-------------- embassy/src/util/waker.rs | 3 ++- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 920d6923..9ea008f0 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -395,9 +395,8 @@ pub struct PortInputFuture<'a> { impl<'a> Drop for PortInputFuture<'a> { fn drop(&mut self) { - unsafe { AnyPin::steal(self.pin_port) } - .conf() - .modify(|_, w| w.sense().disabled()); + let pin = unsafe { AnyPin::steal(self.pin_port) }; + pin.conf().modify(|_, w| w.sense().disabled()); } } @@ -405,18 +404,13 @@ impl<'a> Future for PortInputFuture<'a> { type Output = (); fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let dis = unsafe { AnyPin::steal(self.pin_port) } - .conf() - .read() - .sense() - .is_disabled(); - - if dis { - return Poll::Ready(()); - } - PORT_WAKERS[self.pin_port as usize].register(cx.waker()); - Poll::Pending + let pin = unsafe { AnyPin::steal(self.pin_port) }; + if pin.conf().read().sense().is_disabled() { + Poll::Ready(()) + } else { + Poll::Pending + } } } diff --git a/embassy/src/util/waker.rs b/embassy/src/util/waker.rs index cd53cca6..39315509 100644 --- a/embassy/src/util/waker.rs +++ b/embassy/src/util/waker.rs @@ -1,7 +1,7 @@ use core::ptr::{self, NonNull}; use core::task::Waker; -use atomic_polyfill::{AtomicPtr, Ordering}; +use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering}; use crate::executor::raw::{task_from_waker, wake_task, TaskHeader}; @@ -63,6 +63,7 @@ impl AtomicWaker { pub fn register(&self, w: &Waker) { let w = unsafe { task_from_waker(w) }; self.waker.store(w.as_ptr(), Ordering::Relaxed); + compiler_fence(Ordering::SeqCst); } /// Wake the registered waker, if any. From 3eccddc44db8d6c91d874a7be353aef3c90b8d43 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Mar 2021 02:08:58 +0100 Subject: [PATCH 28/45] nrf/uarte: use rxstarted/txstarted events to track whether a wait for stop is necessary on drop. --- embassy-nrf/src/uarte.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 06493da6..63dedcdc 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -40,8 +40,6 @@ impl Default for Config { struct State { peri: T, - did_stoprx: AtomicBool, - did_stoptx: AtomicBool, endrx_waker: AtomicWaker, endtx_waker: AtomicWaker, @@ -102,6 +100,11 @@ impl<'d, T: Instance> Uarte<'d, T> { // Disable all interrupts r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); + // Reset rxstarted, txstarted. These are used by drop to know whether a transfer was + // stopped midway or not. + r.events_rxstarted.reset(); + r.events_txstarted.reset(); + // Enable r.enable.write(|w| w.enable().enabled()); @@ -109,8 +112,6 @@ impl<'d, T: Instance> Uarte<'d, T> { inner: Peripheral::new( irq, State { - did_stoprx: AtomicBool::new(false), - did_stoptx: AtomicBool::new(false), peri: uarte, endrx_waker: AtomicWaker::new(), endtx_waker: AtomicWaker::new(), @@ -129,8 +130,6 @@ impl PeripheralState for State { type Interrupt = T::Interrupt; fn on_interrupt(&self) { - info!("irq"); - let r = self.peri.regs(); if r.events_endrx.read().bits() != 0 { self.endrx_waker.wake(); @@ -157,8 +156,8 @@ impl<'a, T: Instance> Drop for Uarte<'a, T> { let s = unsafe { Pin::new_unchecked(&mut self.inner) }.state(); let r = s.peri.regs(); - let did_stoprx = s.did_stoprx.load(Ordering::Relaxed); - let did_stoptx = s.did_stoptx.load(Ordering::Relaxed); + let did_stoprx = r.events_rxstarted.read().bits() != 0; + let did_stoptx = r.events_txstarted.read().bits() != 0; info!("did_stoprx {} did_stoptx {}", did_stoprx, did_stoptx); // Wait for rxto or txstopped, if needed. @@ -196,7 +195,6 @@ impl<'d, T: Instance> Read for Uarte<'d, T> { let s = self.inner().state(); let r = s.peri.regs(); - let did_stoprx = &s.did_stoprx; let drop = OnDrop::new(move || { info!("read drop: stopping"); @@ -207,7 +205,6 @@ impl<'d, T: Instance> Read for Uarte<'d, T> { while r.events_endrx.read().bits() == 0 {} info!("read drop: stopped"); - did_stoprx.store(true, Ordering::Relaxed); }); r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); @@ -231,7 +228,7 @@ impl<'d, T: Instance> Read for Uarte<'d, T> { .await; compiler_fence(Ordering::SeqCst); - s.did_stoprx.store(false, Ordering::Relaxed); + r.events_rxstarted.reset(); drop.defuse(); Ok(()) @@ -255,7 +252,6 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { let s = self.inner().state(); let r = s.peri.regs(); - let did_stoptx = &s.did_stoptx; let drop = OnDrop::new(move || { info!("write drop: stopping"); @@ -266,7 +262,6 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { // TX is stopped almost instantly, spinning is fine. while r.events_endtx.read().bits() == 0 {} info!("write drop: stopped"); - did_stoptx.store(true, Ordering::Relaxed); }); r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); @@ -290,7 +285,7 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { .await; compiler_fence(Ordering::SeqCst); - s.did_stoptx.store(false, Ordering::Relaxed); + r.events_txstarted.reset(); drop.defuse(); Ok(()) From 5646926cca8fcb1d3286199bfe54a3666eae30c9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Mar 2021 03:12:58 +0100 Subject: [PATCH 29/45] nrf/rtc: update to new api --- embassy-extras/src/macros.rs | 23 +-- embassy-nrf-examples/src/bin/buffered_uart.rs | 1 + .../src/bin/executor_fairness_test.rs | 12 +- .../src/bin/gpiote_channel.rs | 1 + embassy-nrf-examples/src/bin/gpiote_port.rs | 11 +- embassy-nrf-examples/src/bin/multiprio.rs | 17 ++- embassy-nrf-examples/src/bin/qspi.rs | 15 +- embassy-nrf-examples/src/bin/raw_spawn.rs | 10 +- embassy-nrf-examples/src/bin/rtc_raw.rs | 62 -------- embassy-nrf-examples/src/bin/spim.rs | 22 +-- .../src/bin/{rtc_async.rs => timer.rs} | 15 +- embassy-nrf-examples/src/bin/uart.rs | 22 +-- embassy-nrf/src/lib.rs | 136 +++++++++--------- embassy-nrf/src/rtc.rs | 86 +++++------ 14 files changed, 197 insertions(+), 236 deletions(-) delete mode 100644 embassy-nrf-examples/src/bin/rtc_raw.rs rename embassy-nrf-examples/src/bin/{rtc_async.rs => timer.rs} (80%) diff --git a/embassy-extras/src/macros.rs b/embassy-extras/src/macros.rs index a0464378..0659a0b7 100644 --- a/embassy-extras/src/macros.rs +++ b/embassy-extras/src/macros.rs @@ -1,14 +1,14 @@ #[macro_export] macro_rules! peripherals { - ($($(#[$cfg:meta])? $name:ident: $type:ident),*$(,)?) => { + ($($(#[$cfg:meta])? $name:ident),*$(,)?) => { pub mod peripherals { $( $(#[$cfg])? #[allow(non_camel_case_types)] - pub struct $type { _private: () } + pub struct $name { _private: () } $(#[$cfg])? - impl embassy::util::Steal for $type { + impl embassy::util::Steal for $name { #[inline] unsafe fn steal() -> Self { Self{ _private: ()} @@ -16,29 +16,30 @@ macro_rules! peripherals { } $(#[$cfg])? - impl embassy::util::PeripheralBorrow for $type { - type Target = $type; + impl embassy::util::PeripheralBorrow for $name { + type Target = $name; #[inline] - unsafe fn unborrow(self) -> $type { + unsafe fn unborrow(self) -> $name { self } } $(#[$cfg])? - impl embassy::util::PeripheralBorrow for &mut $type { - type Target = $type; + impl embassy::util::PeripheralBorrow for &mut $name { + type Target = $name; #[inline] - unsafe fn unborrow(self) -> $type { + unsafe fn unborrow(self) -> $name { ::core::ptr::read(self) } } )* } + #[allow(non_snake_case)] pub struct Peripherals { $( $(#[$cfg])? - pub $name: peripherals::$type, + pub $name: peripherals::$name, )* } @@ -66,7 +67,7 @@ macro_rules! peripherals { Self { $( $(#[$cfg])? - $name: ::steal(), + $name: ::steal(), )* } } diff --git a/embassy-nrf-examples/src/bin/buffered_uart.rs b/embassy-nrf-examples/src/bin/buffered_uart.rs index 71e9b4a7..c7017128 100644 --- a/embassy-nrf-examples/src/bin/buffered_uart.rs +++ b/embassy-nrf-examples/src/bin/buffered_uart.rs @@ -3,6 +3,7 @@ #![feature(min_type_alias_impl_trait)] #![feature(impl_trait_in_bindings)] #![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] #[path = "../example_common.rs"] mod example_common; diff --git a/embassy-nrf-examples/src/bin/executor_fairness_test.rs b/embassy-nrf-examples/src/bin/executor_fairness_test.rs index 6d0a311d..cfcfd949 100644 --- a/embassy-nrf-examples/src/bin/executor_fairness_test.rs +++ b/embassy-nrf-examples/src/bin/executor_fairness_test.rs @@ -3,18 +3,20 @@ #![feature(min_type_alias_impl_trait)] #![feature(impl_trait_in_bindings)] #![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] #[path = "../example_common.rs"] mod example_common; use example_common::*; +use core::mem; use core::task::Poll; use cortex_m_rt::entry; use defmt::panic; use embassy::executor::{task, Executor}; use embassy::time::{Duration, Instant, Timer}; use embassy::util::Forever; -use embassy_nrf::pac; +use embassy_nrf::peripherals; use embassy_nrf::{interrupt, rtc}; use nrf52840_hal::clocks; @@ -42,17 +44,17 @@ async fn run3() { .await; } -static RTC: Forever> = Forever::new(); -static ALARM: Forever> = Forever::new(); +static RTC: Forever> = Forever::new(); +static ALARM: Forever> = Forever::new(); static EXECUTOR: Forever = Forever::new(); #[entry] fn main() -> ! { info!("Hello World!"); - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + let p = unwrap!(embassy_nrf::Peripherals::take()); - clocks::Clocks::new(p.CLOCK) + clocks::Clocks::new(unsafe { mem::transmute(()) }) .enable_ext_hfosc() .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) .start_lfclk(); diff --git a/embassy-nrf-examples/src/bin/gpiote_channel.rs b/embassy-nrf-examples/src/bin/gpiote_channel.rs index 3764ba1c..599882a9 100644 --- a/embassy-nrf-examples/src/bin/gpiote_channel.rs +++ b/embassy-nrf-examples/src/bin/gpiote_channel.rs @@ -3,6 +3,7 @@ #![feature(min_type_alias_impl_trait)] #![feature(impl_trait_in_bindings)] #![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] #[path = "../example_common.rs"] mod example_common; diff --git a/embassy-nrf-examples/src/bin/gpiote_port.rs b/embassy-nrf-examples/src/bin/gpiote_port.rs index 556a199f..199a33da 100644 --- a/embassy-nrf-examples/src/bin/gpiote_port.rs +++ b/embassy-nrf-examples/src/bin/gpiote_port.rs @@ -3,6 +3,7 @@ #![feature(min_type_alias_impl_trait)] #![feature(impl_trait_in_bindings)] #![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] #[path = "../example_common.rs"] mod example_common; @@ -32,23 +33,23 @@ async fn button(n: usize, mut pin: PortInput<'static, AnyPin>) { async fn run() { let p = Peripherals::take().unwrap(); - let g = gpiote::initialize(p.gpiote, interrupt::take!(GPIOTE)); + let g = gpiote::initialize(p.GPIOTE, interrupt::take!(GPIOTE)); let button1 = button( 1, - PortInput::new(g, Input::new(p.p0_11.degrade(), Pull::Up)), + PortInput::new(g, Input::new(p.P0_11.degrade(), Pull::Up)), ); let button2 = button( 2, - PortInput::new(g, Input::new(p.p0_12.degrade(), Pull::Up)), + PortInput::new(g, Input::new(p.P0_12.degrade(), Pull::Up)), ); let button3 = button( 3, - PortInput::new(g, Input::new(p.p0_24.degrade(), Pull::Up)), + PortInput::new(g, Input::new(p.P0_24.degrade(), Pull::Up)), ); let button4 = button( 4, - PortInput::new(g, Input::new(p.p0_25.degrade(), Pull::Up)), + PortInput::new(g, Input::new(p.P0_25.degrade(), Pull::Up)), ); futures::join!(button1, button2, button3, button4); } diff --git a/embassy-nrf-examples/src/bin/multiprio.rs b/embassy-nrf-examples/src/bin/multiprio.rs index 65c64621..017de3c0 100644 --- a/embassy-nrf-examples/src/bin/multiprio.rs +++ b/embassy-nrf-examples/src/bin/multiprio.rs @@ -58,9 +58,12 @@ #![feature(min_type_alias_impl_trait)] #![feature(impl_trait_in_bindings)] #![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] #[path = "../example_common.rs"] mod example_common; +use core::mem; + use example_common::*; use cortex_m_rt::entry; @@ -71,7 +74,7 @@ use embassy::executor::{task, Executor, InterruptExecutor}; use embassy::interrupt::InterruptExt; use embassy::time::{Duration, Instant, Timer}; use embassy::util::Forever; -use embassy_nrf::{interrupt, pac, rtc}; +use embassy_nrf::{interrupt, peripherals, rtc}; #[task] async fn run_high() { @@ -115,21 +118,21 @@ async fn run_low() { } } -static RTC: Forever> = Forever::new(); -static ALARM_HIGH: Forever> = Forever::new(); +static RTC: Forever> = Forever::new(); +static ALARM_HIGH: Forever> = Forever::new(); static EXECUTOR_HIGH: Forever> = Forever::new(); -static ALARM_MED: Forever> = Forever::new(); +static ALARM_MED: Forever> = Forever::new(); static EXECUTOR_MED: Forever> = Forever::new(); -static ALARM_LOW: Forever> = Forever::new(); +static ALARM_LOW: Forever> = Forever::new(); static EXECUTOR_LOW: Forever = Forever::new(); #[entry] fn main() -> ! { info!("Hello World!"); - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + let p = unwrap!(embassy_nrf::Peripherals::take()); - clocks::Clocks::new(p.CLOCK) + clocks::Clocks::new(unsafe { mem::transmute(()) }) .enable_ext_hfosc() .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) .start_lfclk(); diff --git a/embassy-nrf-examples/src/bin/qspi.rs b/embassy-nrf-examples/src/bin/qspi.rs index 1637b397..4e24a13d 100644 --- a/embassy-nrf-examples/src/bin/qspi.rs +++ b/embassy-nrf-examples/src/bin/qspi.rs @@ -3,6 +3,7 @@ #![feature(min_type_alias_impl_trait)] #![feature(impl_trait_in_bindings)] #![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] #[path = "../example_common.rs"] mod example_common; @@ -28,12 +29,12 @@ struct AlignedBuf([u8; 4096]); async fn run() { let p = Peripherals::take().unwrap(); - let csn = p.p0_17; - let sck = p.p0_19; - let io0 = p.p0_20; - let io1 = p.p0_21; - let io2 = p.p0_22; - let io3 = p.p0_23; + let csn = p.P0_17; + let sck = p.P0_19; + let io0 = p.P0_20; + let io1 = p.P0_21; + let io2 = p.P0_22; + let io3 = p.P0_23; let config = qspi::Config { read_opcode: qspi::ReadOpcode::READ4IO, @@ -44,7 +45,7 @@ async fn run() { }; let irq = interrupt::take!(QSPI); - let q = qspi::Qspi::new(p.qspi, irq, sck, csn, io0, io1, io2, io3, config); + let q = qspi::Qspi::new(p.QSPI, irq, sck, csn, io0, io1, io2, io3, config); pin_mut!(q); let mut id = [1; 3]; diff --git a/embassy-nrf-examples/src/bin/raw_spawn.rs b/embassy-nrf-examples/src/bin/raw_spawn.rs index 3747b49f..1dd60403 100644 --- a/embassy-nrf-examples/src/bin/raw_spawn.rs +++ b/embassy-nrf-examples/src/bin/raw_spawn.rs @@ -13,7 +13,7 @@ use defmt::panic; use embassy::executor::Executor; use embassy::time::{Duration, Timer}; use embassy::util::Forever; -use embassy_nrf::pac; +use embassy_nrf::peripherals; use embassy_nrf::{interrupt, rtc}; use nrf52840_hal::clocks; @@ -31,17 +31,17 @@ async fn run2() { } } -static RTC: Forever> = Forever::new(); -static ALARM: Forever> = Forever::new(); +static RTC: Forever> = Forever::new(); +static ALARM: Forever> = Forever::new(); static EXECUTOR: Forever = Forever::new(); #[entry] fn main() -> ! { info!("Hello World!"); - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + let p = unwrap!(embassy_nrf::Peripherals::take()); - clocks::Clocks::new(p.CLOCK) + clocks::Clocks::new(unsafe { mem::transmute(()) }) .enable_ext_hfosc() .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) .start_lfclk(); diff --git a/embassy-nrf-examples/src/bin/rtc_raw.rs b/embassy-nrf-examples/src/bin/rtc_raw.rs deleted file mode 100644 index 884ca92b..00000000 --- a/embassy-nrf-examples/src/bin/rtc_raw.rs +++ /dev/null @@ -1,62 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use core::mem::MaybeUninit; -use cortex_m_rt::entry; -use defmt::panic; -use embassy::time::{Alarm, Clock}; -use embassy_nrf::{interrupt, rtc}; -use nrf52840_hal::clocks; - -static mut RTC: MaybeUninit> = MaybeUninit::uninit(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - - clocks::Clocks::new(p.CLOCK) - .enable_ext_hfosc() - .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) - .start_lfclk(); - - let irq = interrupt::take!(RTC1); - - let rtc: &'static _ = unsafe { - let ptr = RTC.as_mut_ptr(); - ptr.write(rtc::RTC::new(p.RTC1, irq)); - &*ptr - }; - - let alarm = rtc.alarm0(); - - rtc.start(); - - alarm.set_callback(|_| info!("ALARM TRIGGERED"), core::ptr::null_mut()); - alarm.set(53719); - - info!("initialized!"); - - let mut val = 0; - let mut printval = 0; - loop { - let val2 = rtc.now(); - if val2 < val { - info!("timer ran backwards! {} -> {}", val as u32, val2 as u32); - } - val = val2; - - if val > printval + 32768 { - info!("tick {}", val as u32); - printval = val; - } - } -} diff --git a/embassy-nrf-examples/src/bin/spim.rs b/embassy-nrf-examples/src/bin/spim.rs index f4fb22ba..77058bf2 100644 --- a/embassy-nrf-examples/src/bin/spim.rs +++ b/embassy-nrf-examples/src/bin/spim.rs @@ -3,17 +3,21 @@ #![feature(min_type_alias_impl_trait)] #![feature(impl_trait_in_bindings)] #![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] #[path = "../example_common.rs"] mod example_common; +use core::mem; + use cortex_m_rt::entry; use defmt::panic; use embassy::executor::{task, Executor}; use embassy::util::Forever; +use embassy::util::Steal; use embassy_nrf::gpio::{Level, Output, OutputDrive}; -use embassy_nrf::Peripherals; -use embassy_nrf::{interrupt, pac, rtc, spim}; +use embassy_nrf::{interrupt, rtc, spim}; +use embassy_nrf::{peripherals, Peripherals}; use embassy_traits::spi::FullDuplex; use embedded_hal::digital::v2::*; use example_common::*; @@ -24,7 +28,7 @@ use nrf52840_hal::clocks; async fn run() { info!("running!"); - let p = Peripherals::take().unwrap(); + let p = unsafe { Peripherals::steal() }; let config = spim::Config { frequency: spim::Frequency::M16, @@ -33,10 +37,10 @@ async fn run() { }; let irq = interrupt::take!(SPIM3); - let spim = spim::Spim::new(p.spim3, irq, p.p0_29, p.p0_28, p.p0_30, config); + let spim = spim::Spim::new(p.SPIM3, irq, p.P0_29, p.P0_28, p.P0_30, config); pin_mut!(spim); - let mut ncs = Output::new(p.p0_31, Level::High, OutputDrive::Standard); + let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard); // Example on how to talk to an ENC28J60 chip @@ -84,17 +88,17 @@ async fn run() { info!("erevid: {=[?]}", rx); } -static RTC: Forever> = Forever::new(); -static ALARM: Forever> = Forever::new(); +static RTC: Forever> = Forever::new(); +static ALARM: Forever> = Forever::new(); static EXECUTOR: Forever = Forever::new(); #[entry] fn main() -> ! { info!("Hello World!"); - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + let p = unwrap!(embassy_nrf::Peripherals::take()); - clocks::Clocks::new(p.CLOCK) + clocks::Clocks::new(unsafe { mem::transmute(()) }) .enable_ext_hfosc() .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) .start_lfclk(); diff --git a/embassy-nrf-examples/src/bin/rtc_async.rs b/embassy-nrf-examples/src/bin/timer.rs similarity index 80% rename from embassy-nrf-examples/src/bin/rtc_async.rs rename to embassy-nrf-examples/src/bin/timer.rs index ec437425..41e5d77a 100644 --- a/embassy-nrf-examples/src/bin/rtc_async.rs +++ b/embassy-nrf-examples/src/bin/timer.rs @@ -3,9 +3,12 @@ #![feature(min_type_alias_impl_trait)] #![feature(impl_trait_in_bindings)] #![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] #[path = "../example_common.rs"] mod example_common; +use core::mem; + use example_common::*; use cortex_m_rt::entry; @@ -13,7 +16,7 @@ use defmt::panic; use embassy::executor::{task, Executor}; use embassy::time::{Duration, Timer}; use embassy::util::Forever; -use embassy_nrf::pac; +use embassy_nrf::peripherals; use embassy_nrf::{interrupt, rtc}; use nrf52840_hal::clocks; @@ -33,21 +36,21 @@ async fn run2() { } } -static RTC: Forever> = Forever::new(); -static ALARM: Forever> = Forever::new(); +static RTC: Forever> = Forever::new(); +static ALARM: Forever> = Forever::new(); static EXECUTOR: Forever = Forever::new(); #[entry] fn main() -> ! { info!("Hello World!"); - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - - clocks::Clocks::new(p.CLOCK) + clocks::Clocks::new(unsafe { mem::transmute(()) }) .enable_ext_hfosc() .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) .start_lfclk(); + let p = unwrap!(embassy_nrf::Peripherals::take()); + let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); rtc.start(); diff --git a/embassy-nrf-examples/src/bin/uart.rs b/embassy-nrf-examples/src/bin/uart.rs index 7efb3ebe..d8644167 100644 --- a/embassy-nrf-examples/src/bin/uart.rs +++ b/embassy-nrf-examples/src/bin/uart.rs @@ -3,34 +3,34 @@ #![feature(min_type_alias_impl_trait)] #![feature(impl_trait_in_bindings)] #![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] #[path = "../example_common.rs"] mod example_common; +use core::mem; + use embassy_nrf::gpio::NoPin; use example_common::*; use cortex_m_rt::entry; use defmt::panic; use embassy::executor::{task, Executor}; -use embassy::time::{Duration, Timer}; use embassy::traits::uart::{Read, Write}; -use embassy::util::Forever; -use embassy_nrf::{interrupt, pac, rtc, uarte, Peripherals}; -use futures::future::{select, Either}; +use embassy::util::{Forever, Steal}; +use embassy_nrf::{interrupt, peripherals, rtc, uarte, Peripherals}; use futures::pin_mut; use nrf52840_hal::clocks; -use nrf52840_hal::gpio; #[task] async fn run() { - let p = Peripherals::take().unwrap(); + let p = unsafe { Peripherals::steal() }; let mut config = uarte::Config::default(); config.parity = uarte::Parity::EXCLUDED; config.baudrate = uarte::Baudrate::BAUD115200; let irq = interrupt::take!(UARTE0_UART0); - let uart = unsafe { uarte::Uarte::new(p.uarte0, irq, p.p0_08, p.p0_06, NoPin, NoPin, config) }; + let uart = unsafe { uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, NoPin, NoPin, config) }; pin_mut!(uart); info!("uarte initialized!"); @@ -78,17 +78,17 @@ async fn run() { } } -static RTC: Forever> = Forever::new(); -static ALARM: Forever> = Forever::new(); +static RTC: Forever> = Forever::new(); +static ALARM: Forever> = Forever::new(); static EXECUTOR: Forever = Forever::new(); #[entry] fn main() -> ! { info!("Hello World!"); - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + let p = unwrap!(embassy_nrf::Peripherals::take()); - clocks::Clocks::new(p.CLOCK) + clocks::Clocks::new(unsafe { mem::transmute(()) }) .enable_ext_hfosc() .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) .start_lfclk(); diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 009cb99b..9e5132c5 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -106,110 +106,110 @@ pub mod uarte; embassy_extras::peripherals! { // RTC - rtc0: RTC0, - rtc1: RTC1, + RTC0, + RTC1, #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] - rtc2: RTC2, + RTC2, // QSPI #[cfg(feature = "52840")] - qspi: QSPI, + QSPI, // UARTE - uarte0: UARTE0, + UARTE0, #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] - uarte1: UARTE1, + UARTE1, // SPIM // TODO this is actually shared with SPI, SPIM, SPIS, TWI, TWIS, TWIS. // When they're all implemented, they should be only one peripheral here. - spim0: SPIM0, + SPIM0, #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] - spim1: SPIM1, + SPIM1, #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] - spim2: SPIM2, + SPIM2, #[cfg(any(feature = "52833", feature = "52840"))] - spim3: SPIM3, + SPIM3, // SAADC - saadc: SAADC, + SAADC, // GPIOTE - gpiote: GPIOTE, - gpiote_ch_0: GPIOTE_CH0, - gpiote_ch_1: GPIOTE_CH1, - gpiote_ch_2: GPIOTE_CH2, - gpiote_ch_3: GPIOTE_CH3, - gpiote_ch_4: GPIOTE_CH4, - gpiote_ch_5: GPIOTE_CH5, - gpiote_ch_6: GPIOTE_CH6, - gpiote_ch_7: GPIOTE_CH7, + GPIOTE, + GPIOTE_CH0, + GPIOTE_CH1, + GPIOTE_CH2, + GPIOTE_CH3, + GPIOTE_CH4, + GPIOTE_CH5, + GPIOTE_CH6, + GPIOTE_CH7, // GPIO port 0 - p0_00: P0_00, - p0_01: P0_01, - p0_02: P0_02, - p0_03: P0_03, - p0_04: P0_04, - p0_05: P0_05, - p0_06: P0_06, - p0_07: P0_07, - p0_08: P0_08, - p0_09: P0_09, - p0_10: P0_10, - p0_11: P0_11, - p0_12: P0_12, - p0_13: P0_13, - p0_14: P0_14, - p0_15: P0_15, - p0_16: P0_16, - p0_17: P0_17, - p0_18: P0_18, - p0_19: P0_19, - p0_20: P0_20, - p0_21: P0_21, - p0_22: P0_22, - p0_23: P0_23, - p0_24: P0_24, - p0_25: P0_25, - p0_26: P0_26, - p0_27: P0_27, - p0_28: P0_28, - p0_29: P0_29, - p0_30: P0_30, - p0_31: P0_31, + P0_00, + P0_01, + P0_02, + P0_03, + P0_04, + P0_05, + P0_06, + P0_07, + P0_08, + P0_09, + P0_10, + P0_11, + P0_12, + P0_13, + P0_14, + P0_15, + P0_16, + P0_17, + P0_18, + P0_19, + P0_20, + P0_21, + P0_22, + P0_23, + P0_24, + P0_25, + P0_26, + P0_27, + P0_28, + P0_29, + P0_30, + P0_31, // GPIO port 1 #[cfg(any(feature = "52833", feature = "52840"))] - p1_00: P1_00, + P1_00, #[cfg(any(feature = "52833", feature = "52840"))] - p1_01: P1_01, + P1_01, #[cfg(any(feature = "52833", feature = "52840"))] - p1_02: P1_02, + P1_02, #[cfg(any(feature = "52833", feature = "52840"))] - p1_03: P1_03, + P1_03, #[cfg(any(feature = "52833", feature = "52840"))] - p1_04: P1_04, + P1_04, #[cfg(any(feature = "52833", feature = "52840"))] - p1_05: P1_05, + P1_05, #[cfg(any(feature = "52833", feature = "52840"))] - p1_06: P1_06, + P1_06, #[cfg(any(feature = "52833", feature = "52840"))] - p1_07: P1_07, + P1_07, #[cfg(any(feature = "52833", feature = "52840"))] - p1_08: P1_08, + P1_08, #[cfg(any(feature = "52833", feature = "52840"))] - p1_09: P1_09, + P1_09, #[cfg(any(feature = "52833", feature = "52840"))] - p1_10: P1_10, + P1_10, #[cfg(any(feature = "52833", feature = "52840"))] - p1_11: P1_11, + P1_11, #[cfg(any(feature = "52833", feature = "52840"))] - p1_12: P1_12, + P1_12, #[cfg(any(feature = "52833", feature = "52840"))] - p1_13: P1_13, + P1_13, #[cfg(any(feature = "52833", feature = "52840"))] - p1_14: P1_14, + P1_14, #[cfg(any(feature = "52833", feature = "52840"))] - p1_15: P1_15, + P1_15, } diff --git a/embassy-nrf/src/rtc.rs b/embassy-nrf/src/rtc.rs index e0e645fe..7d29d72b 100644 --- a/embassy-nrf/src/rtc.rs +++ b/embassy-nrf/src/rtc.rs @@ -1,13 +1,12 @@ use core::cell::Cell; -use core::ops::Deref; use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; use embassy::interrupt::InterruptExt; use embassy::time::Clock; -use crate::interrupt; use crate::interrupt::{CriticalSection, Interrupt, Mutex}; -use crate::pac::rtc0; +use crate::pac; +use crate::{interrupt, peripherals}; // RTC timekeeping works with something we call "periods", which are time intervals // of 2^23 ticks. The RTC counter value is 24 bits, so one "overflow cycle" is 2 periods. @@ -96,19 +95,20 @@ impl RTC { } pub fn start(&'static self) { - self.rtc.cc[3].write(|w| unsafe { w.bits(0x800000) }); + let r = self.rtc.regs(); + r.cc[3].write(|w| unsafe { w.bits(0x800000) }); - self.rtc.intenset.write(|w| { + r.intenset.write(|w| { let w = w.ovrflw().set(); let w = w.compare3().set(); w }); - self.rtc.tasks_clear.write(|w| unsafe { w.bits(1) }); - self.rtc.tasks_start.write(|w| unsafe { w.bits(1) }); + r.tasks_clear.write(|w| unsafe { w.bits(1) }); + r.tasks_start.write(|w| unsafe { w.bits(1) }); // Wait for clear - while self.rtc.counter.read().bits() != 0 {} + while r.counter.read().bits() != 0 {} self.irq.set_handler(|ptr| unsafe { let this = &*(ptr as *const () as *const Self); @@ -120,19 +120,20 @@ impl RTC { } fn on_interrupt(&self) { - if self.rtc.events_ovrflw.read().bits() == 1 { - self.rtc.events_ovrflw.write(|w| w); + let r = self.rtc.regs(); + if r.events_ovrflw.read().bits() == 1 { + r.events_ovrflw.write(|w| w); self.next_period(); } - if self.rtc.events_compare[3].read().bits() == 1 { - self.rtc.events_compare[3].write(|w| w); + if r.events_compare[3].read().bits() == 1 { + r.events_compare[3].write(|w| w); self.next_period(); } for n in 0..ALARM_COUNT { - if self.rtc.events_compare[n].read().bits() == 1 { - self.rtc.events_compare[n].write(|w| w); + if r.events_compare[n].read().bits() == 1 { + r.events_compare[n].write(|w| w); interrupt::free(|cs| { self.trigger_alarm(n, cs); }) @@ -142,6 +143,7 @@ impl RTC { fn next_period(&self) { interrupt::free(|cs| { + let r = self.rtc.regs(); let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; let t = (period as u64) << 23; @@ -151,15 +153,16 @@ impl RTC { let diff = at - t; if diff < 0xc00000 { - self.rtc.cc[n].write(|w| unsafe { w.bits(at as u32 & 0xFFFFFF) }); - self.rtc.intenset.write(|w| unsafe { w.bits(compare_n(n)) }); + r.cc[n].write(|w| unsafe { w.bits(at as u32 & 0xFFFFFF) }); + r.intenset.write(|w| unsafe { w.bits(compare_n(n)) }); } } }) } fn trigger_alarm(&self, n: usize, cs: &CriticalSection) { - self.rtc.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); + let r = self.rtc.regs(); + r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); let alarm = &self.alarms.borrow(cs)[n]; alarm.timestamp.set(u64::MAX); @@ -190,6 +193,8 @@ impl RTC { return; } + let r = self.rtc.regs(); + // If it hasn't triggered yet, setup it in the compare channel. let diff = timestamp - t; if diff < 0xc00000 { @@ -206,12 +211,12 @@ impl RTC { // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, // and we don't do that here. let safe_timestamp = timestamp.max(t + 3); - self.rtc.cc[n].write(|w| unsafe { w.bits(safe_timestamp as u32 & 0xFFFFFF) }); - self.rtc.intenset.write(|w| unsafe { w.bits(compare_n(n)) }); + r.cc[n].write(|w| unsafe { w.bits(safe_timestamp as u32 & 0xFFFFFF) }); + r.intenset.write(|w| unsafe { w.bits(compare_n(n)) }); } else { // If it's too far in the future, don't setup the compare channel yet. // It will be setup later by `next_period`. - self.rtc.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); + r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); } }) } @@ -232,7 +237,7 @@ impl embassy::time::Clock for RTC { // `period` MUST be read before `counter`, see comment at the top for details. let period = self.period.load(Ordering::Relaxed); compiler_fence(Ordering::Acquire); - let counter = self.rtc.counter.read().bits(); + let counter = self.rtc.regs().counter.read().bits(); calc_now(period, counter) } } @@ -257,31 +262,32 @@ impl embassy::time::Alarm for Alarm { } mod sealed { - pub trait Instance {} + use super::*; + pub trait Instance { + fn regs(&self) -> &pac::rtc0::RegisterBlock; + } +} - impl Instance for crate::pac::RTC0 {} - impl Instance for crate::pac::RTC1 {} - #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] - impl Instance for crate::pac::RTC2 {} +macro_rules! make_impl { + ($type:ident, $irq:ident) => { + impl sealed::Instance for peripherals::$type { + fn regs(&self) -> &pac::rtc0::RegisterBlock { + unsafe { &*pac::$type::ptr() } + } + } + impl Instance for peripherals::$type { + type Interrupt = interrupt::$irq; + } + }; } /// Implemented by all RTC instances. -pub trait Instance: - sealed::Instance + Deref + Sized + 'static -{ +pub trait Instance: sealed::Instance + 'static { /// The interrupt associated with this RTC instance. type Interrupt: Interrupt; } -impl Instance for crate::pac::RTC0 { - type Interrupt = interrupt::RTC0; -} - -impl Instance for crate::pac::RTC1 { - type Interrupt = interrupt::RTC1; -} - +make_impl!(RTC0, RTC0); +make_impl!(RTC1, RTC1); #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] -impl Instance for crate::pac::RTC2 { - type Interrupt = interrupt::RTC2; -} +make_impl!(RTC2, RTC2); From 2c248dab56a645b37bcbd2313339bde1acd5499c Mon Sep 17 00:00:00 2001 From: Richard Dodd Date: Sat, 27 Mar 2021 03:20:58 +0100 Subject: [PATCH 30/45] nrf/spim: make mosi,miso optional --- embassy-nrf/src/spim.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index c84861f3..5d55a3cc 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -9,7 +9,8 @@ use embassy_extras::unborrow; use futures::future::poll_fn; use traits::spi::FullDuplex; -use crate::gpio::Pin as GpioPin; +use crate::gpio::sealed::Pin as _; +use crate::gpio::{OptionalPin, Pin as GpioPin}; use crate::interrupt::{self, Interrupt}; use crate::{pac, peripherals, slice_in_ram_or}; @@ -43,8 +44,8 @@ impl<'d, T: Instance> Spim<'d, T> { spim: impl PeripheralBorrow + 'd, irq: impl PeripheralBorrow + 'd, sck: impl PeripheralBorrow + 'd, - miso: impl PeripheralBorrow + 'd, - mosi: impl PeripheralBorrow + 'd, + miso: impl PeripheralBorrow + 'd, + mosi: impl PeripheralBorrow + 'd, config: Config, ) -> Self { unborrow!(spim, irq, sck, miso, mosi); @@ -53,21 +54,30 @@ impl<'d, T: Instance> Spim<'d, T> { // Configure pins sck.conf().write(|w| w.dir().output().drive().h0h1()); - mosi.conf().write(|w| w.dir().output().drive().h0h1()); - miso.conf().write(|w| w.input().connect().drive().h0h1()); + if let Some(mosi) = mosi.pin_mut() { + mosi.conf().write(|w| w.dir().output().drive().h0h1()); + } + if let Some(miso) = miso.pin_mut() { + miso.conf().write(|w| w.input().connect().drive().h0h1()); + } match config.mode.polarity { Polarity::IdleHigh => { sck.set_high(); - mosi.set_high(); + if let Some(mosi) = mosi.pin_mut() { + mosi.set_high(); + } } Polarity::IdleLow => { sck.set_low(); - mosi.set_low(); + if let Some(mosi) = mosi.pin_mut() { + mosi.set_low(); + } } } // Select pins. + // Note: OptionalPin reports 'disabled' for psel_bits when no pin was selected. r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) }); r.psel.mosi.write(|w| unsafe { w.bits(mosi.psel_bits()) }); r.psel.miso.write(|w| unsafe { w.bits(miso.psel_bits()) }); From a338841797e52e5a2032246ac63d29080014d16c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Mar 2021 03:33:32 +0100 Subject: [PATCH 31/45] extras: add impl_unborrow macro --- embassy-extras/src/macros.rs | 21 +++++++++++++++++++++ embassy-nrf/src/gpio.rs | 30 +++--------------------------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/embassy-extras/src/macros.rs b/embassy-extras/src/macros.rs index 0659a0b7..e8d7a6e3 100644 --- a/embassy-extras/src/macros.rs +++ b/embassy-extras/src/macros.rs @@ -84,3 +84,24 @@ macro_rules! unborrow { )* } } + +#[macro_export] +macro_rules! impl_unborrow { + ($type:ident) => { + impl PeripheralBorrow for $type { + type Target = $type; + #[inline] + unsafe fn unborrow(self) -> Self::Target { + self + } + } + + impl<'a> PeripheralBorrow for &'a mut $type { + type Target = $type; + #[inline] + unsafe fn unborrow(self) -> Self::Target { + unsafe { ::core::ptr::read(self) } + } + } + }; +} diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 0d566ff3..bda5acef 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -3,7 +3,7 @@ use core::hint::unreachable_unchecked; use core::marker::PhantomData; use embassy::util::PeripheralBorrow; -use embassy_extras::unborrow; +use embassy_extras::{impl_unborrow, unborrow}; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; use gpio::pin_cnf::DRIVE_A; @@ -305,6 +305,7 @@ impl AnyPin { } } +impl_unborrow!(AnyPin); impl Pin for AnyPin {} impl sealed::Pin for AnyPin { #[inline] @@ -313,24 +314,6 @@ impl sealed::Pin for AnyPin { } } -impl PeripheralBorrow for AnyPin { - type Target = AnyPin; - #[inline] - unsafe fn unborrow(self) -> Self::Target { - self - } -} - -impl<'a> PeripheralBorrow for &'a mut AnyPin { - type Target = AnyPin; - #[inline] - unsafe fn unborrow(self) -> Self::Target { - AnyPin { - pin_port: self.pin_port, - } - } -} - // ==================== pub trait OptionalPin: sealed::OptionalPin + Sized { @@ -379,6 +362,7 @@ impl sealed::Pin for DummyPin { #[derive(Clone, Copy, Debug)] pub struct NoPin; +impl_unborrow!(NoPin); impl sealed::OptionalPin for NoPin {} impl OptionalPin for NoPin { type Pin = DummyPin; @@ -394,14 +378,6 @@ impl OptionalPin for NoPin { } } -impl PeripheralBorrow for NoPin { - type Target = NoPin; - #[inline] - unsafe fn unborrow(self) -> Self::Target { - self - } -} - // ==================== macro_rules! make_impl { From 2bd9323f28537da035692e48820ce8687e627c9e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Mar 2021 03:50:18 +0100 Subject: [PATCH 32/45] nrf/gpiote: update input channel to new API --- .../src/bin/gpiote_channel.rs | 45 +++-- embassy-nrf/src/gpiote.rs | 164 ++++++++++-------- 2 files changed, 122 insertions(+), 87 deletions(-) diff --git a/embassy-nrf-examples/src/bin/gpiote_channel.rs b/embassy-nrf-examples/src/bin/gpiote_channel.rs index 599882a9..d223df7a 100644 --- a/embassy-nrf-examples/src/bin/gpiote_channel.rs +++ b/embassy-nrf-examples/src/bin/gpiote_channel.rs @@ -11,31 +11,44 @@ use example_common::*; use cortex_m_rt::entry; use defmt::panic; -use nrf52840_hal::gpio; use embassy::executor::{task, Executor}; use embassy::util::Forever; -use embassy_nrf::gpiote::{Gpiote, InputChannel, InputChannelPolarity}; -use embassy_nrf::interrupt; +use embassy_nrf::gpio::{Input, Pull}; +use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; +use embassy_nrf::{interrupt, Peripherals}; #[task] async fn run() { - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - let port0 = gpio::p0::Parts::new(p.P0); - - let (g, chs) = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); + let p = Peripherals::take().unwrap(); + let g = gpiote::initialize(p.GPIOTE, interrupt::take!(GPIOTE)); info!("Starting!"); - let pin1 = port0.p0_11.into_pullup_input().degrade(); - let pin2 = port0.p0_12.into_pullup_input().degrade(); - let pin3 = port0.p0_24.into_pullup_input().degrade(); - let pin4 = port0.p0_25.into_pullup_input().degrade(); - - let ch1 = InputChannel::new(g, chs.ch0, pin1, InputChannelPolarity::HiToLo); - let ch2 = InputChannel::new(g, chs.ch1, pin2, InputChannelPolarity::LoToHi); - let ch3 = InputChannel::new(g, chs.ch2, pin3, InputChannelPolarity::Toggle); - let ch4 = InputChannel::new(g, chs.ch3, pin4, InputChannelPolarity::Toggle); + let ch1 = InputChannel::new( + g, + p.GPIOTE_CH0, + Input::new(p.P0_11, Pull::Up), + InputChannelPolarity::HiToLo, + ); + let ch2 = InputChannel::new( + g, + p.GPIOTE_CH1, + Input::new(p.P0_12, Pull::Up), + InputChannelPolarity::LoToHi, + ); + let ch3 = InputChannel::new( + g, + p.GPIOTE_CH2, + Input::new(p.P0_24, Pull::Up), + InputChannelPolarity::Toggle, + ); + let ch4 = InputChannel::new( + g, + p.GPIOTE_CH3, + Input::new(p.P0_25, Pull::Up), + InputChannelPolarity::Toggle, + ); let button1 = async { loop { diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 9ea008f0..95e49324 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -10,10 +10,12 @@ use core::task::{Context, Poll}; use embassy::interrupt::InterruptExt; use embassy::traits::gpio::{WaitForHigh, WaitForLow}; use embassy::util::{AtomicWaker, PeripheralBorrow, Signal}; +use embassy_extras::impl_unborrow; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; +use futures::future::poll_fn; use crate::gpio::sealed::Pin as _; -use crate::gpio::{AnyPin, Input, Pin as GpioPin, Pull}; +use crate::gpio::{AnyPin, Input, Pin as GpioPin, Port, Pull}; use crate::pac; use crate::pac::generic::Reg; use crate::pac::gpiote::_TASKS_OUT; @@ -30,44 +32,6 @@ pub const PIN_COUNT: usize = 48; #[cfg(not(any(feature = "52833", feature = "52840")))] pub const PIN_COUNT: usize = 32; -pub trait ChannelID { - fn number(&self) -> usize; -} - -macro_rules! impl_channel { - ($ChX:ident, $n:expr) => { - pub struct $ChX(()); - impl $ChX { - pub fn degrade(self) -> ChAny { - ChAny($n) - } - } - - impl ChannelID for $ChX { - fn number(&self) -> usize { - $n - } - } - }; -} - -impl_channel!(Ch0, 0); -impl_channel!(Ch1, 1); -impl_channel!(Ch2, 2); -impl_channel!(Ch3, 3); -impl_channel!(Ch4, 4); -impl_channel!(Ch5, 5); -impl_channel!(Ch6, 6); -impl_channel!(Ch7, 7); - -pub struct ChAny(u8); - -impl ChannelID for ChAny { - fn number(&self) -> usize { - self.0 as usize - } -} - const NEW_AWR: AtomicWaker = AtomicWaker::new(); static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AWR; CHANNEL_COUNT]; static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AWR; PIN_COUNT]; @@ -123,7 +87,7 @@ unsafe fn on_irq(_ctx: *mut ()) { for i in 0..CHANNEL_COUNT { if g.events_in[i].read().bits() != 0 { - g.events_in[i].write(|w| w); + g.intenclr.write(|w| unsafe { w.bits(1 << i) }); CHANNEL_WAKERS[i].wake(); } } @@ -163,32 +127,31 @@ impl Iterator for BitIter { } } -/* -pub struct InputChannel { +pub struct InputChannel<'d, C: Channel, T: GpioPin> { ch: C, - pin: GpioPin>, + pin: Input<'d, T>, } -impl Drop for InputChannel { +impl<'d, C: Channel, T: GpioPin> Drop for InputChannel<'d, C, T> { fn drop(&mut self) { - let g = unsafe { &*GPIOTE::ptr() }; - let index = self.ch.number(); - g.config[index].write(|w| w.mode().disabled()); - g.intenclr.write(|w| unsafe { w.bits(1 << index) }); + let g = unsafe { &*pac::GPIOTE::ptr() }; + let num = self.ch.number() as usize; + g.config[num].write(|w| w.mode().disabled()); + g.intenclr.write(|w| unsafe { w.bits(1 << num) }); } } -impl InputChannel { +impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { pub fn new( _init: Initialized, ch: C, - pin: GpioPin>, + pin: Input<'d, T>, polarity: InputChannelPolarity, ) -> Self { - let g = unsafe { &*GPIOTE::ptr() }; - let index = ch.number(); + let g = unsafe { &*pac::GPIOTE::ptr() }; + let num = ch.number() as usize; - g.config[index].write(|w| { + g.config[num].write(|w| { match polarity { InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(), InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(), @@ -196,38 +159,52 @@ impl InputChannel { InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(), }; #[cfg(any(feature = "52833", feature = "52840"))] - w.port().bit(match pin.port() { + w.port().bit(match pin.pin.port() { Port::Port0 => false, Port::Port1 => true, }); - unsafe { w.psel().bits(pin.pin()) } + unsafe { w.psel().bits(pin.pin.pin()) } }); - CHANNEL_WAKERS[index].reset(); - - // Enable interrupt - g.intenset.write(|w| unsafe { w.bits(1 << index) }); + g.events_in[num].reset(); InputChannel { ch, pin } } - pub fn free(self) -> (C, GpioPin>) { - let m = ManuallyDrop::new(self); - let ch = unsafe { ptr::read(&m.ch) }; - let pin = unsafe { ptr::read(&m.pin) }; - (ch, pin) - } - pub async fn wait(&self) { - let index = self.ch.number(); - CHANNEL_WAKERS[index].wait().await; - } + let g = unsafe { &*pac::GPIOTE::ptr() }; + let num = self.ch.number() as usize; - pub fn pin(&self) -> &GpioPin> { - &self.pin + // Enable interrupt + g.events_in[num].reset(); + g.intenset.write(|w| unsafe { w.bits(1 << num) }); + + poll_fn(|cx| { + CHANNEL_WAKERS[num].register(cx.waker()); + + if g.events_in[num].read().bits() != 0 { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; } } +impl<'d, C: Channel, T: GpioPin> InputPin for InputChannel<'d, C, T> { + type Error = Infallible; + + fn is_high(&self) -> Result { + self.pin.is_high() + } + + fn is_low(&self) -> Result { + self.pin.is_low() + } +} + +/* pub struct OutputChannel { ch: C, pin: GpioPin>, @@ -414,3 +391,48 @@ impl<'a> Future for PortInputFuture<'a> { } } } + +mod sealed { + pub trait Channel { + fn number(&self) -> u8; + } +} + +pub trait Channel: sealed::Channel + Sized { + fn degrade(self) -> AnyChannel { + AnyChannel { + number: self.number(), + } + } +} + +pub struct AnyChannel { + number: u8, +} +impl_unborrow!(AnyChannel); +impl Channel for AnyChannel {} +impl sealed::Channel for AnyChannel { + fn number(&self) -> u8 { + self.number + } +} + +macro_rules! impl_channel { + ($type:ident, $number:expr) => { + impl sealed::Channel for peripherals::$type { + fn number(&self) -> u8 { + $number + } + } + impl Channel for peripherals::$type {} + }; +} + +impl_channel!(GPIOTE_CH0, 0); +impl_channel!(GPIOTE_CH1, 1); +impl_channel!(GPIOTE_CH2, 2); +impl_channel!(GPIOTE_CH3, 3); +impl_channel!(GPIOTE_CH4, 4); +impl_channel!(GPIOTE_CH5, 5); +impl_channel!(GPIOTE_CH6, 6); +impl_channel!(GPIOTE_CH7, 7); From 90f599bc2fdc9ff94002970d9c147e02e6961acf Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Mar 2021 04:01:48 +0100 Subject: [PATCH 33/45] nrf/gpiote: update output channel to new API --- embassy-nrf/src/gpio.rs | 2 +- embassy-nrf/src/gpiote.rs | 89 +++++++++++++++------------------------ 2 files changed, 34 insertions(+), 57 deletions(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index bda5acef..a6d2fc07 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -117,7 +117,7 @@ pub enum OutputDrive { /// GPIO output driver. pub struct Output<'d, T: Pin> { - pin: T, + pub(crate) pin: T, phantom: PhantomData<&'d mut T>, } diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 95e49324..32f085a6 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -15,7 +15,7 @@ use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; use futures::future::poll_fn; use crate::gpio::sealed::Pin as _; -use crate::gpio::{AnyPin, Input, Pin as GpioPin, Port, Pull}; +use crate::gpio::{AnyPin, Input, Output, Pin as GpioPin, Port, Pull}; use crate::pac; use crate::pac::generic::Reg; use crate::pac::gpiote::_TASKS_OUT; @@ -204,37 +204,35 @@ impl<'d, C: Channel, T: GpioPin> InputPin for InputChannel<'d, C, T> { } } -/* -pub struct OutputChannel { +pub struct OutputChannel<'d, C: Channel, T: GpioPin> { ch: C, - pin: GpioPin>, + pin: Output<'d, T>, } -impl Drop for OutputChannel { +impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> { fn drop(&mut self) { - let g = unsafe { &*GPIOTE::ptr() }; - let index = self.ch.number(); - g.config[index].write(|w| w.mode().disabled()); - g.intenclr.write(|w| unsafe { w.bits(1 << index) }); + let g = unsafe { &*pac::GPIOTE::ptr() }; + let num = self.ch.number() as usize; + g.config[num].write(|w| w.mode().disabled()); + g.intenclr.write(|w| unsafe { w.bits(1 << num) }); } } -impl OutputChannel { +impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { pub fn new( - _gpiote: Gpiote, + _init: Initialized, ch: C, - pin: GpioPin>, - level: Level, + pin: Output<'d, T>, polarity: OutputChannelPolarity, ) -> Self { - let g = unsafe { &*GPIOTE::ptr() }; - let index = ch.number(); + let g = unsafe { &*pac::GPIOTE::ptr() }; + let num = ch.number() as usize; - g.config[index].write(|w| { + g.config[num].write(|w| { w.mode().task(); - match level { - Level::High => w.outinit().high(), - Level::Low => w.outinit().low(), + match pin.is_set_high().unwrap() { + true => w.outinit().high(), + false => w.outinit().low(), }; match polarity { OutputChannelPolarity::Set => w.polarity().lo_to_hi(), @@ -242,77 +240,56 @@ impl OutputChannel { OutputChannelPolarity::Toggle => w.polarity().toggle(), }; #[cfg(any(feature = "52833", feature = "52840"))] - w.port().bit(match pin.port() { + w.port().bit(match pin.pin.port() { Port::Port0 => false, Port::Port1 => true, }); - unsafe { w.psel().bits(pin.pin()) } + unsafe { w.psel().bits(pin.pin.pin()) } }); - // Enable interrupt - g.intenset.write(|w| unsafe { w.bits(1 << index) }); - OutputChannel { ch, pin } } - pub fn free(self) -> (C, GpioPin>) { - let m = ManuallyDrop::new(self); - let ch = unsafe { ptr::read(&m.ch) }; - let pin = unsafe { ptr::read(&m.pin) }; - (ch, pin) - } - /// Triggers `task out` (as configured with task_out_polarity, defaults to Toggle). pub fn out(&self) { - let g = unsafe { &*GPIOTE::ptr() }; - let index = self.ch.number(); - - g.tasks_out[index].write(|w| unsafe { w.bits(1) }); + let g = unsafe { &*pac::GPIOTE::ptr() }; + g.tasks_out[self.ch.number() as usize].write(|w| unsafe { w.bits(1) }); } + /// Triggers `task set` (set associated pin high). #[cfg(not(feature = "51"))] pub fn set(&self) { - let g = unsafe { &*GPIOTE::ptr() }; - let index = self.ch.number(); - - g.tasks_set[index].write(|w| unsafe { w.bits(1) }); + let g = unsafe { &*pac::GPIOTE::ptr() }; + g.tasks_set[self.ch.number() as usize].write(|w| unsafe { w.bits(1) }); } + /// Triggers `task clear` (set associated pin low). #[cfg(not(feature = "51"))] pub fn clear(&self) { - let g = unsafe { &*GPIOTE::ptr() }; - let index = self.ch.number(); - - g.tasks_clr[index].write(|w| unsafe { w.bits(1) }); + let g = unsafe { &*pac::GPIOTE::ptr() }; + g.tasks_clr[self.ch.number() as usize].write(|w| unsafe { w.bits(1) }); } /// Returns reference to task_out endpoint for PPI. pub fn task_out(&self) -> &Reg { - let g = unsafe { &*GPIOTE::ptr() }; - let index = self.ch.number(); - - &g.tasks_out[index] + let g = unsafe { &*pac::GPIOTE::ptr() }; + &g.tasks_out[self.ch.number() as usize] } /// Returns reference to task_clr endpoint for PPI. #[cfg(not(feature = "51"))] pub fn task_clr(&self) -> &Reg { - let g = unsafe { &*GPIOTE::ptr() }; - let index = self.ch.number(); - - &g.tasks_clr[index] + let g = unsafe { &*pac::GPIOTE::ptr() }; + &g.tasks_clr[self.ch.number() as usize] } /// Returns reference to task_set endpoint for PPI. #[cfg(not(feature = "51"))] pub fn task_set(&self) -> &Reg { - let g = unsafe { &*GPIOTE::ptr() }; - let index = self.ch.number(); - - &g.tasks_set[index] + let g = unsafe { &*pac::GPIOTE::ptr() }; + &g.tasks_set[self.ch.number() as usize] } } - */ /// GPIO input driver with support pub struct PortInput<'d, T: GpioPin> { From 646be40ac582d88bfe58daa9c60502a6256f4da5 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Mar 2021 04:27:57 +0100 Subject: [PATCH 34/45] nrf/gpiote: make number() public, change to usize --- embassy-nrf/src/gpiote.rs | 58 ++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 32f085a6..c321c0fd 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -1,15 +1,11 @@ use core::convert::Infallible; use core::future::Future; -use core::intrinsics::transmute; use core::marker::PhantomData; -use core::mem::{self, ManuallyDrop}; -use core::ops::Deref; use core::pin::Pin; -use core::ptr; use core::task::{Context, Poll}; use embassy::interrupt::InterruptExt; use embassy::traits::gpio::{WaitForHigh, WaitForLow}; -use embassy::util::{AtomicWaker, PeripheralBorrow, Signal}; +use embassy::util::AtomicWaker; use embassy_extras::impl_unborrow; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; use futures::future::poll_fn; @@ -19,7 +15,6 @@ use crate::gpio::{AnyPin, Input, Output, Pin as GpioPin, Port, Pull}; use crate::pac; use crate::pac::generic::Reg; use crate::pac::gpiote::_TASKS_OUT; -use crate::pac::p0 as pac_gpio; use crate::{interrupt, peripherals}; #[cfg(not(feature = "51"))] @@ -32,9 +27,9 @@ pub const PIN_COUNT: usize = 48; #[cfg(not(any(feature = "52833", feature = "52840")))] pub const PIN_COUNT: usize = 32; -const NEW_AWR: AtomicWaker = AtomicWaker::new(); -static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AWR; CHANNEL_COUNT]; -static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AWR; PIN_COUNT]; +const NEW_AW: AtomicWaker = AtomicWaker::new(); +static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT]; +static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AW; PIN_COUNT]; pub enum InputChannelPolarity { None, @@ -135,7 +130,7 @@ pub struct InputChannel<'d, C: Channel, T: GpioPin> { impl<'d, C: Channel, T: GpioPin> Drop for InputChannel<'d, C, T> { fn drop(&mut self) { let g = unsafe { &*pac::GPIOTE::ptr() }; - let num = self.ch.number() as usize; + let num = self.ch.number(); g.config[num].write(|w| w.mode().disabled()); g.intenclr.write(|w| unsafe { w.bits(1 << num) }); } @@ -149,7 +144,7 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { polarity: InputChannelPolarity, ) -> Self { let g = unsafe { &*pac::GPIOTE::ptr() }; - let num = ch.number() as usize; + let num = ch.number(); g.config[num].write(|w| { match polarity { @@ -173,7 +168,7 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { pub async fn wait(&self) { let g = unsafe { &*pac::GPIOTE::ptr() }; - let num = self.ch.number() as usize; + let num = self.ch.number(); // Enable interrupt g.events_in[num].reset(); @@ -212,7 +207,7 @@ pub struct OutputChannel<'d, C: Channel, T: GpioPin> { impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> { fn drop(&mut self) { let g = unsafe { &*pac::GPIOTE::ptr() }; - let num = self.ch.number() as usize; + let num = self.ch.number(); g.config[num].write(|w| w.mode().disabled()); g.intenclr.write(|w| unsafe { w.bits(1 << num) }); } @@ -226,7 +221,7 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { polarity: OutputChannelPolarity, ) -> Self { let g = unsafe { &*pac::GPIOTE::ptr() }; - let num = ch.number() as usize; + let num = ch.number(); g.config[num].write(|w| { w.mode().task(); @@ -253,41 +248,41 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { /// Triggers `task out` (as configured with task_out_polarity, defaults to Toggle). pub fn out(&self) { let g = unsafe { &*pac::GPIOTE::ptr() }; - g.tasks_out[self.ch.number() as usize].write(|w| unsafe { w.bits(1) }); + g.tasks_out[self.ch.number()].write(|w| unsafe { w.bits(1) }); } /// Triggers `task set` (set associated pin high). #[cfg(not(feature = "51"))] pub fn set(&self) { let g = unsafe { &*pac::GPIOTE::ptr() }; - g.tasks_set[self.ch.number() as usize].write(|w| unsafe { w.bits(1) }); + g.tasks_set[self.ch.number()].write(|w| unsafe { w.bits(1) }); } /// Triggers `task clear` (set associated pin low). #[cfg(not(feature = "51"))] pub fn clear(&self) { let g = unsafe { &*pac::GPIOTE::ptr() }; - g.tasks_clr[self.ch.number() as usize].write(|w| unsafe { w.bits(1) }); + g.tasks_clr[self.ch.number()].write(|w| unsafe { w.bits(1) }); } /// Returns reference to task_out endpoint for PPI. pub fn task_out(&self) -> &Reg { let g = unsafe { &*pac::GPIOTE::ptr() }; - &g.tasks_out[self.ch.number() as usize] + &g.tasks_out[self.ch.number()] } /// Returns reference to task_clr endpoint for PPI. #[cfg(not(feature = "51"))] pub fn task_clr(&self) -> &Reg { let g = unsafe { &*pac::GPIOTE::ptr() }; - &g.tasks_clr[self.ch.number() as usize] + &g.tasks_clr[self.ch.number()] } /// Returns reference to task_set endpoint for PPI. #[cfg(not(feature = "51"))] pub fn task_set(&self) -> &Reg { let g = unsafe { &*pac::GPIOTE::ptr() }; - &g.tasks_set[self.ch.number() as usize] + &g.tasks_set[self.ch.number()] } } @@ -370,15 +365,14 @@ impl<'a> Future for PortInputFuture<'a> { } mod sealed { - pub trait Channel { - fn number(&self) -> u8; - } + pub trait Channel {} } pub trait Channel: sealed::Channel + Sized { + fn number(&self) -> usize; fn degrade(self) -> AnyChannel { AnyChannel { - number: self.number(), + number: self.number() as u8, } } } @@ -387,21 +381,21 @@ pub struct AnyChannel { number: u8, } impl_unborrow!(AnyChannel); -impl Channel for AnyChannel {} -impl sealed::Channel for AnyChannel { - fn number(&self) -> u8 { - self.number +impl sealed::Channel for AnyChannel {} +impl Channel for AnyChannel { + fn number(&self) -> usize { + self.number as usize } } macro_rules! impl_channel { ($type:ident, $number:expr) => { - impl sealed::Channel for peripherals::$type { - fn number(&self) -> u8 { - $number + impl sealed::Channel for peripherals::$type {} + impl Channel for peripherals::$type { + fn number(&self) -> usize { + $number as usize } } - impl Channel for peripherals::$type {} }; } From e88d52e0dae970e1704b2b29afe1013fd6cc2af7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Mar 2021 04:28:26 +0100 Subject: [PATCH 35/45] extras: fix missing absolute path in impl_borrow --- embassy-extras/src/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-extras/src/macros.rs b/embassy-extras/src/macros.rs index e8d7a6e3..9110f225 100644 --- a/embassy-extras/src/macros.rs +++ b/embassy-extras/src/macros.rs @@ -88,7 +88,7 @@ macro_rules! unborrow { #[macro_export] macro_rules! impl_unborrow { ($type:ident) => { - impl PeripheralBorrow for $type { + impl ::embassy::util::PeripheralBorrow for $type { type Target = $type; #[inline] unsafe fn unborrow(self) -> Self::Target { @@ -96,7 +96,7 @@ macro_rules! impl_unborrow { } } - impl<'a> PeripheralBorrow for &'a mut $type { + impl<'a> ::embassy::util::PeripheralBorrow for &'a mut $type { type Target = $type; #[inline] unsafe fn unborrow(self) -> Self::Target { From 26705ec32862a00e79cf334019aa3fbd4596bf17 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Mar 2021 04:40:05 +0100 Subject: [PATCH 36/45] nrf/ppi: add peris and traits --- embassy-nrf/src/lib.rs | 48 ++++++++++++++ embassy-nrf/src/ppi.rs | 143 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 embassy-nrf/src/ppi.rs diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 9e5132c5..1bcaf548 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -97,6 +97,7 @@ pub mod buffered_uarte; pub mod gpio; pub mod gpiote; pub mod interrupt; +pub mod ppi; #[cfg(feature = "52840")] pub mod qspi; pub mod rtc; @@ -145,6 +146,53 @@ embassy_extras::peripherals! { GPIOTE_CH6, GPIOTE_CH7, + // PPI + PPI_CH0, + PPI_CH1, + PPI_CH2, + PPI_CH3, + PPI_CH4, + PPI_CH5, + PPI_CH6, + PPI_CH7, + PPI_CH8, + PPI_CH9, + PPI_CH10, + PPI_CH11, + PPI_CH12, + PPI_CH13, + PPI_CH14, + PPI_CH15, + #[cfg(not(feature = "51"))] + PPI_CH16, + #[cfg(not(feature = "51"))] + PPI_CH17, + #[cfg(not(feature = "51"))] + PPI_CH18, + #[cfg(not(feature = "51"))] + PPI_CH19, + PPI_CH20, + PPI_CH21, + PPI_CH22, + PPI_CH23, + PPI_CH24, + PPI_CH25, + PPI_CH26, + PPI_CH27, + PPI_CH28, + PPI_CH29, + PPI_CH30, + PPI_CH31, + + PPI_GROUP0, + PPI_GROUP1, + PPI_GROUP2, + PPI_GROUP3, + #[cfg(not(feature = "51"))] + PPI_GROUP4, + #[cfg(not(feature = "51"))] + PPI_GROUP5, + // GPIO port 0 P0_00, P0_01, diff --git a/embassy-nrf/src/ppi.rs b/embassy-nrf/src/ppi.rs new file mode 100644 index 00000000..c06b212c --- /dev/null +++ b/embassy-nrf/src/ppi.rs @@ -0,0 +1,143 @@ +//! 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 embassy_extras::impl_unborrow; + +use crate::peripherals; + +// ====================== +// traits + +mod sealed { + pub trait ConfigurableChannel {} + pub trait Channel {} + pub trait Group {} +} + +pub trait Channel: sealed::Channel + Sized { + fn number(&self) -> usize; + fn degrade(self) -> AnyChannel { + AnyChannel { + number: self.number() as u8, + } + } +} +pub trait ConfigurableChannel: Channel + sealed::ConfigurableChannel {} + +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, +} +impl_unborrow!(AnyChannel); +impl sealed::Channel for AnyChannel {} +impl Channel for AnyChannel { + fn number(&self) -> usize { + self.number as usize + } +} + +macro_rules! impl_channel { + ($type:ident, $number:expr, configurable) => { + impl_channel!($type, $number); + impl sealed::ConfigurableChannel for peripherals::$type {} + impl ConfigurableChannel for peripherals::$type {} + }; + ($type:ident, $number:expr) => { + impl sealed::Channel for peripherals::$type {} + impl Channel for peripherals::$type { + fn number(&self) -> usize { + $number + } + } + }; +} + +impl_channel!(PPI_CH0, 0, configurable); +impl_channel!(PPI_CH1, 1, configurable); +impl_channel!(PPI_CH2, 2, configurable); +impl_channel!(PPI_CH3, 3, configurable); +impl_channel!(PPI_CH4, 4, configurable); +impl_channel!(PPI_CH5, 5, configurable); +impl_channel!(PPI_CH6, 6, configurable); +impl_channel!(PPI_CH7, 7, configurable); +impl_channel!(PPI_CH8, 8, configurable); +impl_channel!(PPI_CH9, 9, configurable); +impl_channel!(PPI_CH10, 10, configurable); +impl_channel!(PPI_CH11, 11, configurable); +impl_channel!(PPI_CH12, 12, configurable); +impl_channel!(PPI_CH13, 13, configurable); +impl_channel!(PPI_CH14, 14, configurable); +impl_channel!(PPI_CH15, 15, configurable); +#[cfg(not(feature = "51"))] +impl_channel!(PPI_CH16, 16, configurable); +#[cfg(not(feature = "51"))] +impl_channel!(PPI_CH17, 17, configurable); +#[cfg(not(feature = "51"))] +impl_channel!(PPI_CH18, 18, configurable); +#[cfg(not(feature = "51"))] +impl_channel!(PPI_CH19, 19, configurable); +impl_channel!(PPI_CH20, 20); +impl_channel!(PPI_CH21, 21); +impl_channel!(PPI_CH22, 22); +impl_channel!(PPI_CH23, 23); +impl_channel!(PPI_CH24, 24); +impl_channel!(PPI_CH25, 25); +impl_channel!(PPI_CH26, 26); +impl_channel!(PPI_CH27, 27); +impl_channel!(PPI_CH28, 28); +impl_channel!(PPI_CH29, 29); +impl_channel!(PPI_CH30, 30); +impl_channel!(PPI_CH31, 31); + +// ====================== +// groups + +pub struct AnyGroup { + number: u8, +} +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 = "51"))] +impl_group!(PPI_GROUP4, 4); +#[cfg(not(feature = "51"))] +impl_group!(PPI_GROUP5, 5); From b6496a85d89beb0f9bc4d3db2f39d82e8768e5da Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 27 Mar 2021 16:13:32 +0100 Subject: [PATCH 37/45] nrf/ppi: implement and add example --- embassy-nrf-examples/src/bin/ppi.rs | 112 ++++++++++++++++++++++++++++ embassy-nrf/src/gpiote.rs | 44 ++++++----- embassy-nrf/src/ppi.rs | 97 +++++++++++++++++++++++- 3 files changed, 231 insertions(+), 22 deletions(-) create mode 100644 embassy-nrf-examples/src/bin/ppi.rs diff --git a/embassy-nrf-examples/src/bin/ppi.rs b/embassy-nrf-examples/src/bin/ppi.rs new file mode 100644 index 00000000..87854fa5 --- /dev/null +++ b/embassy-nrf-examples/src/bin/ppi.rs @@ -0,0 +1,112 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use core::future::pending; + +use example_common::*; + +use cortex_m_rt::entry; +use defmt::panic; + +use embassy::executor::{task, Executor}; +use embassy::util::Forever; +use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; +use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; +use embassy_nrf::ppi::Ppi; +use embassy_nrf::{interrupt, Peripherals}; +use futures::future; +use gpiote::{OutputChannel, OutputChannelPolarity}; + +#[task] +async fn run() { + let p = Peripherals::take().unwrap(); + let g = gpiote::initialize(p.GPIOTE, interrupt::take!(GPIOTE)); + + info!("Starting!"); + + let button1 = InputChannel::new( + g, + p.GPIOTE_CH0, + Input::new(p.P0_11, Pull::Up), + InputChannelPolarity::HiToLo, + ); + let button2 = InputChannel::new( + g, + p.GPIOTE_CH1, + Input::new(p.P0_12, Pull::Up), + InputChannelPolarity::HiToLo, + ); + let button3 = InputChannel::new( + g, + p.GPIOTE_CH2, + Input::new(p.P0_24, Pull::Up), + InputChannelPolarity::HiToLo, + ); + let button4 = InputChannel::new( + g, + p.GPIOTE_CH3, + Input::new(p.P0_25, Pull::Up), + InputChannelPolarity::HiToLo, + ); + + let led1 = OutputChannel::new( + g, + p.GPIOTE_CH4, + Output::new(p.P0_13, Level::Low, OutputDrive::Standard), + OutputChannelPolarity::Toggle, + ); + + let led2 = OutputChannel::new( + g, + p.GPIOTE_CH5, + Output::new(p.P0_14, Level::Low, OutputDrive::Standard), + OutputChannelPolarity::Toggle, + ); + + let mut ppi = Ppi::new(p.PPI_CH0); + ppi.set_event(button1.event_in()); + ppi.set_task(led1.task_out()); + ppi.enable(); + + let mut ppi = Ppi::new(p.PPI_CH1); + ppi.set_event(button2.event_in()); + ppi.set_task(led1.task_clr()); + ppi.enable(); + + let mut ppi = Ppi::new(p.PPI_CH2); + ppi.set_event(button3.event_in()); + ppi.set_task(led1.task_set()); + 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.enable(); + + info!("PPI setup!"); + info!("Press button 1 to toggle LED 1"); + info!("Press button 2 to turn on LED 1"); + info!("Press button 3 to turn off LED 1"); + info!("Press button 4 to toggle LEDs 1 and 2"); + // Block forever so the above drivers don't get dropped + pending::<()>().await; +} + +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let executor = EXECUTOR.put(Executor::new()); + executor.run(|spawner| { + unwrap!(spawner.spawn(run())); + }); +} diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index c321c0fd..412eef1b 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -7,19 +7,15 @@ use embassy::interrupt::InterruptExt; use embassy::traits::gpio::{WaitForHigh, WaitForLow}; use embassy::util::AtomicWaker; use embassy_extras::impl_unborrow; -use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; +use embedded_hal::digital::v2::{InputPin, StatefulOutputPin}; use futures::future::poll_fn; use crate::gpio::sealed::Pin as _; -use crate::gpio::{AnyPin, Input, Output, Pin as GpioPin, Port, Pull}; +use crate::gpio::{AnyPin, Input, Output, Pin as GpioPin, Port}; use crate::pac; -use crate::pac::generic::Reg; -use crate::pac::gpiote::_TASKS_OUT; +use crate::ppi::{Event, Task}; use crate::{interrupt, peripherals}; -#[cfg(not(feature = "51"))] -use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET}; - pub const CHANNEL_COUNT: usize = 8; #[cfg(any(feature = "52833", feature = "52840"))] @@ -53,7 +49,7 @@ pub struct Initialized { _private: (), } -pub fn initialize(gpiote: peripherals::GPIOTE, irq: interrupt::GPIOTE) -> Initialized { +pub fn initialize(_gpiote: peripherals::GPIOTE, irq: interrupt::GPIOTE) -> Initialized { #[cfg(any(feature = "52833", feature = "52840"))] let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; #[cfg(not(any(feature = "52833", feature = "52840")))] @@ -122,6 +118,7 @@ impl Iterator for BitIter { } } +/// GPIOTE channel driver in input mode pub struct InputChannel<'d, C: Channel, T: GpioPin> { ch: C, pin: Input<'d, T>, @@ -185,6 +182,12 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { }) .await; } + + /// 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()]) + } } impl<'d, C: Channel, T: GpioPin> InputPin for InputChannel<'d, C, T> { @@ -199,9 +202,10 @@ impl<'d, C: Channel, T: GpioPin> InputPin for InputChannel<'d, C, T> { } } +/// GPIOTE channel driver in output mode pub struct OutputChannel<'d, C: Channel, T: GpioPin> { ch: C, - pin: Output<'d, T>, + _pin: Output<'d, T>, } impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> { @@ -242,7 +246,7 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { unsafe { w.psel().bits(pin.pin.pin()) } }); - OutputChannel { ch, pin } + OutputChannel { ch, _pin: pin } } /// Triggers `task out` (as configured with task_out_polarity, defaults to Toggle). @@ -265,28 +269,28 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { g.tasks_clr[self.ch.number()].write(|w| unsafe { w.bits(1) }); } - /// Returns reference to task_out endpoint for PPI. - pub fn task_out(&self) -> &Reg { + /// Returns the OUT task, for use with PPI. + pub fn task_out(&self) -> Task { let g = unsafe { &*pac::GPIOTE::ptr() }; - &g.tasks_out[self.ch.number()] + Task::from_reg(&g.tasks_out[self.ch.number()]) } - /// Returns reference to task_clr endpoint for PPI. + /// Returns the CLR task, for use with PPI. #[cfg(not(feature = "51"))] - pub fn task_clr(&self) -> &Reg { + pub fn task_clr(&self) -> Task { let g = unsafe { &*pac::GPIOTE::ptr() }; - &g.tasks_clr[self.ch.number()] + Task::from_reg(&g.tasks_clr[self.ch.number()]) } - /// Returns reference to task_set endpoint for PPI. + /// Returns the SET task, for use with PPI. #[cfg(not(feature = "51"))] - pub fn task_set(&self) -> &Reg { + pub fn task_set(&self) -> Task { let g = unsafe { &*pac::GPIOTE::ptr() }; - &g.tasks_set[self.ch.number()] + Task::from_reg(&g.tasks_set[self.ch.number()]) } } -/// GPIO input driver with support +/// GPIOTE port input driver pub struct PortInput<'d, T: GpioPin> { pin: Input<'d, T>, } diff --git a/embassy-nrf/src/ppi.rs b/embassy-nrf/src/ppi.rs index c06b212c..0129a2a4 100644 --- a/embassy-nrf/src/ppi.rs +++ b/embassy-nrf/src/ppi.rs @@ -9,13 +9,106 @@ //! 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 embassy_extras::impl_unborrow; +use core::marker::PhantomData; +use core::ptr::NonNull; +use embassy::util::PeripheralBorrow; +use embassy_extras::{impl_unborrow, unborrow}; -use crate::peripherals; +use crate::{pac, peripherals}; + +// ====================== +// driver + +pub struct Ppi<'d, C: Channel> { + ch: C, + phantom: PhantomData<&'d mut C>, +} + +impl<'d, C: Channel> Ppi<'d, C> { + pub fn new(ch: impl PeripheralBorrow + 'd) -> Self { + unborrow!(ch); + let mut this = Self { + ch, + phantom: PhantomData, + }; + #[cfg(not(feature = "51"))] + this.clear_fork_task(); + this + } + + /// Enables the channel. + pub fn enable(&mut self) { + let r = unsafe { &*pac::PPI::ptr() }; + r.chenset + .write(|w| unsafe { w.bits(1 << self.ch.number()) }); + } + + /// Disables the channel. + pub fn disable(&mut self) { + let r = unsafe { &*pac::PPI::ptr() }; + r.chenclr + .write(|w| unsafe { w.bits(1 << self.ch.number()) }); + } + + #[cfg(not(feature = "51"))] + /// Sets the fork task that must be triggered when the configured event occurs. The user must + /// provide a reference to the task. + pub fn set_fork_task(&mut self, task: Task) { + let r = unsafe { &*pac::PPI::ptr() }; + r.fork[self.ch.number()] + .tep + .write(|w| unsafe { w.bits(task.0.as_ptr() as u32) }) + } + + #[cfg(not(feature = "51"))] + /// Clear the fork task endpoint. Previously set task will no longer be triggered. + pub fn clear_fork_task(&mut self) { + let r = unsafe { &*pac::PPI::ptr() }; + r.fork[self.ch.number()].tep.write(|w| unsafe { w.bits(0) }) + } +} + +impl<'d, C: Channel> Drop for Ppi<'d, C> { + fn drop(&mut self) { + self.disable() + } +} + +impl<'d, C: ConfigurableChannel> Ppi<'d, C> { + /// Sets the task to be triggered when the configured event occurs. + pub fn set_task(&mut self, task: Task) { + let r = unsafe { &*pac::PPI::ptr() }; + r.ch[self.ch.number()] + .tep + .write(|w| unsafe { w.bits(task.0.as_ptr() as u32) }) + } + + /// Sets the event that will trigger the chosen task(s). + pub fn set_event(&mut self, event: Event) { + let r = unsafe { &*pac::PPI::ptr() }; + r.ch[self.ch.number()] + .eep + .write(|w| unsafe { w.bits(event.0.as_ptr() as u32) }) + } +} // ====================== // 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 ()) }) + } +} + mod sealed { pub trait ConfigurableChannel {} pub trait Channel {} From aa0341056ea086a6ec084d78a381066ae2333e53 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 28 Mar 2021 22:39:09 +0200 Subject: [PATCH 38/45] nrf/uarte: deal with hwfc correctly --- embassy-nrf/src/uarte.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 63dedcdc..5effe046 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -11,14 +11,14 @@ use embassy_extras::peripheral_shared::{Peripheral, PeripheralState}; use embassy_extras::unborrow; use futures::future::poll_fn; -use crate::fmt::{assert, *}; +use crate::fmt::{assert, panic, *}; use crate::gpio::sealed::Pin as _; use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin}; -use crate::hal::pac; -use crate::hal::target_constants::EASY_DMA_SIZE; use crate::interrupt; use crate::interrupt::Interrupt; +use crate::pac; use crate::peripherals; +use crate::target_constants::EASY_DMA_SIZE; // 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}; @@ -94,8 +94,18 @@ impl<'d, T: Instance> Uarte<'d, T> { } r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); + // Configure + let hardware_flow_control = match (rts.pin().is_some(), cts.pin().is_some()) { + (false, false) => false, + (true, true) => true, + _ => panic!("RTS and CTS pins must be either both set or none set."), + }; + r.config.write(|w| { + w.hwfc().bit(hardware_flow_control); + w.parity().variant(config.parity); + w + }); r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); - r.config.write(|w| w.parity().variant(config.parity)); // Disable all interrupts r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); From 31b817ed273ccecc4297a8a64d01b564bf51ae88 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 28 Mar 2021 22:40:41 +0200 Subject: [PATCH 39/45] nrf/timer: add instance traits --- embassy-nrf/src/lib.rs | 10 ++++++++++ embassy-nrf/src/timer.rs | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 embassy-nrf/src/timer.rs diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 1bcaf548..67ff9dc3 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -103,6 +103,7 @@ pub mod qspi; pub mod rtc; pub mod saadc; pub mod spim; +pub mod timer; pub mod uarte; embassy_extras::peripherals! { @@ -135,6 +136,15 @@ embassy_extras::peripherals! { // SAADC SAADC, + // TIMER + TIMER0, + TIMER1, + TIMER2, + #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] + TIMER3, + #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] + TIMER4, + // GPIOTE GPIOTE, GPIOTE_CH0, diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs new file mode 100644 index 00000000..6307a15e --- /dev/null +++ b/embassy-nrf/src/timer.rs @@ -0,0 +1,43 @@ +use embassy::interrupt::Interrupt; + +use crate::{interrupt, pac, peripherals}; + +mod sealed { + use super::*; + + pub trait Instance { + fn regs(&self) -> &pac::timer0::RegisterBlock; + } + pub trait ExtendedInstance {} +} + +pub trait Instance: sealed::Instance + 'static { + type Interrupt: Interrupt; +} +pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} + +macro_rules! make_impl { + ($type:ident, $irq:ident) => { + impl sealed::Instance for peripherals::$type { + fn regs(&self) -> &pac::timer0::RegisterBlock { + unsafe { &*(pac::$type::ptr() as *const pac::timer0::RegisterBlock) } + } + } + impl Instance for peripherals::$type { + type Interrupt = interrupt::$irq; + } + }; + ($type:ident, $irq:ident, extended) => { + make_impl!($type, $irq); + impl sealed::ExtendedInstance for peripherals::$type {} + impl ExtendedInstance for peripherals::$type {} + }; +} + +make_impl!(TIMER0, TIMER0); +make_impl!(TIMER1, TIMER1); +make_impl!(TIMER2, TIMER2); +#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] +make_impl!(TIMER3, TIMER3, extended); +#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] +make_impl!(TIMER4, TIMER4, extended); From 00e5f3035219656823ec7a2451f4ebae6802e1b8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 28 Mar 2021 22:41:07 +0200 Subject: [PATCH 40/45] nrf/ppi: add AnyConfigurableChannel --- embassy-nrf/src/ppi.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/src/ppi.rs b/embassy-nrf/src/ppi.rs index 0129a2a4..6487267d 100644 --- a/embassy-nrf/src/ppi.rs +++ b/embassy-nrf/src/ppi.rs @@ -123,7 +123,13 @@ pub trait Channel: sealed::Channel + Sized { } } } -pub trait ConfigurableChannel: Channel + sealed::ConfigurableChannel {} +pub trait ConfigurableChannel: Channel + sealed::ConfigurableChannel { + fn degrade_configurable(self) -> AnyConfigurableChannel { + AnyConfigurableChannel { + number: self.number() as u8, + } + } +} pub trait Group: sealed::Group + Sized { fn number(&self) -> usize; @@ -148,6 +154,19 @@ impl Channel for AnyChannel { } } +pub struct AnyConfigurableChannel { + number: u8, +} +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 + } +} + macro_rules! impl_channel { ($type:ident, $number:expr, configurable) => { impl_channel!($type, $number); From 3a18373828577e5e9d06e9f5c108376fef32fe18 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 28 Mar 2021 22:41:45 +0200 Subject: [PATCH 41/45] nrf/uarte: update BufferedUarte to new APi --- embassy-nrf-examples/src/bin/buffered_uart.rs | 78 +++-- embassy-nrf/Cargo.toml | 16 +- embassy-nrf/src/buffered_uarte.rs | 287 ++++++++---------- embassy-nrf/src/lib.rs | 11 - 4 files changed, 172 insertions(+), 220 deletions(-) diff --git a/embassy-nrf-examples/src/bin/buffered_uart.rs b/embassy-nrf-examples/src/bin/buffered_uart.rs index c7017128..80b24d2b 100644 --- a/embassy-nrf-examples/src/bin/buffered_uart.rs +++ b/embassy-nrf-examples/src/bin/buffered_uart.rs @@ -7,54 +7,49 @@ #[path = "../example_common.rs"] mod example_common; +use core::mem; + +use embassy_nrf::gpio::NoPin; use example_common::*; use cortex_m_rt::entry; use defmt::panic; use futures::pin_mut; -use nrf52840_hal as hal; -use nrf52840_hal::gpio; +use nrf52840_hal::clocks; use embassy::executor::{task, Executor}; use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; -use embassy::util::Forever; -use embassy_nrf::buffered_uarte; -use embassy_nrf::interrupt; - -static mut TX_BUFFER: [u8; 4096] = [0; 4096]; -static mut RX_BUFFER: [u8; 4096] = [0; 4096]; +use embassy::util::{Forever, Steal}; +use embassy_nrf::{buffered_uarte::BufferedUarte, interrupt, peripherals, rtc, uarte, Peripherals}; #[task] async fn run() { - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + let p = unsafe { Peripherals::steal() }; - let port0 = gpio::p0::Parts::new(p.P0); + let mut config = uarte::Config::default(); + config.parity = uarte::Parity::EXCLUDED; + config.baudrate = uarte::Baudrate::BAUD115200; - let pins = buffered_uarte::Pins { - rxd: port0.p0_08.into_floating_input().degrade(), - txd: port0 - .p0_06 - .into_push_pull_output(gpio::Level::Low) - .degrade(), - cts: None, - rts: None, - }; - - let ppi = hal::ppi::Parts::new(p.PPI); + let mut tx_buffer = [0u8; 4096]; + let mut rx_buffer = [0u8; 4096]; let irq = interrupt::take!(UARTE0_UART0); - let u = buffered_uarte::BufferedUarte::new( - p.UARTE0, - p.TIMER0, - ppi.ppi0, - ppi.ppi1, - irq, - unsafe { &mut RX_BUFFER }, - unsafe { &mut TX_BUFFER }, - pins, - buffered_uarte::Parity::EXCLUDED, - buffered_uarte::Baudrate::BAUD115200, - ); + let u = unsafe { + BufferedUarte::new( + p.UARTE0, + p.TIMER0, + p.PPI_CH0, + p.PPI_CH1, + irq, + p.P0_08, + p.P0_06, + NoPin, + NoPin, + config, + &mut rx_buffer, + &mut tx_buffer, + ) + }; pin_mut!(u); info!("uarte initialized!"); @@ -80,13 +75,30 @@ async fn run() { } } +static RTC: Forever> = Forever::new(); +static ALARM: Forever> = Forever::new(); static EXECUTOR: Forever = Forever::new(); #[entry] fn main() -> ! { info!("Hello World!"); + let p = unwrap!(embassy_nrf::Peripherals::take()); + + clocks::Clocks::new(unsafe { mem::transmute(()) }) + .enable_ext_hfosc() + .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) + .start_lfclk(); + + let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); + rtc.start(); + + unsafe { embassy::time::set_clock(rtc) }; + + let alarm = ALARM.put(rtc.alarm0()); let executor = EXECUTOR.put(Executor::new()); + executor.set_alarm(alarm); + executor.run(|spawner| { unwrap!(spawner.spawn(run())); }); diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index f26e892d..3ab2c60b 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -11,11 +11,11 @@ defmt-info = [ ] defmt-warn = [ ] defmt-error = [ ] -52810 = ["nrf52810-pac", "nrf52810-hal"] -52811 = ["nrf52811-pac"] #, "nrf52811-hal"] -52832 = ["nrf52832-pac", "nrf52832-hal"] -52833 = ["nrf52833-pac", "nrf52833-hal"] -52840 = ["nrf52840-pac", "nrf52840-hal"] +52810 = ["nrf52810-pac"] +52811 = ["nrf52811-pac"] +52832 = ["nrf52832-pac"] +52833 = ["nrf52833-pac"] +52840 = ["nrf52840-pac"] [dependencies] @@ -36,9 +36,3 @@ nrf52811-pac = { version = "0.9.1", optional = true } nrf52832-pac = { version = "0.9.0", optional = true } nrf52833-pac = { version = "0.9.0", optional = true } nrf52840-pac = { version = "0.9.0", optional = true } - -nrf52810-hal = { version = "0.12.1", optional = true } -#nrf52811-hal = { version = "0.12.1", optional = true } # doesn't exist yet -nrf52832-hal = { version = "0.12.1", optional = true } -nrf52833-hal = { version = "0.12.1", optional = true } -nrf52840-hal = { version = "0.12.1", optional = true } diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 6cc5f132..702ccde0 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -1,30 +1,24 @@ -//! HAL interface to the UARTE peripheral -//! -//! See product specification: -//! -//! - nrf52832: Section 35 -//! - nrf52840: Section 6.34 use core::cmp::min; use core::mem; -use core::ops::Deref; 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::util::WakerRegistration; -use embassy_extras::low_power_wait_until; +use embassy::util::{PeripheralBorrow, WakerRegistration}; use embassy_extras::peripheral::{PeripheralMutex, PeripheralState}; use embassy_extras::ring_buffer::RingBuffer; -use embedded_hal::digital::v2::OutputPin; +use embassy_extras::{low_power_wait_until, unborrow}; -use crate::fmt::*; -use crate::hal::ppi::ConfigurablePpi; -use crate::interrupt::{self, Interrupt}; +use crate::fmt::{panic, *}; +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::timer::Instance as TimerInstance; +use crate::uarte::{Config, Instance as UarteInstance}; // Re-export SVD variants to allow user to directly set values -pub use crate::hal::uarte::Pins; pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; #[derive(Copy, Clone, Debug, PartialEq)] @@ -39,17 +33,17 @@ enum TxState { Transmitting(usize), } -struct State<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> { +struct State<'d, U: UarteInstance, T: TimerInstance> { uarte: U, timer: T, - ppi_channel_1: P1, - ppi_channel_2: P2, + _ppi_ch1: Ppi<'d, AnyConfigurableChannel>, + _ppi_ch2: Ppi<'d, AnyConfigurableChannel>, - rx: RingBuffer<'a>, + rx: RingBuffer<'d>, rx_state: RxState, rx_waker: WakerRegistration, - tx: RingBuffer<'a>, + tx: RingBuffer<'d>, tx_state: TxState, tx_waker: WakerRegistration, } @@ -62,115 +56,112 @@ struct State<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: Configu /// are disabled before using `Uarte`. See product specification: /// - nrf52832: Section 15.2 /// - nrf52840: Section 6.1.2 -pub struct BufferedUarte< - 'a, - U: Instance, - T: TimerInstance, - P1: ConfigurablePpi, - P2: ConfigurablePpi, -> { - inner: PeripheralMutex>, +pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { + inner: PeripheralMutex>, } -impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> - BufferedUarte<'a, U, T, P1, P2> -{ - pub fn new( - uarte: U, - timer: T, - mut ppi_channel_1: P1, - mut ppi_channel_2: P2, - irq: U::Interrupt, - rx_buffer: &'a mut [u8], - tx_buffer: &'a mut [u8], - mut pins: Pins, - parity: Parity, - baudrate: Baudrate, +impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { + /// unsafe: may not leak self or futures + pub unsafe fn new( + uarte: impl PeripheralBorrow + 'd, + timer: impl PeripheralBorrow + 'd, + ppi_ch1: impl PeripheralBorrow + 'd, + ppi_ch2: impl PeripheralBorrow + 'd, + irq: impl PeripheralBorrow + 'd, + rxd: impl PeripheralBorrow + 'd, + txd: impl PeripheralBorrow + 'd, + cts: impl PeripheralBorrow + 'd, + rts: impl PeripheralBorrow + 'd, + config: Config, + rx_buffer: &'d mut [u8], + tx_buffer: &'d mut [u8], ) -> Self { - // Select pins - uarte.psel.rxd.write(|w| { - unsafe { w.bits(pins.rxd.psel_bits()) }; - w.connect().connected() - }); - pins.txd.set_high().unwrap(); - uarte.psel.txd.write(|w| { - unsafe { w.bits(pins.txd.psel_bits()) }; - w.connect().connected() - }); + unborrow!(uarte, timer, ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts); - // Optional pins - uarte.psel.cts.write(|w| { - if let Some(ref pin) = pins.cts { - unsafe { w.bits(pin.psel_bits()) }; - w.connect().connected() - } else { - w.connect().disconnected() - } - }); + let r = uarte.regs(); + let rt = timer.regs(); - uarte.psel.rts.write(|w| { - if let Some(ref pin) = pins.rts { - unsafe { w.bits(pin.psel_bits()) }; - w.connect().connected() - } else { - w.connect().disconnected() - } - }); + rxd.conf().write(|w| w.input().connect().drive().h0h1()); + r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); - // Enable UARTE instance - uarte.enable.write(|w| w.enable().enabled()); + txd.set_high(); + txd.conf().write(|w| w.dir().output().drive().h0h1()); + r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); - // Enable interrupts - uarte.intenset.write(|w| w.endrx().set().endtx().set()); + if let Some(pin) = rts.pin_mut() { + pin.set_high(); + pin.conf().write(|w| w.dir().output().drive().h0h1()); + } + r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); + + if let Some(pin) = cts.pin_mut() { + pin.conf().write(|w| w.input().connect().drive().h0h1()); + } + r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); + + r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); + r.config.write(|w| w.parity().variant(config.parity)); // Configure - let hardware_flow_control = pins.rts.is_some() && pins.cts.is_some(); - uarte - .config - .write(|w| w.hwfc().bit(hardware_flow_control).parity().variant(parity)); + let hardware_flow_control = match (rts.pin().is_some(), cts.pin().is_some()) { + (false, false) => false, + (true, true) => true, + _ => panic!("RTS and CTS pins must be either both set or none set."), + }; + r.config.write(|w| { + w.hwfc().bit(hardware_flow_control); + w.parity().variant(config.parity); + w + }); + r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); - // Configure frequency - uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); + // Enable interrupts + r.intenset.write(|w| w.endrx().set().endtx().set()); // Disable the irq, let the Registration enable it when everything is set up. irq.disable(); irq.pend(); + // Enable UARTE instance + r.enable.write(|w| w.enable().enabled()); + // BAUDRATE register values are `baudrate * 2^32 / 16000000` // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values // // We want to stop RX if line is idle for 2 bytes worth of time // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) // This gives us the amount of 16M ticks for 20 bits. - let timeout = 0x8000_0000 / (baudrate as u32 / 40); + let timeout = 0x8000_0000 / (config.baudrate as u32 / 40); - timer.tasks_stop.write(|w| unsafe { w.bits(1) }); - timer.bitmode.write(|w| w.bitmode()._32bit()); - timer.prescaler.write(|w| unsafe { w.prescaler().bits(0) }); - timer.cc[0].write(|w| unsafe { w.bits(timeout) }); - timer.mode.write(|w| w.mode().timer()); - timer.shorts.write(|w| { + rt.tasks_stop.write(|w| unsafe { w.bits(1) }); + rt.bitmode.write(|w| w.bitmode()._32bit()); + rt.prescaler.write(|w| unsafe { w.prescaler().bits(0) }); + rt.cc[0].write(|w| unsafe { w.bits(timeout) }); + rt.mode.write(|w| w.mode().timer()); + rt.shorts.write(|w| { w.compare0_clear().set_bit(); w.compare0_stop().set_bit(); w }); - ppi_channel_1.set_event_endpoint(&uarte.events_rxdrdy); - ppi_channel_1.set_task_endpoint(&timer.tasks_clear); - ppi_channel_1.set_fork_task_endpoint(&timer.tasks_start); - ppi_channel_1.enable(); + let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade_configurable()); + ppi_ch1.set_event(Event::from_reg(&r.events_rxdrdy)); + ppi_ch1.set_task(Task::from_reg(&rt.tasks_clear)); + ppi_ch1.set_fork_task(Task::from_reg(&rt.tasks_start)); + ppi_ch1.enable(); - ppi_channel_2.set_event_endpoint(&timer.events_compare[0]); - ppi_channel_2.set_task_endpoint(&uarte.tasks_stoprx); - ppi_channel_2.enable(); + let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade_configurable()); + ppi_ch2.set_event(Event::from_reg(&rt.events_compare[0])); + ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx)); + ppi_ch2.enable(); BufferedUarte { inner: PeripheralMutex::new( State { uarte, timer, - ppi_channel_1, - ppi_channel_2, + _ppi_ch1: ppi_ch1, + _ppi_ch2: ppi_ch2, rx: RingBuffer::new(rx_buffer), rx_state: RxState::Idle, @@ -187,25 +178,23 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi pub fn set_baudrate(self: Pin<&mut Self>, baudrate: Baudrate) { self.inner().with(|state, _irq| { - let timeout = 0x8000_0000 / (baudrate as u32 / 40); - state.timer.cc[0].write(|w| unsafe { w.bits(timeout) }); - state.timer.tasks_clear.write(|w| unsafe { w.bits(1) }); + let r = state.uarte.regs(); + let rt = state.timer.regs(); - state - .uarte - .baudrate - .write(|w| w.baudrate().variant(baudrate)); + let timeout = 0x8000_0000 / (baudrate as u32 / 40); + rt.cc[0].write(|w| unsafe { w.bits(timeout) }); + rt.tasks_clear.write(|w| unsafe { w.bits(1) }); + + r.baudrate.write(|w| w.baudrate().variant(baudrate)); }); } - fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex>> { + fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex>> { unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } } } -impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> AsyncBufRead - for BufferedUarte<'a, U, T, P1, P2> -{ +impl<'d, U: UarteInstance, T: TimerInstance> AsyncBufRead for BufferedUarte<'d, U, T> { fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let mut inner = self.inner(); inner.as_mut().register_interrupt(); @@ -242,9 +231,7 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi } } -impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> AsyncWrite - for BufferedUarte<'a, U, T, P1, P2> -{ +impl<'d, U: UarteInstance, T: TimerInstance> AsyncWrite for BufferedUarte<'d, U, T> { fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { let mut inner = self.inner(); inner.as_mut().register_interrupt(); @@ -276,32 +263,36 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi } } -impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> Drop - for State<'a, U, T, P1, P2> -{ +impl<'a, U: UarteInstance, T: TimerInstance> Drop for State<'a, U, T> { fn drop(&mut self) { - self.timer.tasks_stop.write(|w| unsafe { w.bits(1) }); + let r = self.uarte.regs(); + let rt = self.timer.regs(); + + // TODO this probably deadlocks. do like Uarte instead. + + rt.tasks_stop.write(|w| unsafe { w.bits(1) }); if let RxState::Receiving = self.rx_state { - self.uarte.tasks_stoprx.write(|w| unsafe { w.bits(1) }); + r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); } if let TxState::Transmitting(_) = self.tx_state { - self.uarte.tasks_stoptx.write(|w| unsafe { w.bits(1) }); + r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); } if let RxState::Receiving = self.rx_state { - low_power_wait_until(|| self.uarte.events_endrx.read().bits() == 1); + low_power_wait_until(|| r.events_endrx.read().bits() == 1); } if let TxState::Transmitting(_) = self.tx_state { - low_power_wait_until(|| self.uarte.events_endtx.read().bits() == 1); + low_power_wait_until(|| r.events_endtx.read().bits() == 1); } } } -impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> PeripheralState - for State<'a, U, T, P1, P2> -{ +impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for State<'a, U, T> { type Interrupt = U::Interrupt; fn on_interrupt(&mut self) { trace!("irq: start"); + let r = self.uarte.regs(); + let rt = self.timer.regs(); + loop { match self.rx_state { RxState::Idle => { @@ -313,11 +304,11 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi self.rx_state = RxState::Receiving; // Set up the DMA read - self.uarte.rxd.ptr.write(|w| + r.rxd.ptr.write(|w| // The PTR field is a full 32 bits wide and accepts the full range // of values. unsafe { w.ptr().bits(buf.as_ptr() as u32) }); - self.uarte.rxd.maxcnt.write(|w| + r.rxd.maxcnt.write(|w| // We're giving it the length of the buffer, so no danger of // accessing invalid memory. We have verified that the length of the // buffer fits in an `u8`, so the cast to `u8` is also fine. @@ -328,7 +319,7 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len()); // Start UARTE Receive transaction - self.uarte.tasks_startrx.write(|w| + r.tasks_startrx.write(|w| // `1` is a valid value to write to task registers. unsafe { w.bits(1) }); } @@ -336,14 +327,14 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi } RxState::Receiving => { trace!(" irq_rx: in state receiving"); - if self.uarte.events_endrx.read().bits() != 0 { - self.timer.tasks_stop.write(|w| unsafe { w.bits(1) }); + if r.events_endrx.read().bits() != 0 { + rt.tasks_stop.write(|w| unsafe { w.bits(1) }); - let n: usize = self.uarte.rxd.amount.read().amount().bits() as usize; + let n: usize = r.rxd.amount.read().amount().bits() as usize; trace!(" irq_rx: endrx {:?}", n); self.rx.push(n); - self.uarte.events_endrx.reset(); + r.events_endrx.reset(); self.rx_waker.wake(); self.rx_state = RxState::Idle; @@ -364,11 +355,11 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi self.tx_state = TxState::Transmitting(buf.len()); // Set up the DMA write - self.uarte.txd.ptr.write(|w| + r.txd.ptr.write(|w| // The PTR field is a full 32 bits wide and accepts the full range // of values. unsafe { w.ptr().bits(buf.as_ptr() as u32) }); - self.uarte.txd.maxcnt.write(|w| + r.txd.maxcnt.write(|w| // We're giving it the length of the buffer, so no danger of // accessing invalid memory. We have verified that the length of the // buffer fits in an `u8`, so the cast to `u8` is also fine. @@ -378,7 +369,7 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi unsafe { w.maxcnt().bits(buf.len() as _) }); // Start UARTE Transmit transaction - self.uarte.tasks_starttx.write(|w| + r.tasks_starttx.write(|w| // `1` is a valid value to write to task registers. unsafe { w.bits(1) }); } @@ -386,8 +377,8 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi } TxState::Transmitting(n) => { trace!(" irq_tx: in state Transmitting"); - if self.uarte.events_endtx.read().bits() != 0 { - self.uarte.events_endtx.reset(); + if r.events_endtx.read().bits() != 0 { + r.events_endtx.reset(); trace!(" irq_tx: endtx {:?}", n); self.tx.pop(n); @@ -402,37 +393,3 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi trace!("irq: end"); } } - -mod sealed { - pub trait Instance {} - - impl Instance for crate::pac::UARTE0 {} - #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] - impl Instance for crate::pac::UARTE1 {} - - pub trait TimerInstance {} - impl TimerInstance for crate::pac::TIMER0 {} - impl TimerInstance for crate::pac::TIMER1 {} - impl TimerInstance for crate::pac::TIMER2 {} -} - -pub trait Instance: Deref + sealed::Instance { - type Interrupt: Interrupt; -} - -impl Instance for pac::UARTE0 { - type Interrupt = interrupt::UARTE0_UART0; -} - -#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] -impl Instance for pac::UARTE1 { - type Interrupt = interrupt::UARTE1; -} - -pub trait TimerInstance: - Deref + sealed::TimerInstance -{ -} -impl TimerInstance for crate::pac::TIMER0 {} -impl TimerInstance for crate::pac::TIMER1 {} -impl TimerInstance for crate::pac::TIMER2 {} diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 67ff9dc3..042050d2 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -40,17 +40,6 @@ pub use nrf52833_pac as pac; #[cfg(feature = "52840")] pub use nrf52840_pac as pac; -#[cfg(feature = "52810")] -pub use nrf52810_hal as hal; -#[cfg(feature = "52811")] -pub use nrf52811_hal as hal; -#[cfg(feature = "52832")] -pub use nrf52832_hal as hal; -#[cfg(feature = "52833")] -pub use nrf52833_hal as hal; -#[cfg(feature = "52840")] -pub use nrf52840_hal as hal; - /// Length of Nordic EasyDMA differs for MCUs #[cfg(any( feature = "52810", From 48cf1f6ebf0906de1b043b7e6213a0f6ec70b207 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 29 Mar 2021 00:42:08 +0200 Subject: [PATCH 42/45] nrf/system: add configure --- embassy-nrf-examples/Cargo.toml | 1 - embassy-nrf-examples/src/bin/buffered_uart.rs | 17 +---- .../src/bin/executor_fairness_test.rs | 9 +-- embassy-nrf-examples/src/bin/multiprio.rs | 10 +-- embassy-nrf-examples/src/bin/ppi.rs | 1 - embassy-nrf-examples/src/bin/raw_spawn.rs | 13 +--- embassy-nrf-examples/src/bin/spim.rs | 10 +-- embassy-nrf-examples/src/bin/timer.rs | 13 +--- embassy-nrf-examples/src/bin/uart.rs | 12 +-- embassy-nrf-examples/src/example_common.rs | 1 - embassy-nrf/Cargo.toml | 10 +-- embassy-nrf/src/lib.rs | 1 + embassy-nrf/src/system.rs | 76 +++++++++++++++++++ 13 files changed, 97 insertions(+), 77 deletions(-) create mode 100644 embassy-nrf/src/system.rs diff --git a/embassy-nrf-examples/Cargo.toml b/embassy-nrf-examples/Cargo.toml index 432e8950..2a5b52dd 100644 --- a/embassy-nrf-examples/Cargo.toml +++ b/embassy-nrf-examples/Cargo.toml @@ -28,5 +28,4 @@ cortex-m = { version = "0.7.1", features = ["inline-asm"] } cortex-m-rt = "0.6.13" embedded-hal = { version = "0.2.4" } panic-probe = "0.1.0" -nrf52840-hal = { version = "0.12.1" } futures = { version = "0.3.8", default-features = false, features = ["async-await"] } \ No newline at end of file diff --git a/embassy-nrf-examples/src/bin/buffered_uart.rs b/embassy-nrf-examples/src/bin/buffered_uart.rs index 80b24d2b..c7c82e84 100644 --- a/embassy-nrf-examples/src/bin/buffered_uart.rs +++ b/embassy-nrf-examples/src/bin/buffered_uart.rs @@ -7,20 +7,16 @@ #[path = "../example_common.rs"] mod example_common; -use core::mem; - -use embassy_nrf::gpio::NoPin; -use example_common::*; use cortex_m_rt::entry; use defmt::panic; -use futures::pin_mut; -use nrf52840_hal::clocks; - use embassy::executor::{task, Executor}; use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; use embassy::util::{Forever, Steal}; +use embassy_nrf::gpio::NoPin; use embassy_nrf::{buffered_uarte::BufferedUarte, interrupt, peripherals, rtc, uarte, Peripherals}; +use example_common::*; +use futures::pin_mut; #[task] async fn run() { @@ -85,14 +81,9 @@ fn main() -> ! { let p = unwrap!(embassy_nrf::Peripherals::take()); - clocks::Clocks::new(unsafe { mem::transmute(()) }) - .enable_ext_hfosc() - .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) - .start_lfclk(); - + unsafe { embassy_nrf::system::configure(Default::default()) }; let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); rtc.start(); - unsafe { embassy::time::set_clock(rtc) }; let alarm = ALARM.put(rtc.alarm0()); diff --git a/embassy-nrf-examples/src/bin/executor_fairness_test.rs b/embassy-nrf-examples/src/bin/executor_fairness_test.rs index cfcfd949..67610ef0 100644 --- a/embassy-nrf-examples/src/bin/executor_fairness_test.rs +++ b/embassy-nrf-examples/src/bin/executor_fairness_test.rs @@ -9,7 +9,6 @@ mod example_common; use example_common::*; -use core::mem; use core::task::Poll; use cortex_m_rt::entry; use defmt::panic; @@ -18,7 +17,6 @@ use embassy::time::{Duration, Instant, Timer}; use embassy::util::Forever; use embassy_nrf::peripherals; use embassy_nrf::{interrupt, rtc}; -use nrf52840_hal::clocks; #[task] async fn run1() { @@ -54,14 +52,9 @@ fn main() -> ! { let p = unwrap!(embassy_nrf::Peripherals::take()); - clocks::Clocks::new(unsafe { mem::transmute(()) }) - .enable_ext_hfosc() - .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) - .start_lfclk(); - + unsafe { embassy_nrf::system::configure(Default::default()) }; let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); rtc.start(); - unsafe { embassy::time::set_clock(rtc) }; let alarm = ALARM.put(rtc.alarm0()); diff --git a/embassy-nrf-examples/src/bin/multiprio.rs b/embassy-nrf-examples/src/bin/multiprio.rs index 017de3c0..aa2824f6 100644 --- a/embassy-nrf-examples/src/bin/multiprio.rs +++ b/embassy-nrf-examples/src/bin/multiprio.rs @@ -62,14 +62,10 @@ #[path = "../example_common.rs"] mod example_common; -use core::mem; - use example_common::*; use cortex_m_rt::entry; use defmt::panic; -use nrf52840_hal::clocks; - use embassy::executor::{task, Executor, InterruptExecutor}; use embassy::interrupt::InterruptExt; use embassy::time::{Duration, Instant, Timer}; @@ -132,11 +128,7 @@ fn main() -> ! { let p = unwrap!(embassy_nrf::Peripherals::take()); - clocks::Clocks::new(unsafe { mem::transmute(()) }) - .enable_ext_hfosc() - .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) - .start_lfclk(); - + unsafe { embassy_nrf::system::configure(Default::default()) }; let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); rtc.start(); unsafe { embassy::time::set_clock(rtc) }; diff --git a/embassy-nrf-examples/src/bin/ppi.rs b/embassy-nrf-examples/src/bin/ppi.rs index 87854fa5..382c18f8 100644 --- a/embassy-nrf-examples/src/bin/ppi.rs +++ b/embassy-nrf-examples/src/bin/ppi.rs @@ -20,7 +20,6 @@ use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; use embassy_nrf::ppi::Ppi; use embassy_nrf::{interrupt, Peripherals}; -use futures::future; use gpiote::{OutputChannel, OutputChannelPolarity}; #[task] diff --git a/embassy-nrf-examples/src/bin/raw_spawn.rs b/embassy-nrf-examples/src/bin/raw_spawn.rs index 1dd60403..f8e021d9 100644 --- a/embassy-nrf-examples/src/bin/raw_spawn.rs +++ b/embassy-nrf-examples/src/bin/raw_spawn.rs @@ -3,19 +3,17 @@ #[path = "../example_common.rs"] mod example_common; -use core::mem; - -use embassy::executor::raw::Task; use example_common::*; +use core::mem; use cortex_m_rt::entry; use defmt::panic; +use embassy::executor::raw::Task; use embassy::executor::Executor; use embassy::time::{Duration, Timer}; use embassy::util::Forever; use embassy_nrf::peripherals; use embassy_nrf::{interrupt, rtc}; -use nrf52840_hal::clocks; async fn run1() { loop { @@ -41,14 +39,9 @@ fn main() -> ! { let p = unwrap!(embassy_nrf::Peripherals::take()); - clocks::Clocks::new(unsafe { mem::transmute(()) }) - .enable_ext_hfosc() - .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) - .start_lfclk(); - + unsafe { embassy_nrf::system::configure(Default::default()) }; let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); rtc.start(); - unsafe { embassy::time::set_clock(rtc) }; let alarm = ALARM.put(rtc.alarm0()); diff --git a/embassy-nrf-examples/src/bin/spim.rs b/embassy-nrf-examples/src/bin/spim.rs index 77058bf2..5e2340ff 100644 --- a/embassy-nrf-examples/src/bin/spim.rs +++ b/embassy-nrf-examples/src/bin/spim.rs @@ -8,8 +8,6 @@ #[path = "../example_common.rs"] mod example_common; -use core::mem; - use cortex_m_rt::entry; use defmt::panic; use embassy::executor::{task, Executor}; @@ -22,7 +20,6 @@ use embassy_traits::spi::FullDuplex; use embedded_hal::digital::v2::*; use example_common::*; use futures::pin_mut; -use nrf52840_hal::clocks; #[task] async fn run() { @@ -98,13 +95,10 @@ fn main() -> ! { let p = unwrap!(embassy_nrf::Peripherals::take()); - clocks::Clocks::new(unsafe { mem::transmute(()) }) - .enable_ext_hfosc() - .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) - .start_lfclk(); - + unsafe { embassy_nrf::system::configure(Default::default()) }; let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); rtc.start(); + unsafe { embassy::time::set_clock(rtc) }; unsafe { embassy::time::set_clock(rtc) }; diff --git a/embassy-nrf-examples/src/bin/timer.rs b/embassy-nrf-examples/src/bin/timer.rs index 41e5d77a..47d5d677 100644 --- a/embassy-nrf-examples/src/bin/timer.rs +++ b/embassy-nrf-examples/src/bin/timer.rs @@ -7,8 +7,6 @@ #[path = "../example_common.rs"] mod example_common; -use core::mem; - use example_common::*; use cortex_m_rt::entry; @@ -16,9 +14,7 @@ use defmt::panic; use embassy::executor::{task, Executor}; use embassy::time::{Duration, Timer}; use embassy::util::Forever; -use embassy_nrf::peripherals; -use embassy_nrf::{interrupt, rtc}; -use nrf52840_hal::clocks; +use embassy_nrf::{interrupt, peripherals, rtc}; #[task] async fn run1() { @@ -44,16 +40,11 @@ static EXECUTOR: Forever = Forever::new(); fn main() -> ! { info!("Hello World!"); - clocks::Clocks::new(unsafe { mem::transmute(()) }) - .enable_ext_hfosc() - .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) - .start_lfclk(); - let p = unwrap!(embassy_nrf::Peripherals::take()); + unsafe { embassy_nrf::system::configure(Default::default()) }; let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); rtc.start(); - unsafe { embassy::time::set_clock(rtc) }; let alarm = ALARM.put(rtc.alarm0()); diff --git a/embassy-nrf-examples/src/bin/uart.rs b/embassy-nrf-examples/src/bin/uart.rs index d8644167..9bbcb3d4 100644 --- a/embassy-nrf-examples/src/bin/uart.rs +++ b/embassy-nrf-examples/src/bin/uart.rs @@ -7,9 +7,6 @@ #[path = "../example_common.rs"] mod example_common; -use core::mem; - -use embassy_nrf::gpio::NoPin; use example_common::*; use cortex_m_rt::entry; @@ -17,9 +14,9 @@ use defmt::panic; use embassy::executor::{task, Executor}; use embassy::traits::uart::{Read, Write}; use embassy::util::{Forever, Steal}; +use embassy_nrf::gpio::NoPin; use embassy_nrf::{interrupt, peripherals, rtc, uarte, Peripherals}; use futures::pin_mut; -use nrf52840_hal::clocks; #[task] async fn run() { @@ -88,14 +85,9 @@ fn main() -> ! { let p = unwrap!(embassy_nrf::Peripherals::take()); - clocks::Clocks::new(unsafe { mem::transmute(()) }) - .enable_ext_hfosc() - .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) - .start_lfclk(); - + unsafe { embassy_nrf::system::configure(Default::default()) }; let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); rtc.start(); - unsafe { embassy::time::set_clock(rtc) }; let alarm = ALARM.put(rtc.alarm0()); diff --git a/embassy-nrf-examples/src/example_common.rs b/embassy-nrf-examples/src/example_common.rs index d16964d4..54d63383 100644 --- a/embassy-nrf-examples/src/example_common.rs +++ b/embassy-nrf-examples/src/example_common.rs @@ -1,7 +1,6 @@ #![macro_use] use defmt_rtt as _; // global logger -use nrf52840_hal as _; use panic_probe as _; pub use defmt::*; diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 3ab2c60b..8ec5b087 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -31,8 +31,8 @@ embedded-hal = { version = "0.2.4" } embedded-dma = { version = "0.1.2" } futures = { version = "0.3.5", default-features = false } -nrf52810-pac = { version = "0.9.0", optional = true } -nrf52811-pac = { version = "0.9.1", optional = true } -nrf52832-pac = { version = "0.9.0", optional = true } -nrf52833-pac = { version = "0.9.0", optional = true } -nrf52840-pac = { version = "0.9.0", optional = true } +nrf52810-pac = { version = "0.9.0", optional = true, features = [ "rt" ]} +nrf52811-pac = { version = "0.9.1", optional = true, features = [ "rt" ]} +nrf52832-pac = { version = "0.9.0", optional = true, features = [ "rt" ]} +nrf52833-pac = { version = "0.9.0", optional = true, features = [ "rt" ]} +nrf52840-pac = { version = "0.9.0", optional = true, features = [ "rt" ]} diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 042050d2..33d764fb 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -92,6 +92,7 @@ pub mod qspi; pub mod rtc; pub mod saadc; pub mod spim; +pub mod system; pub mod timer; pub mod uarte; diff --git a/embassy-nrf/src/system.rs b/embassy-nrf/src/system.rs new file mode 100644 index 00000000..5d36e66f --- /dev/null +++ b/embassy-nrf/src/system.rs @@ -0,0 +1,76 @@ +use crate::pac; + +pub enum HfclkSource { + Internal, + ExternalXtal, +} + +pub enum LfclkSource { + InternalRC, + Synthesized, + ExternalXtal, + ExternalLowSwing, + ExternalFullSwing, +} + +#[non_exhaustive] +pub struct Config { + pub hfclk_source: HfclkSource, + pub lfclk_source: LfclkSource, +} + +impl Default for Config { + fn default() -> Self { + Self { + // There are hobby nrf52 boards out there without external XTALs... + // Default everything to internal so it Just Works. User can enable external + // xtals if they know they have them. + hfclk_source: HfclkSource::Internal, + lfclk_source: LfclkSource::InternalRC, + } + } +} + +/// safety: must only call once. +pub unsafe fn configure(config: Config) { + let r = &*pac::CLOCK::ptr(); + + // Start HFCLK. + match config.hfclk_source { + HfclkSource::Internal => {} + HfclkSource::ExternalXtal => { + // Datasheet says this is likely to take 0.36ms + r.events_hfclkstarted.write(|w| unsafe { w.bits(0) }); + r.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); + while r.events_hfclkstarted.read().bits() == 0 {} + } + } + + // Configure LFCLK. + match config.lfclk_source { + LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()), + LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()), + + LfclkSource::ExternalXtal => r.lfclksrc.write(move |w| w.src().xtal()), + + LfclkSource::ExternalLowSwing => r.lfclksrc.write(move |w| { + w.src().xtal(); + w.external().enabled(); + w.bypass().disabled(); + w + }), + LfclkSource::ExternalFullSwing => r.lfclksrc.write(move |w| { + w.src().xtal(); + w.external().enabled(); + w.bypass().enabled(); + w + }), + } + + // Start LFCLK. + // Datasheet says this could take 100us from synth source + // 600us from rc source, 0.25s from an external source. + r.events_lfclkstarted.write(|w| unsafe { w.bits(0) }); + r.tasks_lfclkstart.write(|w| unsafe { w.bits(1) }); + while r.events_lfclkstarted.read().bits() == 0 {} +} From b9e709403d8073861ae9f5010ddf2cfa6d90f41e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 29 Mar 2021 00:44:11 +0200 Subject: [PATCH 43/45] nrf: better macro naming. --- embassy-nrf/src/gpio.rs | 98 ++++++++++++++++++++-------------------- embassy-nrf/src/qspi.rs | 4 +- embassy-nrf/src/rtc.rs | 8 ++-- embassy-nrf/src/spim.rs | 12 ++--- embassy-nrf/src/timer.rs | 14 +++--- embassy-nrf/src/uarte.rs | 6 +-- 6 files changed, 71 insertions(+), 71 deletions(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index a6d2fc07..dcfaa47c 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -380,7 +380,7 @@ impl OptionalPin for NoPin { // ==================== -macro_rules! make_impl { +macro_rules! impl_pin { ($type:ident, $port_num:expr, $pin_num:expr) => { impl Pin for peripherals::$type {} impl sealed::Pin for peripherals::$type { @@ -392,56 +392,56 @@ macro_rules! make_impl { }; } -make_impl!(P0_00, 0, 0); -make_impl!(P0_01, 0, 1); -make_impl!(P0_02, 0, 2); -make_impl!(P0_03, 0, 3); -make_impl!(P0_04, 0, 4); -make_impl!(P0_05, 0, 5); -make_impl!(P0_06, 0, 6); -make_impl!(P0_07, 0, 7); -make_impl!(P0_08, 0, 8); -make_impl!(P0_09, 0, 9); -make_impl!(P0_10, 0, 10); -make_impl!(P0_11, 0, 11); -make_impl!(P0_12, 0, 12); -make_impl!(P0_13, 0, 13); -make_impl!(P0_14, 0, 14); -make_impl!(P0_15, 0, 15); -make_impl!(P0_16, 0, 16); -make_impl!(P0_17, 0, 17); -make_impl!(P0_18, 0, 18); -make_impl!(P0_19, 0, 19); -make_impl!(P0_20, 0, 20); -make_impl!(P0_21, 0, 21); -make_impl!(P0_22, 0, 22); -make_impl!(P0_23, 0, 23); -make_impl!(P0_24, 0, 24); -make_impl!(P0_25, 0, 25); -make_impl!(P0_26, 0, 26); -make_impl!(P0_27, 0, 27); -make_impl!(P0_28, 0, 28); -make_impl!(P0_29, 0, 29); -make_impl!(P0_30, 0, 30); -make_impl!(P0_31, 0, 31); +impl_pin!(P0_00, 0, 0); +impl_pin!(P0_01, 0, 1); +impl_pin!(P0_02, 0, 2); +impl_pin!(P0_03, 0, 3); +impl_pin!(P0_04, 0, 4); +impl_pin!(P0_05, 0, 5); +impl_pin!(P0_06, 0, 6); +impl_pin!(P0_07, 0, 7); +impl_pin!(P0_08, 0, 8); +impl_pin!(P0_09, 0, 9); +impl_pin!(P0_10, 0, 10); +impl_pin!(P0_11, 0, 11); +impl_pin!(P0_12, 0, 12); +impl_pin!(P0_13, 0, 13); +impl_pin!(P0_14, 0, 14); +impl_pin!(P0_15, 0, 15); +impl_pin!(P0_16, 0, 16); +impl_pin!(P0_17, 0, 17); +impl_pin!(P0_18, 0, 18); +impl_pin!(P0_19, 0, 19); +impl_pin!(P0_20, 0, 20); +impl_pin!(P0_21, 0, 21); +impl_pin!(P0_22, 0, 22); +impl_pin!(P0_23, 0, 23); +impl_pin!(P0_24, 0, 24); +impl_pin!(P0_25, 0, 25); +impl_pin!(P0_26, 0, 26); +impl_pin!(P0_27, 0, 27); +impl_pin!(P0_28, 0, 28); +impl_pin!(P0_29, 0, 29); +impl_pin!(P0_30, 0, 30); +impl_pin!(P0_31, 0, 31); #[cfg(any(feature = "52833", feature = "52840"))] mod _p1 { use super::*; - make_impl!(P1_00, 1, 0); - make_impl!(P1_01, 1, 1); - make_impl!(P1_02, 1, 2); - make_impl!(P1_03, 1, 3); - make_impl!(P1_04, 1, 4); - make_impl!(P1_05, 1, 5); - make_impl!(P1_06, 1, 6); - make_impl!(P1_07, 1, 7); - make_impl!(P1_08, 1, 8); - make_impl!(P1_09, 1, 9); - make_impl!(P1_10, 1, 10); - make_impl!(P1_11, 1, 11); - make_impl!(P1_12, 1, 12); - make_impl!(P1_13, 1, 13); - make_impl!(P1_14, 1, 14); - make_impl!(P1_15, 1, 15); + impl_pin!(P1_00, 1, 0); + impl_pin!(P1_01, 1, 1); + impl_pin!(P1_02, 1, 2); + impl_pin!(P1_03, 1, 3); + impl_pin!(P1_04, 1, 4); + impl_pin!(P1_05, 1, 5); + impl_pin!(P1_06, 1, 6); + impl_pin!(P1_07, 1, 7); + impl_pin!(P1_08, 1, 8); + impl_pin!(P1_09, 1, 9); + impl_pin!(P1_10, 1, 10); + impl_pin!(P1_11, 1, 11); + impl_pin!(P1_12, 1, 12); + impl_pin!(P1_13, 1, 13); + impl_pin!(P1_14, 1, 14); + impl_pin!(P1_15, 1, 15); } diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 10564ba5..e05186ab 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -363,7 +363,7 @@ pub trait Instance: sealed::Instance + 'static { type Interrupt: Interrupt; } -macro_rules! make_impl { +macro_rules! impl_instance { ($type:ident, $irq:ident) => { impl sealed::Instance for peripherals::$type { fn regs(&self) -> &pac::qspi::RegisterBlock { @@ -376,4 +376,4 @@ macro_rules! make_impl { }; } -make_impl!(QSPI, QSPI); +impl_instance!(QSPI, QSPI); diff --git a/embassy-nrf/src/rtc.rs b/embassy-nrf/src/rtc.rs index 7d29d72b..cbb5a87e 100644 --- a/embassy-nrf/src/rtc.rs +++ b/embassy-nrf/src/rtc.rs @@ -268,7 +268,7 @@ mod sealed { } } -macro_rules! make_impl { +macro_rules! impl_instance { ($type:ident, $irq:ident) => { impl sealed::Instance for peripherals::$type { fn regs(&self) -> &pac::rtc0::RegisterBlock { @@ -287,7 +287,7 @@ pub trait Instance: sealed::Instance + 'static { type Interrupt: Interrupt; } -make_impl!(RTC0, RTC0); -make_impl!(RTC1, RTC1); +impl_instance!(RTC0, RTC0); +impl_instance!(RTC1, RTC1); #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] -make_impl!(RTC2, RTC2); +impl_instance!(RTC2, RTC2); diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 5d55a3cc..93ca52c6 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -224,7 +224,7 @@ pub trait Instance: sealed::Instance + 'static { type Interrupt: Interrupt; } -macro_rules! make_impl { +macro_rules! impl_instance { ($type:ident, $irq:ident) => { impl sealed::Instance for peripherals::$type { fn regs(&self) -> &pac::spim0::RegisterBlock { @@ -238,15 +238,15 @@ macro_rules! make_impl { } #[cfg(feature = "52810")] -make_impl!(SPIM0, SPIM0_SPIS0_SPI0); +impl_instance!(SPIM0, SPIM0_SPIS0_SPI0); #[cfg(not(feature = "52810"))] -make_impl!(SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); +impl_instance!(SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] -make_impl!(SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_instance!(SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] -make_impl!(SPIM2, SPIM2_SPIS2_SPI2); +impl_instance!(SPIM2, SPIM2_SPIS2_SPI2); #[cfg(any(feature = "52833", feature = "52840"))] -make_impl!(SPIM3, SPIM3); +impl_instance!(SPIM3, SPIM3); diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 6307a15e..d74e3cfa 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -16,7 +16,7 @@ pub trait Instance: sealed::Instance + 'static { } pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} -macro_rules! make_impl { +macro_rules! impl_instance { ($type:ident, $irq:ident) => { impl sealed::Instance for peripherals::$type { fn regs(&self) -> &pac::timer0::RegisterBlock { @@ -28,16 +28,16 @@ macro_rules! make_impl { } }; ($type:ident, $irq:ident, extended) => { - make_impl!($type, $irq); + impl_instance!($type, $irq); impl sealed::ExtendedInstance for peripherals::$type {} impl ExtendedInstance for peripherals::$type {} }; } -make_impl!(TIMER0, TIMER0); -make_impl!(TIMER1, TIMER1); -make_impl!(TIMER2, TIMER2); +impl_instance!(TIMER0, TIMER0); +impl_instance!(TIMER1, TIMER1); +impl_instance!(TIMER2, TIMER2); #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] -make_impl!(TIMER3, TIMER3, extended); +impl_instance!(TIMER3, TIMER3, extended); #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] -make_impl!(TIMER4, TIMER4, extended); +impl_instance!(TIMER4, TIMER4, extended); diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 5effe046..957fa4c7 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -315,7 +315,7 @@ pub trait Instance: sealed::Instance + 'static { type Interrupt: Interrupt; } -macro_rules! make_impl { +macro_rules! impl_instance { ($type:ident, $irq:ident) => { impl sealed::Instance for peripherals::$type { fn regs(&self) -> &pac::uarte0::RegisterBlock { @@ -328,6 +328,6 @@ macro_rules! make_impl { }; } -make_impl!(UARTE0, UARTE0_UART0); +impl_instance!(UARTE0, UARTE0_UART0); #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] -make_impl!(UARTE1, UARTE1); +impl_instance!(UARTE1, UARTE1); From 5b74e326e5da8214eec9360e67f42ff2ca3905e8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 29 Mar 2021 00:55:05 +0200 Subject: [PATCH 44/45] nrf/qpsi: make config non_exhaustive --- embassy-nrf-examples/src/bin/qspi.rs | 9 +-------- embassy-nrf/src/qspi.rs | 13 +++++++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/embassy-nrf-examples/src/bin/qspi.rs b/embassy-nrf-examples/src/bin/qspi.rs index 4e24a13d..2005b997 100644 --- a/embassy-nrf-examples/src/bin/qspi.rs +++ b/embassy-nrf-examples/src/bin/qspi.rs @@ -36,14 +36,7 @@ async fn run() { let io2 = p.P0_22; let io3 = p.P0_23; - let config = qspi::Config { - read_opcode: qspi::ReadOpcode::READ4IO, - write_opcode: qspi::WriteOpcode::PP4IO, - xip_offset: 0, - write_page_size: qspi::WritePageSize::_256BYTES, - deep_power_down: None, - }; - + let config = qspi::Config::default(); let irq = interrupt::take!(QSPI); let q = qspi::Qspi::new(p.QSPI, irq, sck, csn, io0, io1, io2, io3, config); pin_mut!(q); diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index e05186ab..033c9e01 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -36,6 +36,7 @@ pub struct DeepPowerDownConfig { pub exit_time: u16, } +#[non_exhaustive] pub struct Config { pub xip_offset: u32, pub read_opcode: ReadOpcode, @@ -44,6 +45,18 @@ pub struct Config { pub deep_power_down: Option, } +impl Default for Config { + fn default() -> Self { + Self { + read_opcode: ReadOpcode::READ4IO, + write_opcode: WriteOpcode::PP4IO, + xip_offset: 0, + write_page_size: WritePageSize::_256BYTES, + deep_power_down: None, + } + } +} + pub struct Qspi<'d, T: Instance> { peri: T, irq: T::Interrupt, From 3a0ddb8104694717cb573aa508acb4a8bbba3ff7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 29 Mar 2021 01:14:18 +0200 Subject: [PATCH 45/45] stm32/serial: update to new traits. --- embassy-stm32f4-examples/src/bin/serial.rs | 7 +- embassy-stm32f4/src/serial.rs | 149 +++++++++++---------- 2 files changed, 84 insertions(+), 72 deletions(-) diff --git a/embassy-stm32f4-examples/src/bin/serial.rs b/embassy-stm32f4-examples/src/bin/serial.rs index 49a588c2..c8e7f288 100644 --- a/embassy-stm32f4-examples/src/bin/serial.rs +++ b/embassy-stm32f4-examples/src/bin/serial.rs @@ -12,10 +12,11 @@ use example_common::{panic, *}; use cortex_m::singleton; use cortex_m_rt::entry; use embassy::executor::{task, Executor}; -use embassy::traits::uart::Uart; +use embassy::traits::uart::{Read, Write}; use embassy::util::Forever; use embassy_stm32f4::interrupt; use embassy_stm32f4::serial; +use futures::pin_mut; use stm32f4xx_hal::dma::StreamsTuple; use stm32f4xx_hal::prelude::*; use stm32f4xx_hal::serial::config::Config; @@ -76,10 +77,12 @@ async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) { clocks, ) }; + pin_mut!(serial); + let buf = singleton!(: [u8; 30] = [0; 30]).unwrap(); buf[5] = 0x01; - serial.send(buf).await.unwrap(); + serial.write(buf).await.unwrap(); } static EXECUTOR: Forever = Forever::new(); diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index c8dc0598..7539abf5 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -1,17 +1,12 @@ -//! Async low power Serial. -//! -//! The peripheral is autmatically enabled and disabled as required to save power. -//! Lowest power consumption can only be guaranteed if the send receive futures -//! are dropped correctly (e.g. not using `mem::forget()`). +//! Async Serial. use core::future::Future; use core::marker::PhantomData; - -use futures::{select_biased, FutureExt}; - +use core::pin::Pin; use embassy::interrupt::Interrupt; -use embassy::traits::uart::{Error, IdleUart, Uart}; +use embassy::traits::uart::{Error, Read, ReadUntilIdle, Write}; use embassy::util::InterruptFuture; +use futures::{select_biased, FutureExt}; use crate::hal::{ dma, @@ -89,7 +84,7 @@ where } } -impl Uart for Serial +impl Read for Serial where USART: serial::Instance + PeriAddress @@ -101,56 +96,19 @@ where RSTREAM: Stream + WithInterrupt + 'static, CHANNEL: Channel + 'static, { - type SendFuture<'a> = impl Future> + 'a; - type ReceiveFuture<'a> = impl Future> + 'a; - - /// Sends serial data. - fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a> { - #[allow(mutable_transmutes)] - let static_buf = unsafe { core::mem::transmute::<&'a [u8], &'static mut [u8]>(buf) }; - - let tx_stream = self.tx_stream.take().unwrap(); - let usart = self.usart.take().unwrap(); - - async move { - let mut tx_transfer = Transfer::init( - tx_stream, - usart, - static_buf, - None, - DmaConfig::default() - .transfer_complete_interrupt(true) - .memory_increment(true) - .double_buffer(false), - ); - - let fut = InterruptFuture::new(&mut self.tx_int); - - tx_transfer.start(|_usart| {}); - fut.await; - - let (tx_stream, usart, _buf, _) = tx_transfer.free(); - - self.tx_stream.replace(tx_stream); - self.usart.replace(usart); - - Ok(()) - } - } + type ReadFuture<'a> = impl Future> + 'a; /// Receives serial data. /// /// The future is pending until the buffer is completely filled. - /// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel - /// unfinished transfers after a timeout to prevent lockup when no more data - /// is incoming. - fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a> { + fn read<'a>(self: Pin<&'a mut Self>, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { + let this = unsafe { self.get_unchecked_mut() }; let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) }; - let rx_stream = self.rx_stream.take().unwrap(); - let usart = self.usart.take().unwrap(); - async move { + let rx_stream = this.rx_stream.take().unwrap(); + let usart = this.usart.take().unwrap(); + let mut rx_transfer = Transfer::init( rx_stream, usart, @@ -162,20 +120,20 @@ where .double_buffer(false), ); - let fut = InterruptFuture::new(&mut self.rx_int); + let fut = InterruptFuture::new(&mut this.rx_int); rx_transfer.start(|_usart| {}); fut.await; let (rx_stream, usart, _, _) = rx_transfer.free(); - self.rx_stream.replace(rx_stream); - self.usart.replace(usart); + this.rx_stream.replace(rx_stream); + this.usart.replace(usart); Ok(()) } } } -impl IdleUart for Serial +impl Write for Serial where USART: serial::Instance + PeriAddress @@ -187,20 +145,74 @@ where RSTREAM: Stream + WithInterrupt + 'static, CHANNEL: Channel + 'static, { - type ReceiveFuture<'a> = impl Future> + 'a; + type WriteFuture<'a> = impl Future> + 'a; + + /// Sends serial data. + fn write<'a>(self: Pin<&'a mut Self>, buf: &'a [u8]) -> Self::WriteFuture<'a> { + let this = unsafe { self.get_unchecked_mut() }; + #[allow(mutable_transmutes)] + let static_buf = unsafe { core::mem::transmute::<&'a [u8], &'static mut [u8]>(buf) }; + + async move { + let tx_stream = this.tx_stream.take().unwrap(); + let usart = this.usart.take().unwrap(); + + let mut tx_transfer = Transfer::init( + tx_stream, + usart, + static_buf, + None, + DmaConfig::default() + .transfer_complete_interrupt(true) + .memory_increment(true) + .double_buffer(false), + ); + + let fut = InterruptFuture::new(&mut this.tx_int); + + tx_transfer.start(|_usart| {}); + fut.await; + + let (tx_stream, usart, _buf, _) = tx_transfer.free(); + + this.tx_stream.replace(tx_stream); + this.usart.replace(usart); + + Ok(()) + } + } +} + +impl ReadUntilIdle for Serial +where + USART: serial::Instance + + PeriAddress + + DMASet + + DMASet + + WithInterrupt + + 'static, + TSTREAM: Stream + WithInterrupt + 'static, + RSTREAM: Stream + WithInterrupt + 'static, + CHANNEL: Channel + 'static, +{ + type ReadUntilIdleFuture<'a> = impl Future> + 'a; /// Receives serial data. /// /// The future is pending until either the buffer is completely full, or the RX line falls idle after receiving some data. /// /// Returns the number of bytes read. - fn receive_until_idle<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a> { + fn read_until_idle<'a>( + self: Pin<&'a mut Self>, + buf: &'a mut [u8], + ) -> Self::ReadUntilIdleFuture<'a> { + let this = unsafe { self.get_unchecked_mut() }; let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) }; - let rx_stream = self.rx_stream.take().unwrap(); - let usart = self.usart.take().unwrap(); - async move { + let rx_stream = this.rx_stream.take().unwrap(); + let usart = this.usart.take().unwrap(); + unsafe { /* __HAL_UART_ENABLE_IT(&uart->UartHandle, UART_IT_IDLE); */ (*USART::ptr()).cr1.modify(|_, w| w.idleie().set_bit()); @@ -223,15 +235,12 @@ where let total_bytes = RSTREAM::get_number_of_transfers() as usize; - let fut = InterruptFuture::new(&mut self.rx_int); - let fut_idle = InterruptFuture::new(&mut self.usart_int); + let fut = InterruptFuture::new(&mut this.rx_int); + let fut_idle = InterruptFuture::new(&mut this.usart_int); rx_transfer.start(|_usart| {}); - select_biased! { - () = fut.fuse() => {}, - () = fut_idle.fuse() => {}, - } + futures::future::select(fut, fut_idle).await; let (rx_stream, usart, _, _) = rx_transfer.free(); @@ -240,8 +249,8 @@ where unsafe { (*USART::ptr()).cr1.modify(|_, w| w.idleie().clear_bit()); } - self.rx_stream.replace(rx_stream); - self.usart.replace(usart); + this.rx_stream.replace(rx_stream); + this.usart.replace(usart); Ok(total_bytes - remaining_bytes) }