diff options
| author | Mathias <[email protected]> | 2022-08-26 09:05:12 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-09-26 20:34:55 +0200 |
| commit | ee76831f93e792757bf43136be712c343c4d5336 (patch) | |
| tree | 8bd9604b974e357e1c976069dd45cb2c7e034ecb | |
| parent | 75e93cc142c1c017e94dd28f6f04d3a4cb1ac67b (diff) | |
Add BufferedUart implementation, and feature-guard time-driver initialization, to free up TIMER peripheral if not used with embassy executor
| -rw-r--r-- | embassy-rp/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-rp/src/uart/buffered.rs | 286 | ||||
| -rw-r--r-- | embassy-rp/src/uart/mod.rs (renamed from embassy-rp/src/uart.rs) | 84 |
3 files changed, 369 insertions, 2 deletions
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index c43fd7e72..211b6a401 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml | |||
| @@ -52,6 +52,7 @@ cortex-m = "0.7.6" | |||
| 52 | critical-section = "1.1" | 52 | critical-section = "1.1" |
| 53 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 53 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 54 | chrono = { version = "0.4", default-features = false, optional = true } | 54 | chrono = { version = "0.4", default-features = false, optional = true } |
| 55 | embedded-io = { version = "0.3.0", features = ["async"], optional = true } | ||
| 55 | 56 | ||
| 56 | rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } | 57 | rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } |
| 57 | #rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } | 58 | #rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } |
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs new file mode 100644 index 000000000..c31af8018 --- /dev/null +++ b/embassy-rp/src/uart/buffered.rs | |||
| @@ -0,0 +1,286 @@ | |||
| 1 | use core::future::Future; | ||
| 2 | use core::task::Poll; | ||
| 3 | |||
| 4 | use atomic_polyfill::{compiler_fence, Ordering}; | ||
| 5 | use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; | ||
| 6 | use embassy_hal_common::ring_buffer::RingBuffer; | ||
| 7 | use embassy_sync::waitqueue::WakerRegistration; | ||
| 8 | use futures::future::poll_fn; | ||
| 9 | |||
| 10 | use super::*; | ||
| 11 | |||
| 12 | pub struct State<'d, T: Instance>(StateStorage<StateInner<'d, T>>); | ||
| 13 | impl<'d, T: Instance> State<'d, T> { | ||
| 14 | pub fn new() -> Self { | ||
| 15 | Self(StateStorage::new()) | ||
| 16 | } | ||
| 17 | } | ||
| 18 | |||
| 19 | struct StateInner<'d, T: Instance> { | ||
| 20 | phantom: PhantomData<&'d mut T>, | ||
| 21 | |||
| 22 | rx_waker: WakerRegistration, | ||
| 23 | rx: RingBuffer<'d>, | ||
| 24 | |||
| 25 | tx_waker: WakerRegistration, | ||
| 26 | tx: RingBuffer<'d>, | ||
| 27 | } | ||
| 28 | |||
| 29 | unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {} | ||
| 30 | unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {} | ||
| 31 | |||
| 32 | pub struct BufferedUart<'d, T: Instance> { | ||
| 33 | inner: PeripheralMutex<'d, StateInner<'d, T>>, | ||
| 34 | } | ||
| 35 | |||
| 36 | impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} | ||
| 37 | |||
| 38 | impl<'d, T: Instance> BufferedUart<'d, T> { | ||
| 39 | pub fn new<M: Mode>( | ||
| 40 | state: &'d mut State<'d, T>, | ||
| 41 | _uart: Uart<'d, T, M>, | ||
| 42 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 43 | tx_buffer: &'d mut [u8], | ||
| 44 | rx_buffer: &'d mut [u8], | ||
| 45 | ) -> BufferedUart<'d, T> { | ||
| 46 | into_ref!(irq); | ||
| 47 | |||
| 48 | let r = T::regs(); | ||
| 49 | unsafe { | ||
| 50 | r.uartimsc().modify(|w| { | ||
| 51 | // TODO: Should and more or fewer interrupts be enabled? | ||
| 52 | w.set_rxim(true); | ||
| 53 | w.set_rtim(true); | ||
| 54 | }); | ||
| 55 | } | ||
| 56 | |||
| 57 | Self { | ||
| 58 | inner: PeripheralMutex::new(irq, &mut state.0, move || StateInner { | ||
| 59 | phantom: PhantomData, | ||
| 60 | tx: RingBuffer::new(tx_buffer), | ||
| 61 | tx_waker: WakerRegistration::new(), | ||
| 62 | |||
| 63 | rx: RingBuffer::new(rx_buffer), | ||
| 64 | rx_waker: WakerRegistration::new(), | ||
| 65 | }), | ||
| 66 | } | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | impl<'d, T: Instance> StateInner<'d, T> | ||
| 71 | where | ||
| 72 | Self: 'd, | ||
| 73 | { | ||
| 74 | fn on_rx(&mut self) { | ||
| 75 | let r = T::regs(); | ||
| 76 | unsafe { | ||
| 77 | let ris = r.uartris().read(); | ||
| 78 | // Clear interrupt flags | ||
| 79 | r.uarticr().write(|w| { | ||
| 80 | w.set_rxic(true); | ||
| 81 | w.set_rtic(true); | ||
| 82 | }); | ||
| 83 | |||
| 84 | if ris.rxris() { | ||
| 85 | if ris.peris() { | ||
| 86 | warn!("Parity error"); | ||
| 87 | } | ||
| 88 | if ris.feris() { | ||
| 89 | warn!("Framing error"); | ||
| 90 | } | ||
| 91 | if ris.beris() { | ||
| 92 | warn!("Break error"); | ||
| 93 | } | ||
| 94 | if ris.oeris() { | ||
| 95 | warn!("Overrun error"); | ||
| 96 | } | ||
| 97 | |||
| 98 | let buf = self.rx.push_buf(); | ||
| 99 | if !buf.is_empty() { | ||
| 100 | buf[0] = r.uartdr().read().data(); | ||
| 101 | self.rx.push(1); | ||
| 102 | } else { | ||
| 103 | warn!("RX buffer full, discard received byte"); | ||
| 104 | } | ||
| 105 | |||
| 106 | if self.rx.is_full() { | ||
| 107 | self.rx_waker.wake(); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | if ris.rtris() { | ||
| 112 | self.rx_waker.wake(); | ||
| 113 | }; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | fn on_tx(&mut self) { | ||
| 118 | let r = T::regs(); | ||
| 119 | unsafe { | ||
| 120 | let ris = r.uartris().read(); | ||
| 121 | // Clear interrupt flags | ||
| 122 | r.uarticr().write(|w| { | ||
| 123 | w.set_rtic(true); | ||
| 124 | }); | ||
| 125 | |||
| 126 | if ris.txris() { | ||
| 127 | let buf = self.tx.pop_buf(); | ||
| 128 | if !buf.is_empty() { | ||
| 129 | r.uartimsc().modify(|w| { | ||
| 130 | w.set_txim(true); | ||
| 131 | }); | ||
| 132 | r.uartdr().write(|w| w.set_data(buf[0].into())); | ||
| 133 | self.tx.pop(1); | ||
| 134 | self.tx_waker.wake(); | ||
| 135 | } else { | ||
| 136 | // Disable interrupt until we have something to transmit again | ||
| 137 | r.uartimsc().modify(|w| { | ||
| 138 | w.set_txim(false); | ||
| 139 | }); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | impl<'d, T: Instance> PeripheralState for StateInner<'d, T> | ||
| 147 | where | ||
| 148 | Self: 'd, | ||
| 149 | { | ||
| 150 | type Interrupt = T::Interrupt; | ||
| 151 | fn on_interrupt(&mut self) { | ||
| 152 | self.on_rx(); | ||
| 153 | self.on_tx(); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | impl embedded_io::Error for Error { | ||
| 158 | fn kind(&self) -> embedded_io::ErrorKind { | ||
| 159 | embedded_io::ErrorKind::Other | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | impl<'d, T: Instance> embedded_io::Io for BufferedUart<'d, T> { | ||
| 164 | type Error = Error; | ||
| 165 | } | ||
| 166 | |||
| 167 | impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { | ||
| 168 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 169 | where | ||
| 170 | Self: 'a; | ||
| 171 | |||
| 172 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 173 | poll_fn(move |cx| { | ||
| 174 | let mut do_pend = false; | ||
| 175 | let res = self.inner.with(|state| { | ||
| 176 | compiler_fence(Ordering::SeqCst); | ||
| 177 | |||
| 178 | // We have data ready in buffer? Return it. | ||
| 179 | let data = state.rx.pop_buf(); | ||
| 180 | if !data.is_empty() { | ||
| 181 | let len = data.len().min(buf.len()); | ||
| 182 | buf[..len].copy_from_slice(&data[..len]); | ||
| 183 | |||
| 184 | if state.rx.is_full() { | ||
| 185 | do_pend = true; | ||
| 186 | } | ||
| 187 | state.rx.pop(len); | ||
| 188 | |||
| 189 | return Poll::Ready(Ok(len)); | ||
| 190 | } | ||
| 191 | |||
| 192 | state.rx_waker.register(cx.waker()); | ||
| 193 | Poll::Pending | ||
| 194 | }); | ||
| 195 | |||
| 196 | if do_pend { | ||
| 197 | self.inner.pend(); | ||
| 198 | } | ||
| 199 | |||
| 200 | res | ||
| 201 | }) | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> { | ||
| 206 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> | ||
| 207 | where | ||
| 208 | Self: 'a; | ||
| 209 | |||
| 210 | fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { | ||
| 211 | poll_fn(move |cx| { | ||
| 212 | self.inner.with(|state| { | ||
| 213 | compiler_fence(Ordering::SeqCst); | ||
| 214 | |||
| 215 | // We have data ready in buffer? Return it. | ||
| 216 | let buf = state.rx.pop_buf(); | ||
| 217 | if !buf.is_empty() { | ||
| 218 | let buf: &[u8] = buf; | ||
| 219 | // Safety: buffer lives as long as uart | ||
| 220 | let buf: &[u8] = unsafe { core::mem::transmute(buf) }; | ||
| 221 | return Poll::Ready(Ok(buf)); | ||
| 222 | } | ||
| 223 | |||
| 224 | state.rx_waker.register(cx.waker()); | ||
| 225 | Poll::<Result<&[u8], Self::Error>>::Pending | ||
| 226 | }) | ||
| 227 | }) | ||
| 228 | } | ||
| 229 | |||
| 230 | fn consume(&mut self, amt: usize) { | ||
| 231 | let signal = self.inner.with(|state| { | ||
| 232 | let full = state.rx.is_full(); | ||
| 233 | state.rx.pop(amt); | ||
| 234 | full | ||
| 235 | }); | ||
| 236 | if signal { | ||
| 237 | self.inner.pend(); | ||
| 238 | } | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { | ||
| 243 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 244 | where | ||
| 245 | Self: 'a; | ||
| 246 | |||
| 247 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 248 | poll_fn(move |cx| { | ||
| 249 | let (poll, empty) = self.inner.with(|state| { | ||
| 250 | let empty = state.tx.is_empty(); | ||
| 251 | let tx_buf = state.tx.push_buf(); | ||
| 252 | if tx_buf.is_empty() { | ||
| 253 | state.tx_waker.register(cx.waker()); | ||
| 254 | return (Poll::Pending, empty); | ||
| 255 | } | ||
| 256 | |||
| 257 | let n = core::cmp::min(tx_buf.len(), buf.len()); | ||
| 258 | tx_buf[..n].copy_from_slice(&buf[..n]); | ||
| 259 | state.tx.push(n); | ||
| 260 | |||
| 261 | (Poll::Ready(Ok(n)), empty) | ||
| 262 | }); | ||
| 263 | if empty { | ||
| 264 | self.inner.pend(); | ||
| 265 | } | ||
| 266 | poll | ||
| 267 | }) | ||
| 268 | } | ||
| 269 | |||
| 270 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | ||
| 271 | where | ||
| 272 | Self: 'a; | ||
| 273 | |||
| 274 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 275 | poll_fn(move |cx| { | ||
| 276 | self.inner.with(|state| { | ||
| 277 | if !state.tx.is_empty() { | ||
| 278 | state.tx_waker.register(cx.waker()); | ||
| 279 | return Poll::Pending; | ||
| 280 | } | ||
| 281 | |||
| 282 | Poll::Ready(Ok(())) | ||
| 283 | }) | ||
| 284 | }) | ||
| 285 | } | ||
| 286 | } | ||
diff --git a/embassy-rp/src/uart.rs b/embassy-rp/src/uart/mod.rs index 987b716b4..3b71d87be 100644 --- a/embassy-rp/src/uart.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -475,6 +475,76 @@ mod eh1 { | |||
| 475 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> { | 475 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> { |
| 476 | type Error = Error; | 476 | type Error = Error; |
| 477 | } | 477 | } |
| 478 | |||
| 479 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for UartRx<'d, T, M> { | ||
| 480 | fn read(&mut self) -> nb::Result<u8, Self::Error> { | ||
| 481 | let r = T::regs(); | ||
| 482 | unsafe { | ||
| 483 | let dr = r.uartdr().read(); | ||
| 484 | |||
| 485 | if dr.oe() { | ||
| 486 | Err(nb::Error::Other(Error::Overrun)) | ||
| 487 | } else if dr.be() { | ||
| 488 | Err(nb::Error::Other(Error::Break)) | ||
| 489 | } else if dr.pe() { | ||
| 490 | Err(nb::Error::Other(Error::Parity)) | ||
| 491 | } else if dr.fe() { | ||
| 492 | Err(nb::Error::Other(Error::Framing)) | ||
| 493 | } else if dr.fe() { | ||
| 494 | Ok(dr.data()) | ||
| 495 | } else { | ||
| 496 | Err(nb::Error::WouldBlock) | ||
| 497 | } | ||
| 498 | } | ||
| 499 | } | ||
| 500 | } | ||
| 501 | |||
| 502 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for UartTx<'d, T, M> { | ||
| 503 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 504 | self.blocking_write(buffer) | ||
| 505 | } | ||
| 506 | |||
| 507 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 508 | self.blocking_flush() | ||
| 509 | } | ||
| 510 | } | ||
| 511 | |||
| 512 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for UartTx<'d, T, M> { | ||
| 513 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | ||
| 514 | self.blocking_write(&[char]).map_err(nb::Error::Other) | ||
| 515 | } | ||
| 516 | |||
| 517 | fn flush(&mut self) -> nb::Result<(), Self::Error> { | ||
| 518 | self.blocking_flush().map_err(nb::Error::Other) | ||
| 519 | } | ||
| 520 | } | ||
| 521 | |||
| 522 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for Uart<'d, T, M> { | ||
| 523 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { | ||
| 524 | embedded_hal_02::serial::Read::read(&mut self.rx) | ||
| 525 | } | ||
| 526 | } | ||
| 527 | |||
| 528 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for Uart<'d, T, M> { | ||
| 529 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 530 | self.blocking_write(buffer) | ||
| 531 | } | ||
| 532 | |||
| 533 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 534 | self.blocking_flush() | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for Uart<'d, T, M> { | ||
| 539 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | ||
| 540 | self.blocking_write(&[char]).map_err(nb::Error::Other) | ||
| 541 | } | ||
| 542 | |||
| 543 | fn flush(&mut self) -> nb::Result<(), Self::Error> { | ||
| 544 | self.blocking_flush().map_err(nb::Error::Other) | ||
| 545 | } | ||
| 546 | } | ||
| 547 | |||
| 478 | } | 548 | } |
| 479 | 549 | ||
| 480 | #[cfg(all( | 550 | #[cfg(all( |
| @@ -532,6 +602,12 @@ mod eha { | |||
| 532 | } | 602 | } |
| 533 | } | 603 | } |
| 534 | 604 | ||
| 605 | #[cfg(feature = "nightly")] | ||
| 606 | mod buffered; | ||
| 607 | #[cfg(feature = "nightly")] | ||
| 608 | pub use buffered::*; | ||
| 609 | |||
| 610 | |||
| 535 | mod sealed { | 611 | mod sealed { |
| 536 | use super::*; | 612 | use super::*; |
| 537 | 613 | ||
| @@ -541,6 +617,8 @@ mod sealed { | |||
| 541 | const TX_DREQ: u8; | 617 | const TX_DREQ: u8; |
| 542 | const RX_DREQ: u8; | 618 | const RX_DREQ: u8; |
| 543 | 619 | ||
| 620 | type Interrupt: crate::interrupt::Interrupt; | ||
| 621 | |||
| 544 | fn regs() -> pac::uart::Uart; | 622 | fn regs() -> pac::uart::Uart; |
| 545 | } | 623 | } |
| 546 | pub trait TxPin<T: Instance> {} | 624 | pub trait TxPin<T: Instance> {} |
| @@ -571,6 +649,8 @@ macro_rules! impl_instance { | |||
| 571 | impl sealed::Instance for peripherals::$inst { | 649 | impl sealed::Instance for peripherals::$inst { |
| 572 | const TX_DREQ: u8 = $tx_dreq; | 650 | const TX_DREQ: u8 = $tx_dreq; |
| 573 | const RX_DREQ: u8 = $rx_dreq; | 651 | const RX_DREQ: u8 = $rx_dreq; |
| 652 | |||
| 653 | type Interrupt = crate::interrupt::$irq; | ||
| 574 | 654 | ||
| 575 | fn regs() -> pac::uart::Uart { | 655 | fn regs() -> pac::uart::Uart { |
| 576 | pac::$inst | 656 | pac::$inst |
| @@ -580,8 +660,8 @@ macro_rules! impl_instance { | |||
| 580 | }; | 660 | }; |
| 581 | } | 661 | } |
| 582 | 662 | ||
| 583 | impl_instance!(UART0, UART0, 20, 21); | 663 | impl_instance!(UART0, UART0_IRQ, 20, 21); |
| 584 | impl_instance!(UART1, UART1, 22, 23); | 664 | impl_instance!(UART1, UART1_IRQ, 22, 23); |
| 585 | 665 | ||
| 586 | pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} | 666 | pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} |
| 587 | pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} | 667 | pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} |
