Merge branch 'master' of https://github.com/akiles/embassy into st-usb
This commit is contained in:
commit
3242990690
3
.github/workflows/rust.yml
vendored
3
.github/workflows/rust.yml
vendored
@ -52,6 +52,9 @@ jobs:
|
|||||||
- package: embassy-stm32f4
|
- package: embassy-stm32f4
|
||||||
target: thumbv7em-none-eabi
|
target: thumbv7em-none-eabi
|
||||||
features: stm32f405
|
features: stm32f405
|
||||||
|
- package: embassy-stm32f4
|
||||||
|
target: thumbv7em-none-eabi
|
||||||
|
features: stm32f446
|
||||||
- package: embassy-stm32f4
|
- package: embassy-stm32f4
|
||||||
target: thumbv7em-none-eabi
|
target: thumbv7em-none-eabi
|
||||||
features: stm32f405,defmt
|
features: stm32f405,defmt
|
||||||
|
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"rust-analyzer.assist.importMergeBehavior": "last",
|
"rust-analyzer.assist.importMergeBehavior": "last",
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
|
"rust.target": "thumbv7em-none-eabihf",
|
||||||
"rust-analyzer.cargo.allFeatures": false,
|
"rust-analyzer.cargo.allFeatures": false,
|
||||||
"rust-analyzer.checkOnSave.allFeatures": false,
|
"rust-analyzer.checkOnSave.allFeatures": false,
|
||||||
"rust-analyzer.checkOnSave.allTargets": false,
|
"rust-analyzer.checkOnSave.allTargets": false,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Embassy
|
# Embassy
|
||||||
|
|
||||||
Embassy is a project to make async/await a first-class option for embedded development.
|
Embassy is a project to make async/await a first-class option for embedded development. For more information and instructions to
|
||||||
|
get started, click [here](https://github.com/embassy-rs/embassy/wiki).
|
||||||
|
|
||||||
## Traits and types
|
## Traits and types
|
||||||
|
|
||||||
|
@ -43,5 +43,7 @@ cortex-m-rt = "0.6.13"
|
|||||||
cortex-m = "0.7.1"
|
cortex-m = "0.7.1"
|
||||||
embedded-hal = { version = "0.2.4" }
|
embedded-hal = { version = "0.2.4" }
|
||||||
embedded-dma = { version = "0.1.2" }
|
embedded-dma = { version = "0.1.2" }
|
||||||
|
bxcan = "0.5.0"
|
||||||
|
nb = "*"
|
||||||
stm32f4xx-hal = { version = "0.8.3", features = ["rt", "can"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git", optional = true }
|
stm32f4xx-hal = { version = "0.8.3", features = ["rt", "can"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git", optional = true }
|
||||||
stm32l0xx-hal = { version = "0.7.0", features = ["rt"], git = "https://github.com/stm32-rs/stm32l0xx-hal.git", optional = true }
|
stm32l0xx-hal = { version = "0.7.0", features = ["rt"], optional = true }
|
@ -95,6 +95,25 @@ macro_rules! can {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "stm32f401",
|
||||||
|
feature = "stm32f405",
|
||||||
|
feature = "stm32f407",
|
||||||
|
feature = "stm32f410",
|
||||||
|
feature = "stm32f411",
|
||||||
|
feature = "stm32f412",
|
||||||
|
feature = "stm32f413",
|
||||||
|
feature = "stm32f415",
|
||||||
|
feature = "stm32f417",
|
||||||
|
feature = "stm32f423",
|
||||||
|
feature = "stm32f427",
|
||||||
|
feature = "stm32f429",
|
||||||
|
feature = "stm32f437",
|
||||||
|
feature = "stm32f439",
|
||||||
|
feature = "stm32f446",
|
||||||
|
feature = "stm32f469",
|
||||||
|
feature = "stm32f479",
|
||||||
|
))]
|
||||||
can! {
|
can! {
|
||||||
CAN1 => (CAN1_TX, CAN1_RX0),
|
CAN1 => (CAN1_TX, CAN1_RX0),
|
||||||
CAN2 => (CAN2_TX, CAN2_RX0),
|
CAN2 => (CAN2_TX, CAN2_RX0),
|
@ -3,35 +3,57 @@ use core::mem;
|
|||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
use cortex_m;
|
use cortex_m;
|
||||||
|
|
||||||
use embassy::traits::gpio::{WaitForFallingEdge, WaitForRisingEdge};
|
use crate::hal::gpio;
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "stm32f401",
|
||||||
|
feature = "stm32f405",
|
||||||
|
feature = "stm32f407",
|
||||||
|
feature = "stm32f410",
|
||||||
|
feature = "stm32f411",
|
||||||
|
feature = "stm32f412",
|
||||||
|
feature = "stm32f413",
|
||||||
|
feature = "stm32f415",
|
||||||
|
feature = "stm32f417",
|
||||||
|
feature = "stm32f423",
|
||||||
|
feature = "stm32f427",
|
||||||
|
feature = "stm32f429",
|
||||||
|
feature = "stm32f437",
|
||||||
|
feature = "stm32f439",
|
||||||
|
feature = "stm32f446",
|
||||||
|
feature = "stm32f469",
|
||||||
|
feature = "stm32f479",
|
||||||
|
))]
|
||||||
|
use crate::hal::syscfg::SysCfg;
|
||||||
|
|
||||||
|
#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
|
||||||
|
use crate::hal::syscfg::SYSCFG as SysCfg;
|
||||||
|
|
||||||
|
use embassy::traits::gpio::{
|
||||||
|
WaitForAnyEdge, WaitForFallingEdge, WaitForHigh, WaitForLow, WaitForRisingEdge,
|
||||||
|
};
|
||||||
use embassy::util::InterruptFuture;
|
use embassy::util::InterruptFuture;
|
||||||
|
|
||||||
use crate::hal::gpio;
|
|
||||||
use crate::hal::gpio::Edge;
|
|
||||||
use crate::hal::syscfg::SysCfg;
|
|
||||||
use crate::pac::EXTI;
|
|
||||||
use embedded_hal::digital::v2 as digital;
|
use embedded_hal::digital::v2 as digital;
|
||||||
|
|
||||||
use crate::interrupt;
|
use crate::interrupt;
|
||||||
|
|
||||||
pub struct ExtiPin<T: gpio::ExtiPin + WithInterrupt> {
|
pub struct ExtiPin<T: Instance> {
|
||||||
pin: T,
|
pin: T,
|
||||||
interrupt: T::Interrupt,
|
interrupt: T::Interrupt,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: gpio::ExtiPin + WithInterrupt> ExtiPin<T> {
|
impl<T: Instance> ExtiPin<T> {
|
||||||
pub fn new(mut pin: T, interrupt: T::Interrupt) -> Self {
|
pub fn new(mut pin: T, interrupt: T::Interrupt, syscfg: &mut SysCfg) -> Self {
|
||||||
let mut syscfg: SysCfg = unsafe { mem::transmute(()) };
|
|
||||||
|
|
||||||
cortex_m::interrupt::free(|_| {
|
cortex_m::interrupt::free(|_| {
|
||||||
pin.make_interrupt_source(&mut syscfg);
|
pin.make_source(syscfg);
|
||||||
});
|
});
|
||||||
|
|
||||||
Self { pin, interrupt }
|
Self { pin, interrupt }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: gpio::ExtiPin + WithInterrupt + digital::OutputPin> digital::OutputPin for ExtiPin<T> {
|
impl<T: Instance + digital::OutputPin> digital::OutputPin for ExtiPin<T> {
|
||||||
type Error = T::Error;
|
type Error = T::Error;
|
||||||
|
|
||||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
@ -43,9 +65,7 @@ impl<T: gpio::ExtiPin + WithInterrupt + digital::OutputPin> digital::OutputPin f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: gpio::ExtiPin + WithInterrupt + digital::StatefulOutputPin> digital::StatefulOutputPin
|
impl<T: Instance + digital::StatefulOutputPin> digital::StatefulOutputPin for ExtiPin<T> {
|
||||||
for ExtiPin<T>
|
|
||||||
{
|
|
||||||
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
||||||
self.pin.is_set_low()
|
self.pin.is_set_low()
|
||||||
}
|
}
|
||||||
@ -55,9 +75,7 @@ impl<T: gpio::ExtiPin + WithInterrupt + digital::StatefulOutputPin> digital::Sta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: gpio::ExtiPin + WithInterrupt + digital::ToggleableOutputPin> digital::ToggleableOutputPin
|
impl<T: Instance + digital::ToggleableOutputPin> digital::ToggleableOutputPin for ExtiPin<T> {
|
||||||
for ExtiPin<T>
|
|
||||||
{
|
|
||||||
type Error = T::Error;
|
type Error = T::Error;
|
||||||
|
|
||||||
fn toggle(&mut self) -> Result<(), Self::Error> {
|
fn toggle(&mut self) -> Result<(), Self::Error> {
|
||||||
@ -65,7 +83,7 @@ impl<T: gpio::ExtiPin + WithInterrupt + digital::ToggleableOutputPin> digital::T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: gpio::ExtiPin + WithInterrupt + digital::InputPin> digital::InputPin for ExtiPin<T> {
|
impl<T: Instance + digital::InputPin> digital::InputPin for ExtiPin<T> {
|
||||||
type Error = T::Error;
|
type Error = T::Error;
|
||||||
|
|
||||||
fn is_high(&self) -> Result<bool, Self::Error> {
|
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||||
@ -77,6 +95,73 @@ impl<T: gpio::ExtiPin + WithInterrupt + digital::InputPin> digital::InputPin for
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Instance + digital::InputPin + 'static> ExtiPin<T> {
|
||||||
|
fn wait_for_state<'a>(self: Pin<&'a mut Self>, state: bool) -> impl Future<Output = ()> + 'a {
|
||||||
|
let s = unsafe { self.get_unchecked_mut() };
|
||||||
|
|
||||||
|
s.pin.clear_pending_bit();
|
||||||
|
async move {
|
||||||
|
let fut = InterruptFuture::new(&mut s.interrupt);
|
||||||
|
let pin = &mut s.pin;
|
||||||
|
cortex_m::interrupt::free(|_| {
|
||||||
|
pin.trigger_edge(if state {
|
||||||
|
EdgeOption::Rising
|
||||||
|
} else {
|
||||||
|
EdgeOption::Falling
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (state && s.pin.is_high().unwrap_or(false))
|
||||||
|
|| (!state && s.pin.is_low().unwrap_or(false))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fut.await;
|
||||||
|
|
||||||
|
s.pin.clear_pending_bit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance + 'static> ExtiPin<T> {
|
||||||
|
fn wait_for_edge<'a>(
|
||||||
|
self: Pin<&'a mut Self>,
|
||||||
|
state: EdgeOption,
|
||||||
|
) -> impl Future<Output = ()> + 'a {
|
||||||
|
let s = unsafe { self.get_unchecked_mut() };
|
||||||
|
|
||||||
|
s.pin.clear_pending_bit();
|
||||||
|
async move {
|
||||||
|
let fut = InterruptFuture::new(&mut s.interrupt);
|
||||||
|
let pin = &mut s.pin;
|
||||||
|
cortex_m::interrupt::free(|_| {
|
||||||
|
pin.trigger_edge(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
fut.await;
|
||||||
|
|
||||||
|
s.pin.clear_pending_bit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance + digital::InputPin + 'static> WaitForHigh for ExtiPin<T> {
|
||||||
|
type Future<'a> = impl Future<Output = ()> + 'a;
|
||||||
|
|
||||||
|
fn wait_for_high<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
||||||
|
self.wait_for_state(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance + digital::InputPin + 'static> WaitForLow for ExtiPin<T> {
|
||||||
|
type Future<'a> = impl Future<Output = ()> + 'a;
|
||||||
|
|
||||||
|
fn wait_for_low<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
||||||
|
self.wait_for_state(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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
|
||||||
@ -88,49 +173,27 @@ impl<T: gpio::ExtiPin + WithInterrupt + digital::InputPin> digital::InputPin for
|
|||||||
EXTI15_10_IRQn EXTI15_10_IRQHandler Handler for pins connected to line 10 to 15
|
EXTI15_10_IRQn EXTI15_10_IRQHandler Handler for pins connected to line 10 to 15
|
||||||
*/
|
*/
|
||||||
|
|
||||||
impl<T: gpio::ExtiPin + WithInterrupt + 'static> WaitForRisingEdge for ExtiPin<T> {
|
impl<T: Instance + 'static> WaitForRisingEdge for ExtiPin<T> {
|
||||||
type Future<'a> = impl Future<Output = ()> + 'a;
|
type Future<'a> = impl Future<Output = ()> + 'a;
|
||||||
|
|
||||||
fn wait_for_rising_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
fn wait_for_rising_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
||||||
let s = unsafe { self.get_unchecked_mut() };
|
self.wait_for_edge(EdgeOption::Rising)
|
||||||
|
|
||||||
s.pin.clear_interrupt_pending_bit();
|
|
||||||
async move {
|
|
||||||
let fut = InterruptFuture::new(&mut s.interrupt);
|
|
||||||
let pin = &mut s.pin;
|
|
||||||
cortex_m::interrupt::free(|_| {
|
|
||||||
let mut exti: EXTI = unsafe { mem::transmute(()) };
|
|
||||||
|
|
||||||
pin.trigger_on_edge(&mut exti, Edge::RISING);
|
|
||||||
pin.enable_interrupt(&mut exti);
|
|
||||||
});
|
|
||||||
fut.await;
|
|
||||||
|
|
||||||
s.pin.clear_interrupt_pending_bit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: gpio::ExtiPin + WithInterrupt + 'static> WaitForFallingEdge for ExtiPin<T> {
|
impl<T: Instance + 'static> WaitForFallingEdge for ExtiPin<T> {
|
||||||
type Future<'a> = impl Future<Output = ()> + 'a;
|
type Future<'a> = impl Future<Output = ()> + 'a;
|
||||||
|
|
||||||
fn wait_for_falling_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
fn wait_for_falling_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
||||||
let s = unsafe { self.get_unchecked_mut() };
|
self.wait_for_edge(EdgeOption::Falling)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s.pin.clear_interrupt_pending_bit();
|
impl<T: Instance + 'static> WaitForAnyEdge for ExtiPin<T> {
|
||||||
async move {
|
type Future<'a> = impl Future<Output = ()> + 'a;
|
||||||
let fut = InterruptFuture::new(&mut s.interrupt);
|
|
||||||
let pin = &mut s.pin;
|
|
||||||
cortex_m::interrupt::free(|_| {
|
|
||||||
let mut exti: EXTI = unsafe { mem::transmute(()) };
|
|
||||||
|
|
||||||
pin.trigger_on_edge(&mut exti, Edge::FALLING);
|
fn wait_for_any_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
||||||
pin.enable_interrupt(&mut exti);
|
self.wait_for_edge(EdgeOption::RisingFalling)
|
||||||
});
|
|
||||||
fut.await;
|
|
||||||
|
|
||||||
s.pin.clear_interrupt_pending_bit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,10 +201,23 @@ mod private {
|
|||||||
pub trait Sealed {}
|
pub trait Sealed {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum EdgeOption {
|
||||||
|
Rising,
|
||||||
|
Falling,
|
||||||
|
RisingFalling,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait WithInterrupt: private::Sealed {
|
pub trait WithInterrupt: private::Sealed {
|
||||||
type Interrupt: interrupt::Interrupt;
|
type Interrupt: interrupt::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Instance: WithInterrupt {
|
||||||
|
fn make_source(&mut self, syscfg: &mut SysCfg);
|
||||||
|
fn clear_pending_bit(&mut self);
|
||||||
|
fn trigger_edge(&mut self, edge: EdgeOption);
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! exti {
|
macro_rules! exti {
|
||||||
($set:ident, [
|
($set:ident, [
|
||||||
$($INT:ident => $pin:ident,)+
|
$($INT:ident => $pin:ident,)+
|
||||||
@ -151,8 +227,88 @@ macro_rules! exti {
|
|||||||
impl<T> WithInterrupt for gpio::$set::$pin<T> {
|
impl<T> WithInterrupt for gpio::$set::$pin<T> {
|
||||||
type Interrupt = interrupt::$INT;
|
type Interrupt = interrupt::$INT;
|
||||||
}
|
}
|
||||||
)+
|
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "stm32f401",
|
||||||
|
feature = "stm32f405",
|
||||||
|
feature = "stm32f407",
|
||||||
|
feature = "stm32f410",
|
||||||
|
feature = "stm32f411",
|
||||||
|
feature = "stm32f412",
|
||||||
|
feature = "stm32f413",
|
||||||
|
feature = "stm32f415",
|
||||||
|
feature = "stm32f417",
|
||||||
|
feature = "stm32f423",
|
||||||
|
feature = "stm32f427",
|
||||||
|
feature = "stm32f429",
|
||||||
|
feature = "stm32f437",
|
||||||
|
feature = "stm32f439",
|
||||||
|
feature = "stm32f446",
|
||||||
|
feature = "stm32f469",
|
||||||
|
feature = "stm32f479",
|
||||||
|
))]
|
||||||
|
impl<T> Instance for gpio::$set::$pin<gpio::Input<T>> {
|
||||||
|
fn make_source(&mut self, syscfg: &mut SysCfg) {
|
||||||
|
use crate::hal::gpio::ExtiPin;
|
||||||
|
self.make_interrupt_source(syscfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_pending_bit(&mut self) {
|
||||||
|
use crate::hal::{gpio::Edge, gpio::ExtiPin, syscfg::SysCfg};
|
||||||
|
|
||||||
|
self.clear_interrupt_pending_bit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trigger_edge(&mut self, edge: EdgeOption) {
|
||||||
|
use crate::hal::{gpio::Edge, gpio::ExtiPin, syscfg::SysCfg};
|
||||||
|
use crate::pac::EXTI;
|
||||||
|
let mut exti: EXTI = unsafe { mem::transmute(()) };
|
||||||
|
let edge = match edge {
|
||||||
|
EdgeOption::Falling => Edge::FALLING,
|
||||||
|
EdgeOption::Rising => Edge::RISING,
|
||||||
|
EdgeOption::RisingFalling => Edge::RISING_FALLING,
|
||||||
|
};
|
||||||
|
self.trigger_on_edge(&mut exti, edge);
|
||||||
|
self.enable_interrupt(&mut exti);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
|
||||||
|
impl<T> Instance for gpio::$set::$pin<T> {
|
||||||
|
fn make_source(&mut self, syscfg: &mut SysCfg) {}
|
||||||
|
|
||||||
|
fn clear_pending_bit(&mut self) {
|
||||||
|
use crate::hal::{
|
||||||
|
exti::{Exti, ExtiLine, GpioLine, TriggerEdge},
|
||||||
|
syscfg::SYSCFG,
|
||||||
|
};
|
||||||
|
|
||||||
|
Exti::unpend(GpioLine::from_raw_line(self.pin_number()).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trigger_edge(&mut self, edge: EdgeOption) {
|
||||||
|
use crate::hal::{
|
||||||
|
exti::{Exti, ExtiLine, GpioLine, TriggerEdge},
|
||||||
|
syscfg::SYSCFG,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::pac::EXTI;
|
||||||
|
|
||||||
|
let edge = match edge {
|
||||||
|
EdgeOption::Falling => TriggerEdge::Falling,
|
||||||
|
EdgeOption::Rising => TriggerEdge::Rising,
|
||||||
|
EdgeOption::RisingFalling => TriggerEdge::Both,
|
||||||
|
};
|
||||||
|
|
||||||
|
let exti: EXTI = unsafe { mem::transmute(()) };
|
||||||
|
let mut exti = Exti::new(exti);
|
||||||
|
let port = self.port();
|
||||||
|
let mut syscfg: SYSCFG = unsafe { mem::transmute(()) };
|
||||||
|
let line = GpioLine::from_raw_line(self.pin_number()).unwrap();
|
||||||
|
exti.listen_gpio(&mut syscfg, port, line, edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,3 +689,111 @@ exti!(gpiok, [
|
|||||||
EXTI9_5 => PK6,
|
EXTI9_5 => PK6,
|
||||||
EXTI9_5 => PK7,
|
EXTI9_5 => PK7,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
|
||||||
|
exti!(gpioa, [
|
||||||
|
EXTI0_1 => PA0,
|
||||||
|
EXTI0_1 => PA1,
|
||||||
|
EXTI2_3 => PA2,
|
||||||
|
EXTI2_3 => PA3,
|
||||||
|
EXTI4_15 => PA4,
|
||||||
|
EXTI4_15 => PA5,
|
||||||
|
EXTI4_15 => PA6,
|
||||||
|
EXTI4_15 => PA7,
|
||||||
|
EXTI4_15 => PA8,
|
||||||
|
EXTI4_15 => PA9,
|
||||||
|
EXTI4_15 => PA10,
|
||||||
|
EXTI4_15 => PA11,
|
||||||
|
EXTI4_15 => PA12,
|
||||||
|
EXTI4_15 => PA13,
|
||||||
|
EXTI4_15 => PA14,
|
||||||
|
EXTI4_15 => PA15,
|
||||||
|
]);
|
||||||
|
|
||||||
|
#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
|
||||||
|
exti!(gpiob, [
|
||||||
|
EXTI0_1 => PB0,
|
||||||
|
EXTI0_1 => PB1,
|
||||||
|
EXTI2_3 => PB2,
|
||||||
|
EXTI2_3 => PB3,
|
||||||
|
EXTI4_15 => PB4,
|
||||||
|
EXTI4_15 => PB5,
|
||||||
|
EXTI4_15 => PB6,
|
||||||
|
EXTI4_15 => PB7,
|
||||||
|
EXTI4_15 => PB8,
|
||||||
|
EXTI4_15 => PB9,
|
||||||
|
EXTI4_15 => PB10,
|
||||||
|
EXTI4_15 => PB11,
|
||||||
|
EXTI4_15 => PB12,
|
||||||
|
EXTI4_15 => PB13,
|
||||||
|
EXTI4_15 => PB14,
|
||||||
|
EXTI4_15 => PB15,
|
||||||
|
]);
|
||||||
|
|
||||||
|
#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
|
||||||
|
exti!(gpioc, [
|
||||||
|
EXTI0_1 => PC0,
|
||||||
|
EXTI0_1 => PC1,
|
||||||
|
EXTI2_3 => PC2,
|
||||||
|
EXTI2_3 => PC3,
|
||||||
|
EXTI4_15 => PC4,
|
||||||
|
EXTI4_15 => PC5,
|
||||||
|
EXTI4_15 => PC6,
|
||||||
|
EXTI4_15 => PC7,
|
||||||
|
EXTI4_15 => PC8,
|
||||||
|
EXTI4_15 => PC9,
|
||||||
|
EXTI4_15 => PC10,
|
||||||
|
EXTI4_15 => PC11,
|
||||||
|
EXTI4_15 => PC12,
|
||||||
|
EXTI4_15 => PC13,
|
||||||
|
EXTI4_15 => PC14,
|
||||||
|
EXTI4_15 => PC15,
|
||||||
|
]);
|
||||||
|
|
||||||
|
#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
|
||||||
|
exti!(gpiod, [
|
||||||
|
EXTI0_1 => PD0,
|
||||||
|
EXTI0_1 => PD1,
|
||||||
|
EXTI2_3 => PD2,
|
||||||
|
EXTI2_3 => PD3,
|
||||||
|
EXTI4_15 => PD4,
|
||||||
|
EXTI4_15 => PD5,
|
||||||
|
EXTI4_15 => PD6,
|
||||||
|
EXTI4_15 => PD7,
|
||||||
|
EXTI4_15 => PD8,
|
||||||
|
EXTI4_15 => PD9,
|
||||||
|
EXTI4_15 => PD10,
|
||||||
|
EXTI4_15 => PD11,
|
||||||
|
EXTI4_15 => PD12,
|
||||||
|
EXTI4_15 => PD13,
|
||||||
|
EXTI4_15 => PD14,
|
||||||
|
EXTI4_15 => PD15,
|
||||||
|
]);
|
||||||
|
|
||||||
|
#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
|
||||||
|
exti!(gpioe, [
|
||||||
|
EXTI0_1 => PE0,
|
||||||
|
EXTI0_1 => PE1,
|
||||||
|
EXTI2_3 => PE2,
|
||||||
|
EXTI2_3 => PE3,
|
||||||
|
EXTI4_15 => PE4,
|
||||||
|
EXTI4_15 => PE5,
|
||||||
|
EXTI4_15 => PE6,
|
||||||
|
EXTI4_15 => PE7,
|
||||||
|
EXTI4_15 => PE8,
|
||||||
|
EXTI4_15 => PE9,
|
||||||
|
EXTI4_15 => PE10,
|
||||||
|
EXTI4_15 => PE11,
|
||||||
|
EXTI4_15 => PE12,
|
||||||
|
EXTI4_15 => PE13,
|
||||||
|
EXTI4_15 => PE14,
|
||||||
|
EXTI4_15 => PE15,
|
||||||
|
]);
|
||||||
|
|
||||||
|
#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
|
||||||
|
exti!(gpioh, [
|
||||||
|
EXTI0_1 => PH0,
|
||||||
|
EXTI0_1 => PH1,
|
||||||
|
EXTI4_15 => PH9,
|
||||||
|
EXTI4_15 => PH10,
|
||||||
|
]);
|
@ -889,7 +889,7 @@ mod irqs {
|
|||||||
declare!(TIM8_CC);
|
declare!(TIM8_CC);
|
||||||
declare!(DMA1_STREAM7);
|
declare!(DMA1_STREAM7);
|
||||||
declare!(FMC);
|
declare!(FMC);
|
||||||
declare!(SDIO);
|
// declare!(SDIO);
|
||||||
declare!(TIM5);
|
declare!(TIM5);
|
||||||
declare!(SPI3);
|
declare!(SPI3);
|
||||||
declare!(UART4);
|
declare!(UART4);
|
||||||
|
@ -32,12 +32,33 @@ pub use {stm32l0xx_hal as hal, stm32l0xx_hal::pac};
|
|||||||
|
|
||||||
pub mod fmt;
|
pub mod fmt;
|
||||||
|
|
||||||
|
pub mod exti;
|
||||||
pub mod interrupt;
|
pub mod interrupt;
|
||||||
|
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
feature = "stm32f401",
|
feature = "stm32f401",
|
||||||
feature = "stm32f405",
|
feature = "stm32f405",
|
||||||
feature = "stm32f407",
|
feature = "stm32f407",
|
||||||
|
feature = "stm32f412",
|
||||||
|
feature = "stm32f413",
|
||||||
|
feature = "stm32f415",
|
||||||
|
feature = "stm32f417",
|
||||||
|
feature = "stm32f423",
|
||||||
|
feature = "stm32f427",
|
||||||
|
feature = "stm32f429",
|
||||||
|
feature = "stm32f437",
|
||||||
|
feature = "stm32f439",
|
||||||
|
feature = "stm32f446",
|
||||||
|
feature = "stm32f469",
|
||||||
|
feature = "stm32f479",
|
||||||
|
))]
|
||||||
|
pub mod can;
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "stm32f401",
|
||||||
|
feature = "stm32f405",
|
||||||
|
feature = "stm32f407",
|
||||||
|
feature = "stm32f410",
|
||||||
feature = "stm32f411",
|
feature = "stm32f411",
|
||||||
feature = "stm32f412",
|
feature = "stm32f412",
|
||||||
feature = "stm32f413",
|
feature = "stm32f413",
|
||||||
@ -52,4 +73,6 @@ pub mod interrupt;
|
|||||||
feature = "stm32f469",
|
feature = "stm32f469",
|
||||||
feature = "stm32f479",
|
feature = "stm32f479",
|
||||||
))]
|
))]
|
||||||
|
pub mod rtc;
|
||||||
|
|
||||||
unsafe impl embassy_extras::usb::USBInterrupt for interrupt::OTG_FS {}
|
unsafe impl embassy_extras::usb::USBInterrupt for interrupt::OTG_FS {}
|
||||||
|
@ -24,8 +24,9 @@ async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) {
|
|||||||
let gpioa = dp.GPIOA.split();
|
let gpioa = dp.GPIOA.split();
|
||||||
|
|
||||||
let button = gpioa.pa0.into_pull_up_input();
|
let button = gpioa.pa0.into_pull_up_input();
|
||||||
|
let mut syscfg = dp.SYSCFG.constrain();
|
||||||
|
|
||||||
let pin = ExtiPin::new(button, interrupt::take!(EXTI0));
|
let pin = ExtiPin::new(button, interrupt::take!(EXTI0), &mut syscfg);
|
||||||
pin_mut!(pin);
|
pin_mut!(pin);
|
||||||
|
|
||||||
info!("Starting loop");
|
info!("Starting loop");
|
||||||
|
@ -37,6 +37,7 @@ defmt = { version = "0.2.0", optional = true }
|
|||||||
log = { version = "0.4.11", optional = true }
|
log = { version = "0.4.11", optional = true }
|
||||||
cortex-m-rt = "0.6.13"
|
cortex-m-rt = "0.6.13"
|
||||||
cortex-m = "0.7.1"
|
cortex-m = "0.7.1"
|
||||||
|
futures = { version = "0.3.5", default-features = false, features = ["async-await"] }
|
||||||
embedded-hal = { version = "0.2.4" }
|
embedded-hal = { version = "0.2.4" }
|
||||||
embedded-dma = { version = "0.1.2" }
|
embedded-dma = { version = "0.1.2" }
|
||||||
stm32f4xx-hal = { version = "0.8.3", features = ["rt", "can"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"}
|
stm32f4xx-hal = { version = "0.8.3", features = ["rt", "can"], git = "https://github.com/stm32-rs/stm32f4xx-hal.git"}
|
||||||
|
@ -307,12 +307,11 @@ compile_error!(
|
|||||||
"Multile chip features activated. You must activate exactly one of the following features: "
|
"Multile chip features activated. You must activate exactly one of the following features: "
|
||||||
);
|
);
|
||||||
|
|
||||||
pub use embassy_stm32::{fmt, hal, interrupt, pac};
|
pub use embassy_stm32::{exti, fmt, hal, interrupt, pac, rtc};
|
||||||
|
|
||||||
#[cfg(not(any(feature = "stm32f401", feature = "stm32f410", feature = "stm32f411",)))]
|
#[cfg(not(any(feature = "stm32f401", feature = "stm32f410", feature = "stm32f411",)))]
|
||||||
pub mod can;
|
pub use embassy_stm32::can;
|
||||||
pub mod exti;
|
|
||||||
#[cfg(not(feature = "stm32f410"))]
|
#[cfg(not(feature = "stm32f410"))]
|
||||||
pub mod qei;
|
pub mod qei;
|
||||||
pub mod rtc;
|
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
|
@ -7,8 +7,10 @@
|
|||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use futures::{select_biased, FutureExt};
|
||||||
|
|
||||||
use embassy::interrupt::Interrupt;
|
use embassy::interrupt::Interrupt;
|
||||||
use embassy::traits::uart::{Error, Uart};
|
use embassy::traits::uart::{Error, IdleUart, Uart};
|
||||||
use embassy::util::InterruptFuture;
|
use embassy::util::InterruptFuture;
|
||||||
|
|
||||||
use crate::hal::{
|
use crate::hal::{
|
||||||
@ -19,7 +21,7 @@ use crate::hal::{
|
|||||||
rcc::Clocks,
|
rcc::Clocks,
|
||||||
serial,
|
serial,
|
||||||
serial::config::{Config as SerialConfig, DmaConfig as SerialDmaConfig},
|
serial::config::{Config as SerialConfig, DmaConfig as SerialDmaConfig},
|
||||||
serial::{Event as SerialEvent, Pins, Serial as HalSerial},
|
serial::{Event as SerialEvent, Pins},
|
||||||
};
|
};
|
||||||
use crate::interrupt;
|
use crate::interrupt;
|
||||||
use crate::pac;
|
use crate::pac;
|
||||||
@ -29,14 +31,14 @@ pub struct Serial<
|
|||||||
USART: PeriAddress<MemSize = u8> + WithInterrupt,
|
USART: PeriAddress<MemSize = u8> + WithInterrupt,
|
||||||
TSTREAM: Stream + WithInterrupt,
|
TSTREAM: Stream + WithInterrupt,
|
||||||
RSTREAM: Stream + WithInterrupt,
|
RSTREAM: Stream + WithInterrupt,
|
||||||
CHANNEL: dma::traits::Channel,
|
CHANNEL: Channel,
|
||||||
> {
|
> {
|
||||||
tx_stream: Option<TSTREAM>,
|
tx_stream: Option<TSTREAM>,
|
||||||
rx_stream: Option<RSTREAM>,
|
rx_stream: Option<RSTREAM>,
|
||||||
usart: Option<USART>,
|
usart: Option<USART>,
|
||||||
tx_int: TSTREAM::Interrupt,
|
tx_int: TSTREAM::Interrupt,
|
||||||
rx_int: RSTREAM::Interrupt,
|
rx_int: RSTREAM::Interrupt,
|
||||||
_usart_int: USART::Interrupt,
|
usart_int: USART::Interrupt,
|
||||||
channel: PhantomData<CHANNEL>,
|
channel: PhantomData<CHANNEL>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,12 +70,10 @@ where
|
|||||||
PINS: Pins<USART>,
|
PINS: Pins<USART>,
|
||||||
{
|
{
|
||||||
config.dma = SerialDmaConfig::TxRx;
|
config.dma = SerialDmaConfig::TxRx;
|
||||||
let mut serial = HalSerial::new(usart, pins, config, clocks).unwrap();
|
|
||||||
|
|
||||||
serial.listen(SerialEvent::Idle);
|
let (usart, _) = serial::Serial::new(usart, pins, config, clocks)
|
||||||
// serial.listen(SerialEvent::Txe);
|
.unwrap()
|
||||||
|
.release();
|
||||||
let (usart, _) = serial.release();
|
|
||||||
|
|
||||||
let (tx_stream, rx_stream) = streams;
|
let (tx_stream, rx_stream) = streams;
|
||||||
|
|
||||||
@ -83,8 +83,8 @@ where
|
|||||||
usart: Some(usart),
|
usart: Some(usart),
|
||||||
tx_int: tx_int,
|
tx_int: tx_int,
|
||||||
rx_int: rx_int,
|
rx_int: rx_int,
|
||||||
_usart_int: usart_int,
|
usart_int: usart_int,
|
||||||
channel: core::marker::PhantomData,
|
channel: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,10 +127,10 @@ where
|
|||||||
let fut = InterruptFuture::new(&mut self.tx_int);
|
let fut = InterruptFuture::new(&mut self.tx_int);
|
||||||
|
|
||||||
tx_transfer.start(|_usart| {});
|
tx_transfer.start(|_usart| {});
|
||||||
|
|
||||||
fut.await;
|
fut.await;
|
||||||
|
|
||||||
let (tx_stream, usart, _buf, _) = tx_transfer.free();
|
let (tx_stream, usart, _buf, _) = tx_transfer.free();
|
||||||
|
|
||||||
self.tx_stream.replace(tx_stream);
|
self.tx_stream.replace(tx_stream);
|
||||||
self.usart.replace(usart);
|
self.usart.replace(usart);
|
||||||
|
|
||||||
@ -163,7 +163,6 @@ where
|
|||||||
);
|
);
|
||||||
|
|
||||||
let fut = InterruptFuture::new(&mut self.rx_int);
|
let fut = InterruptFuture::new(&mut self.rx_int);
|
||||||
|
|
||||||
rx_transfer.start(|_usart| {});
|
rx_transfer.start(|_usart| {});
|
||||||
fut.await;
|
fut.await;
|
||||||
|
|
||||||
@ -176,6 +175,79 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<USART, TSTREAM, RSTREAM, CHANNEL> IdleUart 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 ReceiveFuture<'a> = impl Future<Output = Result<usize, Error>> + 'a;
|
||||||
|
|
||||||
|
/// Receives serial data.
|
||||||
|
///
|
||||||
|
/// The future is pending until either the buffer is completely full, or the RX line falls idle after receiving some data.
|
||||||
|
///
|
||||||
|
/// Returns the number of bytes read.
|
||||||
|
fn receive_until_idle<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a> {
|
||||||
|
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 {
|
||||||
|
unsafe {
|
||||||
|
/* __HAL_UART_ENABLE_IT(&uart->UartHandle, UART_IT_IDLE); */
|
||||||
|
(*USART::ptr()).cr1.modify(|_, w| w.idleie().set_bit());
|
||||||
|
|
||||||
|
/* __HAL_UART_CLEAR_IDLEFLAG(&uart->UartHandle); */
|
||||||
|
(*USART::ptr()).sr.read();
|
||||||
|
(*USART::ptr()).dr.read();
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut rx_transfer = Transfer::init(
|
||||||
|
rx_stream,
|
||||||
|
usart,
|
||||||
|
static_buf,
|
||||||
|
None,
|
||||||
|
DmaConfig::default()
|
||||||
|
.transfer_complete_interrupt(true)
|
||||||
|
.memory_increment(true)
|
||||||
|
.double_buffer(false),
|
||||||
|
);
|
||||||
|
|
||||||
|
let total_bytes = RSTREAM::get_number_of_transfers() as usize;
|
||||||
|
|
||||||
|
let fut = InterruptFuture::new(&mut self.rx_int);
|
||||||
|
let fut_idle = InterruptFuture::new(&mut self.usart_int);
|
||||||
|
|
||||||
|
rx_transfer.start(|_usart| {});
|
||||||
|
|
||||||
|
select_biased! {
|
||||||
|
() = fut.fuse() => {},
|
||||||
|
() = fut_idle.fuse() => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
let (rx_stream, usart, _, _) = rx_transfer.free();
|
||||||
|
|
||||||
|
let remaining_bytes = RSTREAM::get_number_of_transfers() as usize;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
(*USART::ptr()).cr1.modify(|_, w| w.idleie().clear_bit());
|
||||||
|
}
|
||||||
|
self.rx_stream.replace(rx_stream);
|
||||||
|
self.usart.replace(usart);
|
||||||
|
|
||||||
|
Ok(total_bytes - remaining_bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod private {
|
mod private {
|
||||||
pub trait Sealed {}
|
pub trait Sealed {}
|
||||||
}
|
}
|
||||||
@ -278,6 +350,6 @@ usart! {
|
|||||||
|
|
||||||
UART4 => (UART4),
|
UART4 => (UART4),
|
||||||
UART5 => (UART5),
|
UART5 => (UART5),
|
||||||
UART7 => (UART7),
|
// UART7 => (UART7),
|
||||||
UART8 => (UART8),
|
// UART8 => (UART8),
|
||||||
}
|
}
|
||||||
|
@ -1,268 +0,0 @@
|
|||||||
use core::future::Future;
|
|
||||||
use core::mem;
|
|
||||||
use core::pin::Pin;
|
|
||||||
|
|
||||||
use embassy::traits::gpio::{
|
|
||||||
WaitForAnyEdge, WaitForFallingEdge, WaitForHigh, WaitForLow, WaitForRisingEdge,
|
|
||||||
};
|
|
||||||
use embassy::util::InterruptFuture;
|
|
||||||
|
|
||||||
use crate::hal::{
|
|
||||||
exti::{Exti, ExtiLine, GpioLine, TriggerEdge},
|
|
||||||
gpio,
|
|
||||||
syscfg::SYSCFG,
|
|
||||||
};
|
|
||||||
use crate::interrupt;
|
|
||||||
use crate::pac::EXTI;
|
|
||||||
use embedded_hal::digital::v2::InputPin;
|
|
||||||
|
|
||||||
pub struct ExtiPin<T: PinWithInterrupt> {
|
|
||||||
pin: T,
|
|
||||||
interrupt: T::Interrupt,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: PinWithInterrupt + 'static> ExtiPin<T> {
|
|
||||||
pub fn new(pin: T, interrupt: T::Interrupt) -> ExtiPin<T> {
|
|
||||||
ExtiPin { pin, interrupt }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wait_for_edge<'a>(
|
|
||||||
self: Pin<&'a mut Self>,
|
|
||||||
edge: TriggerEdge,
|
|
||||||
) -> impl Future<Output = ()> + 'a {
|
|
||||||
let line = self.pin.line();
|
|
||||||
let s = unsafe { self.get_unchecked_mut() };
|
|
||||||
|
|
||||||
Exti::unpend(line);
|
|
||||||
|
|
||||||
async move {
|
|
||||||
let exti: EXTI = unsafe { mem::transmute(()) };
|
|
||||||
let mut exti = Exti::new(exti);
|
|
||||||
|
|
||||||
let fut = InterruptFuture::new(&mut s.interrupt);
|
|
||||||
|
|
||||||
let port = s.pin.port();
|
|
||||||
cortex_m::interrupt::free(|_| {
|
|
||||||
let mut syscfg: SYSCFG = unsafe { mem::transmute(()) };
|
|
||||||
exti.listen_gpio(&mut syscfg, port, line, edge);
|
|
||||||
});
|
|
||||||
|
|
||||||
fut.await;
|
|
||||||
|
|
||||||
Exti::unpend(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: InputPin + PinWithInterrupt + 'static> ExtiPin<T> {
|
|
||||||
fn wait_for_state<'a>(self: Pin<&'a mut Self>, state: bool) -> impl Future<Output = ()> + 'a {
|
|
||||||
let line = self.pin.line();
|
|
||||||
let s = unsafe { self.get_unchecked_mut() };
|
|
||||||
|
|
||||||
Exti::unpend(line);
|
|
||||||
|
|
||||||
async move {
|
|
||||||
let exti: EXTI = unsafe { mem::transmute(()) };
|
|
||||||
let mut exti = Exti::new(exti);
|
|
||||||
|
|
||||||
let fut = InterruptFuture::new(&mut s.interrupt);
|
|
||||||
|
|
||||||
let port = s.pin.port();
|
|
||||||
cortex_m::interrupt::free(|_| {
|
|
||||||
let mut syscfg: SYSCFG = unsafe { mem::transmute(()) };
|
|
||||||
let edge = if state {
|
|
||||||
TriggerEdge::Rising
|
|
||||||
} else {
|
|
||||||
TriggerEdge::Falling
|
|
||||||
};
|
|
||||||
exti.listen_gpio(&mut syscfg, port, line, edge);
|
|
||||||
});
|
|
||||||
|
|
||||||
let pin_has_state = if state {
|
|
||||||
s.pin.is_high()
|
|
||||||
} else {
|
|
||||||
s.pin.is_low()
|
|
||||||
}
|
|
||||||
.unwrap_or(false);
|
|
||||||
if pin_has_state {
|
|
||||||
return ();
|
|
||||||
}
|
|
||||||
|
|
||||||
fut.await;
|
|
||||||
|
|
||||||
Exti::unpend(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: PinWithInterrupt + 'static> WaitForRisingEdge for ExtiPin<T> {
|
|
||||||
type Future<'a> = impl Future<Output = ()> + 'a;
|
|
||||||
|
|
||||||
fn wait_for_rising_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
|
||||||
self.wait_for_edge(TriggerEdge::Rising)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: PinWithInterrupt + 'static> WaitForFallingEdge for ExtiPin<T> {
|
|
||||||
type Future<'a> = impl Future<Output = ()> + 'a;
|
|
||||||
|
|
||||||
fn wait_for_falling_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
|
||||||
self.wait_for_edge(TriggerEdge::Falling)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: PinWithInterrupt + 'static> WaitForAnyEdge for ExtiPin<T> {
|
|
||||||
type Future<'a> = impl Future<Output = ()> + 'a;
|
|
||||||
|
|
||||||
fn wait_for_any_edge<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
|
||||||
self.wait_for_edge(TriggerEdge::Both)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: InputPin + PinWithInterrupt + 'static> WaitForHigh for ExtiPin<T> {
|
|
||||||
type Future<'a> = impl Future<Output = ()> + 'a;
|
|
||||||
|
|
||||||
fn wait_for_high<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
|
||||||
self.wait_for_state(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: InputPin + PinWithInterrupt + 'static> WaitForLow for ExtiPin<T> {
|
|
||||||
type Future<'a> = impl Future<Output = ()> + 'a;
|
|
||||||
|
|
||||||
fn wait_for_low<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
|
||||||
self.wait_for_state(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod private {
|
|
||||||
pub trait Sealed {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait PinWithInterrupt: private::Sealed {
|
|
||||||
type Interrupt: interrupt::Interrupt;
|
|
||||||
fn port(&self) -> gpio::Port;
|
|
||||||
fn line(&self) -> GpioLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! exti {
|
|
||||||
($set:ident, [
|
|
||||||
$($INT:ident => $pin:ident,)+
|
|
||||||
]) => {
|
|
||||||
$(
|
|
||||||
impl<T> private::Sealed for gpio::$set::$pin<T> {}
|
|
||||||
impl<T> PinWithInterrupt for gpio::$set::$pin<T> {
|
|
||||||
type Interrupt = interrupt::$INT;
|
|
||||||
fn port(&self) -> gpio::Port {
|
|
||||||
self.port()
|
|
||||||
}
|
|
||||||
fn line(&self) -> GpioLine {
|
|
||||||
GpioLine::from_raw_line(self.pin_number()).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
exti!(gpioa, [
|
|
||||||
EXTI0_1 => PA0,
|
|
||||||
EXTI0_1 => PA1,
|
|
||||||
EXTI2_3 => PA2,
|
|
||||||
EXTI2_3 => PA3,
|
|
||||||
EXTI4_15 => PA4,
|
|
||||||
EXTI4_15 => PA5,
|
|
||||||
EXTI4_15 => PA6,
|
|
||||||
EXTI4_15 => PA7,
|
|
||||||
EXTI4_15 => PA8,
|
|
||||||
EXTI4_15 => PA9,
|
|
||||||
EXTI4_15 => PA10,
|
|
||||||
EXTI4_15 => PA11,
|
|
||||||
EXTI4_15 => PA12,
|
|
||||||
EXTI4_15 => PA13,
|
|
||||||
EXTI4_15 => PA14,
|
|
||||||
EXTI4_15 => PA15,
|
|
||||||
]);
|
|
||||||
|
|
||||||
exti!(gpiob, [
|
|
||||||
EXTI0_1 => PB0,
|
|
||||||
EXTI0_1 => PB1,
|
|
||||||
EXTI2_3 => PB2,
|
|
||||||
EXTI2_3 => PB3,
|
|
||||||
EXTI4_15 => PB4,
|
|
||||||
EXTI4_15 => PB5,
|
|
||||||
EXTI4_15 => PB6,
|
|
||||||
EXTI4_15 => PB7,
|
|
||||||
EXTI4_15 => PB8,
|
|
||||||
EXTI4_15 => PB9,
|
|
||||||
EXTI4_15 => PB10,
|
|
||||||
EXTI4_15 => PB11,
|
|
||||||
EXTI4_15 => PB12,
|
|
||||||
EXTI4_15 => PB13,
|
|
||||||
EXTI4_15 => PB14,
|
|
||||||
EXTI4_15 => PB15,
|
|
||||||
]);
|
|
||||||
|
|
||||||
exti!(gpioc, [
|
|
||||||
EXTI0_1 => PC0,
|
|
||||||
EXTI0_1 => PC1,
|
|
||||||
EXTI2_3 => PC2,
|
|
||||||
EXTI2_3 => PC3,
|
|
||||||
EXTI4_15 => PC4,
|
|
||||||
EXTI4_15 => PC5,
|
|
||||||
EXTI4_15 => PC6,
|
|
||||||
EXTI4_15 => PC7,
|
|
||||||
EXTI4_15 => PC8,
|
|
||||||
EXTI4_15 => PC9,
|
|
||||||
EXTI4_15 => PC10,
|
|
||||||
EXTI4_15 => PC11,
|
|
||||||
EXTI4_15 => PC12,
|
|
||||||
EXTI4_15 => PC13,
|
|
||||||
EXTI4_15 => PC14,
|
|
||||||
EXTI4_15 => PC15,
|
|
||||||
]);
|
|
||||||
|
|
||||||
exti!(gpiod, [
|
|
||||||
EXTI0_1 => PD0,
|
|
||||||
EXTI0_1 => PD1,
|
|
||||||
EXTI2_3 => PD2,
|
|
||||||
EXTI2_3 => PD3,
|
|
||||||
EXTI4_15 => PD4,
|
|
||||||
EXTI4_15 => PD5,
|
|
||||||
EXTI4_15 => PD6,
|
|
||||||
EXTI4_15 => PD7,
|
|
||||||
EXTI4_15 => PD8,
|
|
||||||
EXTI4_15 => PD9,
|
|
||||||
EXTI4_15 => PD10,
|
|
||||||
EXTI4_15 => PD11,
|
|
||||||
EXTI4_15 => PD12,
|
|
||||||
EXTI4_15 => PD13,
|
|
||||||
EXTI4_15 => PD14,
|
|
||||||
EXTI4_15 => PD15,
|
|
||||||
]);
|
|
||||||
|
|
||||||
exti!(gpioe, [
|
|
||||||
EXTI0_1 => PE0,
|
|
||||||
EXTI0_1 => PE1,
|
|
||||||
EXTI2_3 => PE2,
|
|
||||||
EXTI2_3 => PE3,
|
|
||||||
EXTI4_15 => PE4,
|
|
||||||
EXTI4_15 => PE5,
|
|
||||||
EXTI4_15 => PE6,
|
|
||||||
EXTI4_15 => PE7,
|
|
||||||
EXTI4_15 => PE8,
|
|
||||||
EXTI4_15 => PE9,
|
|
||||||
EXTI4_15 => PE10,
|
|
||||||
EXTI4_15 => PE11,
|
|
||||||
EXTI4_15 => PE12,
|
|
||||||
EXTI4_15 => PE13,
|
|
||||||
EXTI4_15 => PE14,
|
|
||||||
EXTI4_15 => PE15,
|
|
||||||
]);
|
|
||||||
|
|
||||||
exti!(gpioh, [
|
|
||||||
EXTI0_1 => PH0,
|
|
||||||
EXTI0_1 => PH1,
|
|
||||||
EXTI4_15 => PH9,
|
|
||||||
EXTI4_15 => PH10,
|
|
||||||
]);
|
|
@ -19,6 +19,4 @@ compile_error!(
|
|||||||
"Multile chip features activated. You must activate exactly one of the following features: "
|
"Multile chip features activated. You must activate exactly one of the following features: "
|
||||||
);
|
);
|
||||||
|
|
||||||
pub use embassy_stm32::{fmt, hal, interrupt, pac};
|
pub use embassy_stm32::{exti, fmt, hal, interrupt, pac};
|
||||||
|
|
||||||
pub mod exti;
|
|
||||||
|
@ -4,6 +4,9 @@ use core::pin::Pin;
|
|||||||
pub trait Delay {
|
pub trait Delay {
|
||||||
type DelayFuture<'a>: Future<Output = ()> + 'a;
|
type DelayFuture<'a>: Future<Output = ()> + 'a;
|
||||||
|
|
||||||
|
/// Future that completes after now + millis
|
||||||
fn delay_ms<'a>(self: Pin<&'a mut Self>, millis: u64) -> Self::DelayFuture<'a>;
|
fn delay_ms<'a>(self: Pin<&'a mut Self>, millis: u64) -> Self::DelayFuture<'a>;
|
||||||
|
|
||||||
|
/// Future that completes after now + micros
|
||||||
fn delay_us<'a>(self: Pin<&'a mut Self>, micros: u64) -> Self::DelayFuture<'a>;
|
fn delay_us<'a>(self: Pin<&'a mut Self>, micros: u64) -> Self::DelayFuture<'a>;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,15 @@ pub enum Error {
|
|||||||
pub trait Uart {
|
pub trait Uart {
|
||||||
type ReceiveFuture<'a>: Future<Output = Result<(), Error>>;
|
type ReceiveFuture<'a>: Future<Output = Result<(), Error>>;
|
||||||
type SendFuture<'a>: Future<Output = Result<(), Error>>;
|
type SendFuture<'a>: Future<Output = Result<(), Error>>;
|
||||||
|
/// Receive into the buffer until the buffer is full
|
||||||
fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'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 send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a>;
|
fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait IdleUart {
|
||||||
|
type ReceiveFuture<'a>: Future<Output = Result<usize, Error>>;
|
||||||
|
/// Receive into the buffer until the buffer is full or the line is idle after some bytes are received
|
||||||
|
/// Return the number of bytes received
|
||||||
|
fn receive_until_idle<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a>;
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@ use futures::Stream;
|
|||||||
use super::raw;
|
use super::raw;
|
||||||
use crate::time::{Duration, Instant};
|
use crate::time::{Duration, Instant};
|
||||||
|
|
||||||
|
/// Delay abstraction using embassy's clock.
|
||||||
pub struct Delay {
|
pub struct Delay {
|
||||||
_data: PhantomData<bool>,
|
_data: PhantomData<bool>,
|
||||||
}
|
}
|
||||||
@ -30,12 +31,14 @@ impl crate::traits::delay::Delay for Delay {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A future that completes at a specified [Instant](struct.Instant.html).
|
||||||
pub struct Timer {
|
pub struct Timer {
|
||||||
expires_at: Instant,
|
expires_at: Instant,
|
||||||
yielded_once: bool,
|
yielded_once: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Timer {
|
impl Timer {
|
||||||
|
/// Expire at specified [Instant](struct.Instant.html)
|
||||||
pub fn at(expires_at: Instant) -> Self {
|
pub fn at(expires_at: Instant) -> Self {
|
||||||
Self {
|
Self {
|
||||||
expires_at,
|
expires_at,
|
||||||
@ -43,6 +46,26 @@ impl Timer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Expire after specified [Duration](struct.Duration.html).
|
||||||
|
/// This can be used as a `sleep` abstraction.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ``` no_run
|
||||||
|
/// # #![feature(trait_alias)]
|
||||||
|
/// # #![feature(min_type_alias_impl_trait)]
|
||||||
|
/// # #![feature(impl_trait_in_bindings)]
|
||||||
|
/// # #![feature(type_alias_impl_trait)]
|
||||||
|
/// #
|
||||||
|
/// # fn foo() {}
|
||||||
|
/// use embassy::executor::task;
|
||||||
|
/// use embassy::time::{Duration, Timer};
|
||||||
|
///
|
||||||
|
/// #[task]
|
||||||
|
/// async fn demo_sleep_seconds() {
|
||||||
|
/// // suspend this task for one second.
|
||||||
|
/// Timer::after(Duration::from_secs(1)).await;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn after(duration: Duration) -> Self {
|
pub fn after(duration: Duration) -> Self {
|
||||||
Self {
|
Self {
|
||||||
expires_at: Instant::now() + duration,
|
expires_at: Instant::now() + duration,
|
||||||
@ -66,12 +89,62 @@ impl Future for Timer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Asynchronous stream that yields every Duration, indefinitely.
|
||||||
|
///
|
||||||
|
/// This stream will tick at uniform intervals, even if blocking work is performed between ticks.
|
||||||
|
///
|
||||||
|
/// For instance, consider the following code fragment.
|
||||||
|
/// ``` no_run
|
||||||
|
/// # #![feature(trait_alias)]
|
||||||
|
/// # #![feature(min_type_alias_impl_trait)]
|
||||||
|
/// # #![feature(impl_trait_in_bindings)]
|
||||||
|
/// # #![feature(type_alias_impl_trait)]
|
||||||
|
/// #
|
||||||
|
/// use embassy::executor::task;
|
||||||
|
/// use embassy::time::{Duration, Timer};
|
||||||
|
/// # fn foo() {}
|
||||||
|
///
|
||||||
|
/// #[task]
|
||||||
|
/// async fn ticker_example_0() {
|
||||||
|
/// loop {
|
||||||
|
/// foo();
|
||||||
|
/// Timer::after(Duration::from_secs(1)).await;
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This fragment will not call `foo` every second.
|
||||||
|
/// Instead, it will call it every second + the time it took to previously call `foo`.
|
||||||
|
///
|
||||||
|
/// Example using ticker, which will consistently call `foo` once a second.
|
||||||
|
///
|
||||||
|
/// ``` no_run
|
||||||
|
/// # #![feature(trait_alias)]
|
||||||
|
/// # #![feature(min_type_alias_impl_trait)]
|
||||||
|
/// # #![feature(impl_trait_in_bindings)]
|
||||||
|
/// # #![feature(type_alias_impl_trait)]
|
||||||
|
/// #
|
||||||
|
/// use embassy::executor::task;
|
||||||
|
/// use embassy::time::{Duration, Ticker};
|
||||||
|
/// use futures::StreamExt;
|
||||||
|
/// # fn foo(){}
|
||||||
|
///
|
||||||
|
/// #[task]
|
||||||
|
/// async fn ticker_example_1() {
|
||||||
|
/// let mut ticker = Ticker::every(Duration::from_secs(1));
|
||||||
|
/// loop {
|
||||||
|
/// foo();
|
||||||
|
/// ticker.next().await;
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub struct Ticker {
|
pub struct Ticker {
|
||||||
expires_at: Instant,
|
expires_at: Instant,
|
||||||
duration: Duration,
|
duration: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ticker {
|
impl Ticker {
|
||||||
|
/// Creates a new ticker that ticks at the specified duration interval.
|
||||||
pub fn every(duration: Duration) -> Self {
|
pub fn every(duration: Duration) -> Self {
|
||||||
let expires_at = Instant::now() + duration;
|
let expires_at = Instant::now() + duration;
|
||||||
Self {
|
Self {
|
||||||
|
@ -5,6 +5,7 @@ use super::TICKS_PER_SECOND;
|
|||||||
|
|
||||||
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
/// Represents the difference between two [Instant](struct.Instant.html)s
|
||||||
pub struct Duration {
|
pub struct Duration {
|
||||||
pub(crate) ticks: u64,
|
pub(crate) ticks: u64,
|
||||||
}
|
}
|
||||||
@ -26,49 +27,55 @@ impl Duration {
|
|||||||
self.ticks * 1_000_000 / TICKS_PER_SECOND
|
self.ticks * 1_000_000 / TICKS_PER_SECOND
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a duration from the specified number of clock ticks
|
||||||
pub const fn from_ticks(ticks: u64) -> Duration {
|
pub const fn from_ticks(ticks: u64) -> Duration {
|
||||||
Duration { ticks }
|
Duration { ticks }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a duration from the specified number of seconds
|
||||||
pub const fn from_secs(secs: u64) -> Duration {
|
pub const fn from_secs(secs: u64) -> Duration {
|
||||||
Duration {
|
Duration {
|
||||||
ticks: secs * TICKS_PER_SECOND,
|
ticks: secs * TICKS_PER_SECOND,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a duration from the specified number of milliseconds
|
||||||
pub const fn from_millis(millis: u64) -> Duration {
|
pub const fn from_millis(millis: u64) -> Duration {
|
||||||
Duration {
|
Duration {
|
||||||
ticks: millis * TICKS_PER_SECOND / 1000,
|
ticks: millis * TICKS_PER_SECOND / 1000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/// Creates a duration from the specified number of microseconds
|
||||||
NOTE: us delays may not be as accurate
|
/// NOTE: Delays this small may be inaccurate.
|
||||||
*/
|
|
||||||
pub const fn from_micros(micros: u64) -> Duration {
|
pub const fn from_micros(micros: u64) -> Duration {
|
||||||
Duration {
|
Duration {
|
||||||
ticks: micros * TICKS_PER_SECOND / 1_000_000,
|
ticks: micros * TICKS_PER_SECOND / 1_000_000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds one Duration to another, returning a new Duration or None in the event of an overflow.
|
||||||
pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
|
pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
|
||||||
self.ticks
|
self.ticks
|
||||||
.checked_add(rhs.ticks)
|
.checked_add(rhs.ticks)
|
||||||
.map(|ticks| Duration { ticks })
|
.map(|ticks| Duration { ticks })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Subtracts one Duration to another, returning a new Duration or None in the event of an overflow.
|
||||||
pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
|
pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
|
||||||
self.ticks
|
self.ticks
|
||||||
.checked_sub(rhs.ticks)
|
.checked_sub(rhs.ticks)
|
||||||
.map(|ticks| Duration { ticks })
|
.map(|ticks| Duration { ticks })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Multiplies one Duration by a scalar u32, returning a new Duration or None in the event of an overflow.
|
||||||
pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
|
pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
|
||||||
self.ticks
|
self.ticks
|
||||||
.checked_mul(rhs as _)
|
.checked_mul(rhs as _)
|
||||||
.map(|ticks| Duration { ticks })
|
.map(|ticks| Duration { ticks })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Divides one Duration a scalar u32, returning a new Duration or None in the event of an overflow.
|
||||||
pub fn checked_div(self, rhs: u32) -> Option<Duration> {
|
pub fn checked_div(self, rhs: u32) -> Option<Duration> {
|
||||||
self.ticks
|
self.ticks
|
||||||
.checked_div(rhs as _)
|
.checked_div(rhs as _)
|
||||||
|
@ -6,6 +6,7 @@ use super::{now, Duration};
|
|||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
/// An Instant in time, based on the MCU's clock ticks since startup.
|
||||||
pub struct Instant {
|
pub struct Instant {
|
||||||
ticks: u64,
|
ticks: u64,
|
||||||
}
|
}
|
||||||
@ -14,44 +15,55 @@ impl Instant {
|
|||||||
pub const MIN: Instant = Instant { ticks: u64::MIN };
|
pub const MIN: Instant = Instant { ticks: u64::MIN };
|
||||||
pub const MAX: Instant = Instant { ticks: u64::MAX };
|
pub const MAX: Instant = Instant { ticks: u64::MAX };
|
||||||
|
|
||||||
|
/// Returns an Instant representing the current time.
|
||||||
pub fn now() -> Instant {
|
pub fn now() -> Instant {
|
||||||
Instant { ticks: now() }
|
Instant { ticks: now() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Instant as clock ticks since MCU start.
|
||||||
pub const fn from_ticks(ticks: u64) -> Self {
|
pub const fn from_ticks(ticks: u64) -> Self {
|
||||||
Self { ticks }
|
Self { ticks }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Instant as milliseconds since MCU start.
|
||||||
pub const fn from_millis(millis: u64) -> Self {
|
pub const fn from_millis(millis: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ticks: millis * TICKS_PER_SECOND as u64 / 1000,
|
ticks: millis * TICKS_PER_SECOND as u64 / 1000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Instant representing seconds since MCU start.
|
||||||
pub const fn from_secs(seconds: u64) -> Self {
|
pub const fn from_secs(seconds: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ticks: seconds * TICKS_PER_SECOND as u64,
|
ticks: seconds * TICKS_PER_SECOND as u64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Instant as ticks since MCU start.
|
||||||
|
|
||||||
pub const fn as_ticks(&self) -> u64 {
|
pub const fn as_ticks(&self) -> u64 {
|
||||||
self.ticks
|
self.ticks
|
||||||
}
|
}
|
||||||
|
/// Instant as seconds since MCU start.
|
||||||
|
|
||||||
pub const fn as_secs(&self) -> u64 {
|
pub const fn as_secs(&self) -> u64 {
|
||||||
self.ticks / TICKS_PER_SECOND as u64
|
self.ticks / TICKS_PER_SECOND as u64
|
||||||
}
|
}
|
||||||
|
/// Instant as miliseconds since MCU start.
|
||||||
|
|
||||||
pub const fn as_millis(&self) -> u64 {
|
pub const fn as_millis(&self) -> u64 {
|
||||||
self.ticks * 1000 / TICKS_PER_SECOND as u64
|
self.ticks * 1000 / TICKS_PER_SECOND as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Duration between this Instant and another Instant
|
||||||
|
/// Panics on over/underflow.
|
||||||
pub fn duration_since(&self, earlier: Instant) -> Duration {
|
pub fn duration_since(&self, earlier: Instant) -> Duration {
|
||||||
Duration {
|
Duration {
|
||||||
ticks: self.ticks.checked_sub(earlier.ticks).unwrap(),
|
ticks: self.ticks.checked_sub(earlier.ticks).unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Duration between this Instant and another Instant
|
||||||
pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
|
pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
|
||||||
if self.ticks < earlier.ticks {
|
if self.ticks < earlier.ticks {
|
||||||
None
|
None
|
||||||
@ -62,6 +74,8 @@ impl Instant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the duration since the "earlier" Instant.
|
||||||
|
/// If the "earlier" instant is in the future, the duration is set to zero.
|
||||||
pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
|
pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
|
||||||
Duration {
|
Duration {
|
||||||
ticks: if self.ticks < earlier.ticks {
|
ticks: if self.ticks < earlier.ticks {
|
||||||
@ -72,6 +86,7 @@ impl Instant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Duration elapsed since this Instant.
|
||||||
pub fn elapsed(&self) -> Duration {
|
pub fn elapsed(&self) -> Duration {
|
||||||
Instant::now() - *self
|
Instant::now() - *self
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
//! Time abstractions
|
||||||
|
//! To use these abstractions, first call `set_clock` with an instance of an [Clock](trait.Clock.html).
|
||||||
|
//!
|
||||||
mod duration;
|
mod duration;
|
||||||
mod instant;
|
mod instant;
|
||||||
mod traits;
|
mod traits;
|
||||||
@ -14,10 +17,16 @@ pub const TICKS_PER_SECOND: u64 = 32768;
|
|||||||
|
|
||||||
static mut CLOCK: Option<&'static dyn Clock> = None;
|
static mut CLOCK: Option<&'static dyn Clock> = None;
|
||||||
|
|
||||||
|
/// Sets the clock used for the timing abstractions
|
||||||
|
///
|
||||||
|
/// Safety: Sets a mutable global.
|
||||||
pub unsafe fn set_clock(clock: &'static dyn Clock) {
|
pub unsafe fn set_clock(clock: &'static dyn Clock) {
|
||||||
CLOCK = Some(clock);
|
CLOCK = Some(clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the current timestamp in ticks.
|
||||||
|
/// This is guaranteed to be monotonic, i.e. a call to now() will always return
|
||||||
|
/// a greater or equal value than earler calls.
|
||||||
pub(crate) fn now() -> u64 {
|
pub(crate) fn now() -> u64 {
|
||||||
unsafe { unwrap!(CLOCK, "No clock set").now() }
|
unsafe { unwrap!(CLOCK, "No clock set").now() }
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
use crate::fmt::panic;
|
use crate::fmt::panic;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
|
/// An explosive ordinance that panics if it is improperly disposed of.
|
||||||
|
///
|
||||||
|
/// This is to forbid dropping futures, when there is absolutely no other choice.
|
||||||
|
///
|
||||||
|
/// To correctly dispose of this device, call the [defuse](struct.DropBomb.html#method.defuse)
|
||||||
|
/// method before this object is dropped.
|
||||||
pub struct DropBomb {
|
pub struct DropBomb {
|
||||||
_private: (),
|
_private: (),
|
||||||
}
|
}
|
||||||
@ -10,6 +16,7 @@ impl DropBomb {
|
|||||||
Self { _private: () }
|
Self { _private: () }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Diffuses the bomb, rendering it safe to drop.
|
||||||
pub fn defuse(self) {
|
pub fn defuse(self) {
|
||||||
mem::forget(self)
|
mem::forget(self)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,25 @@ use core::mem::MaybeUninit;
|
|||||||
|
|
||||||
use atomic_polyfill::{AtomicBool, Ordering};
|
use atomic_polyfill::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
/// Type with static lifetime that may be written to once at runtime.
|
||||||
|
///
|
||||||
|
/// This may be used to initialize static objects at runtime, typically in the init routine.
|
||||||
|
/// This is useful for objects such as Embassy's RTC, which cannot be initialized in a const
|
||||||
|
/// context.
|
||||||
|
///
|
||||||
|
/// Note: IF a global mutable variable is desired, use a CriticalSectionMutex or ThreadModeMutex instead.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use embassy::util::Forever;
|
||||||
|
/// // Using an integer for the sake of keeping this example self-contained,
|
||||||
|
/// // see https://github.com/embassy-rs/embassy/wiki/Getting-Started for a more "proper" example.
|
||||||
|
/// static SOME_INT: Forever<u32> =Forever::new();
|
||||||
|
///
|
||||||
|
/// // put returns a mutable pointer to the object stored in the forever, which may then be passed
|
||||||
|
/// // around.
|
||||||
|
/// let mut x = SOME_INT.put(42);
|
||||||
|
/// assert_eq!(*x, 42);
|
||||||
|
/// ```
|
||||||
pub struct Forever<T> {
|
pub struct Forever<T> {
|
||||||
used: AtomicBool,
|
used: AtomicBool,
|
||||||
t: UnsafeCell<MaybeUninit<T>>,
|
t: UnsafeCell<MaybeUninit<T>>,
|
||||||
@ -19,6 +38,11 @@ impl<T> Forever<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gives this `Forever` a value.
|
||||||
|
///
|
||||||
|
/// Panics if this `Forever` already has a value.
|
||||||
|
///
|
||||||
|
/// Returns a mutable reference to the stored value.
|
||||||
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
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
//! Async utilities
|
||||||
mod drop_bomb;
|
mod drop_bomb;
|
||||||
mod forever;
|
mod forever;
|
||||||
mod mutex;
|
mod mutex;
|
||||||
|
@ -10,6 +10,9 @@ use crate::executor;
|
|||||||
use crate::fmt::panic;
|
use crate::fmt::panic;
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use crate::interrupt::{Interrupt, InterruptExt};
|
||||||
|
|
||||||
|
/// Synchronization primitive. Allows creating awaitable signals that may be passed between tasks.
|
||||||
|
///
|
||||||
|
/// For more advanced use cases, please consider [futures-intrusive](https://crates.io/crates/futures-intrusive) channels or mutexes.
|
||||||
pub struct Signal<T> {
|
pub struct Signal<T> {
|
||||||
state: UnsafeCell<State<T>>,
|
state: UnsafeCell<State<T>>,
|
||||||
}
|
}
|
||||||
@ -30,6 +33,7 @@ impl<T: Send> Signal<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mark this Signal as completed.
|
||||||
pub fn signal(&self, val: T) {
|
pub fn signal(&self, val: T) {
|
||||||
cortex_m::interrupt::free(|_| unsafe {
|
cortex_m::interrupt::free(|_| unsafe {
|
||||||
let state = &mut *self.state.get();
|
let state = &mut *self.state.get();
|
||||||
@ -64,10 +68,12 @@ impl<T: Send> Signal<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Future that completes when this Signal has been signaled.
|
||||||
pub fn wait(&self) -> impl Future<Output = T> + '_ {
|
pub fn wait(&self) -> impl Future<Output = T> + '_ {
|
||||||
futures::future::poll_fn(move |cx| self.poll_wait(cx))
|
futures::future::poll_fn(move |cx| self.poll_wait(cx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// non-blocking method to check whether this signal has been signaled.
|
||||||
pub fn signaled(&self) -> bool {
|
pub fn signaled(&self) -> bool {
|
||||||
cortex_m::interrupt::free(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_)))
|
cortex_m::interrupt::free(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_)))
|
||||||
}
|
}
|
||||||
@ -80,6 +86,25 @@ unsafe impl cortex_m::interrupt::Nr for NrWrap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a future that completes when the specified Interrupt is triggered.
|
||||||
|
///
|
||||||
|
/// The input handler is unregistered when this Future is dropped.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ``` no_compile
|
||||||
|
/// use embassy::traits::*;
|
||||||
|
/// use embassy::util::InterruptFuture;
|
||||||
|
/// use embassy::executor::task;
|
||||||
|
/// use embassy_stm32f4::interrupt; // Adjust this to your MCU's embassy HAL.
|
||||||
|
/// #[task]
|
||||||
|
/// async fn demo_interrupt_future() {
|
||||||
|
/// // Using STM32f446 interrupt names, adjust this to your application as necessary.
|
||||||
|
/// // Wait for TIM2 to tick.
|
||||||
|
/// let mut tim2_interrupt = interrupt::take!(TIM2);
|
||||||
|
/// InterruptFuture::new(&mut tim2_interrupt).await;
|
||||||
|
/// // TIM2 interrupt went off, do something...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub struct InterruptFuture<'a, I: Interrupt> {
|
pub struct InterruptFuture<'a, I: Interrupt> {
|
||||||
interrupt: &'a mut I,
|
interrupt: &'a mut I,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user