async_stm32f1xx/lib.rs
1//! Abstractions for asynchronous programming on the STM32F1xx family of microcontrollers.
2//!
3//! This crate provides [`futures`]-based abstractions for asynchronous programming with peripherals from [`stm32f1xx_hal`]:
4//!
5//! - [`AsyncTimer`](crate::timer::AsyncTimer) allows delaying the current task, wrapping [`Timer`](stm32f1xx_hal::timer::Timer).
6//! - [`TxSink`](crate::serial::TxSink) allows [`Sink`](futures::sink::Sink)-based USART transmissions, wrapping [`TxDma`](stm32f1xx_hal::dma::TxDma).
7//! - [`RxStream`](crate::serial::RxStream) allows [`Stream`](futures::stream::Stream)-based USART receives, wrapping [`RxDma`](stm32f1xx_hal::dma::RxDma).
8//!
9//! To properly schedule wakeups, this crate implements the following interrupts:
10//!
11//! - [`TIM2`](stm32f1xx_hal::pac::Interrupt::TIM2), [`TIM3`](stm32f1xx_hal::pac::Interrupt::TIM3)
12//! - [`DMA1_CHANNEL4`](stm32f1xx_hal::pac::Interrupt::DMA1_CHANNEL4), [`DMA1_CHANNEL7`](stm32f1xx_hal::pac::Interrupt::DMA1_CHANNEL7), [`DMA1_CHANNEL2`](stm32f1xx_hal::pac::Interrupt::DMA1_CHANNEL2)
13//! - [`DMA1_CHANNEL5`](stm32f1xx_hal::pac::Interrupt::DMA1_CHANNEL5), [`DMA1_CHANNEL6`](stm32f1xx_hal::pac::Interrupt::DMA1_CHANNEL6), [`DMA1_CHANNEL3`](stm32f1xx_hal::pac::Interrupt::DMA1_CHANNEL3)
14
15#![no_std]
16#![deny(clippy::all, rust_2018_idioms)]
17#![warn(missing_docs)]
18
19/// Creates a new interrupt waking a [`Waker`].
20///
21/// As this interrupt will be declared in this macro, it can't be used for anything else.
22///
23/// # Examples
24///
25/// This macro is useful for implementing [`Future::poll`]:
26///
27/// ```
28/// fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
29/// if self.is_ready() {
30/// Poll::Ready(())
31/// } else {
32/// waker_interrupt!(TIM2, cx.waker().clone());
33/// Poll::Pending
34/// }
35/// }
36/// ```
37///
38/// [`Waker`]: core::task::Waker
39/// [`Future::poll`]: core::future::Future::poll
40macro_rules! waker_interrupt {
41 ($INT:ident, $waker:expr) => {{
42 use core::sync::atomic::{self, Ordering};
43 use stm32f1xx_hal::pac::{interrupt, Interrupt, NVIC};
44
45 static mut WAKER: Option<Waker> = None;
46
47 #[interrupt]
48 fn $INT() {
49 // Safety: This context is disabled while the lower priority context accesses WAKER
50 if let Some(waker) = unsafe { WAKER.as_ref() } {
51 waker.wake_by_ref();
52
53 NVIC::mask(Interrupt::$INT);
54 }
55 }
56
57 NVIC::mask(Interrupt::$INT);
58 atomic::compiler_fence(Ordering::Acquire);
59 // Safety: The other relevant context, the interrupt, is disabled
60 unsafe { WAKER = Some($waker) }
61 NVIC::unpend(Interrupt::$INT);
62 atomic::compiler_fence(Ordering::Release);
63 // Safety: This is the end of a mask-based critical section
64 unsafe { NVIC::unmask(Interrupt::$INT) }
65 }};
66}
67
68pub mod serial;
69pub mod timer;