From 9bcb0c36dc23c3faa946296e9ee05a073f6d2882 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 4 Mar 2021 17:20:35 -0600 Subject: [PATCH] implement generics on serial --- embassy-stm32f4-examples/src/bin/serial.rs | 23 ++- embassy-stm32f4/src/serial.rs | 210 +++++++++++++-------- 2 files changed, 152 insertions(+), 81 deletions(-) diff --git a/embassy-stm32f4-examples/src/bin/serial.rs b/embassy-stm32f4-examples/src/bin/serial.rs index 72fd1a2f..6351f728 100644 --- a/embassy-stm32f4-examples/src/bin/serial.rs +++ b/embassy-stm32f4-examples/src/bin/serial.rs @@ -14,6 +14,7 @@ use embassy::traits::uart::Uart; use embassy::util::Forever; use embassy_stm32f4::interrupt; use embassy_stm32f4::serial; +use stm32f4xx_hal::dma::StreamsTuple; use stm32f4xx_hal::prelude::*; use stm32f4xx_hal::serial::config::Config; use stm32f4xx_hal::stm32; @@ -38,10 +39,12 @@ async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) { .pclk1(24.mhz()) .freeze(); + let streams = StreamsTuple::new(dp.DMA2); + let mut serial = unsafe { serial::Serial::new( dp.USART1, - dp.DMA2, + (streams.7, streams.2), ( gpioa.pa9.into_alternate_af7(), gpioa.pa10.into_alternate_af7(), @@ -53,6 +56,24 @@ async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) { clocks, ) }; + + let streams = StreamsTuple::new(dp.DMA1); + + let mut serial = unsafe { + serial::Serial::new( + dp.USART2, + (streams.6, streams.5), + ( + gpioa.pa2.into_alternate_af7(), + gpioa.pa3.into_alternate_af7(), + ), + interrupt::take!(DMA1_STREAM6), + interrupt::take!(DMA1_STREAM5), + interrupt::take!(USART2), + Config::default().baudrate(9600.bps()), + clocks, + ) + }; let buf = singleton!(: [u8; 30] = [0; 30]).unwrap(); buf[5] = 0x01; diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index 8a90e9fa..36d569a9 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -8,129 +8,120 @@ use core::future::Future; use core::ptr; use core::sync::atomic::{self, Ordering}; -use embassy::interrupt::InterruptExt; +use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::traits::uart::{Error, Uart}; -use embassy::util::Signal; +use embassy::util::InterruptFuture; +use crate::hal::dma; use crate::hal::dma::config::DmaConfig; use crate::hal::dma::traits::{PeriAddress, Stream}; -use crate::hal::dma::{Stream2, Stream7, StreamsTuple, Transfer}; +use crate::hal::dma::{MemoryToPeripheral, PeripheralToMemory, Transfer}; use crate::hal::rcc::Clocks; +use crate::hal::serial; use crate::hal::serial::config::{Config as SerialConfig, DmaConfig as SerialDmaConfig}; use crate::hal::serial::Pins; use crate::hal::serial::{Event as SerialEvent, Serial as HalSerial}; use crate::interrupt; -use crate::pac::{DMA2, USART1}; +use crate::pac; /// Interface to the Serial peripheral -pub struct Serial, TSTREAM: Stream, RSTREAM: Stream> { +pub struct Serial< + USART: PeriAddress, + TSTREAM: Stream, + RSTREAM: Stream, + CHANNEL: dma::traits::Channel, + TINT: Interrupt, + RINT: Interrupt, + UINT: Interrupt, +> { tx_stream: Option, rx_stream: Option, usart: Option, - tx_int: interrupt::DMA2_STREAM7, - rx_int: interrupt::DMA2_STREAM2, - usart_int: interrupt::USART1, + tx_int: TINT, + rx_int: RINT, + usart_int: UINT, + channel: core::marker::PhantomData, } -struct State { - tx_int: Signal<()>, - rx_int: Signal<()>, -} +// static mut INSTANCE: *const Serial, Stream2> = ptr::null_mut(); -static STATE: State = State { - tx_int: Signal::new(), - rx_int: Signal::new(), -}; - -static mut INSTANCE: *const Serial, Stream2> = ptr::null_mut(); - -impl Serial, Stream2> { +impl + Serial +where + USART: serial::Instance + + dma::traits::PeriAddress + + dma::traits::DMASet + + dma::traits::DMASet + + WithInterrupt, + TSTREAM: Stream + WithInterrupt, + RSTREAM: Stream + WithInterrupt, + CHANNEL: dma::traits::Channel, + TINT: Interrupt, + RINT: Interrupt, + UINT: Interrupt, +{ // Leaking futures is forbidden! pub unsafe fn new( - usart: USART1, - dma: DMA2, + usart: USART, + streams: (TSTREAM, RSTREAM), pins: PINS, - tx_int: interrupt::DMA2_STREAM7, - rx_int: interrupt::DMA2_STREAM2, - usart_int: interrupt::USART1, + tx_int: TINT, + rx_int: RINT, + usart_int: UINT, mut config: SerialConfig, clocks: Clocks, ) -> Self where - PINS: Pins, + PINS: Pins, { config.dma = SerialDmaConfig::TxRx; - let mut serial = HalSerial::usart1(usart, pins, config, clocks).unwrap(); + let mut serial = HalSerial::new(usart, pins, config, clocks).unwrap(); serial.listen(SerialEvent::Idle); // serial.listen(SerialEvent::Txe); let (usart, _) = serial.release(); - // Register ISR - tx_int.set_handler(Self::on_tx_irq); - rx_int.set_handler(Self::on_rx_irq); - usart_int.set_handler(Self::on_rx_irq); - // usart_int.unpend(); - // usart_int.enable(); - - let streams = StreamsTuple::new(dma); + let (tx_stream, rx_stream) = streams; Serial { - tx_stream: Some(streams.7), - rx_stream: Some(streams.2), + tx_stream: Some(tx_stream), + rx_stream: Some(rx_stream), usart: Some(usart), tx_int: tx_int, rx_int: rx_int, usart_int: usart_int, + channel: core::marker::PhantomData, } } - - unsafe fn on_tx_irq(_ctx: *mut ()) { - let s = &(*INSTANCE); - - s.tx_int.disable(); - - STATE.tx_int.signal(()); - } - - unsafe fn on_rx_irq(_ctx: *mut ()) { - let s = &(*INSTANCE); - - atomic::compiler_fence(Ordering::Acquire); - s.rx_int.disable(); - s.usart_int.disable(); - atomic::compiler_fence(Ordering::Release); - - STATE.rx_int.signal(()); - } - - unsafe fn on_usart_irq(_ctx: *mut ()) { - let s = &(*INSTANCE); - - atomic::compiler_fence(Ordering::Acquire); - s.rx_int.disable(); - s.usart_int.disable(); - atomic::compiler_fence(Ordering::Release); - - STATE.rx_int.signal(()); - } } -impl Uart for Serial, Stream2> { +impl Uart + for Serial +where + USART: serial::Instance + + dma::traits::PeriAddress + + dma::traits::DMASet + + dma::traits::DMASet + + WithInterrupt + + 'static, + TSTREAM: Stream + WithInterrupt + 'static, + RSTREAM: Stream + WithInterrupt + 'static, + CHANNEL: dma::traits::Channel + 'static, + TINT: Interrupt + 'static, + RINT: Interrupt + 'static, + UINT: Interrupt + 'static, +{ type SendFuture<'a> = impl Future> + 'a; type ReceiveFuture<'a> = impl Future> + 'a; /// Sends serial data. fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a> { - unsafe { INSTANCE = self }; - #[allow(mutable_transmutes)] let static_buf = unsafe { core::mem::transmute::<&'a [u8], &'static mut [u8]>(buf) }; let tx_stream = self.tx_stream.take().unwrap(); let usart = self.usart.take().unwrap(); - STATE.tx_int.reset(); async move { let mut tx_transfer = Transfer::init( @@ -144,11 +135,11 @@ impl Uart for Serial, Stream2> { .double_buffer(false), ); - self.tx_int.unpend(); - self.tx_int.enable(); + let fut = InterruptFuture::new(&mut self.tx_int); + tx_transfer.start(|_usart| {}); - STATE.tx_int.wait().await; + fut.await; let (tx_stream, usart, _buf, _) = tx_transfer.free(); self.tx_stream.replace(tx_stream); @@ -165,12 +156,11 @@ impl Uart for Serial, Stream2> { /// unfinished transfers after a timeout to prevent lockup when no more data /// is incoming. fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a> { - unsafe { INSTANCE = self }; - 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(); - STATE.rx_int.reset(); + async move { let mut rx_transfer = Transfer::init( rx_stream, @@ -182,14 +172,74 @@ impl Uart for Serial, Stream2> { .memory_increment(true) .double_buffer(false), ); - self.rx_int.unpend(); - self.rx_int.enable(); + + let fut = InterruptFuture::new(&mut self.rx_int); + rx_transfer.start(|_usart| {}); - STATE.rx_int.wait().await; + fut.await; + let (rx_stream, usart, _, _) = rx_transfer.free(); self.rx_stream.replace(rx_stream); self.usart.replace(usart); + Ok(()) } } } + +mod private { + pub trait Sealed {} +} + +pub trait WithInterrupt: private::Sealed { + type Instance; +} + +macro_rules! dma { + ($($PER:ident => ($dma:ident, $stream:ident),)+) => { + $( + impl private::Sealed for dma::$stream {} + impl WithInterrupt for dma::$stream { + type Instance = interrupt::$PER; + } + )+ + } + } + +macro_rules! usart { + ($($PER:ident => ($usart:ident),)+) => { + $( + impl private::Sealed for pac::$usart {} + impl WithInterrupt for pac::$usart { + type Instance = interrupt::$PER; + } + )+ + } +} + +dma! { + DMA2_STREAM0 => (DMA2, Stream0), + DMA2_STREAM1 => (DMA2, Stream1), + DMA2_STREAM2 => (DMA2, Stream2), + DMA2_STREAM3 => (DMA2, Stream3), + DMA2_STREAM4 => (DMA2, Stream4), + DMA2_STREAM5 => (DMA2, Stream5), + DMA2_STREAM6 => (DMA2, Stream6), + DMA2_STREAM7 => (DMA2, Stream7), + DMA1_STREAM0 => (DMA1, Stream0), + DMA1_STREAM1 => (DMA1, Stream1), + DMA1_STREAM2 => (DMA1, Stream2), + DMA1_STREAM3 => (DMA1, Stream3), + DMA1_STREAM4 => (DMA1, Stream4), + DMA1_STREAM5 => (DMA1, Stream5), + DMA1_STREAM6 => (DMA1, Stream6), +} + +usart! { + USART1 => (USART1), + USART2 => (USART2), + USART3 => (USART3), + UART4 => (UART4), + UART5 => (UART5), + USART6 => (USART6), +}