implement on irqs

This commit is contained in:
xoviat 2020-12-31 17:59:01 -06:00
parent cc8d162859
commit d5cb9bebaa
2 changed files with 65 additions and 50 deletions

View File

@ -329,34 +329,34 @@ pub use stm32f4xx_hal::stm32 as pac;
/// ///
/// [`Waker`]: core::task::Waker /// [`Waker`]: core::task::Waker
/// [`Future::poll`]: core::future::Future::poll /// [`Future::poll`]: core::future::Future::poll
macro_rules! waker_interrupt { // macro_rules! waker_interrupt {
($INT:ident, $waker:expr) => {{ // ($INT:ident, $waker:expr) => {{
use core::sync::atomic::{self, Ordering}; // use core::sync::atomic::{self, Ordering};
use core::task::Waker; // use core::task::Waker;
use stm32f4xx_hal::pac::{interrupt, Interrupt, NVIC}; // use stm32f4xx_hal::pac::{interrupt, Interrupt, NVIC};
//
static mut WAKER: Option<Waker> = None; // static mut WAKER: Option<Waker> = None;
//
#[interrupt] // #[interrupt]
fn $INT() { // fn $INT() {
// Safety: This context is disabled while the lower priority context accesses WAKER // // Safety: This context is disabled while the lower priority context accesses WAKER
if let Some(waker) = unsafe { WAKER.as_ref() } { // if let Some(waker) = unsafe { WAKER.as_ref() } {
waker.wake_by_ref(); // waker.wake_by_ref();
//
NVIC::mask(Interrupt::$INT); // NVIC::mask(Interrupt::$INT);
} // }
} // }
//
NVIC::mask(Interrupt::$INT); // NVIC::mask(Interrupt::$INT);
atomic::compiler_fence(Ordering::Acquire); // atomic::compiler_fence(Ordering::Acquire);
// Safety: The other relevant context, the interrupt, is disabled // // Safety: The other relevant context, the interrupt, is disabled
unsafe { WAKER = Some($waker) } // unsafe { WAKER = Some($waker) }
NVIC::unpend(Interrupt::$INT); // NVIC::unpend(Interrupt::$INT);
atomic::compiler_fence(Ordering::Release); // atomic::compiler_fence(Ordering::Release);
// Safety: This is the end of a mask-based critical section // // Safety: This is the end of a mask-based critical section
unsafe { NVIC::unmask(Interrupt::$INT) } // unsafe { NVIC::unmask(Interrupt::$INT) }
}}; // }};
} // }
// This mod MUST go first, so that the others see its macros. // This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt; pub(crate) mod fmt;

View File

@ -4,31 +4,20 @@
//! Lowest power consumption can only be guaranteed if the send receive futures //! Lowest power consumption can only be guaranteed if the send receive futures
//! are dropped correctly (e.g. not using `mem::forget()`). //! are dropped correctly (e.g. not using `mem::forget()`).
use core::cell::UnsafeCell;
use core::cmp::min;
use core::future::Future; use core::future::Future;
use core::marker::PhantomPinned;
use core::ops::Deref;
use core::pin::Pin;
use core::ptr;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::{Context, Poll}; use core::task::{Context, Poll};
use cortex_m::singleton;
use embassy::interrupt::OwnedInterrupt;
use embassy::util::Signal; use embassy::util::Signal;
use embedded_dma::{StaticReadBuffer, StaticWriteBuffer, WriteBuffer}; use embedded_dma::{StaticReadBuffer, StaticWriteBuffer, WriteBuffer};
use crate::fmt::assert;
use crate::hal::dma::config::DmaConfig; use crate::hal::dma::config::DmaConfig;
use crate::hal::dma::traits::{PeriAddress, Stream}; use crate::hal::dma::traits::{PeriAddress, Stream};
use crate::hal::dma::{ use crate::hal::dma::{
Channel4, Channel7, MemoryToPeripheral, PeripheralToMemory, Stream2, Stream7, StreamsTuple, Channel4, MemoryToPeripheral, PeripheralToMemory, Stream2, Stream7, StreamsTuple, Transfer,
Transfer,
}; };
use crate::hal::gpio::gpioa::{PA10, PA9}; use crate::hal::gpio::gpioa::{PA10, PA9};
use crate::hal::gpio::{Alternate, AF10, AF7, AF9}; use crate::hal::gpio::{Alternate, AF7};
use crate::hal::gpio::{Floating, Input, Output, PushPull};
use crate::hal::pac;
use crate::hal::prelude::*; use crate::hal::prelude::*;
use crate::hal::rcc::Clocks; use crate::hal::rcc::Clocks;
use crate::hal::serial::config::{ use crate::hal::serial::config::{
@ -42,8 +31,6 @@ use crate::interrupt;
use crate::pac::Interrupt; use crate::pac::Interrupt;
use crate::pac::{DMA2, USART1}; use crate::pac::{DMA2, USART1};
use embedded_hal::digital::v2::OutputPin;
/// Interface to the Serial peripheral /// Interface to the Serial peripheral
pub struct Serial<USART: PeriAddress<MemSize = u8>, TSTREAM: Stream, RSTREAM: Stream> { pub struct Serial<USART: PeriAddress<MemSize = u8>, TSTREAM: Stream, RSTREAM: Stream> {
// tx_transfer: Transfer<Stream7<DMA2>, Channel4, USART1, MemoryToPeripheral, &mut [u8; 20]>, // tx_transfer: Transfer<Stream7<DMA2>, Channel4, USART1, MemoryToPeripheral, &mut [u8; 20]>,
@ -55,7 +42,7 @@ pub struct Serial<USART: PeriAddress<MemSize = u8>, TSTREAM: Stream, RSTREAM: St
struct State { struct State {
tx_done: Signal<()>, tx_done: Signal<()>,
rx_done: Signal<u32>, rx_done: Signal<()>,
} }
static STATE: State = State { static STATE: State = State {
@ -93,6 +80,15 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
// serial.listen(SerialEvent::Idle); // serial.listen(SerialEvent::Idle);
// Register ISR
tx_int.set_handler(Self::on_tx_irq);
tx_int.unpend();
tx_int.enable();
rx_int.set_handler(Self::on_rx_irq);
rx_int.unpend();
rx_int.enable();
let streams = StreamsTuple::new(dma); let streams = StreamsTuple::new(dma);
Serial { Serial {
@ -102,6 +98,13 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
} }
} }
unsafe fn on_tx_irq() {
STATE.tx_done.signal(());
}
unsafe fn on_rx_irq() {
STATE.rx_done.signal(());
}
/// Sends serial data. /// Sends serial data.
/// ///
/// `tx_buffer` is marked as static as per `embedded-dma` requirements. /// `tx_buffer` is marked as static as per `embedded-dma` requirements.
@ -127,6 +130,8 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
.double_buffer(false), .double_buffer(false),
); );
STATE.tx_done.reset();
SendFuture { SendFuture {
Serial: self, Serial: self,
tx_transfer: Some(tx_transfer), tx_transfer: Some(tx_transfer),
@ -166,6 +171,8 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
.double_buffer(false), .double_buffer(false),
); );
STATE.rx_done.reset();
ReceiveFuture { ReceiveFuture {
Serial: self, Serial: self,
rx_transfer: Some(rx_transfer), rx_transfer: Some(rx_transfer),
@ -213,11 +220,12 @@ where
Poll::Ready(()) Poll::Ready(())
} else { } else {
waker_interrupt!(DMA2_STREAM7, cx.waker().clone()); // waker_interrupt!(DMA2_STREAM7, cx.waker().clone());
taken.start(|usart| {}); taken.start(|_usart| {});
tx_transfer.replace(taken); tx_transfer.replace(taken);
Poll::Pending // Poll::Pending
STATE.tx_done.poll_wait(cx)
} }
} }
} }
@ -263,11 +271,18 @@ where
Poll::Ready(buf) Poll::Ready(buf)
} else { } else {
waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); // waker_interrupt!(DMA2_STREAM2, cx.waker().clone());
taken.start(|usart| {}); taken.start(|_usart| {});
rx_transfer.replace(taken); rx_transfer.replace(taken);
STATE.rx_done.poll_wait(cx);
/*
Note: we have to do this because rx_transfer owns the buffer and we can't
access it until the transfer is completed. Therefore we can't pass
the buffer to poll_wait, but we still need to be woken.
*/
Poll::Pending Poll::Pending
} }
} }