diff options
| -rw-r--r-- | embassy-stm32f4/src/serial.rs | 209 | ||||
| -rw-r--r-- | examples-stm32f4/src/serial.rs | 1 |
2 files changed, 63 insertions, 147 deletions
diff --git a/embassy-stm32f4/src/serial.rs b/embassy-stm32f4/src/serial.rs index 5c3e3f1ac..7efb4a0bb 100644 --- a/embassy-stm32f4/src/serial.rs +++ b/embassy-stm32f4/src/serial.rs | |||
| @@ -43,11 +43,13 @@ pub struct Serial<USART: PeriAddress<MemSize = u8>, TSTREAM: Stream, RSTREAM: St | |||
| 43 | struct State { | 43 | struct State { |
| 44 | tx_done: Signal<()>, | 44 | tx_done: Signal<()>, |
| 45 | rx_done: Signal<()>, | 45 | rx_done: Signal<()>, |
| 46 | dma_done: Signal<()>, | ||
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | static STATE: State = State { | 49 | static STATE: State = State { |
| 49 | tx_done: Signal::new(), | 50 | tx_done: Signal::new(), |
| 50 | rx_done: Signal::new(), | 51 | rx_done: Signal::new(), |
| 52 | dma_done: Signal::new(), | ||
| 51 | }; | 53 | }; |
| 52 | 54 | ||
| 53 | impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> { | 55 | impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> { |
| @@ -56,13 +58,14 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> { | |||
| 56 | rxd: PA10<Alternate<AF7>>, | 58 | rxd: PA10<Alternate<AF7>>, |
| 57 | tx_int: interrupt::DMA2_STREAM2Interrupt, | 59 | tx_int: interrupt::DMA2_STREAM2Interrupt, |
| 58 | rx_int: interrupt::DMA2_STREAM7Interrupt, | 60 | rx_int: interrupt::DMA2_STREAM7Interrupt, |
| 61 | usart_int: interrupt::USART1Interrupt, | ||
| 59 | dma: DMA2, | 62 | dma: DMA2, |
| 60 | usart: USART1, | 63 | usart: USART1, |
| 61 | parity: Parity, | 64 | parity: Parity, |
| 62 | baudrate: Bps, | 65 | baudrate: Bps, |
| 63 | clocks: Clocks, | 66 | clocks: Clocks, |
| 64 | ) -> Self { | 67 | ) -> Self { |
| 65 | let serial = HalSerial::usart1( | 68 | let mut serial = HalSerial::usart1( |
| 66 | usart, | 69 | usart, |
| 67 | (txd, rxd), | 70 | (txd, rxd), |
| 68 | SerialConfig { | 71 | SerialConfig { |
| @@ -76,9 +79,10 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> { | |||
| 76 | ) | 79 | ) |
| 77 | .unwrap(); | 80 | .unwrap(); |
| 78 | 81 | ||
| 79 | let (usart, _) = serial.release(); | 82 | serial.listen(SerialEvent::Idle); |
| 83 | serial.listen(SerialEvent::Txe); | ||
| 80 | 84 | ||
| 81 | // serial.listen(SerialEvent::Idle); | 85 | let (usart, _) = serial.release(); |
| 82 | 86 | ||
| 83 | // Register ISR | 87 | // Register ISR |
| 84 | tx_int.set_handler(Self::on_tx_irq); | 88 | tx_int.set_handler(Self::on_tx_irq); |
| @@ -89,6 +93,10 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> { | |||
| 89 | rx_int.unpend(); | 93 | rx_int.unpend(); |
| 90 | rx_int.enable(); | 94 | rx_int.enable(); |
| 91 | 95 | ||
| 96 | // usart_int.set_handler(Self::on_usart_irq); | ||
| 97 | // usart_int.unpend(); | ||
| 98 | // usart_int.enable(); | ||
| 99 | |||
| 92 | let streams = StreamsTuple::new(dma); | 100 | let streams = StreamsTuple::new(dma); |
| 93 | 101 | ||
| 94 | Serial { | 102 | Serial { |
| @@ -105,38 +113,50 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> { | |||
| 105 | unsafe fn on_rx_irq() { | 113 | unsafe fn on_rx_irq() { |
| 106 | STATE.rx_done.signal(()); | 114 | STATE.rx_done.signal(()); |
| 107 | } | 115 | } |
| 116 | |||
| 117 | unsafe fn on_usart_irq() { | ||
| 118 | /* | ||
| 119 | TODO: Signal tx_done if txe | ||
| 120 | */ | ||
| 121 | |||
| 122 | /* | ||
| 123 | TODO: Signal rx_done if idle | ||
| 124 | */ | ||
| 125 | |||
| 126 | // STATE.rx_done.signal(()); | ||
| 127 | } | ||
| 108 | /// Sends serial data. | 128 | /// Sends serial data. |
| 109 | /// | 129 | /// |
| 110 | /// `tx_buffer` is marked as static as per `embedded-dma` requirements. | 130 | /// `tx_buffer` is marked as static as per `embedded-dma` requirements. |
| 111 | /// It it safe to use a buffer with a non static lifetime if memory is not | 131 | /// It it safe to use a buffer with a non static lifetime if memory is not |
| 112 | /// reused until the future has finished. | 132 | /// reused until the future has finished. |
| 113 | pub fn send<'a, B>( | 133 | pub fn send<'a, B>(&'a mut self, tx_buffer: B) -> impl Future<Output = ()> + 'a |
| 114 | &'a mut self, | ||
| 115 | tx_buffer: B, | ||
| 116 | ) -> SendFuture<'a, B, USART1, Stream7<DMA2>, Stream2<DMA2>, Channel4> | ||
| 117 | where | 134 | where |
| 118 | B: WriteBuffer<Word = u8> + 'static, | 135 | B: WriteBuffer<Word = u8> + 'static, |
| 119 | { | 136 | { |
| 120 | let tx_stream = self.tx_stream.take().unwrap(); | 137 | let tx_stream = self.tx_stream.take().unwrap(); |
| 121 | let usart = self.usart.take().unwrap(); | 138 | let usart = self.usart.take().unwrap(); |
| 122 | let mut tx_transfer = Transfer::init( | ||
| 123 | tx_stream, | ||
| 124 | usart, | ||
| 125 | tx_buffer, | ||
| 126 | None, | ||
| 127 | DmaConfig::default() | ||
| 128 | .transfer_complete_interrupt(true) | ||
| 129 | .memory_increment(true) | ||
| 130 | .double_buffer(false), | ||
| 131 | ); | ||
| 132 | |||
| 133 | STATE.tx_done.reset(); | 139 | STATE.tx_done.reset(); |
| 134 | 140 | ||
| 135 | SendFuture { | 141 | async move { |
| 136 | Serial: self, | 142 | let mut tx_transfer = Transfer::init( |
| 137 | tx_transfer: Some(tx_transfer), | 143 | tx_stream, |
| 138 | // tx_stream: Some(tx_stream), | 144 | usart, |
| 139 | // usart: Some(usart), | 145 | tx_buffer, |
| 146 | None, | ||
| 147 | DmaConfig::default() | ||
| 148 | .transfer_complete_interrupt(true) | ||
| 149 | .memory_increment(true) | ||
| 150 | .double_buffer(false), | ||
| 151 | ); | ||
| 152 | |||
| 153 | tx_transfer.start(|_usart| {}); | ||
| 154 | |||
| 155 | STATE.tx_done.wait().await; | ||
| 156 | |||
| 157 | let (tx_stream, usart, _buf, _) = tx_transfer.free(); | ||
| 158 | self.tx_stream.replace(tx_stream); | ||
| 159 | self.usart.replace(usart); | ||
| 140 | } | 160 | } |
| 141 | } | 161 | } |
| 142 | 162 | ||
| @@ -150,140 +170,35 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> { | |||
| 150 | /// `rx_buffer` is marked as static as per `embedded-dma` requirements. | 170 | /// `rx_buffer` is marked as static as per `embedded-dma` requirements. |
| 151 | /// It it safe to use a buffer with a non static lifetime if memory is not | 171 | /// It it safe to use a buffer with a non static lifetime if memory is not |
| 152 | /// reused until the future has finished. | 172 | /// reused until the future has finished. |
| 153 | pub fn receive<'a, B>( | 173 | pub fn receive<'a, B>(&'a mut self, rx_buffer: B) -> impl Future<Output = B> + 'a |
| 154 | &'a mut self, | ||
| 155 | rx_buffer: B, | ||
| 156 | ) -> ReceiveFuture<'a, B, USART1, Stream7<DMA2>, Stream2<DMA2>, Channel4> | ||
| 157 | where | 174 | where |
| 158 | B: WriteBuffer<Word = u8> + 'static, | 175 | B: WriteBuffer<Word = u8> + 'static + Unpin, |
| 159 | { | 176 | { |
| 160 | let rx_stream = self.rx_stream.take().unwrap(); | 177 | let rx_stream = self.rx_stream.take().unwrap(); |
| 161 | let usart = self.usart.take().unwrap(); | 178 | let usart = self.usart.take().unwrap(); |
| 162 | let mut rx_transfer = Transfer::init( | ||
| 163 | rx_stream, | ||
| 164 | usart, | ||
| 165 | rx_buffer, | ||
| 166 | None, | ||
| 167 | DmaConfig::default() | ||
| 168 | .transfer_complete_interrupt(true) | ||
| 169 | .half_transfer_interrupt(true) | ||
| 170 | .memory_increment(true) | ||
| 171 | .double_buffer(false), | ||
| 172 | ); | ||
| 173 | |||
| 174 | STATE.rx_done.reset(); | 179 | STATE.rx_done.reset(); |
| 175 | 180 | ||
| 176 | ReceiveFuture { | 181 | async move { |
| 177 | Serial: self, | 182 | let mut rx_transfer = Transfer::init( |
| 178 | rx_transfer: Some(rx_transfer), | 183 | rx_stream, |
| 179 | } | 184 | usart, |
| 180 | } | 185 | rx_buffer, |
| 181 | } | 186 | None, |
| 182 | 187 | DmaConfig::default() | |
| 183 | /// Future for the [`LowPowerSerial::send()`] method. | 188 | .transfer_complete_interrupt(true) |
| 184 | pub struct SendFuture< | 189 | .memory_increment(true) |
| 185 | 'a, | 190 | .double_buffer(false), |
| 186 | B: WriteBuffer<Word = u8> + 'static, | 191 | ); |
| 187 | USART: PeriAddress<MemSize = u8>, | ||
| 188 | TSTREAM: Stream, | ||
| 189 | RSTREAM: Stream, | ||
| 190 | CHANNEL, | ||
| 191 | > { | ||
| 192 | Serial: &'a mut Serial<USART, TSTREAM, RSTREAM>, | ||
| 193 | tx_transfer: Option<Transfer<TSTREAM, CHANNEL, USART, MemoryToPeripheral, B>>, | ||
| 194 | } | ||
| 195 | |||
| 196 | // impl<'a, B> Drop for SendFuture<'a, B> | ||
| 197 | // where | ||
| 198 | // B: WriteBuffer<Word = u8> + 'static, | ||
| 199 | // { | ||
| 200 | // fn drop(self: &mut Self) {} | ||
| 201 | // } | ||
| 202 | |||
| 203 | impl<'a, B> Future for SendFuture<'a, B, USART1, Stream7<DMA2>, Stream2<DMA2>, Channel4> | ||
| 204 | where | ||
| 205 | B: WriteBuffer<Word = u8> + 'static, | ||
| 206 | { | ||
| 207 | type Output = (); | ||
| 208 | |||
| 209 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { | ||
| 210 | let Self { | ||
| 211 | Serial, | ||
| 212 | tx_transfer, | ||
| 213 | } = unsafe { self.get_unchecked_mut() }; | ||
| 214 | let mut taken = tx_transfer.take().unwrap(); | ||
| 215 | if Stream7::<DMA2>::get_transfer_complete_flag() { | ||
| 216 | let (tx_stream, usart, buf, _) = taken.free(); | ||
| 217 | |||
| 218 | Serial.tx_stream.replace(tx_stream); | ||
| 219 | Serial.usart.replace(usart); | ||
| 220 | |||
| 221 | Poll::Ready(()) | ||
| 222 | } else { | ||
| 223 | // waker_interrupt!(DMA2_STREAM7, cx.waker().clone()); | ||
| 224 | taken.start(|_usart| {}); | ||
| 225 | tx_transfer.replace(taken); | ||
| 226 | |||
| 227 | // Poll::Pending | ||
| 228 | STATE.tx_done.poll_wait(cx) | ||
| 229 | } | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | /// Future for the [`Serial::receive()`] method. | ||
| 234 | pub struct ReceiveFuture< | ||
| 235 | 'a, | ||
| 236 | B: WriteBuffer<Word = u8> + 'static, | ||
| 237 | USART: PeriAddress<MemSize = u8>, | ||
| 238 | TSTREAM: Stream, | ||
| 239 | RSTREAM: Stream, | ||
| 240 | CHANNEL, | ||
| 241 | > { | ||
| 242 | Serial: &'a mut Serial<USART, TSTREAM, RSTREAM>, | ||
| 243 | rx_transfer: Option<Transfer<RSTREAM, CHANNEL, USART, PeripheralToMemory, B>>, | ||
| 244 | } | ||
| 245 | |||
| 246 | // impl<'a, B> Drop for ReceiveFuture<'a, B, USART1, Stream7<DMA2>, Channel4> | ||
| 247 | // where | ||
| 248 | // B: WriteBuffer<Word = u8> + 'static, | ||
| 249 | // { | ||
| 250 | // fn drop(self: &mut Self) {} | ||
| 251 | // } | ||
| 252 | |||
| 253 | impl<'a, B> Future for ReceiveFuture<'a, B, USART1, Stream7<DMA2>, Stream2<DMA2>, Channel4> | ||
| 254 | where | ||
| 255 | B: WriteBuffer<Word = u8> + 'static + Unpin, | ||
| 256 | { | ||
| 257 | type Output = B; | ||
| 258 | |||
| 259 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<B> { | ||
| 260 | let Self { | ||
| 261 | Serial, | ||
| 262 | rx_transfer, | ||
| 263 | } = unsafe { self.get_unchecked_mut() }; | ||
| 264 | let mut taken = rx_transfer.take().unwrap(); | ||
| 265 | |||
| 266 | if Stream7::<DMA2>::get_transfer_complete_flag() { | ||
| 267 | let (rx_stream, usart, buf, _) = rx_transfer.take().unwrap().free(); | ||
| 268 | |||
| 269 | Serial.rx_stream.replace(rx_stream); | ||
| 270 | Serial.usart.replace(usart); | ||
| 271 | 192 | ||
| 272 | Poll::Ready(buf) | 193 | rx_transfer.start(|_usart| {}); |
| 273 | } else { | ||
| 274 | // waker_interrupt!(DMA2_STREAM2, cx.waker().clone()); | ||
| 275 | 194 | ||
| 276 | taken.start(|_usart| {}); | 195 | STATE.rx_done.wait().await; |
| 277 | rx_transfer.replace(taken); | ||
| 278 | 196 | ||
| 279 | STATE.rx_done.poll_wait(cx); | 197 | let (rx_stream, usart, buf, _) = rx_transfer.free(); |
| 198 | self.rx_stream.replace(rx_stream); | ||
| 199 | self.usart.replace(usart); | ||
| 280 | 200 | ||
| 281 | /* | 201 | buf |
| 282 | Note: we have to do this because rx_transfer owns the buffer and we can't | ||
| 283 | access it until the transfer is completed. Therefore we can't pass | ||
| 284 | the buffer to poll_wait, but we still need to be woken. | ||
| 285 | */ | ||
| 286 | Poll::Pending | ||
| 287 | } | 202 | } |
| 288 | } | 203 | } |
| 289 | } | 204 | } |
diff --git a/examples-stm32f4/src/serial.rs b/examples-stm32f4/src/serial.rs index 296da4043..6c757dd2f 100644 --- a/examples-stm32f4/src/serial.rs +++ b/examples-stm32f4/src/serial.rs | |||
| @@ -32,6 +32,7 @@ async fn run(dp: stm32::Peripherals, cp: cortex_m::Peripherals) { | |||
| 32 | gpioa.pa10.into_alternate_af7(), | 32 | gpioa.pa10.into_alternate_af7(), |
| 33 | interrupt::take!(DMA2_STREAM2), | 33 | interrupt::take!(DMA2_STREAM2), |
| 34 | interrupt::take!(DMA2_STREAM7), | 34 | interrupt::take!(DMA2_STREAM7), |
| 35 | interrupt::take!(USART1), | ||
| 35 | dp.DMA2, | 36 | dp.DMA2, |
| 36 | dp.USART1, | 37 | dp.USART1, |
| 37 | config::Parity::ParityNone, | 38 | config::Parity::ParityNone, |
