diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-03-29 01:14:18 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-03-29 01:14:18 +0200 |
| commit | 3a0ddb8104694717cb573aa508acb4a8bbba3ff7 (patch) | |
| tree | e02bef7b7c7d26fe8feef1efe1a1dd03d505b529 | |
| parent | 5b74e326e5da8214eec9360e67f42ff2ca3905e8 (diff) | |
stm32/serial: update to new traits.
| -rw-r--r-- | embassy-stm32f4-examples/src/bin/serial.rs | 7 | ||||
| -rw-r--r-- | embassy-stm32f4/src/serial.rs | 127 |
2 files changed, 73 insertions, 61 deletions
diff --git a/embassy-stm32f4-examples/src/bin/serial.rs b/embassy-stm32f4-examples/src/bin/serial.rs index 49a588c25..c8e7f288f 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, *}; | |||
| 12 | use cortex_m::singleton; | 12 | use cortex_m::singleton; |
| 13 | use cortex_m_rt::entry; | 13 | use cortex_m_rt::entry; |
| 14 | use embassy::executor::{task, Executor}; | 14 | use embassy::executor::{task, Executor}; |
| 15 | use embassy::traits::uart::Uart; | 15 | use embassy::traits::uart::{Read, Write}; |
| 16 | use embassy::util::Forever; | 16 | use embassy::util::Forever; |
| 17 | use embassy_stm32f4::interrupt; | 17 | use embassy_stm32f4::interrupt; |
| 18 | use embassy_stm32f4::serial; | 18 | use embassy_stm32f4::serial; |
| 19 | use futures::pin_mut; | ||
| 19 | use stm32f4xx_hal::dma::StreamsTuple; | 20 | use stm32f4xx_hal::dma::StreamsTuple; |
| 20 | use stm32f4xx_hal::prelude::*; | 21 | use stm32f4xx_hal::prelude::*; |
| 21 | use stm32f4xx_hal::serial::config::Config; | 22 | use stm32f4xx_hal::serial::config::Config; |
| @@ -76,10 +77,12 @@ async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) { | |||
| 76 | clocks, | 77 | clocks, |
| 77 | ) | 78 | ) |
| 78 | }; | 79 | }; |
| 80 | pin_mut!(serial); | ||
| 81 | |||
| 79 | let buf = singleton!(: [u8; 30] = [0; 30]).unwrap(); | 82 | let buf = singleton!(: [u8; 30] = [0; 30]).unwrap(); |
| 80 | 83 | ||
| 81 | buf[5] = 0x01; | 84 | buf[5] = 0x01; |
| 82 | serial.send(buf).await.unwrap(); | 85 | serial.write(buf).await.unwrap(); |
| 83 | } | 86 | } |
| 84 | 87 | ||
| 85 | static EXECUTOR: Forever<Executor> = Forever::new(); | 88 | static EXECUTOR: Forever<Executor> = Forever::new(); |
diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index c8dc0598a..7539abf51 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs | |||
| @@ -1,17 +1,12 @@ | |||
| 1 | //! Async low power Serial. | 1 | //! Async Serial. |
| 2 | //! | ||
| 3 | //! The peripheral is autmatically enabled and disabled as required to save power. | ||
| 4 | //! Lowest power consumption can only be guaranteed if the send receive futures | ||
| 5 | //! are dropped correctly (e.g. not using `mem::forget()`). | ||
| 6 | 2 | ||
| 7 | use core::future::Future; | 3 | use core::future::Future; |
| 8 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| 9 | 5 | use core::pin::Pin; | |
| 10 | use futures::{select_biased, FutureExt}; | ||
| 11 | |||
| 12 | use embassy::interrupt::Interrupt; | 6 | use embassy::interrupt::Interrupt; |
| 13 | use embassy::traits::uart::{Error, IdleUart, Uart}; | 7 | use embassy::traits::uart::{Error, Read, ReadUntilIdle, Write}; |
| 14 | use embassy::util::InterruptFuture; | 8 | use embassy::util::InterruptFuture; |
| 9 | use futures::{select_biased, FutureExt}; | ||
| 15 | 10 | ||
| 16 | use crate::hal::{ | 11 | use crate::hal::{ |
| 17 | dma, | 12 | dma, |
| @@ -89,7 +84,7 @@ where | |||
| 89 | } | 84 | } |
| 90 | } | 85 | } |
| 91 | 86 | ||
| 92 | impl<USART, TSTREAM, RSTREAM, CHANNEL> Uart for Serial<USART, TSTREAM, RSTREAM, CHANNEL> | 87 | impl<USART, TSTREAM, RSTREAM, CHANNEL> Read for Serial<USART, TSTREAM, RSTREAM, CHANNEL> |
| 93 | where | 88 | where |
| 94 | USART: serial::Instance | 89 | USART: serial::Instance |
| 95 | + PeriAddress<MemSize = u8> | 90 | + PeriAddress<MemSize = u8> |
| @@ -101,20 +96,21 @@ where | |||
| 101 | RSTREAM: Stream + WithInterrupt + 'static, | 96 | RSTREAM: Stream + WithInterrupt + 'static, |
| 102 | CHANNEL: Channel + 'static, | 97 | CHANNEL: Channel + 'static, |
| 103 | { | 98 | { |
| 104 | type SendFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; | 99 | type ReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; |
| 105 | type ReceiveFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; | ||
| 106 | |||
| 107 | /// Sends serial data. | ||
| 108 | fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a> { | ||
| 109 | #[allow(mutable_transmutes)] | ||
| 110 | let static_buf = unsafe { core::mem::transmute::<&'a [u8], &'static mut [u8]>(buf) }; | ||
| 111 | 100 | ||
| 112 | let tx_stream = self.tx_stream.take().unwrap(); | 101 | /// Receives serial data. |
| 113 | let usart = self.usart.take().unwrap(); | 102 | /// |
| 103 | /// The future is pending until the buffer is completely filled. | ||
| 104 | fn read<'a>(self: Pin<&'a mut Self>, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 105 | let this = unsafe { self.get_unchecked_mut() }; | ||
| 106 | let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) }; | ||
| 114 | 107 | ||
| 115 | async move { | 108 | async move { |
| 116 | let mut tx_transfer = Transfer::init( | 109 | let rx_stream = this.rx_stream.take().unwrap(); |
| 117 | tx_stream, | 110 | let usart = this.usart.take().unwrap(); |
| 111 | |||
| 112 | let mut rx_transfer = Transfer::init( | ||
| 113 | rx_stream, | ||
| 118 | usart, | 114 | usart, |
| 119 | static_buf, | 115 | static_buf, |
| 120 | None, | 116 | None, |
| @@ -124,35 +120,45 @@ where | |||
| 124 | .double_buffer(false), | 120 | .double_buffer(false), |
| 125 | ); | 121 | ); |
| 126 | 122 | ||
| 127 | let fut = InterruptFuture::new(&mut self.tx_int); | 123 | let fut = InterruptFuture::new(&mut this.rx_int); |
| 128 | 124 | rx_transfer.start(|_usart| {}); | |
| 129 | tx_transfer.start(|_usart| {}); | ||
| 130 | fut.await; | 125 | fut.await; |
| 131 | 126 | ||
| 132 | let (tx_stream, usart, _buf, _) = tx_transfer.free(); | 127 | let (rx_stream, usart, _, _) = rx_transfer.free(); |
| 133 | 128 | this.rx_stream.replace(rx_stream); | |
| 134 | self.tx_stream.replace(tx_stream); | 129 | this.usart.replace(usart); |
| 135 | self.usart.replace(usart); | ||
| 136 | 130 | ||
| 137 | Ok(()) | 131 | Ok(()) |
| 138 | } | 132 | } |
| 139 | } | 133 | } |
| 134 | } | ||
| 140 | 135 | ||
| 141 | /// Receives serial data. | 136 | impl<USART, TSTREAM, RSTREAM, CHANNEL> Write for Serial<USART, TSTREAM, RSTREAM, CHANNEL> |
| 142 | /// | 137 | where |
| 143 | /// The future is pending until the buffer is completely filled. | 138 | USART: serial::Instance |
| 144 | /// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel | 139 | + PeriAddress<MemSize = u8> |
| 145 | /// unfinished transfers after a timeout to prevent lockup when no more data | 140 | + DMASet<TSTREAM, CHANNEL, MemoryToPeripheral> |
| 146 | /// is incoming. | 141 | + DMASet<RSTREAM, CHANNEL, PeripheralToMemory> |
| 147 | fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a> { | 142 | + WithInterrupt |
| 148 | let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) }; | 143 | + 'static, |
| 144 | TSTREAM: Stream + WithInterrupt + 'static, | ||
| 145 | RSTREAM: Stream + WithInterrupt + 'static, | ||
| 146 | CHANNEL: Channel + 'static, | ||
| 147 | { | ||
| 148 | type WriteFuture<'a> = impl Future<Output = Result<(), Error>> + 'a; | ||
| 149 | 149 | ||
| 150 | let rx_stream = self.rx_stream.take().unwrap(); | 150 | /// Sends serial data. |
| 151 | let usart = self.usart.take().unwrap(); | 151 | fn write<'a>(self: Pin<&'a mut Self>, buf: &'a [u8]) -> Self::WriteFuture<'a> { |
| 152 | let this = unsafe { self.get_unchecked_mut() }; | ||
| 153 | #[allow(mutable_transmutes)] | ||
| 154 | let static_buf = unsafe { core::mem::transmute::<&'a [u8], &'static mut [u8]>(buf) }; | ||
| 152 | 155 | ||
| 153 | async move { | 156 | async move { |
| 154 | let mut rx_transfer = Transfer::init( | 157 | let tx_stream = this.tx_stream.take().unwrap(); |
| 155 | rx_stream, | 158 | let usart = this.usart.take().unwrap(); |
| 159 | |||
| 160 | let mut tx_transfer = Transfer::init( | ||
| 161 | tx_stream, | ||
| 156 | usart, | 162 | usart, |
| 157 | static_buf, | 163 | static_buf, |
| 158 | None, | 164 | None, |
| @@ -162,20 +168,22 @@ where | |||
| 162 | .double_buffer(false), | 168 | .double_buffer(false), |
| 163 | ); | 169 | ); |
| 164 | 170 | ||
| 165 | let fut = InterruptFuture::new(&mut self.rx_int); | 171 | let fut = InterruptFuture::new(&mut this.tx_int); |
| 166 | rx_transfer.start(|_usart| {}); | 172 | |
| 173 | tx_transfer.start(|_usart| {}); | ||
| 167 | fut.await; | 174 | fut.await; |
| 168 | 175 | ||
| 169 | let (rx_stream, usart, _, _) = rx_transfer.free(); | 176 | let (tx_stream, usart, _buf, _) = tx_transfer.free(); |
| 170 | self.rx_stream.replace(rx_stream); | 177 | |
| 171 | self.usart.replace(usart); | 178 | this.tx_stream.replace(tx_stream); |
| 179 | this.usart.replace(usart); | ||
| 172 | 180 | ||
| 173 | Ok(()) | 181 | Ok(()) |
| 174 | } | 182 | } |
| 175 | } | 183 | } |
| 176 | } | 184 | } |
| 177 | 185 | ||
| 178 | impl<USART, TSTREAM, RSTREAM, CHANNEL> IdleUart for Serial<USART, TSTREAM, RSTREAM, CHANNEL> | 186 | impl<USART, TSTREAM, RSTREAM, CHANNEL> ReadUntilIdle for Serial<USART, TSTREAM, RSTREAM, CHANNEL> |
| 179 | where | 187 | where |
| 180 | USART: serial::Instance | 188 | USART: serial::Instance |
| 181 | + PeriAddress<MemSize = u8> | 189 | + PeriAddress<MemSize = u8> |
| @@ -187,20 +195,24 @@ where | |||
| 187 | RSTREAM: Stream + WithInterrupt + 'static, | 195 | RSTREAM: Stream + WithInterrupt + 'static, |
| 188 | CHANNEL: Channel + 'static, | 196 | CHANNEL: Channel + 'static, |
| 189 | { | 197 | { |
| 190 | type ReceiveFuture<'a> = impl Future<Output = Result<usize, Error>> + 'a; | 198 | type ReadUntilIdleFuture<'a> = impl Future<Output = Result<usize, Error>> + 'a; |
| 191 | 199 | ||
| 192 | /// Receives serial data. | 200 | /// Receives serial data. |
| 193 | /// | 201 | /// |
| 194 | /// The future is pending until either the buffer is completely full, or the RX line falls idle after receiving some data. | 202 | /// The future is pending until either the buffer is completely full, or the RX line falls idle after receiving some data. |
| 195 | /// | 203 | /// |
| 196 | /// Returns the number of bytes read. | 204 | /// Returns the number of bytes read. |
| 197 | fn receive_until_idle<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a> { | 205 | fn read_until_idle<'a>( |
| 206 | self: Pin<&'a mut Self>, | ||
| 207 | buf: &'a mut [u8], | ||
| 208 | ) -> Self::ReadUntilIdleFuture<'a> { | ||
| 209 | let this = unsafe { self.get_unchecked_mut() }; | ||
| 198 | let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) }; | 210 | let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) }; |
| 199 | 211 | ||
| 200 | let rx_stream = self.rx_stream.take().unwrap(); | ||
| 201 | let usart = self.usart.take().unwrap(); | ||
| 202 | |||
| 203 | async move { | 212 | async move { |
| 213 | let rx_stream = this.rx_stream.take().unwrap(); | ||
| 214 | let usart = this.usart.take().unwrap(); | ||
| 215 | |||
| 204 | unsafe { | 216 | unsafe { |
| 205 | /* __HAL_UART_ENABLE_IT(&uart->UartHandle, UART_IT_IDLE); */ | 217 | /* __HAL_UART_ENABLE_IT(&uart->UartHandle, UART_IT_IDLE); */ |
| 206 | (*USART::ptr()).cr1.modify(|_, w| w.idleie().set_bit()); | 218 | (*USART::ptr()).cr1.modify(|_, w| w.idleie().set_bit()); |
| @@ -223,15 +235,12 @@ where | |||
| 223 | 235 | ||
| 224 | let total_bytes = RSTREAM::get_number_of_transfers() as usize; | 236 | let total_bytes = RSTREAM::get_number_of_transfers() as usize; |
| 225 | 237 | ||
| 226 | let fut = InterruptFuture::new(&mut self.rx_int); | 238 | let fut = InterruptFuture::new(&mut this.rx_int); |
| 227 | let fut_idle = InterruptFuture::new(&mut self.usart_int); | 239 | let fut_idle = InterruptFuture::new(&mut this.usart_int); |
| 228 | 240 | ||
| 229 | rx_transfer.start(|_usart| {}); | 241 | rx_transfer.start(|_usart| {}); |
| 230 | 242 | ||
| 231 | select_biased! { | 243 | futures::future::select(fut, fut_idle).await; |
| 232 | () = fut.fuse() => {}, | ||
| 233 | () = fut_idle.fuse() => {}, | ||
| 234 | } | ||
| 235 | 244 | ||
| 236 | let (rx_stream, usart, _, _) = rx_transfer.free(); | 245 | let (rx_stream, usart, _, _) = rx_transfer.free(); |
| 237 | 246 | ||
| @@ -240,8 +249,8 @@ where | |||
| 240 | unsafe { | 249 | unsafe { |
| 241 | (*USART::ptr()).cr1.modify(|_, w| w.idleie().clear_bit()); | 250 | (*USART::ptr()).cr1.modify(|_, w| w.idleie().clear_bit()); |
| 242 | } | 251 | } |
| 243 | self.rx_stream.replace(rx_stream); | 252 | this.rx_stream.replace(rx_stream); |
| 244 | self.usart.replace(usart); | 253 | this.usart.replace(usart); |
| 245 | 254 | ||
| 246 | Ok(total_bytes - remaining_bytes) | 255 | Ok(total_bytes - remaining_bytes) |
| 247 | } | 256 | } |
