Merge pull request #91 from embassy-rs/borrow-v3

nrf: New API supporting borrowed peripherals
This commit is contained in:
Dario Nieuwenhuis 2021-03-29 01:26:24 +02:00 committed by GitHub
commit af6d708c93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 2991 additions and 1698 deletions

View File

@ -3,7 +3,9 @@
// This mod MUST go first, so that the others see its macros. // This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt; pub(crate) mod fmt;
mod macros;
pub mod peripheral; pub mod peripheral;
pub mod peripheral_shared;
pub mod ring_buffer; pub mod ring_buffer;
pub mod usb; pub mod usb;

View File

@ -0,0 +1,107 @@
#[macro_export]
macro_rules! peripherals {
($($(#[$cfg:meta])? $name:ident),*$(,)?) => {
pub mod peripherals {
$(
$(#[$cfg])?
#[allow(non_camel_case_types)]
pub struct $name { _private: () }
$(#[$cfg])?
impl embassy::util::Steal for $name {
#[inline]
unsafe fn steal() -> Self {
Self{ _private: ()}
}
}
$(#[$cfg])?
impl embassy::util::PeripheralBorrow for $name {
type Target = $name;
#[inline]
unsafe fn unborrow(self) -> $name {
self
}
}
$(#[$cfg])?
impl embassy::util::PeripheralBorrow for &mut $name {
type Target = $name;
#[inline]
unsafe fn unborrow(self) -> $name {
::core::ptr::read(self)
}
}
)*
}
#[allow(non_snake_case)]
pub struct Peripherals {
$(
$(#[$cfg])?
pub $name: peripherals::$name,
)*
}
impl Peripherals {
///Returns all the peripherals *once*
#[inline]
pub fn take() -> Option<Self> {
#[no_mangle]
static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false;
cortex_m::interrupt::free(|_| {
if unsafe { _EMBASSY_DEVICE_PERIPHERALS } {
None
} else {
Some(unsafe { <Self as embassy::util::Steal>::steal() })
}
})
}
}
impl embassy::util::Steal for Peripherals {
#[inline]
unsafe fn steal() -> Self {
Self {
$(
$(#[$cfg])?
$name: <peripherals::$name as embassy::util::Steal>::steal(),
)*
}
}
}
};
}
#[macro_export]
macro_rules! unborrow {
($($name:ident),*) => {
$(
let mut $name = unsafe { $name.unborrow() };
)*
}
}
#[macro_export]
macro_rules! impl_unborrow {
($type:ident) => {
impl ::embassy::util::PeripheralBorrow for $type {
type Target = $type;
#[inline]
unsafe fn unborrow(self) -> Self::Target {
self
}
}
impl<'a> ::embassy::util::PeripheralBorrow for &'a mut $type {
type Target = $type;
#[inline]
unsafe fn unborrow(self) -> Self::Target {
unsafe { ::core::ptr::read(self) }
}
}
};
}

View File

@ -1,7 +1,6 @@
use core::cell::UnsafeCell; use core::cell::UnsafeCell;
use core::marker::{PhantomData, PhantomPinned}; use core::marker::{PhantomData, PhantomPinned};
use core::pin::Pin; use core::pin::Pin;
use core::sync::atomic::{compiler_fence, Ordering};
use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::interrupt::{Interrupt, InterruptExt};
@ -39,8 +38,6 @@ impl<S: PeripheralState> PeripheralMutex<S> {
} }
this.irq.disable(); this.irq.disable();
compiler_fence(Ordering::SeqCst);
this.irq.set_handler(|p| { this.irq.set_handler(|p| {
// Safety: it's OK to get a &mut to the state, since // Safety: it's OK to get a &mut to the state, since
// - We're in the IRQ, no one else can't preempt us // - We're in the IRQ, no one else can't preempt us
@ -50,8 +47,6 @@ impl<S: PeripheralState> PeripheralMutex<S> {
}); });
this.irq this.irq
.set_handler_context((&mut this.state) as *mut _ as *mut ()); .set_handler_context((&mut this.state) as *mut _ as *mut ());
compiler_fence(Ordering::SeqCst);
this.irq.enable(); this.irq.enable();
this.irq_setup_done = true; this.irq_setup_done = true;
@ -61,14 +56,11 @@ impl<S: PeripheralState> PeripheralMutex<S> {
let this = unsafe { self.get_unchecked_mut() }; let this = unsafe { self.get_unchecked_mut() };
this.irq.disable(); this.irq.disable();
compiler_fence(Ordering::SeqCst);
// Safety: it's OK to get a &mut to the state, since the irq is disabled. // Safety: it's OK to get a &mut to the state, since the irq is disabled.
let state = unsafe { &mut *this.state.get() }; let state = unsafe { &mut *this.state.get() };
let r = f(state, &mut this.irq); let r = f(state, &mut this.irq);
compiler_fence(Ordering::SeqCst);
this.irq.enable(); this.irq.enable();
r r

View File

@ -0,0 +1,63 @@
use core::cell::UnsafeCell;
use core::marker::{PhantomData, PhantomPinned};
use core::pin::Pin;
use embassy::interrupt::{Interrupt, InterruptExt};
pub trait PeripheralState {
type Interrupt: Interrupt;
fn on_interrupt(&self);
}
pub struct Peripheral<S: PeripheralState> {
state: UnsafeCell<S>,
irq_setup_done: bool,
irq: S::Interrupt,
_not_send: PhantomData<*mut ()>,
_pinned: PhantomPinned,
}
impl<S: PeripheralState> Peripheral<S> {
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();
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 ());
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<S: PeripheralState> Drop for Peripheral<S> {
fn drop(&mut self) {
self.irq.disable();
self.irq.remove_handler();
}
}

View File

@ -137,6 +137,20 @@ pub fn interrupt_declare(item: TokenStream) -> TokenStream {
&HANDLER &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() result.into()
} }
@ -158,13 +172,11 @@ pub fn interrupt_take(item: TokenStream) -> TokenStream {
static HANDLER: ::embassy::interrupt::Handler; static HANDLER: ::embassy::interrupt::Handler;
} }
let func = HANDLER.func.load(::embassy::export::atomic::Ordering::Acquire); let func = HANDLER.func.load(::embassy::export::atomic::Ordering::Relaxed);
let ctx = HANDLER.ctx.load(::embassy::export::atomic::Ordering::Acquire); let ctx = HANDLER.ctx.load(::embassy::export::atomic::Ordering::Relaxed);
if !func.is_null() {
let func: fn(*mut ()) = ::core::mem::transmute(func); let func: fn(*mut ()) = ::core::mem::transmute(func);
func(ctx) func(ctx)
} }
}
static TAKEN: ::embassy::export::atomic::AtomicBool = ::embassy::export::atomic::AtomicBool::new(false); static TAKEN: ::embassy::export::atomic::AtomicBool = ::embassy::export::atomic::AtomicBool::new(false);

View File

@ -28,5 +28,4 @@ cortex-m = { version = "0.7.1", features = ["inline-asm"] }
cortex-m-rt = "0.6.13" cortex-m-rt = "0.6.13"
embedded-hal = { version = "0.2.4" } embedded-hal = { version = "0.2.4" }
panic-probe = "0.1.0" panic-probe = "0.1.0"
nrf52840-hal = { version = "0.12.1" }
futures = { version = "0.3.8", default-features = false, features = ["async-await"] } futures = { version = "0.3.8", default-features = false, features = ["async-await"] }

View File

@ -3,57 +3,49 @@
#![feature(min_type_alias_impl_trait)] #![feature(min_type_alias_impl_trait)]
#![feature(impl_trait_in_bindings)] #![feature(impl_trait_in_bindings)]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
#[path = "../example_common.rs"] #[path = "../example_common.rs"]
mod example_common; mod example_common;
use example_common::*;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::panic; use defmt::panic;
use futures::pin_mut;
use nrf52840_hal as hal;
use nrf52840_hal::gpio;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; use embassy::io::{AsyncBufReadExt, AsyncWriteExt};
use embassy::util::Forever; use embassy::util::{Forever, Steal};
use embassy_nrf::buffered_uarte; use embassy_nrf::gpio::NoPin;
use embassy_nrf::interrupt; use embassy_nrf::{buffered_uarte::BufferedUarte, interrupt, peripherals, rtc, uarte, Peripherals};
use example_common::*;
static mut TX_BUFFER: [u8; 4096] = [0; 4096]; use futures::pin_mut;
static mut RX_BUFFER: [u8; 4096] = [0; 4096];
#[task] #[task]
async fn run() { 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 { let mut tx_buffer = [0u8; 4096];
rxd: port0.p0_08.into_floating_input().degrade(), let mut rx_buffer = [0u8; 4096];
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 irq = interrupt::take!(UARTE0_UART0); let irq = interrupt::take!(UARTE0_UART0);
let u = buffered_uarte::BufferedUarte::new( let u = unsafe {
BufferedUarte::new(
p.UARTE0, p.UARTE0,
p.TIMER0, p.TIMER0,
ppi.ppi0, p.PPI_CH0,
ppi.ppi1, p.PPI_CH1,
irq, irq,
unsafe { &mut RX_BUFFER }, p.P0_08,
unsafe { &mut TX_BUFFER }, p.P0_06,
pins, NoPin,
buffered_uarte::Parity::EXCLUDED, NoPin,
buffered_uarte::Baudrate::BAUD115200, config,
); &mut rx_buffer,
&mut tx_buffer,
)
};
pin_mut!(u); pin_mut!(u);
info!("uarte initialized!"); info!("uarte initialized!");
@ -79,13 +71,25 @@ async fn run() {
} }
} }
static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new();
static ALARM: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
static EXECUTOR: Forever<Executor> = Forever::new(); static EXECUTOR: Forever<Executor> = Forever::new();
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
info!("Hello World!"); info!("Hello World!");
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());
let executor = EXECUTOR.put(Executor::new()); let executor = EXECUTOR.put(Executor::new());
executor.set_alarm(alarm);
executor.run(|spawner| { executor.run(|spawner| {
unwrap!(spawner.spawn(run())); unwrap!(spawner.spawn(run()));
}); });

View File

@ -3,6 +3,7 @@
#![feature(min_type_alias_impl_trait)] #![feature(min_type_alias_impl_trait)]
#![feature(impl_trait_in_bindings)] #![feature(impl_trait_in_bindings)]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
#[path = "../example_common.rs"] #[path = "../example_common.rs"]
mod example_common; mod example_common;
@ -14,9 +15,8 @@ use defmt::panic;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
use embassy::time::{Duration, Instant, Timer}; use embassy::time::{Duration, Instant, Timer};
use embassy::util::Forever; use embassy::util::Forever;
use embassy_nrf::pac; use embassy_nrf::peripherals;
use embassy_nrf::{interrupt, rtc}; use embassy_nrf::{interrupt, rtc};
use nrf52840_hal::clocks;
#[task] #[task]
async fn run1() { async fn run1() {
@ -42,24 +42,19 @@ async fn run3() {
.await; .await;
} }
static RTC: Forever<rtc::RTC<pac::RTC1>> = Forever::new(); static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new();
static ALARM: Forever<rtc::Alarm<pac::RTC1>> = Forever::new(); static ALARM: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
static EXECUTOR: Forever<Executor> = Forever::new(); static EXECUTOR: Forever<Executor> = Forever::new();
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
info!("Hello World!"); info!("Hello World!");
let p = unwrap!(embassy_nrf::pac::Peripherals::take()); let p = unwrap!(embassy_nrf::Peripherals::take());
clocks::Clocks::new(p.CLOCK)
.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))); let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1)));
rtc.start(); rtc.start();
unsafe { embassy::time::set_clock(rtc) }; unsafe { embassy::time::set_clock(rtc) };
let alarm = ALARM.put(rtc.alarm0()); let alarm = ALARM.put(rtc.alarm0());

View File

@ -3,6 +3,7 @@
#![feature(min_type_alias_impl_trait)] #![feature(min_type_alias_impl_trait)]
#![feature(impl_trait_in_bindings)] #![feature(impl_trait_in_bindings)]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
#[path = "../example_common.rs"] #[path = "../example_common.rs"]
mod example_common; mod example_common;
@ -10,31 +11,44 @@ use example_common::*;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::panic; use defmt::panic;
use nrf52840_hal::gpio;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
use embassy::util::Forever; use embassy::util::Forever;
use embassy_nrf::gpiote::{Gpiote, InputChannel, InputChannelPolarity}; use embassy_nrf::gpio::{Input, Pull};
use embassy_nrf::interrupt; use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity};
use embassy_nrf::{interrupt, Peripherals};
#[task] #[task]
async fn run() { async fn run() {
let p = unwrap!(embassy_nrf::pac::Peripherals::take()); let p = Peripherals::take().unwrap();
let port0 = gpio::p0::Parts::new(p.P0); let g = gpiote::initialize(p.GPIOTE, interrupt::take!(GPIOTE));
let (g, chs) = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE));
info!("Starting!"); info!("Starting!");
let pin1 = port0.p0_11.into_pullup_input().degrade(); let ch1 = InputChannel::new(
let pin2 = port0.p0_12.into_pullup_input().degrade(); g,
let pin3 = port0.p0_24.into_pullup_input().degrade(); p.GPIOTE_CH0,
let pin4 = port0.p0_25.into_pullup_input().degrade(); Input::new(p.P0_11, Pull::Up),
InputChannelPolarity::HiToLo,
let ch1 = InputChannel::new(g, chs.ch0, pin1, InputChannelPolarity::HiToLo); );
let ch2 = InputChannel::new(g, chs.ch1, pin2, InputChannelPolarity::LoToHi); let ch2 = InputChannel::new(
let ch3 = InputChannel::new(g, chs.ch2, pin3, InputChannelPolarity::Toggle); g,
let ch4 = InputChannel::new(g, chs.ch3, pin4, InputChannelPolarity::Toggle); 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 { let button1 = async {
loop { loop {

View File

@ -3,23 +3,24 @@
#![feature(min_type_alias_impl_trait)] #![feature(min_type_alias_impl_trait)]
#![feature(impl_trait_in_bindings)] #![feature(impl_trait_in_bindings)]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
#[path = "../example_common.rs"] #[path = "../example_common.rs"]
mod example_common; mod example_common;
use example_common::*;
use core::pin::Pin; use core::pin::Pin;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::panic; use defmt::panic;
use nrf52840_hal::gpio;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
use embassy::traits::gpio::{WaitForHigh, WaitForLow}; use embassy::traits::gpio::{WaitForHigh, WaitForLow};
use embassy::util::Forever; use embassy::util::Forever;
use embassy_nrf::gpiote::{Gpiote, GpiotePin}; use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull};
use embassy_nrf::gpiote::{self, PortInput};
use embassy_nrf::interrupt; use embassy_nrf::interrupt;
use embassy_nrf::Peripherals;
use example_common::*;
async fn button(n: usize, mut pin: GpiotePin<gpio::PullUp>) { async fn button(n: usize, mut pin: PortInput<'static, AnyPin>) {
loop { loop {
Pin::new(&mut pin).wait_for_low().await; Pin::new(&mut pin).wait_for_low().await;
info!("Button {:?} pressed!", n); info!("Button {:?} pressed!", n);
@ -30,26 +31,25 @@ async fn button(n: usize, mut pin: GpiotePin<gpio::PullUp>) {
#[task] #[task]
async fn run() { async fn run() {
let p = unwrap!(embassy_nrf::pac::Peripherals::take()); let p = Peripherals::take().unwrap();
let port0 = gpio::p0::Parts::new(p.P0);
let (g, _) = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); let g = gpiote::initialize(p.GPIOTE, interrupt::take!(GPIOTE));
let button1 = button( let button1 = button(
1, 1,
GpiotePin::new(g, port0.p0_11.into_pullup_input().degrade()), PortInput::new(g, Input::new(p.P0_11.degrade(), Pull::Up)),
); );
let button2 = button( let button2 = button(
2, 2,
GpiotePin::new(g, port0.p0_12.into_pullup_input().degrade()), PortInput::new(g, Input::new(p.P0_12.degrade(), Pull::Up)),
); );
let button3 = button( let button3 = button(
3, 3,
GpiotePin::new(g, port0.p0_24.into_pullup_input().degrade()), PortInput::new(g, Input::new(p.P0_24.degrade(), Pull::Up)),
); );
let button4 = button( let button4 = button(
4, 4,
GpiotePin::new(g, port0.p0_25.into_pullup_input().degrade()), PortInput::new(g, Input::new(p.P0_25.degrade(), Pull::Up)),
); );
futures::join!(button1, button2, button3, button4); futures::join!(button1, button2, button3, button4);
} }

View File

@ -58,6 +58,7 @@
#![feature(min_type_alias_impl_trait)] #![feature(min_type_alias_impl_trait)]
#![feature(impl_trait_in_bindings)] #![feature(impl_trait_in_bindings)]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
#[path = "../example_common.rs"] #[path = "../example_common.rs"]
mod example_common; mod example_common;
@ -65,13 +66,11 @@ use example_common::*;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::panic; use defmt::panic;
use nrf52840_hal::clocks;
use embassy::executor::{task, Executor, InterruptExecutor}; use embassy::executor::{task, Executor, InterruptExecutor};
use embassy::interrupt::InterruptExt; use embassy::interrupt::InterruptExt;
use embassy::time::{Duration, Instant, Timer}; use embassy::time::{Duration, Instant, Timer};
use embassy::util::Forever; use embassy::util::Forever;
use embassy_nrf::{interrupt, pac, rtc}; use embassy_nrf::{interrupt, peripherals, rtc};
#[task] #[task]
async fn run_high() { async fn run_high() {
@ -115,25 +114,21 @@ async fn run_low() {
} }
} }
static RTC: Forever<rtc::RTC<pac::RTC1>> = Forever::new(); static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new();
static ALARM_HIGH: Forever<rtc::Alarm<pac::RTC1>> = Forever::new(); static ALARM_HIGH: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::SWI1_EGU1>> = Forever::new(); static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::SWI1_EGU1>> = Forever::new();
static ALARM_MED: Forever<rtc::Alarm<pac::RTC1>> = Forever::new(); static ALARM_MED: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::SWI0_EGU0>> = Forever::new(); static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::SWI0_EGU0>> = Forever::new();
static ALARM_LOW: Forever<rtc::Alarm<pac::RTC1>> = Forever::new(); static ALARM_LOW: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
static EXECUTOR_LOW: Forever<Executor> = Forever::new(); static EXECUTOR_LOW: Forever<Executor> = Forever::new();
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
info!("Hello World!"); info!("Hello World!");
let p = unwrap!(embassy_nrf::pac::Peripherals::take()); let p = unwrap!(embassy_nrf::Peripherals::take());
clocks::Clocks::new(p.CLOCK)
.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))); let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1)));
rtc.start(); rtc.start();
unsafe { embassy::time::set_clock(rtc) }; unsafe { embassy::time::set_clock(rtc) };

View File

@ -0,0 +1,111 @@
#![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 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<Executor> = Forever::new();
#[entry]
fn main() -> ! {
info!("Hello World!");
let executor = EXECUTOR.put(Executor::new());
executor.run(|spawner| {
unwrap!(spawner.spawn(run()));
});
}

View File

@ -3,20 +3,20 @@
#![feature(min_type_alias_impl_trait)] #![feature(min_type_alias_impl_trait)]
#![feature(impl_trait_in_bindings)] #![feature(impl_trait_in_bindings)]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
#[path = "../example_common.rs"] #[path = "../example_common.rs"]
mod example_common; mod example_common;
use example_common::*;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::{assert_eq, panic}; use defmt::{assert_eq, panic};
use futures::pin_mut;
use nrf52840_hal::gpio;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
use embassy::traits::flash::Flash; use embassy::traits::flash::Flash;
use embassy::util::Forever; use embassy::util::Forever;
use embassy_nrf::Peripherals;
use embassy_nrf::{interrupt, qspi}; use embassy_nrf::{interrupt, qspi};
use example_common::*;
use futures::pin_mut;
const PAGE_SIZE: usize = 4096; const PAGE_SIZE: usize = 4096;
@ -27,52 +27,18 @@ struct AlignedBuf([u8; 4096]);
#[task] #[task]
async fn run() { async fn run() {
let p = unwrap!(embassy_nrf::pac::Peripherals::take()); let p = Peripherals::take().unwrap();
let port0 = gpio::p0::Parts::new(p.P0); let csn = p.P0_17;
let sck = p.P0_19;
let pins = qspi::Pins { let io0 = p.P0_20;
csn: port0 let io1 = p.P0_21;
.p0_17 let io2 = p.P0_22;
.into_push_pull_output(gpio::Level::High) let io3 = p.P0_23;
.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 config = qspi::Config {
pins,
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 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); pin_mut!(q);
let mut id = [1; 3]; let mut id = [1; 3];
@ -83,7 +49,7 @@ async fn run() {
info!("id: {}", id); info!("id: {}", id);
// Read status register // Read status register
let mut status = [0; 1]; let mut status = [4; 1];
q.as_mut() q.as_mut()
.custom_instruction(0x05, &[], &mut status) .custom_instruction(0x05, &[], &mut status)
.await .await

View File

@ -3,19 +3,17 @@
#[path = "../example_common.rs"] #[path = "../example_common.rs"]
mod example_common; mod example_common;
use core::mem;
use embassy::executor::raw::Task;
use example_common::*; use example_common::*;
use core::mem;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::panic; use defmt::panic;
use embassy::executor::raw::Task;
use embassy::executor::Executor; use embassy::executor::Executor;
use embassy::time::{Duration, Timer}; use embassy::time::{Duration, Timer};
use embassy::util::Forever; use embassy::util::Forever;
use embassy_nrf::pac; use embassy_nrf::peripherals;
use embassy_nrf::{interrupt, rtc}; use embassy_nrf::{interrupt, rtc};
use nrf52840_hal::clocks;
async fn run1() { async fn run1() {
loop { loop {
@ -31,24 +29,19 @@ async fn run2() {
} }
} }
static RTC: Forever<rtc::RTC<pac::RTC1>> = Forever::new(); static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new();
static ALARM: Forever<rtc::Alarm<pac::RTC1>> = Forever::new(); static ALARM: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
static EXECUTOR: Forever<Executor> = Forever::new(); static EXECUTOR: Forever<Executor> = Forever::new();
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
info!("Hello World!"); info!("Hello World!");
let p = unwrap!(embassy_nrf::pac::Peripherals::take()); let p = unwrap!(embassy_nrf::Peripherals::take());
clocks::Clocks::new(p.CLOCK)
.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))); let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1)));
rtc.start(); rtc.start();
unsafe { embassy::time::set_clock(rtc) }; unsafe { embassy::time::set_clock(rtc) };
let alarm = ALARM.put(rtc.alarm0()); let alarm = ALARM.put(rtc.alarm0());

View File

@ -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<rtc::RTC<embassy_nrf::pac::RTC1>> = 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;
}
}
}

View File

@ -3,46 +3,42 @@
#![feature(min_type_alias_impl_trait)] #![feature(min_type_alias_impl_trait)]
#![feature(impl_trait_in_bindings)] #![feature(impl_trait_in_bindings)]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
#[path = "../example_common.rs"] #[path = "../example_common.rs"]
mod example_common; mod example_common;
use embassy_traits::spi::FullDuplex;
use example_common::*;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::panic; use defmt::panic;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
use embassy::util::Forever; use embassy::util::Forever;
use embassy::util::Steal;
use embassy_nrf::gpio::{Level, Output, OutputDrive};
use embassy_nrf::{interrupt, rtc, spim};
use embassy_nrf::{peripherals, Peripherals};
use embassy_traits::spi::FullDuplex;
use embedded_hal::digital::v2::*; use embedded_hal::digital::v2::*;
use example_common::*;
use futures::pin_mut; use futures::pin_mut;
use nrf52840_hal::clocks;
use nrf52840_hal::gpio;
use embassy_nrf::{interrupt, pac, rtc, spim};
#[task] #[task]
async fn run() { async fn run() {
info!("running!"); info!("running!");
let p = unsafe { embassy_nrf::pac::Peripherals::steal() }; let p = unsafe { Peripherals::steal() };
let p0 = gpio::p0::Parts::new(p.P0);
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 { let config = spim::Config {
pins,
frequency: spim::Frequency::M16, frequency: spim::Frequency::M16,
mode: spim::MODE_0, mode: spim::MODE_0,
orc: 0x00, orc: 0x00,
}; };
let mut ncs = p0.p0_31.into_push_pull_output(gpio::Level::High); let irq = interrupt::take!(SPIM3);
let spim = spim::Spim::new(p.SPIM3, interrupt::take!(SPIM3), config); let spim = spim::Spim::new(p.SPIM3, irq, p.P0_29, p.P0_28, p.P0_30, config);
pin_mut!(spim); pin_mut!(spim);
let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard);
// Example on how to talk to an ENC28J60 chip // Example on how to talk to an ENC28J60 chip
// softreset // softreset
@ -89,23 +85,20 @@ async fn run() {
info!("erevid: {=[?]}", rx); info!("erevid: {=[?]}", rx);
} }
static RTC: Forever<rtc::RTC<pac::RTC1>> = Forever::new(); static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new();
static ALARM: Forever<rtc::Alarm<pac::RTC1>> = Forever::new(); static ALARM: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
static EXECUTOR: Forever<Executor> = Forever::new(); static EXECUTOR: Forever<Executor> = Forever::new();
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
info!("Hello World!"); info!("Hello World!");
let p = unwrap!(embassy_nrf::pac::Peripherals::take()); let p = unwrap!(embassy_nrf::Peripherals::take());
clocks::Clocks::new(p.CLOCK)
.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))); let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1)));
rtc.start(); rtc.start();
unsafe { embassy::time::set_clock(rtc) };
unsafe { embassy::time::set_clock(rtc) }; unsafe { embassy::time::set_clock(rtc) };

View File

@ -3,6 +3,7 @@
#![feature(min_type_alias_impl_trait)] #![feature(min_type_alias_impl_trait)]
#![feature(impl_trait_in_bindings)] #![feature(impl_trait_in_bindings)]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
#[path = "../example_common.rs"] #[path = "../example_common.rs"]
mod example_common; mod example_common;
@ -13,9 +14,7 @@ use defmt::panic;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
use embassy::time::{Duration, Timer}; use embassy::time::{Duration, Timer};
use embassy::util::Forever; use embassy::util::Forever;
use embassy_nrf::pac; use embassy_nrf::{interrupt, peripherals, rtc};
use embassy_nrf::{interrupt, rtc};
use nrf52840_hal::clocks;
#[task] #[task]
async fn run1() { async fn run1() {
@ -33,24 +32,19 @@ async fn run2() {
} }
} }
static RTC: Forever<rtc::RTC<pac::RTC1>> = Forever::new(); static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new();
static ALARM: Forever<rtc::Alarm<pac::RTC1>> = Forever::new(); static ALARM: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
static EXECUTOR: Forever<Executor> = Forever::new(); static EXECUTOR: Forever<Executor> = Forever::new();
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
info!("Hello World!"); info!("Hello World!");
let p = unwrap!(embassy_nrf::pac::Peripherals::take()); let p = unwrap!(embassy_nrf::Peripherals::take());
clocks::Clocks::new(p.CLOCK)
.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))); let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1)));
rtc.start(); rtc.start();
unsafe { embassy::time::set_clock(rtc) }; unsafe { embassy::time::set_clock(rtc) };
let alarm = ALARM.put(rtc.alarm0()); let alarm = ALARM.put(rtc.alarm0());

View File

@ -3,6 +3,7 @@
#![feature(min_type_alias_impl_trait)] #![feature(min_type_alias_impl_trait)]
#![feature(impl_trait_in_bindings)] #![feature(impl_trait_in_bindings)]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
#[path = "../example_common.rs"] #[path = "../example_common.rs"]
mod example_common; mod example_common;
@ -11,39 +12,23 @@ use example_common::*;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use defmt::panic; use defmt::panic;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
use embassy::time::{Duration, Timer}; use embassy::traits::uart::{Read, Write};
use embassy::traits::uart::Uart; use embassy::util::{Forever, Steal};
use embassy::util::Forever; use embassy_nrf::gpio::NoPin;
use embassy_nrf::{interrupt, pac, rtc, uarte}; use embassy_nrf::{interrupt, peripherals, rtc, uarte, Peripherals};
use futures::future::{select, Either}; use futures::pin_mut;
use nrf52840_hal::clocks;
use nrf52840_hal::gpio;
#[task] #[task]
async fn run(uart: pac::UARTE0, port: pac::P0) { async fn run() {
// Init UART let p = unsafe { Peripherals::steal() };
let port0 = gpio::p0::Parts::new(port);
let pins = uarte::Pins { let mut config = uarte::Config::default();
rxd: port0.p0_08.into_floating_input().degrade(), config.parity = uarte::Parity::EXCLUDED;
txd: port0 config.baudrate = uarte::Baudrate::BAUD115200;
.p0_06
.into_push_pull_output(gpio::Level::Low)
.degrade(),
cts: None,
rts: None,
};
// NOTE(unsafe): Safe becasue we do not use `mem::forget` anywhere. let irq = interrupt::take!(UARTE0_UART0);
let mut uart = unsafe { let uart = unsafe { uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, NoPin, NoPin, config) };
uarte::Uarte::new( pin_mut!(uart);
uart,
interrupt::take!(UARTE0_UART0),
pins,
uarte::Parity::EXCLUDED,
uarte::Baudrate::BAUD115200,
)
};
info!("uarte initialized!"); info!("uarte initialized!");
@ -51,19 +36,22 @@ async fn run(uart: pac::UARTE0, port: pac::P0) {
let mut buf = [0; 8]; let mut buf = [0; 8];
buf.copy_from_slice(b"Hello!\r\n"); 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!"); info!("wrote hello in uart!");
loop { loop {
let buf_len = buf.len();
info!("reading..."); 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 // `receive()` doesn't return until the buffer has been completely filled with
// incoming data, which in this case is 8 bytes. // incoming data, which in this case is 8 bytes.
// //
// This example shows how to use `select` to run an uart receive concurrently with a // 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. // 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 timer_fut = Timer::after(Duration::from_millis(1000));
let received_len = match select(recv_fut, timer_fut).await { let received_len = match select(recv_fut, timer_fut).await {
// recv_fut completed first, so we've received `buf_len` bytes. // recv_fut completed first, so we've received `buf_len` bytes.
@ -81,38 +69,32 @@ async fn run(uart: pac::UARTE0, port: pac::P0) {
info!("read done, got {}", received); info!("read done, got {}", received);
// Echo back received data // Echo back received data
unwrap!(uart.send(received).await); unwrap!(uart.write(received).await);
} }
*/
} }
} }
static RTC: Forever<rtc::RTC<pac::RTC1>> = Forever::new(); static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new();
static ALARM: Forever<rtc::Alarm<pac::RTC1>> = Forever::new(); static ALARM: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
static EXECUTOR: Forever<Executor> = Forever::new(); static EXECUTOR: Forever<Executor> = Forever::new();
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
info!("Hello World!"); info!("Hello World!");
let p = unwrap!(embassy_nrf::pac::Peripherals::take()); let p = unwrap!(embassy_nrf::Peripherals::take());
clocks::Clocks::new(p.CLOCK)
.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))); let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1)));
rtc.start(); rtc.start();
unsafe { embassy::time::set_clock(rtc) }; unsafe { embassy::time::set_clock(rtc) };
let alarm = ALARM.put(rtc.alarm0()); let alarm = ALARM.put(rtc.alarm0());
let executor = EXECUTOR.put(Executor::new()); let executor = EXECUTOR.put(Executor::new());
executor.set_alarm(alarm); executor.set_alarm(alarm);
let uarte0 = p.UARTE0;
let p0 = p.P0;
executor.run(|spawner| { executor.run(|spawner| {
unwrap!(spawner.spawn(run(uarte0, p0))); unwrap!(spawner.spawn(run()));
}); });
} }

View File

@ -1,7 +1,6 @@
#![macro_use] #![macro_use]
use defmt_rtt as _; // global logger use defmt_rtt as _; // global logger
use nrf52840_hal as _;
use panic_probe as _; use panic_probe as _;
pub use defmt::*; pub use defmt::*;

View File

@ -11,11 +11,11 @@ defmt-info = [ ]
defmt-warn = [ ] defmt-warn = [ ]
defmt-error = [ ] defmt-error = [ ]
52810 = ["nrf52810-pac", "nrf52810-hal"] 52810 = ["nrf52810-pac"]
52811 = ["nrf52811-pac"] #, "nrf52811-hal"] 52811 = ["nrf52811-pac"]
52832 = ["nrf52832-pac", "nrf52832-hal"] 52832 = ["nrf52832-pac"]
52833 = ["nrf52833-pac", "nrf52833-hal"] 52833 = ["nrf52833-pac"]
52840 = ["nrf52840-pac", "nrf52840-hal"] 52840 = ["nrf52840-pac"]
[dependencies] [dependencies]
@ -31,14 +31,8 @@ embedded-hal = { version = "0.2.4" }
embedded-dma = { version = "0.1.2" } embedded-dma = { version = "0.1.2" }
futures = { version = "0.3.5", default-features = false } futures = { version = "0.3.5", default-features = false }
nrf52810-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 } nrf52811-pac = { version = "0.9.1", optional = true, features = [ "rt" ]}
nrf52832-pac = { version = "0.9.0", optional = true } nrf52832-pac = { version = "0.9.0", optional = true, features = [ "rt" ]}
nrf52833-pac = { version = "0.9.0", optional = true } nrf52833-pac = { version = "0.9.0", optional = true, features = [ "rt" ]}
nrf52840-pac = { version = "0.9.0", optional = true } nrf52840-pac = { version = "0.9.0", optional = true, features = [ "rt" ]}
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 }

View File

@ -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::cmp::min;
use core::mem; use core::mem;
use core::ops::Deref;
use core::pin::Pin; use core::pin::Pin;
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
use core::task::{Context, Poll}; use core::task::{Context, Poll};
use embassy::interrupt::InterruptExt; use embassy::interrupt::InterruptExt;
use embassy::io::{AsyncBufRead, AsyncWrite, Result}; use embassy::io::{AsyncBufRead, AsyncWrite, Result};
use embassy::util::WakerRegistration; use embassy::util::{PeripheralBorrow, WakerRegistration};
use embassy_extras::low_power_wait_until;
use embassy_extras::peripheral::{PeripheralMutex, PeripheralState}; use embassy_extras::peripheral::{PeripheralMutex, PeripheralState};
use embassy_extras::ring_buffer::RingBuffer; 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::fmt::{panic, *};
use crate::hal::ppi::ConfigurablePpi; use crate::gpio::sealed::Pin as _;
use crate::interrupt::{self, Interrupt}; use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin};
use crate::pac; 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 // 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}; pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
@ -39,17 +33,17 @@ enum TxState {
Transmitting(usize), Transmitting(usize),
} }
struct State<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> { struct State<'d, U: UarteInstance, T: TimerInstance> {
uarte: U, uarte: U,
timer: T, timer: T,
ppi_channel_1: P1, _ppi_ch1: Ppi<'d, AnyConfigurableChannel>,
ppi_channel_2: P2, _ppi_ch2: Ppi<'d, AnyConfigurableChannel>,
rx: RingBuffer<'a>, rx: RingBuffer<'d>,
rx_state: RxState, rx_state: RxState,
rx_waker: WakerRegistration, rx_waker: WakerRegistration,
tx: RingBuffer<'a>, tx: RingBuffer<'d>,
tx_state: TxState, tx_state: TxState,
tx_waker: WakerRegistration, 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: /// are disabled before using `Uarte`. See product specification:
/// - nrf52832: Section 15.2 /// - nrf52832: Section 15.2
/// - nrf52840: Section 6.1.2 /// - nrf52840: Section 6.1.2
pub struct BufferedUarte< pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> {
'a, inner: PeripheralMutex<State<'d, U, T>>,
U: Instance,
T: TimerInstance,
P1: ConfigurablePpi,
P2: ConfigurablePpi,
> {
inner: PeripheralMutex<State<'a, U, T, P1, P2>>,
} }
impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
BufferedUarte<'a, U, T, P1, P2> /// unsafe: may not leak self or futures
{ pub unsafe fn new(
pub fn new( uarte: impl PeripheralBorrow<Target = U> + 'd,
uarte: U, timer: impl PeripheralBorrow<Target = T> + 'd,
timer: T, ppi_ch1: impl PeripheralBorrow<Target = impl ConfigurableChannel> + 'd,
mut ppi_channel_1: P1, ppi_ch2: impl PeripheralBorrow<Target = impl ConfigurableChannel> + 'd,
mut ppi_channel_2: P2, irq: impl PeripheralBorrow<Target = U::Interrupt> + 'd,
irq: U::Interrupt, rxd: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
rx_buffer: &'a mut [u8], txd: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
tx_buffer: &'a mut [u8], cts: impl PeripheralBorrow<Target = impl GpioOptionalPin> + 'd,
mut pins: Pins, rts: impl PeripheralBorrow<Target = impl GpioOptionalPin> + 'd,
parity: Parity, config: Config,
baudrate: Baudrate, rx_buffer: &'d mut [u8],
tx_buffer: &'d mut [u8],
) -> Self { ) -> Self {
// Select pins unborrow!(uarte, timer, ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts);
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()
});
// Optional pins let r = uarte.regs();
uarte.psel.cts.write(|w| { let rt = timer.regs();
if let Some(ref pin) = pins.cts {
unsafe { w.bits(pin.psel_bits()) }; rxd.conf().write(|w| w.input().connect().drive().h0h1());
w.connect().connected() r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
} else {
w.connect().disconnected() txd.set_high();
txd.conf().write(|w| w.dir().output().drive().h0h1());
r.psel.txd.write(|w| unsafe { w.bits(txd.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()) });
uarte.psel.rts.write(|w| { if let Some(pin) = cts.pin_mut() {
if let Some(ref pin) = pins.rts { pin.conf().write(|w| w.input().connect().drive().h0h1());
unsafe { w.bits(pin.psel_bits()) };
w.connect().connected()
} else {
w.connect().disconnected()
} }
}); r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
// Enable UARTE instance r.baudrate.write(|w| w.baudrate().variant(config.baudrate));
uarte.enable.write(|w| w.enable().enabled()); r.config.write(|w| w.parity().variant(config.parity));
// Enable interrupts
uarte.intenset.write(|w| w.endrx().set().endtx().set());
// Configure // Configure
let hardware_flow_control = pins.rts.is_some() && pins.cts.is_some(); let hardware_flow_control = match (rts.pin().is_some(), cts.pin().is_some()) {
uarte (false, false) => false,
.config (true, true) => true,
.write(|w| w.hwfc().bit(hardware_flow_control).parity().variant(parity)); _ => 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 // Enable interrupts
uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); r.intenset.write(|w| w.endrx().set().endtx().set());
// Disable the irq, let the Registration enable it when everything is set up. // Disable the irq, let the Registration enable it when everything is set up.
irq.disable(); irq.disable();
irq.pend(); irq.pend();
// Enable UARTE instance
r.enable.write(|w| w.enable().enabled());
// BAUDRATE register values are `baudrate * 2^32 / 16000000` // BAUDRATE register values are `baudrate * 2^32 / 16000000`
// source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values // 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 // 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) // 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. // 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) }); rt.tasks_stop.write(|w| unsafe { w.bits(1) });
timer.bitmode.write(|w| w.bitmode()._32bit()); rt.bitmode.write(|w| w.bitmode()._32bit());
timer.prescaler.write(|w| unsafe { w.prescaler().bits(0) }); rt.prescaler.write(|w| unsafe { w.prescaler().bits(0) });
timer.cc[0].write(|w| unsafe { w.bits(timeout) }); rt.cc[0].write(|w| unsafe { w.bits(timeout) });
timer.mode.write(|w| w.mode().timer()); rt.mode.write(|w| w.mode().timer());
timer.shorts.write(|w| { rt.shorts.write(|w| {
w.compare0_clear().set_bit(); w.compare0_clear().set_bit();
w.compare0_stop().set_bit(); w.compare0_stop().set_bit();
w w
}); });
ppi_channel_1.set_event_endpoint(&uarte.events_rxdrdy); let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade_configurable());
ppi_channel_1.set_task_endpoint(&timer.tasks_clear); ppi_ch1.set_event(Event::from_reg(&r.events_rxdrdy));
ppi_channel_1.set_fork_task_endpoint(&timer.tasks_start); ppi_ch1.set_task(Task::from_reg(&rt.tasks_clear));
ppi_channel_1.enable(); ppi_ch1.set_fork_task(Task::from_reg(&rt.tasks_start));
ppi_ch1.enable();
ppi_channel_2.set_event_endpoint(&timer.events_compare[0]); let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade_configurable());
ppi_channel_2.set_task_endpoint(&uarte.tasks_stoprx); ppi_ch2.set_event(Event::from_reg(&rt.events_compare[0]));
ppi_channel_2.enable(); ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx));
ppi_ch2.enable();
BufferedUarte { BufferedUarte {
inner: PeripheralMutex::new( inner: PeripheralMutex::new(
State { State {
uarte, uarte,
timer, timer,
ppi_channel_1, _ppi_ch1: ppi_ch1,
ppi_channel_2, _ppi_ch2: ppi_ch2,
rx: RingBuffer::new(rx_buffer), rx: RingBuffer::new(rx_buffer),
rx_state: RxState::Idle, 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) { pub fn set_baudrate(self: Pin<&mut Self>, baudrate: Baudrate) {
self.inner().with(|state, _irq| { self.inner().with(|state, _irq| {
let timeout = 0x8000_0000 / (baudrate as u32 / 40); let r = state.uarte.regs();
state.timer.cc[0].write(|w| unsafe { w.bits(timeout) }); let rt = state.timer.regs();
state.timer.tasks_clear.write(|w| unsafe { w.bits(1) });
state let timeout = 0x8000_0000 / (baudrate as u32 / 40);
.uarte rt.cc[0].write(|w| unsafe { w.bits(timeout) });
.baudrate rt.tasks_clear.write(|w| unsafe { w.bits(1) });
.write(|w| w.baudrate().variant(baudrate));
r.baudrate.write(|w| w.baudrate().variant(baudrate));
}); });
} }
fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex<State<'a, U, T, P1, P2>>> { fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex<State<'d, U, T>>> {
unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
} }
} }
impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> AsyncBufRead impl<'d, U: UarteInstance, T: TimerInstance> AsyncBufRead for BufferedUarte<'d, U, T> {
for BufferedUarte<'a, U, T, P1, P2>
{
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> {
let mut inner = self.inner(); let mut inner = self.inner();
inner.as_mut().register_interrupt(); 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 impl<'d, U: UarteInstance, T: TimerInstance> AsyncWrite for BufferedUarte<'d, U, T> {
for BufferedUarte<'a, U, T, P1, P2>
{
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> {
let mut inner = self.inner(); let mut inner = self.inner();
inner.as_mut().register_interrupt(); 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 impl<'a, U: UarteInstance, T: TimerInstance> Drop for State<'a, U, T> {
for State<'a, U, T, P1, P2>
{
fn drop(&mut self) { 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 { 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 { 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 { 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 { 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 impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for State<'a, U, T> {
for State<'a, U, T, P1, P2>
{
type Interrupt = U::Interrupt; type Interrupt = U::Interrupt;
fn on_interrupt(&mut self) { fn on_interrupt(&mut self) {
trace!("irq: start"); trace!("irq: start");
let r = self.uarte.regs();
let rt = self.timer.regs();
loop { loop {
match self.rx_state { match self.rx_state {
RxState::Idle => { RxState::Idle => {
@ -313,11 +304,11 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi
self.rx_state = RxState::Receiving; self.rx_state = RxState::Receiving;
// Set up the DMA read // 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 // The PTR field is a full 32 bits wide and accepts the full range
// of values. // of values.
unsafe { w.ptr().bits(buf.as_ptr() as u32) }); 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 // We're giving it the length of the buffer, so no danger of
// accessing invalid memory. We have verified that the length of the // accessing invalid memory. We have verified that the length of the
// buffer fits in an `u8`, so the cast to `u8` is also fine. // 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()); trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len());
// Start UARTE Receive transaction // 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. // `1` is a valid value to write to task registers.
unsafe { w.bits(1) }); unsafe { w.bits(1) });
} }
@ -336,14 +327,14 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi
} }
RxState::Receiving => { RxState::Receiving => {
trace!(" irq_rx: in state receiving"); trace!(" irq_rx: in state receiving");
if self.uarte.events_endrx.read().bits() != 0 { if r.events_endrx.read().bits() != 0 {
self.timer.tasks_stop.write(|w| unsafe { w.bits(1) }); 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); trace!(" irq_rx: endrx {:?}", n);
self.rx.push(n); self.rx.push(n);
self.uarte.events_endrx.reset(); r.events_endrx.reset();
self.rx_waker.wake(); self.rx_waker.wake();
self.rx_state = RxState::Idle; 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()); self.tx_state = TxState::Transmitting(buf.len());
// Set up the DMA write // 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 // The PTR field is a full 32 bits wide and accepts the full range
// of values. // of values.
unsafe { w.ptr().bits(buf.as_ptr() as u32) }); 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 // We're giving it the length of the buffer, so no danger of
// accessing invalid memory. We have verified that the length of the // accessing invalid memory. We have verified that the length of the
// buffer fits in an `u8`, so the cast to `u8` is also fine. // 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 _) }); unsafe { w.maxcnt().bits(buf.len() as _) });
// Start UARTE Transmit transaction // 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. // `1` is a valid value to write to task registers.
unsafe { w.bits(1) }); unsafe { w.bits(1) });
} }
@ -386,8 +377,8 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi
} }
TxState::Transmitting(n) => { TxState::Transmitting(n) => {
trace!(" irq_tx: in state Transmitting"); trace!(" irq_tx: in state Transmitting");
if self.uarte.events_endtx.read().bits() != 0 { if r.events_endtx.read().bits() != 0 {
self.uarte.events_endtx.reset(); r.events_endtx.reset();
trace!(" irq_tx: endtx {:?}", n); trace!(" irq_tx: endtx {:?}", n);
self.tx.pop(n); self.tx.pop(n);
@ -402,37 +393,3 @@ impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi
trace!("irq: end"); 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<Target = pac::uarte0::RegisterBlock> + 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<Target = pac::timer0::RegisterBlock> + sealed::TimerInstance
{
}
impl TimerInstance for crate::pac::TIMER0 {}
impl TimerInstance for crate::pac::TIMER1 {}
impl TimerInstance for crate::pac::TIMER2 {}

447
embassy-nrf/src/gpio.rs Normal file
View File

@ -0,0 +1,447 @@
use core::convert::Infallible;
use core::hint::unreachable_unchecked;
use core::marker::PhantomData;
use embassy::util::PeripheralBorrow;
use embassy_extras::{impl_unborrow, unborrow};
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;
/// 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,
}
/// 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<'d, T: Pin> {
pub(crate) pin: T,
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: Pin> Input<'d, T> {
pub fn new(pin: impl PeripheralBorrow<Target = T> + 'd, pull: Pull) -> Self {
unborrow!(pin);
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,
phantom: PhantomData,
}
}
}
impl<'d, T: Pin> Drop for Input<'d, T> {
fn drop(&mut self) {
self.pin.conf().reset();
}
}
impl<'d, T: Pin> InputPin for Input<'d, T> {
type Error = Infallible;
fn is_high(&self) -> Result<bool, Self::Error> {
self.is_low().map(|v| !v)
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0)
}
}
/// 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<'d, T: Pin> {
pub(crate) pin: T,
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: Pin> Output<'d, T> {
pub fn new(
pin: impl PeripheralBorrow<Target = T> + 'd,
initial_output: Level,
drive: OutputDrive,
) -> Self {
unborrow!(pin);
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().variant(drive);
w.sense().disabled();
w
});
Self {
pin,
phantom: PhantomData,
}
}
}
impl<'d, T: Pin> Drop for Output<'d, T> {
fn drop(&mut self) {
self.pin.conf().reset();
}
}
impl<'d, T: Pin> OutputPin for Output<'d, T> {
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<'d, T: Pin> StatefulOutputPin for Output<'d, T> {
/// Is the output pin set as high?
fn is_set_high(&self) -> Result<bool, Self::Error> {
self.is_set_low().map(|v| !v)
}
/// Is the output pin set as low?
fn is_set_low(&self) -> Result<bool, Self::Error> {
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()
}
}
#[inline]
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(),
}
}
}
#[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()));
}
}
/// 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 {
/// 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 {
0 => 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
}
/// Convert from concrete pin type PX_XX to type erased `AnyPin`.
#[inline]
fn degrade(self) -> AnyPin {
AnyPin {
pin_port: self.pin_port(),
}
}
}
// Type-erased GPIO pin
pub struct AnyPin {
pin_port: u8,
}
impl AnyPin {
#[inline]
pub unsafe fn steal(pin_port: u8) -> Self {
Self { pin_port }
}
}
impl_unborrow!(AnyPin);
impl Pin for AnyPin {}
impl sealed::Pin for AnyPin {
#[inline]
fn pin_port(&self) -> u8 {
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<AnyPin>`.
#[inline]
fn degrade_optional(mut self) -> Option<AnyPin> {
self.pin_mut()
.map(|pin| unsafe { core::ptr::read(pin) }.degrade())
}
}
impl<T: Pin> sealed::OptionalPin for T {}
impl<T: Pin> 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_unborrow!(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
}
}
// ====================
macro_rules! impl_pin {
($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
}
}
};
}
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::*;
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);
}

View File

@ -1,22 +1,20 @@
use core::convert::Infallible;
use core::future::Future; use core::future::Future;
use core::mem::ManuallyDrop; use core::marker::PhantomData;
use core::ops::Deref;
use core::pin::Pin; use core::pin::Pin;
use core::ptr;
use core::task::{Context, Poll}; use core::task::{Context, Poll};
use embassy::interrupt::InterruptExt; use embassy::interrupt::InterruptExt;
use embassy::traits::gpio::{WaitForHigh, WaitForLow}; use embassy::traits::gpio::{WaitForHigh, WaitForLow};
use embassy::util::Signal; use embassy::util::AtomicWaker;
use embassy_extras::impl_unborrow;
use embedded_hal::digital::v2::{InputPin, StatefulOutputPin};
use futures::future::poll_fn;
use crate::hal::gpio::{Input, Level, Output, Pin as GpioPin, Port}; use crate::gpio::sealed::Pin as _;
use crate::interrupt; use crate::gpio::{AnyPin, Input, Output, Pin as GpioPin, Port};
use crate::pac; use crate::pac;
use crate::pac::generic::Reg; use crate::ppi::{Event, Task};
use crate::pac::gpiote::_TASKS_OUT; use crate::{interrupt, peripherals};
use crate::pac::{p0 as pac_gpio, GPIOTE};
#[cfg(not(feature = "51"))]
use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET};
pub const CHANNEL_COUNT: usize = 8; pub const CHANNEL_COUNT: usize = 8;
@ -25,50 +23,9 @@ pub const PIN_COUNT: usize = 48;
#[cfg(not(any(feature = "52833", feature = "52840")))] #[cfg(not(any(feature = "52833", feature = "52840")))]
pub const PIN_COUNT: usize = 32; pub const PIN_COUNT: usize = 32;
pub trait ChannelID { const NEW_AW: AtomicWaker = AtomicWaker::new();
fn number(&self) -> usize; static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT];
} static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AW; PIN_COUNT];
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
}
}
#[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];
pub enum InputChannelPolarity { pub enum InputChannelPolarity {
None, None,
@ -84,25 +41,15 @@ pub enum OutputChannelPolarity {
Toggle, Toggle,
} }
#[derive(Debug, Copy, Clone, Eq, PartialEq)] /// Token indicating GPIOTE has been correctly initialized.
#[cfg_attr(feature = "defmt", derive(defmt::Format))] ///
pub enum NewChannelError { /// This is not an owned singleton, it is Copy. Drivers that make use of GPIOTE require it.
NoFreeChannels, #[derive(Clone, Copy)]
pub struct Initialized {
_private: (),
} }
pub struct Channels { pub fn initialize(_gpiote: peripherals::GPIOTE, irq: interrupt::GPIOTE) -> Initialized {
pub ch0: Ch0,
pub ch1: Ch1,
pub ch2: Ch2,
pub ch3: Ch3,
pub ch4: Ch4,
pub ch5: Ch5,
pub ch6: Ch6,
pub ch7: Ch7,
}
impl Gpiote {
pub fn new(gpiote: GPIOTE, irq: interrupt::GPIOTE) -> (Self, Channels) {
#[cfg(any(feature = "52833", feature = "52840"))] #[cfg(any(feature = "52833", feature = "52840"))]
let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] };
#[cfg(not(any(feature = "52833", feature = "52840")))] #[cfg(not(any(feature = "52833", feature = "52840")))]
@ -116,34 +63,23 @@ impl Gpiote {
} }
// Enable interrupts // Enable interrupts
gpiote.events_port.write(|w| w); let g = unsafe { &*pac::GPIOTE::ptr() };
gpiote.intenset.write(|w| w.port().set()); g.events_port.write(|w| w);
irq.set_handler(Self::on_irq); g.intenset.write(|w| w.port().set());
irq.set_handler(on_irq);
irq.unpend(); irq.unpend();
irq.enable(); irq.enable();
( Initialized { _private: () }
Self(()), }
Channels {
ch0: Ch0(()),
ch1: Ch1(()),
ch2: Ch2(()),
ch3: Ch3(()),
ch4: Ch4(()),
ch5: Ch5(()),
ch6: Ch6(()),
ch7: Ch7(()),
},
)
}
unsafe fn on_irq(_ctx: *mut ()) { unsafe fn on_irq(_ctx: *mut ()) {
let g = &*GPIOTE::ptr(); let g = &*pac::GPIOTE::ptr();
for (event_in, signal) in g.events_in.iter().zip(CHANNEL_SIGNALS.iter()) { for i in 0..CHANNEL_COUNT {
if event_in.read().bits() != 0 { if g.events_in[i].read().bits() != 0 {
event_in.write(|w| w); g.intenclr.write(|w| unsafe { w.bits(1 << i) });
signal.signal(()); CHANNEL_WAKERS[i].wake();
} }
} }
@ -155,216 +91,15 @@ impl Gpiote {
#[cfg(not(any(feature = "52833", feature = "52840")))] #[cfg(not(any(feature = "52833", feature = "52840")))]
let ports = &[&*pac::P0::ptr()]; let ports = &[&*pac::P0::ptr()];
let mut work = true;
while work {
work = false;
for (port, &p) in ports.iter().enumerate() { for (port, &p) in ports.iter().enumerate() {
for pin in BitIter(p.latch.read().bits()) { let bits = p.latch.read().bits();
work = true; for pin in BitIter(bits) {
p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled()); p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled());
p.latch.write(|w| w.bits(1 << pin)); PORT_WAKERS[port * 32 + pin as usize].wake();
PORT_SIGNALS[port * 32 + pin as usize].signal(());
} }
p.latch.write(|w| w.bits(bits));
} }
} }
}
}
}
fn pin_num<T>(pin: &GpioPin<T>) -> 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<T>(pin: &GpioPin<T>) -> &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<T>(pin: &GpioPin<T>) -> &pac_gpio::PIN_CNF {
&pin_block(pin).pin_cnf[pin.pin() as usize]
}
pub struct InputChannel<C: ChannelID, T> {
ch: C,
pin: GpioPin<Input<T>>,
}
impl<C: ChannelID, T> Drop for InputChannel<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) });
}
}
impl<C: ChannelID, T> InputChannel<C, T> {
pub fn new(
_gpiote: Gpiote,
ch: C,
pin: GpioPin<Input<T>>,
polarity: InputChannelPolarity,
) -> Self {
let g = unsafe { &*GPIOTE::ptr() };
let index = ch.number();
g.config[index].write(|w| {
match polarity {
InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(),
InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(),
InputChannelPolarity::None => w.mode().event().polarity().none(),
InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(),
};
#[cfg(any(feature = "52833", feature = "52840"))]
w.port().bit(match pin.port() {
Port::Port0 => false,
Port::Port1 => true,
});
unsafe { w.psel().bits(pin.pin()) }
});
CHANNEL_SIGNALS[index].reset();
// Enable interrupt
g.intenset.write(|w| unsafe { w.bits(1 << index) });
InputChannel { ch, pin }
}
pub fn free(self) -> (C, GpioPin<Input<T>>) {
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_SIGNALS[index].wait().await;
}
pub fn pin(&self) -> &GpioPin<Input<T>> {
&self.pin
}
}
pub struct OutputChannel<C: ChannelID, T> {
ch: C,
pin: GpioPin<Output<T>>,
}
impl<C: ChannelID, T> Drop for OutputChannel<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) });
}
}
impl<C: ChannelID, T> OutputChannel<C, T> {
pub fn new(
_gpiote: Gpiote,
ch: C,
pin: GpioPin<Output<T>>,
level: Level,
polarity: OutputChannelPolarity,
) -> Self {
let g = unsafe { &*GPIOTE::ptr() };
let index = ch.number();
g.config[index].write(|w| {
w.mode().task();
match level {
Level::High => w.outinit().high(),
Level::Low => w.outinit().low(),
};
match polarity {
OutputChannelPolarity::Set => w.polarity().lo_to_hi(),
OutputChannelPolarity::Clear => w.polarity().hi_to_lo(),
OutputChannelPolarity::Toggle => w.polarity().toggle(),
};
#[cfg(any(feature = "52833", feature = "52840"))]
w.port().bit(match pin.port() {
Port::Port0 => false,
Port::Port1 => true,
});
unsafe { w.psel().bits(pin.pin()) }
});
// Enable interrupt
g.intenset.write(|w| unsafe { w.bits(1 << index) });
OutputChannel { ch, pin }
}
pub fn free(self) -> (C, GpioPin<Output<T>>) {
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) });
}
/// 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) });
}
/// 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) });
}
/// Returns reference to task_out endpoint for PPI.
pub fn task_out(&self) -> &Reg<u32, _TASKS_OUT> {
let g = unsafe { &*GPIOTE::ptr() };
let index = self.ch.number();
&g.tasks_out[index]
}
/// Returns reference to task_clr endpoint for PPI.
#[cfg(not(feature = "51"))]
pub fn task_clr(&self) -> &Reg<u32, _TASKS_CLR> {
let g = unsafe { &*GPIOTE::ptr() };
let index = self.ch.number();
&g.tasks_clr[index]
}
/// Returns reference to task_set endpoint for PPI.
#[cfg(not(feature = "51"))]
pub fn task_set(&self) -> &Reg<u32, _TASKS_SET> {
let g = unsafe { &*GPIOTE::ptr() };
let index = self.ch.number();
&g.tasks_set[index]
}
} }
struct BitIter(u32); struct BitIter(u32);
@ -383,72 +118,296 @@ impl Iterator for BitIter {
} }
} }
pub struct GpiotePin<T> { /// GPIOTE channel driver in input mode
pin: GpioPin<Input<T>>, pub struct InputChannel<'d, C: Channel, T: GpioPin> {
ch: C,
pin: Input<'d, T>,
} }
impl<T> Unpin for GpiotePin<T> {} 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();
g.config[num].write(|w| w.mode().disabled());
g.intenclr.write(|w| unsafe { w.bits(1 << num) });
}
}
impl<T> GpiotePin<T> { impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> {
pub fn new(_gpiote: Gpiote, pin: GpioPin<Input<T>>) -> Self { pub fn new(
_init: Initialized,
ch: C,
pin: Input<'d, T>,
polarity: InputChannelPolarity,
) -> Self {
let g = unsafe { &*pac::GPIOTE::ptr() };
let num = ch.number();
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(),
InputChannelPolarity::None => w.mode().event().polarity().none(),
InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(),
};
#[cfg(any(feature = "52833", feature = "52840"))]
w.port().bit(match pin.pin.port() {
Port::Port0 => false,
Port::Port1 => true,
});
unsafe { w.psel().bits(pin.pin.pin()) }
});
g.events_in[num].reset();
InputChannel { ch, pin }
}
pub async fn wait(&self) {
let g = unsafe { &*pac::GPIOTE::ptr() };
let num = self.ch.number();
// 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;
}
/// 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> {
type Error = Infallible;
fn is_high(&self) -> Result<bool, Self::Error> {
self.pin.is_high()
}
fn is_low(&self) -> Result<bool, Self::Error> {
self.pin.is_low()
}
}
/// GPIOTE channel driver in output mode
pub struct OutputChannel<'d, C: Channel, T: GpioPin> {
ch: C,
_pin: Output<'d, T>,
}
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();
g.config[num].write(|w| w.mode().disabled());
g.intenclr.write(|w| unsafe { w.bits(1 << num) });
}
}
impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> {
pub fn new(
_init: Initialized,
ch: C,
pin: Output<'d, T>,
polarity: OutputChannelPolarity,
) -> Self {
let g = unsafe { &*pac::GPIOTE::ptr() };
let num = ch.number();
g.config[num].write(|w| {
w.mode().task();
match pin.is_set_high().unwrap() {
true => w.outinit().high(),
false => w.outinit().low(),
};
match polarity {
OutputChannelPolarity::Set => w.polarity().lo_to_hi(),
OutputChannelPolarity::Clear => w.polarity().hi_to_lo(),
OutputChannelPolarity::Toggle => w.polarity().toggle(),
};
#[cfg(any(feature = "52833", feature = "52840"))]
w.port().bit(match pin.pin.port() {
Port::Port0 => false,
Port::Port1 => true,
});
unsafe { w.psel().bits(pin.pin.pin()) }
});
OutputChannel { ch, _pin: pin }
}
/// 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()].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()].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()].write(|w| unsafe { w.bits(1) });
}
/// Returns the OUT task, for use with PPI.
pub fn task_out(&self) -> Task {
let g = unsafe { &*pac::GPIOTE::ptr() };
Task::from_reg(&g.tasks_out[self.ch.number()])
}
/// Returns the CLR task, for use with PPI.
#[cfg(not(feature = "51"))]
pub fn task_clr(&self) -> Task {
let g = unsafe { &*pac::GPIOTE::ptr() };
Task::from_reg(&g.tasks_clr[self.ch.number()])
}
/// Returns the SET task, for use with PPI.
#[cfg(not(feature = "51"))]
pub fn task_set(&self) -> Task {
let g = unsafe { &*pac::GPIOTE::ptr() };
Task::from_reg(&g.tasks_set[self.ch.number()])
}
}
/// GPIOTE port input driver
pub struct PortInput<'d, T: GpioPin> {
pin: Input<'d, T>,
}
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 } Self { pin }
} }
} }
impl<T: 'static> WaitForHigh for GpiotePin<T> { impl<'d, T: GpioPin> InputPin for PortInput<'d, T> {
type Future<'a> = PortInputFuture<'a, T>; type Error = Infallible;
fn is_high(&self) -> Result<bool, Self::Error> {
self.pin.is_high()
}
fn is_low(&self) -> Result<bool, Self::Error> {
self.pin.is_low()
}
}
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> { fn wait_for_high<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
self.pin.pin.conf().modify(|_, w| w.sense().high());
PortInputFuture { PortInputFuture {
pin: &self.get_mut().pin, pin_port: self.pin.pin.pin_port(),
polarity: PortInputPolarity::High, phantom: PhantomData,
} }
} }
} }
impl<T: 'static> WaitForLow for GpiotePin<T> { impl<'d, T: GpioPin> WaitForLow for PortInput<'d, T> {
type Future<'a> = PortInputFuture<'a, T>; type Future<'a> = PortInputFuture<'a>;
fn wait_for_low<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> { fn wait_for_low<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
self.pin.pin.conf().modify(|_, w| w.sense().low());
PortInputFuture { PortInputFuture {
pin: &self.get_mut().pin, pin_port: self.pin.pin.pin_port(),
polarity: PortInputPolarity::Low, phantom: PhantomData,
} }
} }
} }
impl<T> Deref for GpiotePin<T> { pub struct PortInputFuture<'a> {
type Target = GpioPin<Input<T>>; pin_port: u8,
fn deref(&self) -> &Self::Target { phantom: PhantomData<&'a mut AnyPin>,
&self.pin
}
} }
enum PortInputPolarity { impl<'a> Drop for PortInputFuture<'a> {
High,
Low,
}
pub struct PortInputFuture<'a, T> {
pin: &'a GpioPin<Input<T>>,
polarity: PortInputPolarity,
}
impl<'a, T> Drop for PortInputFuture<'a, T> {
fn drop(&mut self) { fn drop(&mut self) {
pin_conf(&self.pin).modify(|_, w| w.sense().disabled()); let pin = unsafe { AnyPin::steal(self.pin_port) };
PORT_SIGNALS[pin_num(&self.pin)].reset(); pin.conf().modify(|_, w| w.sense().disabled());
} }
} }
impl<'a, T> Future for PortInputFuture<'a, T> { impl<'a> Future for PortInputFuture<'a> {
type Output = (); type Output = ();
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
pin_conf(&self.pin).modify(|_, w| match self.polarity { PORT_WAKERS[self.pin_port as usize].register(cx.waker());
PortInputPolarity::Low => w.sense().low(),
PortInputPolarity::High => w.sense().high(), let pin = unsafe { AnyPin::steal(self.pin_port) };
}); if pin.conf().read().sense().is_disabled() {
PORT_SIGNALS[pin_num(&self.pin)].poll_wait(cx) Poll::Ready(())
} else {
Poll::Pending
}
} }
} }
mod sealed {
pub trait Channel {}
}
pub trait Channel: sealed::Channel + Sized {
fn number(&self) -> usize;
fn degrade(self) -> AnyChannel {
AnyChannel {
number: self.number() as u8,
}
}
}
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) => {
impl sealed::Channel for peripherals::$type {}
impl Channel for peripherals::$type {
fn number(&self) -> usize {
$number as usize
}
}
};
}
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);

View File

@ -40,17 +40,6 @@ pub use nrf52833_pac as pac;
#[cfg(feature = "52840")] #[cfg(feature = "52840")]
pub use nrf52840_pac as pac; 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 /// Length of Nordic EasyDMA differs for MCUs
#[cfg(any( #[cfg(any(
feature = "52810", feature = "52810",
@ -94,10 +83,181 @@ pub(crate) fn slice_in_ram_or<T>(slice: &[u8], err: T) -> Result<(), T> {
pub(crate) mod fmt; pub(crate) mod fmt;
pub mod buffered_uarte; pub mod buffered_uarte;
pub mod gpio;
pub mod gpiote; pub mod gpiote;
pub mod interrupt; pub mod interrupt;
pub mod ppi;
#[cfg(feature = "52840")] #[cfg(feature = "52840")]
pub mod qspi; pub mod qspi;
pub mod rtc; pub mod rtc;
pub mod saadc;
pub mod spim; pub mod spim;
pub mod system;
pub mod timer;
pub mod uarte; pub mod uarte;
embassy_extras::peripherals! {
// RTC
RTC0,
RTC1,
#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))]
RTC2,
// QSPI
#[cfg(feature = "52840")]
QSPI,
// UARTE
UARTE0,
#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))]
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,
#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))]
SPIM1,
#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))]
SPIM2,
#[cfg(any(feature = "52833", feature = "52840"))]
SPIM3,
// 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,
GPIOTE_CH1,
GPIOTE_CH2,
GPIOTE_CH3,
GPIOTE_CH4,
GPIOTE_CH5,
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,
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,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_01,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_02,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_03,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_04,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_05,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_06,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_07,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_08,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_09,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_10,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_11,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_12,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_13,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_14,
#[cfg(any(feature = "52833", feature = "52840"))]
P1_15,
}

255
embassy-nrf/src/ppi.rs Normal file
View File

@ -0,0 +1,255 @@
//! 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 core::marker::PhantomData;
use core::ptr::NonNull;
use embassy::util::PeripheralBorrow;
use embassy_extras::{impl_unborrow, unborrow};
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<Target = C> + '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<T>(reg: &T) -> Self {
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut ()) })
}
}
pub struct Event(pub NonNull<()>);
impl Event {
pub(crate) fn from_reg<T>(reg: &T) -> Self {
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut ()) })
}
}
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 {
fn degrade_configurable(self) -> AnyConfigurableChannel {
AnyConfigurableChannel {
number: self.number() as u8,
}
}
}
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
}
}
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);
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);

View File

@ -1,13 +1,16 @@
use core::future::Future; use core::future::Future;
use core::marker::PhantomData;
use core::pin::Pin; use core::pin::Pin;
use core::task::Poll; use core::task::Poll;
use embassy::interrupt::Interrupt;
use embassy_extras::peripheral::{PeripheralMutex, PeripheralState}; use embassy_extras::peripheral::{PeripheralMutex, PeripheralState};
use embassy_extras::unborrow;
use crate::fmt::{assert, assert_eq, *}; 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::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::ADDRMODE_A as AddressMode;
pub use crate::pac::qspi::ifconfig0::PPSIZE_A as WritePageSize; pub use crate::pac::qspi::ifconfig0::PPSIZE_A as WritePageSize;
@ -25,25 +28,16 @@ pub use crate::pac::qspi::ifconfig0::WRITEOC_A as WriteOpcode;
// - set gpio in high drive // - set gpio in high drive
use embassy::traits::flash::{Error, Flash}; 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; use futures::future::poll_fn;
pub struct Pins {
pub sck: GpioPin<Output<PushPull>>,
pub csn: GpioPin<Output<PushPull>>,
pub io0: GpioPin<Output<PushPull>>,
pub io1: GpioPin<Output<PushPull>>,
pub io2: Option<GpioPin<Output<PushPull>>>,
pub io3: Option<GpioPin<Output<PushPull>>>,
}
pub struct DeepPowerDownConfig { pub struct DeepPowerDownConfig {
pub enter_time: u16, pub enter_time: u16,
pub exit_time: u16, pub exit_time: u16,
} }
#[non_exhaustive]
pub struct Config { pub struct Config {
pub pins: Pins,
pub xip_offset: u32, pub xip_offset: u32,
pub read_opcode: ReadOpcode, pub read_opcode: ReadOpcode,
pub write_opcode: WriteOpcode, pub write_opcode: WriteOpcode,
@ -51,55 +45,59 @@ pub struct Config {
pub deep_power_down: Option<DeepPowerDownConfig>, pub deep_power_down: Option<DeepPowerDownConfig>,
} }
struct State { impl Default for Config {
inner: QSPI, fn default() -> Self {
waker: WakerRegistration, Self {
read_opcode: ReadOpcode::READ4IO,
write_opcode: WriteOpcode::PP4IO,
xip_offset: 0,
write_page_size: WritePageSize::_256BYTES,
deep_power_down: None,
}
}
} }
pub struct Qspi { pub struct Qspi<'d, T: Instance> {
inner: PeripheralMutex<State>, peri: T,
irq: T::Interrupt,
phantom: PhantomData<&'d mut T>,
} }
impl Qspi { impl<'d, T: Instance> Qspi<'d, T> {
pub fn new(qspi: QSPI, irq: interrupt::QSPI, config: Config) -> Self { pub fn new(
qspi.psel.sck.write(|w| { qspi: impl PeripheralBorrow<Target = T> + 'd,
let pin = &config.pins.sck; irq: impl PeripheralBorrow<Target = T::Interrupt> + 'd,
unsafe { w.bits(pin.psel_bits()) }; sck: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
w.connect().connected() csn: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
}); io0: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
qspi.psel.csn.write(|w| { io1: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
let pin = &config.pins.csn; io2: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
unsafe { w.bits(pin.psel_bits()) }; io3: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
w.connect().connected() config: Config,
}); ) -> Self {
qspi.psel.io0.write(|w| { unborrow!(qspi, irq, sck, csn, io0, io1, io2, io3);
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()
}
});
qspi.ifconfig0.write(|mut w| { let r = qspi.regs();
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); w = w.addrmode().variant(AddressMode::_24BIT);
if config.deep_power_down.is_some() { if config.deep_power_down.is_some() {
w = w.dpmenable().enable(); w = w.dpmenable().enable();
@ -113,14 +111,14 @@ impl Qspi {
}); });
if let Some(dpd) = &config.deep_power_down { 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.enter().bits(dpd.enter_time);
w = w.exit().bits(dpd.exit_time); w = w.exit().bits(dpd.exit_time);
w w
}) })
} }
qspi.ifconfig1.write(|w| { r.ifconfig1.write(|w| {
let w = unsafe { w.sckdelay().bits(80) }; let w = unsafe { w.sckdelay().bits(80) };
let w = w.dpmen().exit(); let w = w.dpmen().exit();
let w = w.spimode().mode0(); let w = w.spimode().mode0();
@ -128,48 +126,42 @@ impl Qspi {
w w
}); });
qspi.xipoffset r.xipoffset
.write(|w| unsafe { w.xipoffset().bits(config.xip_offset) }); .write(|w| unsafe { w.xipoffset().bits(config.xip_offset) });
// Enable it // Enable it
qspi.enable.write(|w| w.enable().enabled()); r.enable.write(|w| w.enable().enabled());
qspi.events_ready.reset(); r.events_ready.reset();
qspi.tasks_activate.write(|w| w.tasks_activate().bit(true)); r.tasks_activate.write(|w| w.tasks_activate().bit(true));
while qspi.events_ready.read().bits() == 0 {} while r.events_ready.read().bits() == 0 {}
qspi.events_ready.reset(); r.events_ready.reset();
Self { Self {
inner: PeripheralMutex::new( peri: qspi,
State {
inner: qspi,
waker: WakerRegistration::new(),
},
irq, irq,
), phantom: PhantomData,
} }
} }
pub fn sleep(self: Pin<&mut Self>) { pub fn sleep(mut self: Pin<&mut Self>) {
self.inner().with(|s, _| { let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs();
info!("flash: sleeping"); info!("flash: sleeping");
info!("flash: state = {:?}", s.inner.status.read().bits()); info!("flash: state = {:?}", r.status.read().bits());
s.inner.ifconfig1.modify(|_, w| w.dpmen().enter()); r.ifconfig1.modify(|_, w| w.dpmen().enter());
info!("flash: state = {:?}", s.inner.status.read().bits()); info!("flash: state = {:?}", r.status.read().bits());
cortex_m::asm::delay(1000000); cortex_m::asm::delay(1000000);
info!("flash: state = {:?}", s.inner.status.read().bits()); info!("flash: state = {:?}", r.status.read().bits());
s.inner r.tasks_deactivate.write(|w| w.tasks_deactivate().set_bit());
.tasks_deactivate
.write(|w| w.tasks_deactivate().set_bit());
});
} }
pub async fn custom_instruction<'a>( pub async fn custom_instruction(
mut self: Pin<&'a mut Self>, mut self: Pin<&mut Self>,
opcode: u8, opcode: u8,
req: &'a [u8], req: &[u8],
resp: &'a mut [u8], resp: &mut [u8],
) -> Result<(), Error> { ) -> Result<(), Error> {
let bomb = DropBomb::new(); let bomb = DropBomb::new();
@ -192,14 +184,14 @@ impl Qspi {
let len = core::cmp::max(req.len(), resp.len()) as u8; let len = core::cmp::max(req.len(), resp.len()) as u8;
self.as_mut().inner().with(|s, _| { let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs();
s.inner.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); r.cinstrdat0.write(|w| unsafe { w.bits(dat0) });
s.inner.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); r.cinstrdat1.write(|w| unsafe { w.bits(dat1) });
s.inner.events_ready.reset(); r.events_ready.reset();
s.inner.intenset.write(|w| w.ready().set()); r.intenset.write(|w| w.ready().set());
s.inner.cinstrconf.write(|w| { r.cinstrconf.write(|w| {
let w = unsafe { w.opcode().bits(opcode) }; let w = unsafe { w.opcode().bits(opcode) };
let w = unsafe { w.length().bits(len + 1) }; let w = unsafe { w.length().bits(len + 1) };
let w = w.lio2().bit(true); let w = w.lio2().bit(true);
@ -210,13 +202,13 @@ impl Qspi {
let w = w.lfstop().bit(false); let w = w.lfstop().bit(false);
w w
}); });
});
self.as_mut().wait_ready().await; self.as_mut().wait_ready().await;
self.as_mut().inner().with(|s, _| { let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs();
let dat0 = s.inner.cinstrdat0.read().bits();
let dat1 = s.inner.cinstrdat1.read().bits(); let dat0 = r.cinstrdat0.read().bits();
let dat1 = r.cinstrdat1.read().bits();
for i in 0..4 { for i in 0..4 {
if i < resp.len() { if i < resp.len() {
resp[i] = (dat0 >> (i * 8)) as u8; resp[i] = (dat0 >> (i * 8)) as u8;
@ -227,34 +219,38 @@ impl Qspi {
resp[i] = (dat1 >> (i * 8)) as u8; resp[i] = (dat1 >> (i * 8)) as u8;
} }
} }
});
bomb.defuse(); bomb.defuse();
Ok(()) Ok(())
} }
fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex<State>> { async fn wait_ready(self: Pin<&mut Self>) {
unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } let this = unsafe { self.get_unchecked_mut() };
}
fn wait_ready<'a>(mut self: Pin<&'a mut Self>) -> impl Future<Output = ()> + 'a {
poll_fn(move |cx| { poll_fn(move |cx| {
self.as_mut().inner().with(|s, _irq| { let r = this.peri.regs();
if s.inner.events_ready.read().bits() != 0 {
if r.events_ready.read().bits() != 0 {
r.events_ready.reset();
return Poll::Ready(()); return Poll::Ready(());
} }
s.waker.register(cx.waker());
wake_on_interrupt(&mut this.irq, cx.waker());
Poll::Pending Poll::Pending
}) })
}) .await
} }
} }
impl Flash for Qspi { impl<'d, T: Instance> Flash for Qspi<'d, T> {
type ReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; #[rustfmt::skip]
type WriteFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a;
type ErasePageFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; #[rustfmt::skip]
type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a;
#[rustfmt::skip]
type ErasePageFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a;
fn read<'a>( fn read<'a>(
mut self: Pin<&'a mut Self>, mut self: Pin<&'a mut Self>,
@ -268,26 +264,21 @@ impl Flash for Qspi {
assert_eq!(data.len() as u32 % 4, 0); assert_eq!(data.len() as u32 % 4, 0);
assert_eq!(address as u32 % 4, 0); assert_eq!(address as u32 % 4, 0);
self.as_mut().inner().with(|s, _| { let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs();
s.inner
.read r.read
.src .src
.write(|w| unsafe { w.src().bits(address as u32) }); .write(|w| unsafe { w.src().bits(address as u32) });
s.inner r.read
.read
.dst .dst
.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); .write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) });
s.inner r.read
.read
.cnt .cnt
.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); .write(|w| unsafe { w.cnt().bits(data.len() as u32) });
s.inner.events_ready.reset(); r.events_ready.reset();
s.inner.intenset.write(|w| w.ready().set()); r.intenset.write(|w| w.ready().set());
s.inner r.tasks_readstart.write(|w| w.tasks_readstart().bit(true));
.tasks_readstart
.write(|w| w.tasks_readstart().bit(true));
});
self.as_mut().wait_ready().await; self.as_mut().wait_ready().await;
@ -309,26 +300,20 @@ impl Flash for Qspi {
assert_eq!(data.len() as u32 % 4, 0); assert_eq!(data.len() as u32 % 4, 0);
assert_eq!(address as u32 % 4, 0); assert_eq!(address as u32 % 4, 0);
self.as_mut().inner().with(|s, _| { let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs();
s.inner r.write
.write
.src .src
.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); .write(|w| unsafe { w.src().bits(data.as_ptr() as u32) });
s.inner r.write
.write
.dst .dst
.write(|w| unsafe { w.dst().bits(address as u32) }); .write(|w| unsafe { w.dst().bits(address as u32) });
s.inner r.write
.write
.cnt .cnt
.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); .write(|w| unsafe { w.cnt().bits(data.len() as u32) });
s.inner.events_ready.reset(); r.events_ready.reset();
s.inner.intenset.write(|w| w.ready().set()); r.intenset.write(|w| w.ready().set());
s.inner r.tasks_writestart.write(|w| w.tasks_writestart().bit(true));
.tasks_writestart
.write(|w| w.tasks_writestart().bit(true));
});
self.as_mut().wait_ready().await; self.as_mut().wait_ready().await;
@ -344,19 +329,15 @@ impl Flash for Qspi {
assert_eq!(address as u32 % 4096, 0); assert_eq!(address as u32 % 4096, 0);
self.as_mut().inner().with(|s, _| { let r = unsafe { self.as_mut().get_unchecked_mut() }.peri.regs();
s.inner r.erase
.erase
.ptr .ptr
.write(|w| unsafe { w.ptr().bits(address as u32) }); .write(|w| unsafe { w.ptr().bits(address as u32) });
s.inner.erase.len.write(|w| w.len()._4kb()); r.erase.len.write(|w| w.len()._4kb());
s.inner.events_ready.reset(); r.events_ready.reset();
s.inner.intenset.write(|w| w.ready().set()); r.intenset.write(|w| w.ready().set());
s.inner r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true));
.tasks_erasestart
.write(|w| w.tasks_erasestart().bit(true));
});
self.as_mut().wait_ready().await; self.as_mut().wait_ready().await;
@ -383,13 +364,29 @@ impl Flash for Qspi {
} }
} }
impl PeripheralState for State { mod sealed {
type Interrupt = interrupt::QSPI; use super::*;
fn on_interrupt(&mut self) { pub trait Instance {
if self.inner.events_ready.read().bits() != 0 { fn regs(&self) -> &pac::qspi::RegisterBlock;
self.inner.intenclr.write(|w| w.ready().clear());
self.waker.wake()
}
} }
} }
pub trait Instance: sealed::Instance + 'static {
type Interrupt: Interrupt;
}
macro_rules! impl_instance {
($type:ident, $irq:ident) => {
impl sealed::Instance for peripherals::$type {
fn regs(&self) -> &pac::qspi::RegisterBlock {
unsafe { &*pac::$type::ptr() }
}
}
impl Instance for peripherals::$type {
type Interrupt = interrupt::$irq;
}
};
}
impl_instance!(QSPI, QSPI);

View File

@ -1,13 +1,12 @@
use core::cell::Cell; use core::cell::Cell;
use core::ops::Deref;
use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
use embassy::interrupt::InterruptExt; use embassy::interrupt::InterruptExt;
use embassy::time::Clock; use embassy::time::Clock;
use crate::interrupt;
use crate::interrupt::{CriticalSection, Interrupt, Mutex}; 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 // 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. // of 2^23 ticks. The RTC counter value is 24 bits, so one "overflow cycle" is 2 periods.
@ -96,19 +95,20 @@ impl<T: Instance> RTC<T> {
} }
pub fn start(&'static self) { 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.ovrflw().set();
let w = w.compare3().set(); let w = w.compare3().set();
w w
}); });
self.rtc.tasks_clear.write(|w| unsafe { w.bits(1) }); r.tasks_clear.write(|w| unsafe { w.bits(1) });
self.rtc.tasks_start.write(|w| unsafe { w.bits(1) }); r.tasks_start.write(|w| unsafe { w.bits(1) });
// Wait for clear // Wait for clear
while self.rtc.counter.read().bits() != 0 {} while r.counter.read().bits() != 0 {}
self.irq.set_handler(|ptr| unsafe { self.irq.set_handler(|ptr| unsafe {
let this = &*(ptr as *const () as *const Self); let this = &*(ptr as *const () as *const Self);
@ -120,19 +120,20 @@ impl<T: Instance> RTC<T> {
} }
fn on_interrupt(&self) { fn on_interrupt(&self) {
if self.rtc.events_ovrflw.read().bits() == 1 { let r = self.rtc.regs();
self.rtc.events_ovrflw.write(|w| w); if r.events_ovrflw.read().bits() == 1 {
r.events_ovrflw.write(|w| w);
self.next_period(); self.next_period();
} }
if self.rtc.events_compare[3].read().bits() == 1 { if r.events_compare[3].read().bits() == 1 {
self.rtc.events_compare[3].write(|w| w); r.events_compare[3].write(|w| w);
self.next_period(); self.next_period();
} }
for n in 0..ALARM_COUNT { for n in 0..ALARM_COUNT {
if self.rtc.events_compare[n].read().bits() == 1 { if r.events_compare[n].read().bits() == 1 {
self.rtc.events_compare[n].write(|w| w); r.events_compare[n].write(|w| w);
interrupt::free(|cs| { interrupt::free(|cs| {
self.trigger_alarm(n, cs); self.trigger_alarm(n, cs);
}) })
@ -142,6 +143,7 @@ impl<T: Instance> RTC<T> {
fn next_period(&self) { fn next_period(&self) {
interrupt::free(|cs| { interrupt::free(|cs| {
let r = self.rtc.regs();
let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; let period = self.period.fetch_add(1, Ordering::Relaxed) + 1;
let t = (period as u64) << 23; let t = (period as u64) << 23;
@ -151,15 +153,16 @@ impl<T: Instance> RTC<T> {
let diff = at - t; let diff = at - t;
if diff < 0xc00000 { if diff < 0xc00000 {
self.rtc.cc[n].write(|w| unsafe { w.bits(at as u32 & 0xFFFFFF) }); r.cc[n].write(|w| unsafe { w.bits(at as u32 & 0xFFFFFF) });
self.rtc.intenset.write(|w| unsafe { w.bits(compare_n(n)) }); r.intenset.write(|w| unsafe { w.bits(compare_n(n)) });
} }
} }
}) })
} }
fn trigger_alarm(&self, n: usize, cs: &CriticalSection) { 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]; let alarm = &self.alarms.borrow(cs)[n];
alarm.timestamp.set(u64::MAX); alarm.timestamp.set(u64::MAX);
@ -190,6 +193,8 @@ impl<T: Instance> RTC<T> {
return; return;
} }
let r = self.rtc.regs();
// If it hasn't triggered yet, setup it in the compare channel. // If it hasn't triggered yet, setup it in the compare channel.
let diff = timestamp - t; let diff = timestamp - t;
if diff < 0xc00000 { if diff < 0xc00000 {
@ -206,12 +211,12 @@ impl<T: Instance> RTC<T> {
// by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
// and we don't do that here. // and we don't do that here.
let safe_timestamp = timestamp.max(t + 3); let safe_timestamp = timestamp.max(t + 3);
self.rtc.cc[n].write(|w| unsafe { w.bits(safe_timestamp as u32 & 0xFFFFFF) }); r.cc[n].write(|w| unsafe { w.bits(safe_timestamp as u32 & 0xFFFFFF) });
self.rtc.intenset.write(|w| unsafe { w.bits(compare_n(n)) }); r.intenset.write(|w| unsafe { w.bits(compare_n(n)) });
} else { } else {
// If it's too far in the future, don't setup the compare channel yet. // If it's too far in the future, don't setup the compare channel yet.
// It will be setup later by `next_period`. // 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<T: Instance> embassy::time::Clock for RTC<T> {
// `period` MUST be read before `counter`, see comment at the top for details. // `period` MUST be read before `counter`, see comment at the top for details.
let period = self.period.load(Ordering::Relaxed); let period = self.period.load(Ordering::Relaxed);
compiler_fence(Ordering::Acquire); compiler_fence(Ordering::Acquire);
let counter = self.rtc.counter.read().bits(); let counter = self.rtc.regs().counter.read().bits();
calc_now(period, counter) calc_now(period, counter)
} }
} }
@ -257,31 +262,32 @@ impl<T: Instance> embassy::time::Alarm for Alarm<T> {
} }
mod sealed { mod sealed {
pub trait Instance {} use super::*;
pub trait Instance {
fn regs(&self) -> &pac::rtc0::RegisterBlock;
}
}
impl Instance for crate::pac::RTC0 {} macro_rules! impl_instance {
impl Instance for crate::pac::RTC1 {} ($type:ident, $irq:ident) => {
#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] impl sealed::Instance for peripherals::$type {
impl Instance for crate::pac::RTC2 {} fn regs(&self) -> &pac::rtc0::RegisterBlock {
unsafe { &*pac::$type::ptr() }
}
}
impl Instance for peripherals::$type {
type Interrupt = interrupt::$irq;
}
};
} }
/// Implemented by all RTC instances. /// Implemented by all RTC instances.
pub trait Instance: pub trait Instance: sealed::Instance + 'static {
sealed::Instance + Deref<Target = rtc0::RegisterBlock> + Sized + 'static
{
/// The interrupt associated with this RTC instance. /// The interrupt associated with this RTC instance.
type Interrupt: Interrupt; type Interrupt: Interrupt;
} }
impl Instance for crate::pac::RTC0 { impl_instance!(RTC0, RTC0);
type Interrupt = interrupt::RTC0; impl_instance!(RTC1, RTC1);
}
impl Instance for crate::pac::RTC1 {
type Interrupt = interrupt::RTC1;
}
#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))]
impl Instance for crate::pac::RTC2 { impl_instance!(RTC2, RTC2);
type Interrupt = interrupt::RTC2;
}

242
embassy-nrf/src/saadc.rs Normal file
View File

@ -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<Target = peripherals::SAADC> + 'd,
irq: impl PeripheralBorrow<Target = interrupt::SAADC> + 'd,
positive_pin: impl PeripheralBorrow<Target = T> + '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<Output = i16> + '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<Output = i16> + '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,
}

View File

@ -1,19 +1,21 @@
use core::future::Future; use core::future::Future;
use core::marker::PhantomData;
use core::pin::Pin; use core::pin::Pin;
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll; use core::task::Poll;
use embassy::traits; use embassy::traits;
use embassy::util::WakerRegistration; use embassy::util::{wake_on_interrupt, PeripheralBorrow};
use embassy_extras::peripheral::{PeripheralMutex, PeripheralState}; use embassy_extras::unborrow;
use futures::future::poll_fn; use futures::future::poll_fn;
use traits::spi::FullDuplex; use traits::spi::FullDuplex;
use crate::gpio::sealed::Pin as _;
use crate::gpio::{OptionalPin, Pin as GpioPin};
use crate::interrupt::{self, Interrupt}; 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::{ pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
Frequency, Mode, Phase, Pins, Polarity, MODE_0, MODE_1, MODE_2, MODE_3, pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -25,46 +27,60 @@ pub enum Error {
DMABufferNotInDataMemory, DMABufferNotInDataMemory,
} }
struct State<T: Instance> { pub struct Spim<'d, T: Instance> {
spim: T, peri: T,
waker: WakerRegistration, irq: T::Interrupt,
} phantom: PhantomData<&'d mut T>,
pub struct Spim<T: Instance> {
inner: PeripheralMutex<State<T>>,
} }
pub struct Config { pub struct Config {
pub pins: Pins,
pub frequency: Frequency, pub frequency: Frequency,
pub mode: Mode, pub mode: Mode,
pub orc: u8, pub orc: u8,
} }
impl<T: Instance> Spim<T> { impl<'d, T: Instance> Spim<'d, T> {
pub fn new(mut spim: T, irq: T::Interrupt, config: Config) -> Self { pub fn new(
spim: impl PeripheralBorrow<Target = T> + 'd,
irq: impl PeripheralBorrow<Target = T::Interrupt> + 'd,
sck: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
miso: impl PeripheralBorrow<Target = impl OptionalPin> + 'd,
mosi: impl PeripheralBorrow<Target = impl OptionalPin> + 'd,
config: Config,
) -> Self {
unborrow!(spim, irq, sck, miso, mosi);
let r = spim.regs(); let r = spim.regs();
// Select pins. // Configure pins
r.psel.sck.write(|w| { sck.conf().write(|w| w.dir().output().drive().h0h1());
unsafe { w.bits(config.pins.sck.psel_bits()) }; if let Some(mosi) = mosi.pin_mut() {
w.connect().connected() 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.pins.mosi { match config.mode.polarity {
Some(mosi) => r.psel.mosi.write(|w| { Polarity::IdleHigh => {
unsafe { w.bits(mosi.psel_bits()) }; sck.set_high();
w.connect().connected() if let Some(mosi) = mosi.pin_mut() {
}), mosi.set_high();
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()),
} }
Polarity::IdleLow => {
sck.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()) });
// Enable SPIM instance. // Enable SPIM instance.
r.enable.write(|w| w.enable().enabled()); r.enable.write(|w| w.enable().enabled());
@ -107,22 +123,14 @@ impl<T: Instance> Spim<T> {
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
Self { Self {
inner: PeripheralMutex::new( peri: spim,
State {
spim,
waker: WakerRegistration::new(),
},
irq, irq,
), phantom: PhantomData,
} }
} }
fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex<State<T>>> {
unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
}
} }
impl<T: Instance> FullDuplex<u8> for Spim<T> { impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
type Error = Error; type Error = Error;
#[rustfmt::skip] #[rustfmt::skip]
@ -133,29 +141,28 @@ impl<T: Instance> FullDuplex<u8> for Spim<T> {
type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
fn read<'a>(self: Pin<&'a mut Self>, data: &'a mut [u8]) -> Self::ReadFuture<'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> { 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>( fn read_write<'a>(
mut self: Pin<&'a mut Self>, self: Pin<&'a mut Self>,
rx: &'a mut [u8], rx: &'a mut [u8],
tx: &'a [u8], tx: &'a [u8],
) -> Self::WriteReadFuture<'a> { ) -> Self::WriteReadFuture<'a> {
async move { async move {
let this = unsafe { self.get_unchecked_mut() };
slice_in_ram_or(rx, Error::DMABufferNotInDataMemory)?; slice_in_ram_or(rx, Error::DMABufferNotInDataMemory)?;
slice_in_ram_or(tx, 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 // Conservative compiler fence to prevent optimizations that do not
// take in to account actions by DMA. The fence has been placed here, // take in to account actions by DMA. The fence has been placed here,
// before any DMA action has started. // before any DMA action has started.
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
let r = s.spim.regs(); let r = this.peri.regs();
// Set up the DMA write. // Set up the DMA write.
r.txd r.txd
@ -184,19 +191,20 @@ impl<T: Instance> FullDuplex<u8> for Spim<T> {
// take in to account actions by DMA. The fence has been placed here, // take in to account actions by DMA. The fence has been placed here,
// after all possible DMA actions have completed. // after all possible DMA actions have completed.
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
});
// Wait for 'end' event. // Wait for 'end' event.
poll_fn(|cx| { poll_fn(|cx| {
self.as_mut().inner().with(|s, _irq| { let r = this.peri.regs();
let r = s.spim.regs();
if r.events_end.read().bits() != 0 { if r.events_end.read().bits() != 0 {
r.events_end.reset();
return Poll::Ready(()); return Poll::Ready(());
} }
s.waker.register(cx.waker());
wake_on_interrupt(&mut this.irq, cx.waker());
Poll::Pending Poll::Pending
}) })
})
.await; .await;
Ok(()) Ok(())
@ -204,51 +212,41 @@ impl<T: Instance> FullDuplex<u8> for Spim<T> {
} }
} }
impl<U: Instance> PeripheralState for State<U> {
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 { mod sealed {
use super::*; use super::*;
pub trait Instance { pub trait Instance {
fn regs(&mut self) -> &pac::spim0::RegisterBlock; fn regs(&self) -> &pac::spim0::RegisterBlock;
} }
} }
pub trait Instance: sealed::Instance { pub trait Instance: sealed::Instance + 'static {
type Interrupt: Interrupt; type Interrupt: Interrupt;
} }
macro_rules! make_impl { macro_rules! impl_instance {
($SPIMx:ident, $IRQ:ident) => { ($type:ident, $irq:ident) => {
impl sealed::Instance for pac::$SPIMx { impl sealed::Instance for peripherals::$type {
fn regs(&mut self) -> &pac::spim0::RegisterBlock { fn regs(&self) -> &pac::spim0::RegisterBlock {
self unsafe { &*pac::$type::ptr() }
} }
} }
impl Instance for pac::$SPIMx { impl Instance for peripherals::$type {
type Interrupt = interrupt::$IRQ; type Interrupt = interrupt::$irq;
} }
}; };
} }
#[cfg(feature = "52810")] #[cfg(feature = "52810")]
make_impl!(SPIM0, SPIM0_SPIS0_SPI0); impl_instance!(SPIM0, SPIM0_SPIS0_SPI0);
#[cfg(not(feature = "52810"))] #[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"))] #[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"))] #[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"))] #[cfg(any(feature = "52833", feature = "52840"))]
make_impl!(SPIM3, SPIM3); impl_instance!(SPIM3, SPIM3);

76
embassy-nrf/src/system.rs Normal file
View File

@ -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 {}
}

43
embassy-nrf/src/timer.rs Normal file
View File

@ -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! impl_instance {
($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) => {
impl_instance!($type, $irq);
impl sealed::ExtendedInstance for peripherals::$type {}
impl ExtendedInstance for peripherals::$type {}
};
}
impl_instance!(TIMER0, TIMER0);
impl_instance!(TIMER1, TIMER1);
impl_instance!(TIMER2, TIMER2);
#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))]
impl_instance!(TIMER3, TIMER3, extended);
#[cfg(any(feature = "52832", feature = "52833", feature = "52840"))]
impl_instance!(TIMER4, TIMER4, extended);

View File

@ -1,47 +1,57 @@
//! Async low power UARTE. //! Async UART
//!
//! 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()`).
use core::future::Future; use core::future::Future;
use core::ops::Deref; use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering}; use core::pin::Pin;
use core::task::{Context, Poll}; use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
use core::task::Poll;
use embassy::traits::uart::{Error, Read, Write};
use embassy::util::{AtomicWaker, OnDrop, PeripheralBorrow};
use embassy_extras::peripheral_shared::{Peripheral, PeripheralState};
use embassy_extras::unborrow;
use futures::future::poll_fn;
use embassy::interrupt::InterruptExt; use crate::fmt::{assert, panic, *};
use embassy::util::Signal; use crate::gpio::sealed::Pin as _;
use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin};
use crate::fmt::{assert, *};
use crate::hal::pac;
use crate::hal::prelude::*;
use crate::hal::target_constants::EASY_DMA_SIZE;
use crate::interrupt; use crate::interrupt;
use crate::interrupt::Interrupt; use crate::interrupt::Interrupt;
use crate::pac;
use crate::peripherals;
use crate::target_constants::EASY_DMA_SIZE;
pub use crate::hal::uarte::Pins;
// Re-export SVD variants to allow user to directly set values. // Re-export SVD variants to allow user to directly set values.
pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
#[non_exhaustive]
pub struct Config {
pub parity: Parity,
pub baudrate: Baudrate,
}
impl Default for Config {
fn default() -> Self {
Self {
parity: Parity::EXCLUDED,
baudrate: Baudrate::BAUD115200,
}
}
}
struct State<T: Instance> {
peri: T,
endrx_waker: AtomicWaker,
endtx_waker: AtomicWaker,
}
/// Interface to the UARTE peripheral /// Interface to the UARTE peripheral
pub struct Uarte<T> pub struct Uarte<'d, T: Instance> {
where inner: Peripheral<State<T>>,
T: Instance, phantom: PhantomData<&'d mut T>,
{
instance: T,
irq: T::Interrupt,
pins: Pins,
} }
pub struct State { impl<'d, T: Instance> Uarte<'d, T> {
tx_done: Signal<()>,
rx_done: Signal<u32>,
}
impl<T> Uarte<T>
where
T: Instance,
{
/// Creates the interface to a UARTE instance. /// Creates the interface to a UARTE instance.
/// Sets the baud rate, parity and assigns the pins to the UARTE peripheral. /// Sets the baud rate, parity and assigns the pins to the UARTE peripheral.
/// ///
@ -52,389 +62,272 @@ where
/// or [`receive`](Uarte::receive). /// or [`receive`](Uarte::receive).
#[allow(unused_unsafe)] #[allow(unused_unsafe)]
pub unsafe fn new( pub unsafe fn new(
uarte: T, uarte: impl PeripheralBorrow<Target = T> + 'd,
irq: T::Interrupt, irq: impl PeripheralBorrow<Target = T::Interrupt> + 'd,
mut pins: Pins, rxd: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
parity: Parity, txd: impl PeripheralBorrow<Target = impl GpioPin> + 'd,
baudrate: Baudrate, cts: impl PeripheralBorrow<Target = impl GpioOptionalPin> + 'd,
rts: impl PeripheralBorrow<Target = impl GpioOptionalPin> + 'd,
config: Config,
) -> Self { ) -> Self {
assert!(uarte.enable.read().enable().is_disabled()); unborrow!(uarte, irq, rxd, txd, cts, rts);
uarte.psel.rxd.write(|w| { let r = uarte.regs();
unsafe { w.bits(pins.rxd.psel_bits()) };
w.connect().connected()
});
pins.txd.set_high().unwrap(); assert!(r.enable.read().enable().is_disabled());
uarte.psel.txd.write(|w| {
unsafe { w.bits(pins.txd.psel_bits()) };
w.connect().connected()
});
// Optional pins rxd.conf().write(|w| w.input().connect().drive().h0h1());
uarte.psel.cts.write(|w| { r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
if let Some(ref pin) = pins.cts {
unsafe { w.bits(pin.psel_bits()) }; txd.set_high();
w.connect().connected() txd.conf().write(|w| w.dir().output().drive().h0h1());
} else { r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) });
w.connect().disconnected()
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()) });
uarte.psel.rts.write(|w| { if let Some(pin) = cts.pin_mut() {
if let Some(ref pin) = pins.rts { pin.conf().write(|w| w.input().connect().drive().h0h1());
unsafe { w.bits(pin.psel_bits()) };
w.connect().connected()
} else {
w.connect().disconnected()
} }
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));
uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); // Disable all interrupts
uarte.config.write(|w| w.parity().variant(parity)); r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
// Enable interrupts // Reset rxstarted, txstarted. These are used by drop to know whether a transfer was
uarte.events_endtx.reset(); // stopped midway or not.
uarte.events_endrx.reset(); r.events_rxstarted.reset();
uarte r.events_txstarted.reset();
.intenset
.write(|w| w.endtx().set().txstopped().set().endrx().set().rxto().set());
// Register ISR // Enable
irq.set_handler(Self::on_irq); r.enable.write(|w| w.enable().enabled());
irq.unpend();
irq.enable();
Uarte { Self {
instance: uarte, inner: Peripheral::new(
irq, irq,
pins, State {
peri: uarte,
endrx_waker: AtomicWaker::new(),
endtx_waker: AtomicWaker::new(),
},
),
phantom: PhantomData,
} }
} }
pub fn free(self) -> (T, T::Interrupt, Pins) { fn inner(self: Pin<&mut Self>) -> Pin<&mut Peripheral<State<T>>> {
// Wait for the peripheral to be disabled from the ISR. unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
while self.instance.enable.read().enable().is_enabled() {} }
(self.instance, self.irq, self.pins) }
impl<T: Instance> PeripheralState for State<T> {
type Interrupt = T::Interrupt;
fn on_interrupt(&self) {
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());
} }
fn enable(&mut self) { if r.events_rxto.read().bits() != 0 {
trace!("enable"); r.intenclr.write(|w| w.rxto().clear());
self.instance.enable.write(|w| w.enable().enabled());
} }
if r.events_txstopped.read().bits() != 0 {
fn tx_started(&self) -> bool { r.intenclr.write(|w| w.txstopped().clear());
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 ()) { impl<'a, T: Instance> Drop for Uarte<'a, T> {
let uarte = &*pac::UARTE0::ptr(); fn drop(&mut self) {
info!("uarte drop");
let mut try_disable = false; let s = unsafe { Pin::new_unchecked(&mut self.inner) }.state();
let r = s.peri.regs();
if uarte.events_endtx.read().bits() != 0 { let did_stoprx = r.events_rxstarted.read().bits() != 0;
uarte.events_endtx.reset(); let did_stoptx = r.events_txstarted.read().bits() != 0;
trace!("endtx"); info!("did_stoprx {} did_stoptx {}", did_stoprx, did_stoptx);
compiler_fence(Ordering::SeqCst);
if uarte.events_txstarted.read().bits() != 0 { // Wait for rxto or txstopped, if needed.
// The ENDTX was signal triggered because DMA has finished. r.intenset.write(|w| w.rxto().set().txstopped().set());
uarte.events_txstarted.reset(); while (did_stoprx && r.events_rxto.read().bits() == 0)
try_disable = true; || (did_stoptx && r.events_txstopped.read().bits() == 0)
}
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"); info!("uarte drop: wfe");
uarte.enable.write(|w| w.enable().disabled()); cortex_m::asm::wfe();
}
cortex_m::asm::sev();
// Finally we can disable!
r.enable.write(|w| w.enable().disabled());
info!("uarte drop: done");
// TODO: disable pins
}
}
impl<'d, T: Instance> Read for Uarte<'d, T> {
#[rustfmt::skip]
type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a;
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 s = self.inner().state();
let r = s.peri.regs();
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) });
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) });
poll_fn(|cx| {
s.endrx_waker.register(cx.waker());
if r.events_endrx.read().bits() != 0 {
return Poll::Ready(());
}
Poll::Pending
})
.await;
compiler_fence(Ordering::SeqCst);
r.events_rxstarted.reset();
drop.defuse();
Ok(())
} }
} }
} }
impl<T: Instance> embassy::traits::uart::Uart for Uarte<T> { impl<'d, T: Instance> Write for Uarte<'d, T> {
type ReceiveFuture<'a> = ReceiveFuture<'a, T>; #[rustfmt::skip]
type SendFuture<'a> = SendFuture<'a, T>; type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a;
/// Sends serial data. fn write<'a>(mut self: Pin<&'a mut Self>, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> {
/// self.as_mut().inner().register_interrupt();
/// `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());
T::state().tx_done.reset(); async move {
let ptr = tx_buffer.as_ptr();
SendFuture { let len = tx_buffer.len();
uarte: self,
buf: tx_buffer,
}
}
/// 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());
T::state().rx_done.reset();
ReceiveFuture {
uarte: self,
buf: rx_buffer,
}
}
}
/// Future for the [`Uarte::send()`] method.
pub struct SendFuture<'a, T>
where
T: Instance,
{
uarte: &'a mut Uarte<T>,
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.instance.events_txstarted.reset();
self.uarte
.instance
.tasks_stoptx
.write(|w| unsafe { w.bits(1) });
// TX is stopped almost instantly, spinning is fine.
while !T::state().tx_done.signaled() {}
}
}
}
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<Self::Output> {
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); assert!(len <= EASY_DMA_SIZE);
// TODO: panic if buffer is not in SRAM // TODO: panic if buffer is not in SRAM
uarte.enable(); let s = self.inner().state();
let r = s.peri.regs();
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");
});
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); 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"); trace!("starttx");
uarte.instance.tasks_starttx.write(|w| unsafe { w.bits(1) }); r.tasks_starttx.write(|w| unsafe { w.bits(1) });
while !uarte.tx_started() {} // Make sure transmission has started
poll_fn(|cx| {
s.endtx_waker.register(cx.waker());
if r.events_endtx.read().bits() != 0 {
return Poll::Ready(());
}
Poll::Pending Poll::Pending
} else { })
Poll::Ready(Ok(())) .await;
}
}
}
/// Future for the [`Uarte::receive()`] method.
pub struct ReceiveFuture<'a, T>
where
T: Instance,
{
uarte: &'a mut Uarte<T>,
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.instance.events_rxstarted.reset();
self.uarte
.instance
.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<Self::Output> {
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); compiler_fence(Ordering::SeqCst);
uarte r.events_txstarted.reset();
.instance drop.defuse();
.rxd
.ptr
.write(|w| unsafe { w.ptr().bits(ptr as u32) });
uarte
.instance
.rxd
.maxcnt
.write(|w| unsafe { w.maxcnt().bits(len as _) });
trace!("startrx"); Ok(())
uarte.instance.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. mod sealed {
impl<'a, T> ReceiveFuture<'a, T> use super::*;
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.instance.events_rxstarted.reset(); pub trait Instance {
self.uarte fn regs(&self) -> &pac::uarte0::RegisterBlock;
.instance
.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 private { pub trait Instance: sealed::Instance + 'static {
pub trait Sealed {}
}
pub trait Instance:
Deref<Target = pac::uarte0::RegisterBlock> + Sized + private::Sealed + 'static
{
type Interrupt: Interrupt; type Interrupt: Interrupt;
#[doc(hidden)]
fn state() -> &'static State;
} }
static UARTE0_STATE: State = State { macro_rules! impl_instance {
tx_done: Signal::new(), ($type:ident, $irq:ident) => {
rx_done: Signal::new(), impl sealed::Instance for peripherals::$type {
}; fn regs(&self) -> &pac::uarte0::RegisterBlock {
impl private::Sealed for pac::UARTE0 {} unsafe { &*pac::$type::ptr() }
impl Instance for pac::UARTE0 {
type Interrupt = interrupt::UARTE0_UART0;
fn state() -> &'static State {
&UARTE0_STATE
} }
}
#[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
} }
impl Instance for peripherals::$type {
type Interrupt = interrupt::$irq;
}
};
} }
impl_instance!(UARTE0, UARTE0_UART0);
#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))]
impl_instance!(UARTE1, UARTE1);

View File

@ -12,10 +12,11 @@ use example_common::{panic, *};
use cortex_m::singleton; use cortex_m::singleton;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embassy::executor::{task, Executor}; use embassy::executor::{task, Executor};
use embassy::traits::uart::Uart; use embassy::traits::uart::{Read, Write};
use embassy::util::Forever; use embassy::util::Forever;
use embassy_stm32f4::interrupt; use embassy_stm32f4::interrupt;
use embassy_stm32f4::serial; use embassy_stm32f4::serial;
use futures::pin_mut;
use stm32f4xx_hal::dma::StreamsTuple; use stm32f4xx_hal::dma::StreamsTuple;
use stm32f4xx_hal::prelude::*; use stm32f4xx_hal::prelude::*;
use stm32f4xx_hal::serial::config::Config; use stm32f4xx_hal::serial::config::Config;
@ -76,10 +77,12 @@ async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) {
clocks, clocks,
) )
}; };
pin_mut!(serial);
let buf = singleton!(: [u8; 30] = [0; 30]).unwrap(); let buf = singleton!(: [u8; 30] = [0; 30]).unwrap();
buf[5] = 0x01; buf[5] = 0x01;
serial.send(buf).await.unwrap(); serial.write(buf).await.unwrap();
} }
static EXECUTOR: Forever<Executor> = Forever::new(); static EXECUTOR: Forever<Executor> = Forever::new();

View File

@ -1,17 +1,12 @@
//! Async low power Serial. //! Async 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()`).
use core::future::Future; use core::future::Future;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::pin::Pin;
use futures::{select_biased, FutureExt};
use embassy::interrupt::Interrupt; use embassy::interrupt::Interrupt;
use embassy::traits::uart::{Error, IdleUart, Uart}; use embassy::traits::uart::{Error, Read, ReadUntilIdle, Write};
use embassy::util::InterruptFuture; use embassy::util::InterruptFuture;
use futures::{select_biased, FutureExt};
use crate::hal::{ use crate::hal::{
dma, dma,
@ -89,7 +84,7 @@ where
} }
} }
impl<USART, TSTREAM, RSTREAM, CHANNEL> Uart for Serial<USART, TSTREAM, RSTREAM, CHANNEL> impl<USART, TSTREAM, RSTREAM, CHANNEL> Read for Serial<USART, TSTREAM, RSTREAM, CHANNEL>
where where
USART: serial::Instance USART: serial::Instance
+ PeriAddress<MemSize = u8> + PeriAddress<MemSize = u8>
@ -101,56 +96,19 @@ where
RSTREAM: Stream + WithInterrupt + 'static, RSTREAM: Stream + WithInterrupt + 'static,
CHANNEL: Channel + 'static, CHANNEL: Channel + 'static,
{ {
type SendFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; type ReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
type ReceiveFuture<'a> = impl Future<Output = Result<(), Error>> + '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(())
}
}
/// Receives serial data. /// Receives serial data.
/// ///
/// The future is pending until the buffer is completely filled. /// The future is pending until the buffer is completely filled.
/// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel fn read<'a>(self: Pin<&'a mut Self>, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
/// unfinished transfers after a timeout to prevent lockup when no more data let this = unsafe { self.get_unchecked_mut() };
/// is incoming.
fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a> {
let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) }; 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 { async move {
let rx_stream = this.rx_stream.take().unwrap();
let usart = this.usart.take().unwrap();
let mut rx_transfer = Transfer::init( let mut rx_transfer = Transfer::init(
rx_stream, rx_stream,
usart, usart,
@ -162,20 +120,20 @@ where
.double_buffer(false), .double_buffer(false),
); );
let fut = InterruptFuture::new(&mut self.rx_int); let fut = InterruptFuture::new(&mut this.rx_int);
rx_transfer.start(|_usart| {}); rx_transfer.start(|_usart| {});
fut.await; fut.await;
let (rx_stream, usart, _, _) = rx_transfer.free(); let (rx_stream, usart, _, _) = rx_transfer.free();
self.rx_stream.replace(rx_stream); this.rx_stream.replace(rx_stream);
self.usart.replace(usart); this.usart.replace(usart);
Ok(()) Ok(())
} }
} }
} }
impl<USART, TSTREAM, RSTREAM, CHANNEL> IdleUart for Serial<USART, TSTREAM, RSTREAM, CHANNEL> impl<USART, TSTREAM, RSTREAM, CHANNEL> Write for Serial<USART, TSTREAM, RSTREAM, CHANNEL>
where where
USART: serial::Instance USART: serial::Instance
+ PeriAddress<MemSize = u8> + PeriAddress<MemSize = u8>
@ -187,20 +145,74 @@ where
RSTREAM: Stream + WithInterrupt + 'static, RSTREAM: Stream + WithInterrupt + 'static,
CHANNEL: Channel + 'static, CHANNEL: Channel + 'static,
{ {
type ReceiveFuture<'a> = impl Future<Output = Result<usize, Error>> + 'a; type WriteFuture<'a> = impl Future<Output = Result<(), Error>> + '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<USART, TSTREAM, RSTREAM, CHANNEL> ReadUntilIdle for Serial<USART, TSTREAM, RSTREAM, CHANNEL>
where
USART: serial::Instance
+ PeriAddress<MemSize = u8>
+ DMASet<TSTREAM, CHANNEL, MemoryToPeripheral>
+ DMASet<RSTREAM, CHANNEL, PeripheralToMemory>
+ WithInterrupt
+ 'static,
TSTREAM: Stream + WithInterrupt + 'static,
RSTREAM: Stream + WithInterrupt + 'static,
CHANNEL: Channel + 'static,
{
type ReadUntilIdleFuture<'a> = impl Future<Output = Result<usize, Error>> + 'a;
/// Receives serial data. /// Receives serial data.
/// ///
/// The future is pending until either the buffer is completely full, or the RX line falls idle after receiving some 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. /// 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 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 { async move {
let rx_stream = this.rx_stream.take().unwrap();
let usart = this.usart.take().unwrap();
unsafe { unsafe {
/* __HAL_UART_ENABLE_IT(&uart->UartHandle, UART_IT_IDLE); */ /* __HAL_UART_ENABLE_IT(&uart->UartHandle, UART_IT_IDLE); */
(*USART::ptr()).cr1.modify(|_, w| w.idleie().set_bit()); (*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 total_bytes = RSTREAM::get_number_of_transfers() as usize;
let fut = InterruptFuture::new(&mut self.rx_int); let fut = InterruptFuture::new(&mut this.rx_int);
let fut_idle = InterruptFuture::new(&mut self.usart_int); let fut_idle = InterruptFuture::new(&mut this.usart_int);
rx_transfer.start(|_usart| {}); rx_transfer.start(|_usart| {});
select_biased! { futures::future::select(fut, fut_idle).await;
() = fut.fuse() => {},
() = fut_idle.fuse() => {},
}
let (rx_stream, usart, _, _) = rx_transfer.free(); let (rx_stream, usart, _, _) = rx_transfer.free();
@ -240,8 +249,8 @@ where
unsafe { unsafe {
(*USART::ptr()).cr1.modify(|_, w| w.idleie().clear_bit()); (*USART::ptr()).cr1.modify(|_, w| w.idleie().clear_bit());
} }
self.rx_stream.replace(rx_stream); this.rx_stream.replace(rx_stream);
self.usart.replace(usart); this.usart.replace(usart);
Ok(total_bytes - remaining_bytes) Ok(total_bytes - remaining_bytes)
} }

View File

@ -11,9 +11,17 @@ pub enum Error {
} }
pub trait Flash { pub trait Flash {
type ReadFuture<'a>: Future<Output = Result<(), Error>>; type ReadFuture<'a>: Future<Output = Result<(), Error>>
type WriteFuture<'a>: Future<Output = Result<(), Error>>; where
type ErasePageFuture<'a>: Future<Output = Result<(), Error>>; Self: 'a;
type WriteFuture<'a>: Future<Output = Result<(), Error>>
where
Self: 'a;
type ErasePageFuture<'a>: Future<Output = Result<(), Error>>
where
Self: 'a;
/// Reads data from the flash device. /// Reads data from the flash device.
/// ///

View File

@ -1,4 +1,5 @@
use core::future::Future; use core::future::Future;
use core::pin::Pin;
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -7,18 +8,31 @@ pub enum Error {
Other, Other,
} }
pub trait Uart { pub trait Read {
type ReceiveFuture<'a>: Future<Output = Result<(), Error>>; type ReadFuture<'a>: Future<Output = Result<(), Error>>
type SendFuture<'a>: Future<Output = Result<(), Error>>; where
/// Receive into the buffer until the buffer is full Self: 'a;
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 read<'a>(self: Pin<&'a mut Self>, buf: &'a mut [u8]) -> Self::ReadFuture<'a>;
fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a>;
} }
pub trait IdleUart { pub trait ReadUntilIdle {
type ReceiveFuture<'a>: Future<Output = Result<usize, Error>>; type ReadUntilIdleFuture<'a>: Future<Output = Result<usize, Error>>
where
Self: 'a;
/// Receive into the buffer until the buffer is full or the line is idle after some bytes are received /// 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 /// 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<Output = Result<(), Error>>
where
Self: 'a;
fn write<'a>(self: Pin<&'a mut Self>, buf: &'a [u8]) -> Self::WriteFuture<'a>;
} }

View File

@ -4,9 +4,9 @@ use core::cmp::min;
use core::future::Future; use core::future::Future;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::pin::Pin; use core::pin::Pin;
use core::ptr;
use core::ptr::NonNull; use core::ptr::NonNull;
use core::task::{Context, Poll, Waker}; use core::task::{Context, Poll, Waker};
use core::{mem, ptr};
use super::run_queue::{RunQueue, RunQueueItem}; use super::run_queue::{RunQueue, RunQueueItem};
use super::timer_queue::{TimerQueue, TimerQueueItem}; use super::timer_queue::{TimerQueue, TimerQueueItem};
@ -143,6 +143,10 @@ impl<F: Future + 'static> Task<F> {
} }
Poll::Pending => {} 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);
} }
} }

View File

@ -1,7 +1,7 @@
use core::ptr; use core::ptr;
use cortex_m::peripheral::NVIC; 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_declare as declare;
pub use embassy_macros::interrupt_take as take; pub use embassy_macros::interrupt_take as take;
@ -58,22 +58,27 @@ pub trait InterruptExt: Interrupt {
impl<T: Interrupt + ?Sized> InterruptExt for T { impl<T: Interrupt + ?Sized> InterruptExt for T {
fn set_handler(&self, func: unsafe fn(*mut ())) { fn set_handler(&self, func: unsafe fn(*mut ())) {
compiler_fence(Ordering::SeqCst);
let handler = unsafe { self.__handler() }; 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) { fn remove_handler(&self) {
compiler_fence(Ordering::SeqCst);
let handler = unsafe { self.__handler() }; 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 ()) { fn set_handler_context(&self, ctx: *mut ()) {
let handler = unsafe { self.__handler() }; let handler = unsafe { self.__handler() };
handler.ctx.store(ctx, Ordering::Release); handler.ctx.store(ctx, Ordering::Relaxed);
} }
#[inline] #[inline]
fn enable(&self) { fn enable(&self) {
compiler_fence(Ordering::SeqCst);
unsafe { unsafe {
NVIC::unmask(NrWrap(self.number())); NVIC::unmask(NrWrap(self.number()));
} }
@ -82,6 +87,7 @@ impl<T: Interrupt + ?Sized> InterruptExt for T {
#[inline] #[inline]
fn disable(&self) { fn disable(&self) {
NVIC::mask(NrWrap(self.number())); NVIC::mask(NrWrap(self.number()));
compiler_fence(Ordering::SeqCst);
} }
#[inline] #[inline]

View File

@ -31,6 +31,7 @@ unsafe impl<T> Send for Forever<T> {}
unsafe impl<T> Sync for Forever<T> {} unsafe impl<T> Sync for Forever<T> {}
impl<T> Forever<T> { impl<T> Forever<T> {
#[inline(always)]
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
used: AtomicBool::new(false), used: AtomicBool::new(false),
@ -43,10 +44,11 @@ impl<T> Forever<T> {
/// Panics if this `Forever` already has a value. /// Panics if this `Forever` already has a value.
/// ///
/// Returns a mutable reference to the stored value. /// Returns a mutable reference to the stored value.
#[inline(always)]
pub fn put(&'static self, val: T) -> &'static mut T { pub fn put(&'static self, val: T) -> &'static mut T {
if self if self
.used .used
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_err() .is_err()
{ {
panic!("Forever.put() called multiple times"); panic!("Forever.put() called multiple times");
@ -60,6 +62,25 @@ impl<T> Forever<T> {
} }
} }
#[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 { pub unsafe fn steal(&'static self) -> &'static mut T {
let p = self.t.get(); let p = self.t.get();
let p = (&mut *p).as_mut_ptr(); let p = (&mut *p).as_mut_ptr();

View File

@ -2,6 +2,7 @@
mod drop_bomb; mod drop_bomb;
mod forever; mod forever;
mod mutex; mod mutex;
mod on_drop;
mod portal; mod portal;
mod signal; mod signal;
@ -11,6 +12,16 @@ mod waker;
pub use drop_bomb::*; pub use drop_bomb::*;
pub use forever::*; pub use forever::*;
pub use mutex::*; pub use mutex::*;
pub use on_drop::*;
pub use portal::*; pub use portal::*;
pub use signal::*; pub use signal::*;
pub use waker::*; pub use waker::*;
pub trait PeripheralBorrow {
type Target;
unsafe fn unborrow(self) -> Self::Target;
}
pub trait Steal {
unsafe fn steal() -> Self;
}

View File

@ -0,0 +1,24 @@
use core::mem;
use core::mem::MaybeUninit;
pub struct OnDrop<F: FnOnce()> {
f: MaybeUninit<F>,
}
impl<F: FnOnce()> OnDrop<F> {
pub fn new(f: F) -> Self {
Self {
f: MaybeUninit::new(f),
}
}
pub fn defuse(self) {
mem::forget(self)
}
}
impl<F: FnOnce()> Drop for OnDrop<F> {
fn drop(&mut self) {
unsafe { self.f.as_ptr().read()() }
}
}

View File

@ -5,6 +5,8 @@ use core::ptr;
use core::task::{Context, Poll, Waker}; use core::task::{Context, Poll, Waker};
use cortex_m::peripheral::NVIC; use cortex_m::peripheral::NVIC;
use cortex_m::peripheral::{scb, SCB}; use cortex_m::peripheral::{scb, SCB};
use executor::raw::TaskHeader;
use ptr::NonNull;
use crate::executor; use crate::executor;
use crate::fmt::panic; use crate::fmt::panic;
@ -79,6 +81,30 @@ impl<T: Send> Signal<T> {
} }
} }
// ==========
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); struct NrWrap(u8);
unsafe impl cortex_m::interrupt::Nr for NrWrap { unsafe impl cortex_m::interrupt::Nr for NrWrap {
fn nr(&self) -> u8 { fn nr(&self) -> u8 {
@ -119,26 +145,13 @@ impl<'a, I: Interrupt> Drop for InterruptFuture<'a, I> {
impl<'a, I: Interrupt> InterruptFuture<'a, I> { impl<'a, I: Interrupt> InterruptFuture<'a, I> {
pub fn new(interrupt: &'a mut I) -> Self { pub fn new(interrupt: &'a mut I) -> Self {
interrupt.disable(); interrupt.disable();
interrupt.set_handler(Self::interrupt_handler); interrupt.set_handler(irq_wake_handler);
interrupt.set_handler_context(ptr::null_mut()); interrupt.set_handler_context(ptr::null_mut());
interrupt.unpend(); interrupt.unpend();
interrupt.enable(); interrupt.enable();
Self { interrupt } 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> {} 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<()> { fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
let s = unsafe { self.get_unchecked_mut() }; let s = unsafe { self.get_unchecked_mut() };
s.interrupt.set_handler(Self::interrupt_handler);
s.interrupt.set_handler_context(unsafe { s.interrupt.set_handler_context(unsafe {
executor::raw::task_from_waker(&cx.waker()).cast().as_ptr() executor::raw::task_from_waker(&cx.waker()).cast().as_ptr()
}); });

View File

@ -1,7 +1,7 @@
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
use core::task::Waker; 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}; use crate::executor::raw::{task_from_waker, wake_task, TaskHeader};
@ -48,11 +48,11 @@ impl WakerRegistration {
} }
} }
pub struct AtomicWakerRegistration { pub struct AtomicWaker {
waker: AtomicPtr<TaskHeader>, waker: AtomicPtr<TaskHeader>,
} }
impl AtomicWakerRegistration { impl AtomicWaker {
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
waker: AtomicPtr::new(ptr::null_mut()), waker: AtomicPtr::new(ptr::null_mut()),
@ -62,17 +62,15 @@ impl AtomicWakerRegistration {
/// Register a waker. Overwrites the previous waker, if any. /// Register a waker. Overwrites the previous waker, if any.
pub fn register(&self, w: &Waker) { pub fn register(&self, w: &Waker) {
let w = unsafe { task_from_waker(w) }; let w = unsafe { task_from_waker(w) };
let w2 = self.waker.swap(w.as_ptr(), Ordering::Relaxed); self.waker.store(w.as_ptr(), Ordering::Relaxed);
if !w2.is_null() && w2 != w.as_ptr() { compiler_fence(Ordering::SeqCst);
unsafe { wake_task(NonNull::new_unchecked(w2)) };
}
} }
/// Wake the registered waker, if any. /// Wake the registered waker, if any.
pub fn wake(&self) { pub fn wake(&self) {
let w2 = self.waker.swap(ptr::null_mut(), Ordering::Relaxed); let w2 = self.waker.load(Ordering::Relaxed);
if !w2.is_null() { if let Some(w2) = NonNull::new(w2) {
unsafe { wake_task(NonNull::new_unchecked(w2)) }; unsafe { wake_task(w2) };
} }
} }
} }

View File

@ -49,11 +49,11 @@ impl WakerRegistration {
} }
/// Utility struct to register and wake a waker. /// Utility struct to register and wake a waker.
pub struct AtomicWakerRegistration { pub struct AtomicWaker {
waker: Mutex<Cell<Option<Waker>>>, waker: Mutex<Cell<Option<Waker>>>,
} }
impl AtomicWakerRegistration { impl AtomicWaker {
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
waker: Mutex::new(Cell::new(None)), waker: Mutex::new(Cell::new(None)),
@ -66,11 +66,7 @@ impl AtomicWakerRegistration {
let cell = self.waker.borrow(cs); let cell = self.waker.borrow(cs);
cell.set(match cell.replace(None) { cell.set(match cell.replace(None) {
Some(w2) if (w2.will_wake(w)) => Some(w2), Some(w2) if (w2.will_wake(w)) => Some(w2),
Some(w2) => { _ => Some(w.clone()),
w2.wake();
Some(w.clone())
}
None => Some(w.clone()),
}) })
}) })
} }
@ -80,7 +76,8 @@ impl AtomicWakerRegistration {
cortex_m::interrupt::free(|cs| { cortex_m::interrupt::free(|cs| {
let cell = self.waker.borrow(cs); let cell = self.waker.borrow(cs);
if let Some(w) = cell.replace(None) { if let Some(w) = cell.replace(None) {
w.wake() w.wake_by_ref();
cell.set(Some(w));
} }
}) })
} }