diff --git a/embassy-stm32f4-examples/src/bin/serial.rs b/embassy-stm32f4-examples/src/bin/serial.rs index 49a588c2..c8e7f288 100644 --- a/embassy-stm32f4-examples/src/bin/serial.rs +++ b/embassy-stm32f4-examples/src/bin/serial.rs @@ -12,10 +12,11 @@ use example_common::{panic, *}; use cortex_m::singleton; use cortex_m_rt::entry; use embassy::executor::{task, Executor}; -use embassy::traits::uart::Uart; +use embassy::traits::uart::{Read, Write}; use embassy::util::Forever; use embassy_stm32f4::interrupt; use embassy_stm32f4::serial; +use futures::pin_mut; use stm32f4xx_hal::dma::StreamsTuple; use stm32f4xx_hal::prelude::*; use stm32f4xx_hal::serial::config::Config; @@ -76,10 +77,12 @@ async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) { clocks, ) }; + pin_mut!(serial); + let buf = singleton!(: [u8; 30] = [0; 30]).unwrap(); buf[5] = 0x01; - serial.send(buf).await.unwrap(); + serial.write(buf).await.unwrap(); } static EXECUTOR: Forever = Forever::new(); diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index c8dc0598..7539abf5 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs @@ -1,17 +1,12 @@ -//! Async low power Serial. -//! -//! The peripheral is autmatically enabled and disabled as required to save power. -//! Lowest power consumption can only be guaranteed if the send receive futures -//! are dropped correctly (e.g. not using `mem::forget()`). +//! Async Serial. use core::future::Future; use core::marker::PhantomData; - -use futures::{select_biased, FutureExt}; - +use core::pin::Pin; use embassy::interrupt::Interrupt; -use embassy::traits::uart::{Error, IdleUart, Uart}; +use embassy::traits::uart::{Error, Read, ReadUntilIdle, Write}; use embassy::util::InterruptFuture; +use futures::{select_biased, FutureExt}; use crate::hal::{ dma, @@ -89,7 +84,7 @@ where } } -impl Uart for Serial +impl Read for Serial where USART: serial::Instance + PeriAddress @@ -101,56 +96,19 @@ where RSTREAM: Stream + WithInterrupt + 'static, CHANNEL: Channel + '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> { - #[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(); - - async move { - let mut tx_transfer = Transfer::init( - tx_stream, - usart, - static_buf, - None, - DmaConfig::default() - .transfer_complete_interrupt(true) - .memory_increment(true) - .double_buffer(false), - ); - - let fut = InterruptFuture::new(&mut self.tx_int); - - tx_transfer.start(|_usart| {}); - fut.await; - - let (tx_stream, usart, _buf, _) = tx_transfer.free(); - - self.tx_stream.replace(tx_stream); - self.usart.replace(usart); - - Ok(()) - } - } + type ReadFuture<'a> = impl Future> + 'a; /// Receives serial data. /// /// The future is pending until the buffer is completely filled. - /// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel - /// 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> { + fn read<'a>(self: Pin<&'a mut Self>, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { + let this = unsafe { self.get_unchecked_mut() }; 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 { + let rx_stream = this.rx_stream.take().unwrap(); + let usart = this.usart.take().unwrap(); + let mut rx_transfer = Transfer::init( rx_stream, usart, @@ -162,20 +120,20 @@ where .double_buffer(false), ); - let fut = InterruptFuture::new(&mut self.rx_int); + let fut = InterruptFuture::new(&mut this.rx_int); rx_transfer.start(|_usart| {}); fut.await; let (rx_stream, usart, _, _) = rx_transfer.free(); - self.rx_stream.replace(rx_stream); - self.usart.replace(usart); + this.rx_stream.replace(rx_stream); + this.usart.replace(usart); Ok(()) } } } -impl IdleUart for Serial +impl Write for Serial where USART: serial::Instance + PeriAddress @@ -187,20 +145,74 @@ where RSTREAM: Stream + WithInterrupt + 'static, CHANNEL: Channel + 'static, { - type ReceiveFuture<'a> = impl Future> + 'a; + type WriteFuture<'a> = impl Future> + 'a; + + /// Sends serial data. + fn write<'a>(self: Pin<&'a mut Self>, buf: &'a [u8]) -> Self::WriteFuture<'a> { + let this = unsafe { self.get_unchecked_mut() }; + #[allow(mutable_transmutes)] + let static_buf = unsafe { core::mem::transmute::<&'a [u8], &'static mut [u8]>(buf) }; + + async move { + let tx_stream = this.tx_stream.take().unwrap(); + let usart = this.usart.take().unwrap(); + + let mut tx_transfer = Transfer::init( + tx_stream, + usart, + static_buf, + None, + DmaConfig::default() + .transfer_complete_interrupt(true) + .memory_increment(true) + .double_buffer(false), + ); + + let fut = InterruptFuture::new(&mut this.tx_int); + + tx_transfer.start(|_usart| {}); + fut.await; + + let (tx_stream, usart, _buf, _) = tx_transfer.free(); + + this.tx_stream.replace(tx_stream); + this.usart.replace(usart); + + Ok(()) + } + } +} + +impl ReadUntilIdle for Serial +where + USART: serial::Instance + + PeriAddress + + DMASet + + DMASet + + WithInterrupt + + 'static, + TSTREAM: Stream + WithInterrupt + 'static, + RSTREAM: Stream + WithInterrupt + 'static, + CHANNEL: Channel + 'static, +{ + type ReadUntilIdleFuture<'a> = impl Future> + '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> { + fn read_until_idle<'a>( + self: Pin<&'a mut Self>, + buf: &'a mut [u8], + ) -> Self::ReadUntilIdleFuture<'a> { + let this = unsafe { self.get_unchecked_mut() }; 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 { + let rx_stream = this.rx_stream.take().unwrap(); + let usart = this.usart.take().unwrap(); + unsafe { /* __HAL_UART_ENABLE_IT(&uart->UartHandle, UART_IT_IDLE); */ (*USART::ptr()).cr1.modify(|_, w| w.idleie().set_bit()); @@ -223,15 +235,12 @@ where 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); + let fut = InterruptFuture::new(&mut this.rx_int); + let fut_idle = InterruptFuture::new(&mut this.usart_int); rx_transfer.start(|_usart| {}); - select_biased! { - () = fut.fuse() => {}, - () = fut_idle.fuse() => {}, - } + futures::future::select(fut, fut_idle).await; let (rx_stream, usart, _, _) = rx_transfer.free(); @@ -240,8 +249,8 @@ where unsafe { (*USART::ptr()).cr1.modify(|_, w| w.idleie().clear_bit()); } - self.rx_stream.replace(rx_stream); - self.usart.replace(usart); + this.rx_stream.replace(rx_stream); + this.usart.replace(usart); Ok(total_bytes - remaining_bytes) }