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;