Merge pull request #91 from embassy-rs/borrow-v3
nrf: New API supporting borrowed peripherals
This commit is contained in:
commit
af6d708c93
@ -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;
|
||||||
|
|
||||||
|
107
embassy-extras/src/macros.rs
Normal file
107
embassy-extras/src/macros.rs
Normal 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) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -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
|
||||||
|
63
embassy-extras/src/peripheral_shared.rs
Normal file
63
embassy-extras/src/peripheral_shared.rs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
|
||||||
|
@ -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"] }
|
@ -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()));
|
||||||
});
|
});
|
||||||
|
@ -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());
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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) };
|
||||||
|
111
embassy-nrf-examples/src/bin/ppi.rs
Normal file
111
embassy-nrf-examples/src/bin/ppi.rs
Normal 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()));
|
||||||
|
});
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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());
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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) };
|
||||||
|
|
||||||
|
@ -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());
|
@ -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()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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::*;
|
||||||
|
@ -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 }
|
|
||||||
|
@ -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
447
embassy-nrf/src/gpio.rs
Normal 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);
|
||||||
|
}
|
@ -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);
|
||||||
|
@ -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
255
embassy-nrf/src/ppi.rs
Normal 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);
|
@ -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);
|
||||||
|
@ -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
242
embassy-nrf/src/saadc.rs
Normal 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,
|
||||||
|
}
|
@ -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
76
embassy-nrf/src/system.rs
Normal 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
43
embassy-nrf/src/timer.rs
Normal 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);
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
///
|
///
|
||||||
|
@ -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>;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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]
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
24
embassy/src/util/on_drop.rs
Normal file
24
embassy/src/util/on_drop.rs
Normal 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()() }
|
||||||
|
}
|
||||||
|
}
|
@ -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()
|
||||||
});
|
});
|
||||||
|
@ -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) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user