diff options
| -rw-r--r-- | embassy-stm32/src/usart/buffered.rs | 152 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usart_buffered.rs | 14 | ||||
| -rw-r--r-- | examples/stm32l0/src/bin/usart_irq.rs | 16 |
3 files changed, 61 insertions, 121 deletions
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 6721c44a1..3e23e7ca1 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs | |||
| @@ -43,9 +43,9 @@ pub struct BufferedUartRx<'d, T: BasicInstance> { | |||
| 43 | impl<'d, T: BasicInstance> BufferedUart<'d, T> { | 43 | impl<'d, T: BasicInstance> BufferedUart<'d, T> { |
| 44 | pub fn new( | 44 | pub fn new( |
| 45 | peri: impl Peripheral<P = T> + 'd, | 45 | peri: impl Peripheral<P = T> + 'd, |
| 46 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 46 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 47 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 47 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 48 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 48 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 49 | tx_buffer: &'d mut [u8], | 49 | tx_buffer: &'d mut [u8], |
| 50 | rx_buffer: &'d mut [u8], | 50 | rx_buffer: &'d mut [u8], |
| 51 | config: Config, | 51 | config: Config, |
| @@ -53,14 +53,14 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 53 | T::enable(); | 53 | T::enable(); |
| 54 | T::reset(); | 54 | T::reset(); |
| 55 | 55 | ||
| 56 | Self::new_inner(peri, rx, tx, irq, tx_buffer, rx_buffer, config) | 56 | Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config) |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | pub fn new_with_rtscts( | 59 | pub fn new_with_rtscts( |
| 60 | peri: impl Peripheral<P = T> + 'd, | 60 | peri: impl Peripheral<P = T> + 'd, |
| 61 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 61 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 62 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 62 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 63 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 63 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 64 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, | 64 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, |
| 65 | cts: impl Peripheral<P = impl CtsPin<T>> + 'd, | 65 | cts: impl Peripheral<P = impl CtsPin<T>> + 'd, |
| 66 | tx_buffer: &'d mut [u8], | 66 | tx_buffer: &'d mut [u8], |
| @@ -81,15 +81,15 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 81 | }); | 81 | }); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | Self::new_inner(peri, rx, tx, irq, tx_buffer, rx_buffer, config) | 84 | Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config) |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | #[cfg(not(usart_v1))] | 87 | #[cfg(not(usart_v1))] |
| 88 | pub fn new_with_de( | 88 | pub fn new_with_de( |
| 89 | peri: impl Peripheral<P = T> + 'd, | 89 | peri: impl Peripheral<P = T> + 'd, |
| 90 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 90 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 91 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 91 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 92 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 92 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 93 | de: impl Peripheral<P = impl DePin<T>> + 'd, | 93 | de: impl Peripheral<P = impl DePin<T>> + 'd, |
| 94 | tx_buffer: &'d mut [u8], | 94 | tx_buffer: &'d mut [u8], |
| 95 | rx_buffer: &'d mut [u8], | 95 | rx_buffer: &'d mut [u8], |
| @@ -107,14 +107,14 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 107 | }); | 107 | }); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | Self::new_inner(peri, rx, tx, irq, tx_buffer, rx_buffer, config) | 110 | Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config) |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | fn new_inner( | 113 | fn new_inner( |
| 114 | _peri: impl Peripheral<P = T> + 'd, | 114 | _peri: impl Peripheral<P = T> + 'd, |
| 115 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 115 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 116 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 116 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 117 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 117 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 118 | tx_buffer: &'d mut [u8], | 118 | tx_buffer: &'d mut [u8], |
| 119 | rx_buffer: &'d mut [u8], | 119 | rx_buffer: &'d mut [u8], |
| 120 | config: Config, | 120 | config: Config, |
| @@ -155,8 +155,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 155 | } | 155 | } |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) { | 158 | pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { |
| 159 | (self.rx, self.tx) | 159 | (self.tx, self.rx) |
| 160 | } | 160 | } |
| 161 | } | 161 | } |
| 162 | 162 | ||
| @@ -165,85 +165,46 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { | |||
| 165 | poll_fn(move |cx| { | 165 | poll_fn(move |cx| { |
| 166 | let state = T::buffered_state(); | 166 | let state = T::buffered_state(); |
| 167 | let mut rx_reader = unsafe { state.rx_buf.reader() }; | 167 | let mut rx_reader = unsafe { state.rx_buf.reader() }; |
| 168 | let n = rx_reader.pop(|data| { | 168 | let data = rx_reader.pop_slice(); |
| 169 | let n = data.len().min(buf.len()); | ||
| 170 | buf[..n].copy_from_slice(&data[..n]); | ||
| 171 | n | ||
| 172 | }); | ||
| 173 | if n == 0 { | ||
| 174 | state.rx_waker.register(cx.waker()); | ||
| 175 | return Poll::Pending; | ||
| 176 | } | ||
| 177 | |||
| 178 | // FIXME: | ||
| 179 | // (Re-)Enable the interrupt to receive more data in case it was | ||
| 180 | // disabled because the buffer was full. | ||
| 181 | // let regs = T::regs(); | ||
| 182 | // unsafe { | ||
| 183 | // regs.uartimsc().write_set(|w| { | ||
| 184 | // w.set_rxim(true); | ||
| 185 | // w.set_rtim(true); | ||
| 186 | // }); | ||
| 187 | // } | ||
| 188 | 169 | ||
| 189 | Poll::Ready(Ok(n)) | 170 | if !data.is_empty() { |
| 190 | }) | 171 | let len = data.len().min(buf.len()); |
| 191 | .await | 172 | buf[..len].copy_from_slice(&data[..len]); |
| 192 | 173 | ||
| 193 | // poll_fn(move |cx| { | 174 | let do_pend = state.rx_buf.is_full(); |
| 194 | // let state = T::buffered_state(); | 175 | rx_reader.pop_done(len); |
| 195 | 176 | ||
| 196 | // let mut do_pend = false; | 177 | if do_pend { |
| 197 | // compiler_fence(Ordering::SeqCst); | 178 | unsafe { T::Interrupt::steal().pend() }; |
| 198 | 179 | } | |
| 199 | // // We have data ready in buffer? Return it. | ||
| 200 | // let data = state.rx_buf.pop_buf(); | ||
| 201 | // if !data.is_empty() { | ||
| 202 | // let len = data.len().min(buf.len()); | ||
| 203 | // buf[..len].copy_from_slice(&data[..len]); | ||
| 204 | |||
| 205 | // if state.rx_buf.is_full() { | ||
| 206 | // do_pend = true; | ||
| 207 | // } | ||
| 208 | // state.rx_buf.pop(len); | ||
| 209 | |||
| 210 | // return Poll::Ready(Ok(len)); | ||
| 211 | // } | ||
| 212 | |||
| 213 | // state.rx_waker.register(cx.waker()); | ||
| 214 | 180 | ||
| 215 | // if do_pend { | 181 | return Poll::Ready(Ok(len)); |
| 216 | // inner.pend(); | 182 | } |
| 217 | // } | ||
| 218 | 183 | ||
| 219 | // Poll::Pending | 184 | state.rx_waker.register(cx.waker()); |
| 220 | // }) | 185 | Poll::Pending |
| 221 | // .await | 186 | }) |
| 187 | .await | ||
| 222 | } | 188 | } |
| 223 | 189 | ||
| 224 | fn blocking_read(&self, buf: &mut [u8]) -> Result<usize, Error> { | 190 | fn blocking_read(&self, buf: &mut [u8]) -> Result<usize, Error> { |
| 225 | loop { | 191 | loop { |
| 226 | let state = T::buffered_state(); | 192 | let state = T::buffered_state(); |
| 227 | let mut rx_reader = unsafe { state.rx_buf.reader() }; | 193 | let mut rx_reader = unsafe { state.rx_buf.reader() }; |
| 228 | let n = rx_reader.pop(|data| { | 194 | let data = rx_reader.pop_slice(); |
| 229 | let n = data.len().min(buf.len()); | ||
| 230 | buf[..n].copy_from_slice(&data[..n]); | ||
| 231 | n | ||
| 232 | }); | ||
| 233 | 195 | ||
| 234 | if n > 0 { | 196 | if !data.is_empty() { |
| 235 | // FIXME: | 197 | let len = data.len().min(buf.len()); |
| 236 | // (Re-)Enable the interrupt to receive more data in case it was | 198 | buf[..len].copy_from_slice(&data[..len]); |
| 237 | // disabled because the buffer was full. | ||
| 238 | // let regs = T::regs(); | ||
| 239 | // unsafe { | ||
| 240 | // regs.uartimsc().write_set(|w| { | ||
| 241 | // w.set_rxim(true); | ||
| 242 | // w.set_rtim(true); | ||
| 243 | // }); | ||
| 244 | // } | ||
| 245 | 199 | ||
| 246 | return Ok(n); | 200 | let do_pend = state.rx_buf.is_full(); |
| 201 | rx_reader.pop_done(len); | ||
| 202 | |||
| 203 | if do_pend { | ||
| 204 | unsafe { T::Interrupt::steal().pend() }; | ||
| 205 | } | ||
| 206 | |||
| 207 | return Ok(len); | ||
| 247 | } | 208 | } |
| 248 | } | 209 | } |
| 249 | } | 210 | } |
| @@ -279,22 +240,23 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { | |||
| 279 | async fn write(&self, buf: &[u8]) -> Result<usize, Error> { | 240 | async fn write(&self, buf: &[u8]) -> Result<usize, Error> { |
| 280 | poll_fn(move |cx| { | 241 | poll_fn(move |cx| { |
| 281 | let state = T::buffered_state(); | 242 | let state = T::buffered_state(); |
| 243 | let empty = state.tx_buf.is_empty(); | ||
| 244 | |||
| 282 | let mut tx_writer = unsafe { state.tx_buf.writer() }; | 245 | let mut tx_writer = unsafe { state.tx_buf.writer() }; |
| 283 | let n = tx_writer.push(|data| { | 246 | let data = tx_writer.push_slice(); |
| 284 | let n = data.len().min(buf.len()); | 247 | if data.is_empty() { |
| 285 | data[..n].copy_from_slice(&buf[..n]); | ||
| 286 | n | ||
| 287 | }); | ||
| 288 | if n == 0 { | ||
| 289 | state.tx_waker.register(cx.waker()); | 248 | state.tx_waker.register(cx.waker()); |
| 290 | return Poll::Pending; | 249 | return Poll::Pending; |
| 291 | } | 250 | } |
| 292 | 251 | ||
| 293 | // The TX interrupt only triggers when the there was data in the | 252 | let n = data.len().min(buf.len()); |
| 294 | // FIFO and the number of bytes drops below a threshold. When the | 253 | data[..n].copy_from_slice(&buf[..n]); |
| 295 | // FIFO was empty we have to manually pend the interrupt to shovel | 254 | tx_writer.push_done(n); |
| 296 | // TX data from the buffer into the FIFO. | 255 | |
| 297 | unsafe { T::Interrupt::steal() }.pend(); | 256 | if empty { |
| 257 | unsafe { T::Interrupt::steal() }.pend(); | ||
| 258 | } | ||
| 259 | |||
| 298 | Poll::Ready(Ok(n)) | 260 | Poll::Ready(Ok(n)) |
| 299 | }) | 261 | }) |
| 300 | .await | 262 | .await |
| @@ -316,19 +278,19 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { | |||
| 316 | fn blocking_write(&self, buf: &[u8]) -> Result<usize, Error> { | 278 | fn blocking_write(&self, buf: &[u8]) -> Result<usize, Error> { |
| 317 | loop { | 279 | loop { |
| 318 | let state = T::buffered_state(); | 280 | let state = T::buffered_state(); |
| 281 | let empty = state.tx_buf.is_empty(); | ||
| 282 | |||
| 319 | let mut tx_writer = unsafe { state.tx_buf.writer() }; | 283 | let mut tx_writer = unsafe { state.tx_buf.writer() }; |
| 320 | let n = tx_writer.push(|data| { | 284 | let data = tx_writer.push_slice(); |
| 285 | if !data.is_empty() { | ||
| 321 | let n = data.len().min(buf.len()); | 286 | let n = data.len().min(buf.len()); |
| 322 | data[..n].copy_from_slice(&buf[..n]); | 287 | data[..n].copy_from_slice(&buf[..n]); |
| 323 | n | 288 | tx_writer.push_done(n); |
| 324 | }); | 289 | |
| 290 | if empty { | ||
| 291 | unsafe { T::Interrupt::steal() }.pend(); | ||
| 292 | } | ||
| 325 | 293 | ||
| 326 | if n != 0 { | ||
| 327 | // The TX interrupt only triggers when the there was data in the | ||
| 328 | // FIFO and the number of bytes drops below a threshold. When the | ||
| 329 | // FIFO was empty we have to manually pend the interrupt to shovel | ||
| 330 | // TX data from the buffer into the FIFO. | ||
| 331 | unsafe { T::Interrupt::steal() }.pend(); | ||
| 332 | return Ok(n); | 294 | return Ok(n); |
| 333 | } | 295 | } |
| 334 | } | 296 | } |
diff --git a/examples/stm32f4/src/bin/usart_buffered.rs b/examples/stm32f4/src/bin/usart_buffered.rs index dd171fe13..a93f8baeb 100644 --- a/examples/stm32f4/src/bin/usart_buffered.rs +++ b/examples/stm32f4/src/bin/usart_buffered.rs | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::interrupt; | 7 | use embassy_stm32::interrupt; |
| 8 | use embassy_stm32::usart::{BufferedUart, Config, State}; | 8 | use embassy_stm32::usart::{BufferedUart, Config}; |
| 9 | use embedded_io::asynch::BufRead; | 9 | use embedded_io::asynch::BufRead; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| @@ -16,20 +16,10 @@ async fn main(_spawner: Spawner) { | |||
| 16 | 16 | ||
| 17 | let config = Config::default(); | 17 | let config = Config::default(); |
| 18 | 18 | ||
| 19 | let mut state = State::new(); | ||
| 20 | let irq = interrupt::take!(USART3); | 19 | let irq = interrupt::take!(USART3); |
| 21 | let mut tx_buf = [0u8; 32]; | 20 | let mut tx_buf = [0u8; 32]; |
| 22 | let mut rx_buf = [0u8; 32]; | 21 | let mut rx_buf = [0u8; 32]; |
| 23 | let mut buf_usart = BufferedUart::new( | 22 | let mut buf_usart = BufferedUart::new(p.USART3, irq, p.PD9, p.PD8, &mut tx_buf, &mut rx_buf, config); |
| 24 | &mut state, | ||
| 25 | p.USART3, | ||
| 26 | p.PD9, | ||
| 27 | p.PD8, | ||
| 28 | irq, | ||
| 29 | &mut tx_buf, | ||
| 30 | &mut rx_buf, | ||
| 31 | config, | ||
| 32 | ); | ||
| 33 | 23 | ||
| 34 | loop { | 24 | loop { |
| 35 | let buf = buf_usart.fill_buf().await.unwrap(); | 25 | let buf = buf_usart.fill_buf().await.unwrap(); |
diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs index 8e84cd092..465347004 100644 --- a/examples/stm32l0/src/bin/usart_irq.rs +++ b/examples/stm32l0/src/bin/usart_irq.rs | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::interrupt; | 7 | use embassy_stm32::interrupt; |
| 8 | use embassy_stm32::usart::{BufferedUart, Config, State}; | 8 | use embassy_stm32::usart::{BufferedUart, Config}; |
| 9 | use embedded_io::asynch::{Read, Write}; | 9 | use embedded_io::asynch::{Read, Write}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| @@ -20,20 +20,8 @@ async fn main(_spawner: Spawner) { | |||
| 20 | let mut config = Config::default(); | 20 | let mut config = Config::default(); |
| 21 | config.baudrate = 9600; | 21 | config.baudrate = 9600; |
| 22 | 22 | ||
| 23 | let mut state = State::new(); | ||
| 24 | let irq = interrupt::take!(USART2); | 23 | let irq = interrupt::take!(USART2); |
| 25 | let mut usart = unsafe { | 24 | let mut usart = unsafe { BufferedUart::new(p.USART2, irq, p.PA3, p.PA2, &mut TX_BUFFER, &mut RX_BUFFER, config) }; |
| 26 | BufferedUart::new( | ||
| 27 | &mut state, | ||
| 28 | p.USART2, | ||
| 29 | p.PA3, | ||
| 30 | p.PA2, | ||
| 31 | irq, | ||
| 32 | &mut TX_BUFFER, | ||
| 33 | &mut RX_BUFFER, | ||
| 34 | config, | ||
| 35 | ) | ||
| 36 | }; | ||
| 37 | 25 | ||
| 38 | usart.write_all(b"Hello Embassy World!\r\n").await.unwrap(); | 26 | usart.write_all(b"Hello Embassy World!\r\n").await.unwrap(); |
| 39 | info!("wrote Hello, starting echo"); | 27 | info!("wrote Hello, starting echo"); |
