Merge branch 'master' into spi-trait
This commit is contained in:
commit
5bd705caa5
@ -45,7 +45,7 @@ GPIO pins are set up for the `nrf52840-dk` board (PCA10056)
|
|||||||
- Install `probe-run` with defmt support.
|
- Install `probe-run` with defmt support.
|
||||||
|
|
||||||
```
|
```
|
||||||
cargo install --git https://github.com/knurling-rs/probe-run --branch main --features defmt
|
cargo install probe-run
|
||||||
```
|
```
|
||||||
|
|
||||||
- Run the example
|
- Run the example
|
||||||
|
@ -157,17 +157,17 @@ pub fn interrupt_take(item: TokenStream) -> TokenStream {
|
|||||||
static HANDLER: ::embassy::interrupt::Handler;
|
static HANDLER: ::embassy::interrupt::Handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
let func = HANDLER.func.load(::embassy::atomic::Ordering::Acquire);
|
let func = HANDLER.func.load(::embassy::export::atomic::Ordering::Acquire);
|
||||||
let ctx = HANDLER.ctx.load(::embassy::atomic::Ordering::Acquire);
|
let ctx = HANDLER.ctx.load(::embassy::export::atomic::Ordering::Acquire);
|
||||||
if !func.is_null() {
|
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::atomic::AtomicBool = ::embassy::atomic::AtomicBool::new(false);
|
static TAKEN: ::embassy::export::atomic::AtomicBool = ::embassy::export::atomic::AtomicBool::new(false);
|
||||||
|
|
||||||
if TAKEN.compare_exchange(false, true, ::embassy::atomic::Ordering::AcqRel, ::embassy::atomic::Ordering::Acquire).is_err() {
|
if TAKEN.compare_exchange(false, true, ::embassy::export::atomic::Ordering::AcqRel, ::embassy::export::atomic::Ordering::Acquire).is_err() {
|
||||||
panic!("IRQ Already taken");
|
panic!("IRQ Already taken");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -55,6 +55,8 @@
|
|||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(generic_associated_types)]
|
#![feature(generic_associated_types)]
|
||||||
#![feature(asm)]
|
#![feature(asm)]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../serial_port.rs"]
|
#[path = "../serial_port.rs"]
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
use embassy::executor::task;
|
use embassy::executor::task;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(trait_alias)]
|
#![feature(trait_alias)]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(trait_alias)]
|
#![feature(trait_alias)]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(trait_alias)]
|
#![feature(trait_alias)]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
|
@ -10,6 +10,7 @@ use crate::hal::gpio;
|
|||||||
use crate::hal::gpio::{Edge, ExtiPin as HalExtiPin};
|
use crate::hal::gpio::{Edge, ExtiPin as HalExtiPin};
|
||||||
use crate::hal::syscfg::SysCfg;
|
use crate::hal::syscfg::SysCfg;
|
||||||
use crate::pac::EXTI;
|
use crate::pac::EXTI;
|
||||||
|
use embedded_hal::digital::v2 as digital;
|
||||||
|
|
||||||
use crate::interrupt;
|
use crate::interrupt;
|
||||||
|
|
||||||
@ -42,6 +43,52 @@ pub struct ExtiPin<T: HalExtiPin + WithInterrupt> {
|
|||||||
_mgr: &'static ExtiManager,
|
_mgr: &'static ExtiManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: HalExtiPin + WithInterrupt + digital::OutputPin> digital::OutputPin for ExtiPin<T> {
|
||||||
|
type Error = T::Error;
|
||||||
|
|
||||||
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self.pin.set_low()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self.pin.set_high()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: HalExtiPin + WithInterrupt + digital::StatefulOutputPin> digital::StatefulOutputPin
|
||||||
|
for ExtiPin<T>
|
||||||
|
{
|
||||||
|
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
self.pin.is_set_low()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
self.pin.is_set_high()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: HalExtiPin + WithInterrupt + digital::ToggleableOutputPin> digital::ToggleableOutputPin
|
||||||
|
for ExtiPin<T>
|
||||||
|
{
|
||||||
|
type Error = T::Error;
|
||||||
|
|
||||||
|
fn toggle(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self.pin.toggle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: HalExtiPin + WithInterrupt + digital::InputPin> digital::InputPin for ExtiPin<T> {
|
||||||
|
type Error = T::Error;
|
||||||
|
|
||||||
|
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
self.pin.is_high()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
self.pin.is_low()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Irq Handler Description
|
Irq Handler Description
|
||||||
EXTI0_IRQn EXTI0_IRQHandler Handler for pins connected to line 0
|
EXTI0_IRQn EXTI0_IRQHandler Handler for pins connected to line 0
|
||||||
@ -482,7 +529,7 @@ exti!(gpioj, [
|
|||||||
feature = "stm32f469",
|
feature = "stm32f469",
|
||||||
feature = "stm32f479"
|
feature = "stm32f479"
|
||||||
))]
|
))]
|
||||||
exti!(gpioj, [
|
exti!(gpiok, [
|
||||||
EXTI0 => PK0,
|
EXTI0 => PK0,
|
||||||
EXTI1 => PK1,
|
EXTI1 => PK1,
|
||||||
EXTI2 => PK2,
|
EXTI2 => PK2,
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(generic_associated_types)]
|
#![feature(generic_associated_types)]
|
||||||
#![feature(asm)]
|
#![feature(asm)]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
@ -313,5 +315,6 @@ pub(crate) mod fmt;
|
|||||||
|
|
||||||
pub mod exti;
|
pub mod exti;
|
||||||
pub mod interrupt;
|
pub mod interrupt;
|
||||||
|
pub mod qei;
|
||||||
pub mod rtc;
|
pub mod rtc;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
|
95
embassy-stm32f4/src/qei.rs
Normal file
95
embassy-stm32f4/src/qei.rs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
use crate::interrupt;
|
||||||
|
use core::future::Future;
|
||||||
|
use core::pin::Pin;
|
||||||
|
use embassy::interrupt::Interrupt;
|
||||||
|
use embassy::traits::qei::WaitForRotate;
|
||||||
|
use embedded_hal::Direction;
|
||||||
|
use embedded_hal::Qei as THQei;
|
||||||
|
use stm32f4xx_hal::pac::TIM2;
|
||||||
|
use stm32f4xx_hal::qei::{Pins, Qei as HalQei};
|
||||||
|
|
||||||
|
pub struct Qei<T: Instance, PINS> {
|
||||||
|
qei: HalQei<T, PINS>,
|
||||||
|
int: T::Interrupt,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<PINS: Pins<TIM2>> Qei<TIM2, PINS> {
|
||||||
|
pub fn tim2(tim: TIM2, pins: PINS, interrupt: interrupt::TIM2) -> Self {
|
||||||
|
let qei = HalQei::tim2(tim, pins);
|
||||||
|
|
||||||
|
let tim = unsafe {
|
||||||
|
&mut *(stm32f4xx_hal::stm32::TIM2::ptr()
|
||||||
|
as *mut stm32f4xx_hal::stm32::tim2::RegisterBlock)
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
enable qei interrupt
|
||||||
|
*/
|
||||||
|
tim.dier.write(|w| w.uie().set_bit());
|
||||||
|
|
||||||
|
Qei {
|
||||||
|
qei: qei,
|
||||||
|
int: interrupt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<PINS: Pins<TIM2> + 'static> WaitForRotate for Qei<TIM2, PINS> {
|
||||||
|
type RotateFuture<'a> = impl Future<Output = Direction> + 'a;
|
||||||
|
|
||||||
|
fn wait_for_rotate<'a>(
|
||||||
|
self: Pin<&'a mut Self>,
|
||||||
|
count_down: u16,
|
||||||
|
count_up: u16,
|
||||||
|
) -> Self::RotateFuture<'a> {
|
||||||
|
let s = unsafe { self.get_unchecked_mut() };
|
||||||
|
|
||||||
|
let tim = unsafe {
|
||||||
|
&mut *(stm32f4xx_hal::stm32::TIM2::ptr()
|
||||||
|
as *mut stm32f4xx_hal::stm32::tim2::RegisterBlock)
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
the interrupt will be reached at zero or the max count
|
||||||
|
write the total range to the qei.
|
||||||
|
*/
|
||||||
|
tim.arr
|
||||||
|
.write(|w| unsafe { w.bits((count_down + count_up) as u32) });
|
||||||
|
|
||||||
|
/*
|
||||||
|
set timer to the correct value in the range
|
||||||
|
*/
|
||||||
|
tim.cnt.write(|w| unsafe { w.bits(count_down as u32) });
|
||||||
|
|
||||||
|
/*
|
||||||
|
clear interrupt flag
|
||||||
|
*/
|
||||||
|
tim.sr.write(|w| w.uif().clear_bit());
|
||||||
|
|
||||||
|
async move {
|
||||||
|
embassy::util::InterruptFuture::new(&mut s.int).await;
|
||||||
|
|
||||||
|
if tim.cnt.read().bits() == 0 {
|
||||||
|
Direction::Downcounting
|
||||||
|
} else if tim.cnt.read() == count_down + count_up {
|
||||||
|
Direction::Upcounting
|
||||||
|
} else {
|
||||||
|
panic!("unexpected value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod sealed {
|
||||||
|
pub trait Sealed {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Instance: sealed::Sealed {
|
||||||
|
type Interrupt: interrupt::Interrupt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "stm32f405")]
|
||||||
|
impl sealed::Sealed for TIM2 {}
|
||||||
|
#[cfg(feature = "stm32f405")]
|
||||||
|
impl Instance for TIM2 {
|
||||||
|
type Interrupt = interrupt::TIM2;
|
||||||
|
}
|
@ -9,3 +9,4 @@ std = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
defmt = { version = "0.2.0", optional = true }
|
defmt = { version = "0.2.0", optional = true }
|
||||||
|
embedded-hal = { version = "0.2.3", features = ["unproven"] }
|
||||||
|
@ -91,8 +91,7 @@ impl AddressMode for SevenBitAddress {}
|
|||||||
|
|
||||||
impl AddressMode for TenBitAddress {}
|
impl AddressMode for TenBitAddress {}
|
||||||
|
|
||||||
/// Blocking read
|
pub trait I2c<A: AddressMode = SevenBitAddress> {
|
||||||
pub trait Read<A: AddressMode = SevenBitAddress> {
|
|
||||||
/// Error type
|
/// Error type
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
|
@ -4,11 +4,14 @@
|
|||||||
#![feature(const_fn_fn_ptr_basics)]
|
#![feature(const_fn_fn_ptr_basics)]
|
||||||
#![feature(const_option)]
|
#![feature(const_option)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
pub mod delay;
|
pub mod delay;
|
||||||
pub mod flash;
|
pub mod flash;
|
||||||
pub mod gpio;
|
pub mod gpio;
|
||||||
pub mod i2c;
|
pub mod i2c;
|
||||||
|
pub mod qei;
|
||||||
pub mod spi;
|
pub mod spi;
|
||||||
pub mod uart;
|
pub mod uart;
|
||||||
|
22
embassy-traits/src/qei.rs
Normal file
22
embassy-traits/src/qei.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use core::future::Future;
|
||||||
|
use core::pin::Pin;
|
||||||
|
use embedded_hal::Direction;
|
||||||
|
|
||||||
|
// Wait for a specified number of rotations either up or down
|
||||||
|
pub trait WaitForRotate {
|
||||||
|
type RotateFuture<'a>: Future<Output = Direction> + 'a;
|
||||||
|
|
||||||
|
/// Wait for a specified number of rotations, in ticks, either up or down.
|
||||||
|
///
|
||||||
|
/// Return Direction::Upcounting if the high bound is reached.
|
||||||
|
/// Return Direction::Downcounting if the low bound is reached.
|
||||||
|
///
|
||||||
|
/// Number of ticks is encoder dependent. As an example, if we connect
|
||||||
|
/// the Bourns PEC11H-4120F-S0020, we have 20 ticks per full rotation.
|
||||||
|
/// Other encoders may vary.
|
||||||
|
fn wait_for_rotate<'a>(
|
||||||
|
self: Pin<&'a mut Self>,
|
||||||
|
count_down: u16,
|
||||||
|
count_up: u16,
|
||||||
|
) -> Self::RotateFuture<'a>;
|
||||||
|
}
|
@ -13,6 +13,8 @@ defmt-info = []
|
|||||||
defmt-warn = []
|
defmt-warn = []
|
||||||
defmt-error = []
|
defmt-error = []
|
||||||
|
|
||||||
|
executor-agnostic = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
defmt = { version = "0.2.0", optional = true }
|
defmt = { version = "0.2.0", optional = true }
|
||||||
log = { version = "0.4.11", optional = true }
|
log = { version = "0.4.11", optional = true }
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
pub use embassy_macros::task;
|
pub use embassy_macros::task;
|
||||||
|
|
||||||
|
use atomic_polyfill::Ordering;
|
||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
@ -15,7 +16,6 @@ mod util;
|
|||||||
mod waker;
|
mod waker;
|
||||||
|
|
||||||
use self::util::UninitCell;
|
use self::util::UninitCell;
|
||||||
use crate::atomic::Ordering;
|
|
||||||
use crate::fmt::panic;
|
use crate::fmt::panic;
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use crate::interrupt::{Interrupt, InterruptExt};
|
||||||
use crate::time::Alarm;
|
use crate::time::Alarm;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use atomic_polyfill::{AtomicU32, Ordering};
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
use core::cmp::min;
|
use core::cmp::min;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
@ -9,7 +10,6 @@ use super::run_queue::{RunQueue, RunQueueItem};
|
|||||||
use super::timer_queue::{TimerQueue, TimerQueueItem};
|
use super::timer_queue::{TimerQueue, TimerQueueItem};
|
||||||
use super::util::UninitCell;
|
use super::util::UninitCell;
|
||||||
use super::waker;
|
use super::waker;
|
||||||
use crate::atomic::{AtomicU32, Ordering};
|
|
||||||
use crate::time::{Alarm, Instant};
|
use crate::time::{Alarm, Instant};
|
||||||
|
|
||||||
/// Task is spawned (has a future)
|
/// Task is spawned (has a future)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
use atomic_polyfill::{AtomicPtr, Ordering};
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
use super::raw::Task;
|
use super::raw::Task;
|
||||||
use crate::atomic::{AtomicPtr, Ordering};
|
|
||||||
|
|
||||||
pub(crate) struct RunQueueItem {
|
pub(crate) struct RunQueueItem {
|
||||||
next: AtomicPtr<Task>,
|
next: AtomicPtr<Task>,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
|
use atomic_polyfill::{AtomicPtr, Ordering};
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
use core::cmp::min;
|
use core::cmp::min;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
use super::raw::{Task, STATE_TIMER_QUEUED};
|
use super::raw::{Task, STATE_TIMER_QUEUED};
|
||||||
use crate::atomic::{AtomicPtr, Ordering};
|
|
||||||
use crate::time::Instant;
|
use crate::time::Instant;
|
||||||
|
|
||||||
pub(crate) struct TimerQueueItem {
|
pub(crate) struct TimerQueueItem {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use core::ptr;
|
use core::ptr;
|
||||||
use cortex_m::peripheral::NVIC;
|
use cortex_m::peripheral::NVIC;
|
||||||
|
|
||||||
use crate::atomic::{AtomicBool, AtomicPtr, Ordering};
|
use atomic_polyfill::{AtomicBool, 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;
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#![feature(const_fn_fn_ptr_basics)]
|
#![feature(const_fn_fn_ptr_basics)]
|
||||||
#![feature(const_option)]
|
#![feature(const_option)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(min_type_alias_impl_trait)]
|
||||||
|
#![feature(impl_trait_in_bindings)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
// This mod MUST go first, so that the others see its macros.
|
// This mod MUST go first, so that the others see its macros.
|
||||||
@ -16,4 +18,9 @@ pub mod time;
|
|||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
pub use embassy_traits as traits;
|
pub use embassy_traits as traits;
|
||||||
pub use atomic_polyfill as atomic;
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
/// Implementation details for embassy macros. DO NOT USE.
|
||||||
|
pub mod export {
|
||||||
|
pub use atomic_polyfill as atomic;
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
use crate::atomic::{AtomicBool, Ordering};
|
use atomic_polyfill::{AtomicBool, Ordering};
|
||||||
|
|
||||||
pub struct Forever<T> {
|
pub struct Forever<T> {
|
||||||
used: AtomicBool,
|
used: AtomicBool,
|
||||||
|
@ -3,6 +3,8 @@ mod forever;
|
|||||||
mod mutex;
|
mod mutex;
|
||||||
mod portal;
|
mod portal;
|
||||||
mod signal;
|
mod signal;
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "executor-agnostic", path = "waker_agnostic.rs")]
|
||||||
mod waker;
|
mod waker;
|
||||||
|
|
||||||
pub use drop_bomb::*;
|
pub use drop_bomb::*;
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
use core::mem;
|
use core::ptr::{self, NonNull};
|
||||||
use core::task::Context;
|
|
||||||
use core::task::Waker;
|
use core::task::Waker;
|
||||||
|
|
||||||
|
use atomic_polyfill::{AtomicPtr, Ordering};
|
||||||
|
|
||||||
|
use crate::executor::raw::{task_from_waker, wake_task, Task};
|
||||||
|
|
||||||
/// Utility struct to register and wake a waker.
|
/// Utility struct to register and wake a waker.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WakerRegistration {
|
pub struct WakerRegistration {
|
||||||
waker: Option<Waker>,
|
waker: Option<NonNull<Task>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WakerRegistration {
|
impl WakerRegistration {
|
||||||
@ -15,37 +18,61 @@ impl WakerRegistration {
|
|||||||
|
|
||||||
/// Register a waker. Overwrites the previous waker, if any.
|
/// Register a waker. Overwrites the previous waker, if any.
|
||||||
pub fn register(&mut self, w: &Waker) {
|
pub fn register(&mut self, w: &Waker) {
|
||||||
|
let w = unsafe { task_from_waker(w) };
|
||||||
match self.waker {
|
match self.waker {
|
||||||
// Optimization: If both the old and new Wakers wake the same task, we can simply
|
// Optimization: If both the old and new Wakers wake the same task, do nothing.
|
||||||
// keep the old waker, skipping the clone. (In most executor implementations,
|
Some(w2) if w == w2 => {}
|
||||||
// cloning a waker is somewhat expensive, comparable to cloning an Arc).
|
Some(w2) => {
|
||||||
Some(ref w2) if (w2.will_wake(w)) => {}
|
// We had a waker registered for another task. Wake it, so the other task can
|
||||||
_ => {
|
// reregister itself if it's still interested.
|
||||||
// clone the new waker and store it
|
//
|
||||||
if let Some(old_waker) = mem::replace(&mut self.waker, Some(w.clone())) {
|
// If two tasks are waiting on the same thing concurrently, this will cause them
|
||||||
// We had a waker registered for another task. Wake it, so the other task can
|
// to wake each other in a loop fighting over this WakerRegistration. This wastes
|
||||||
// reregister itself if it's still interested.
|
// CPU but things will still work.
|
||||||
//
|
//
|
||||||
// If two tasks are waiting on the same thing concurrently, this will cause them
|
// If the user wants to have two tasks waiting on the same thing they should use
|
||||||
// to wake each other in a loop fighting over this WakerRegistration. This wastes
|
// a more appropriate primitive that can store multiple wakers.
|
||||||
// CPU but things will still work.
|
|
||||||
//
|
unsafe { wake_task(w2) }
|
||||||
// If the user wants to have two tasks waiting on the same thing they should use
|
self.waker = Some(w);
|
||||||
// a more appropriate primitive that can store multiple wakers.
|
|
||||||
old_waker.wake()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
None => self.waker = Some(w),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wake the registered waker, if any.
|
/// Wake the registered waker, if any.
|
||||||
pub fn wake(&mut self) {
|
pub fn wake(&mut self) {
|
||||||
if let Some(w) = self.waker.take() {
|
if let Some(w) = self.waker.take() {
|
||||||
w.wake()
|
unsafe { wake_task(w) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AtomicWakerRegistration {
|
||||||
|
waker: AtomicPtr<Task>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AtomicWakerRegistration {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
waker: AtomicPtr::new(ptr::null_mut()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn context(&self) -> Option<Context<'_>> {
|
/// Register a waker. Overwrites the previous waker, if any.
|
||||||
self.waker.as_ref().map(|w| Context::from_waker(w))
|
pub fn register(&self, w: &Waker) {
|
||||||
|
let w = unsafe { task_from_waker(w) };
|
||||||
|
let w2 = self.waker.swap(w.as_ptr(), Ordering::Relaxed);
|
||||||
|
if !w2.is_null() && w2 != w.as_ptr() {
|
||||||
|
unsafe { wake_task(NonNull::new_unchecked(w2)) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wake the registered waker, if any.
|
||||||
|
pub fn wake(&self) {
|
||||||
|
let w2 = self.waker.swap(ptr::null_mut(), Ordering::Relaxed);
|
||||||
|
if !w2.is_null() {
|
||||||
|
unsafe { wake_task(NonNull::new_unchecked(w2)) };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
87
embassy/src/util/waker_agnostic.rs
Normal file
87
embassy/src/util/waker_agnostic.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
use core::cell::Cell;
|
||||||
|
use core::mem;
|
||||||
|
use core::task::Waker;
|
||||||
|
|
||||||
|
use cortex_m::interrupt::Mutex;
|
||||||
|
|
||||||
|
/// Utility struct to register and wake a waker.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WakerRegistration {
|
||||||
|
waker: Option<Waker>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WakerRegistration {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self { waker: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a waker. Overwrites the previous waker, if any.
|
||||||
|
pub fn register(&mut self, w: &Waker) {
|
||||||
|
match self.waker {
|
||||||
|
// Optimization: If both the old and new Wakers wake the same task, we can simply
|
||||||
|
// keep the old waker, skipping the clone. (In most executor implementations,
|
||||||
|
// cloning a waker is somewhat expensive, comparable to cloning an Arc).
|
||||||
|
Some(ref w2) if (w2.will_wake(w)) => {}
|
||||||
|
_ => {
|
||||||
|
// clone the new waker and store it
|
||||||
|
if let Some(old_waker) = mem::replace(&mut self.waker, Some(w.clone())) {
|
||||||
|
// We had a waker registered for another task. Wake it, so the other task can
|
||||||
|
// reregister itself if it's still interested.
|
||||||
|
//
|
||||||
|
// If two tasks are waiting on the same thing concurrently, this will cause them
|
||||||
|
// to wake each other in a loop fighting over this WakerRegistration. This wastes
|
||||||
|
// CPU but things will still work.
|
||||||
|
//
|
||||||
|
// If the user wants to have two tasks waiting on the same thing they should use
|
||||||
|
// a more appropriate primitive that can store multiple wakers.
|
||||||
|
old_waker.wake()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wake the registered waker, if any.
|
||||||
|
pub fn wake(&mut self) {
|
||||||
|
if let Some(w) = self.waker.take() {
|
||||||
|
w.wake()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility struct to register and wake a waker.
|
||||||
|
pub struct AtomicWakerRegistration {
|
||||||
|
waker: Mutex<Cell<Option<Waker>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AtomicWakerRegistration {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
waker: Mutex::new(Cell::new(None)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a waker. Overwrites the previous waker, if any.
|
||||||
|
pub fn register(&mut self, w: &Waker) {
|
||||||
|
cortex_m::interrupt::free(|cs| {
|
||||||
|
let cell = self.waker.borrow(cs);
|
||||||
|
cell.set(match cell.replace(None) {
|
||||||
|
Some(w2) if (w2.will_wake(w)) => Some(w2),
|
||||||
|
Some(w2) => {
|
||||||
|
w2.wake();
|
||||||
|
Some(w.clone())
|
||||||
|
}
|
||||||
|
None => Some(w.clone()),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wake the registered waker, if any.
|
||||||
|
pub fn wake(&mut self) {
|
||||||
|
cortex_m::interrupt::free(|cs| {
|
||||||
|
let cell = self.waker.borrow(cs);
|
||||||
|
if let Some(w) = cell.replace(None) {
|
||||||
|
w.wake()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user