diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-09-27 06:00:33 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-09-27 06:00:33 +0000 |
| commit | 82d436075633e179f96d49b6afb9045451a591d4 (patch) | |
| tree | 0e5e66638d2896357070671ff26f8d1cd65269a5 | |
| parent | 86fd4806724a003421897f2e465f0c79e38e849b (diff) | |
| parent | e129a97d48a00d7923886ab3faa82357b2369f13 (diff) | |
Merge #934
934: (embassy-rp): Add Buffered UART implementation r=MathiasKoch a=MathiasKoch
### Questions & concerns:
- ~~Would it make sense to add `RxBufferedUart` and `TxBufferedUart`, for cases where you would want to only buffer one way?~~
- ~~Do I need to be monitoring more interrupt flags than `Receive` & `Receive timeout`?~~
This PR adds working `BufferedUart` implementation, along with `RxBufferedUart` and `TxBufferedUart`. The implementation leaves room for improvement with respect to performance, as it still does not utilize DMA nor the internal UART buffers.
Co-authored-by: Mathias <[email protected]>
Co-authored-by: Dario Nieuwenhuis <[email protected]>
| -rw-r--r-- | embassy-rp/Cargo.toml | 3 | ||||
| -rw-r--r-- | embassy-rp/src/uart/buffered.rs | 489 | ||||
| -rw-r--r-- | embassy-rp/src/uart/mod.rs (renamed from embassy-rp/src/uart.rs) | 87 | ||||
| -rw-r--r-- | tests/rp/.cargo/config.toml | 2 | ||||
| -rw-r--r-- | tests/rp/Cargo.toml | 1 | ||||
| -rw-r--r-- | tests/rp/src/bin/uart_buffered.rs | 44 |
6 files changed, 622 insertions, 4 deletions
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index c43fd7e72..d0cf8025c 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml | |||
| @@ -27,7 +27,7 @@ intrinsics = [] | |||
| 27 | rom-v2-intrinsics = [] | 27 | rom-v2-intrinsics = [] |
| 28 | 28 | ||
| 29 | # Enable nightly-only features | 29 | # Enable nightly-only features |
| 30 | nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb"] | 30 | nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb", "dep:embedded-io"] |
| 31 | 31 | ||
| 32 | # Implement embedded-hal 1.0 alpha traits. | 32 | # Implement embedded-hal 1.0 alpha traits. |
| 33 | # Implement embedded-hal-async traits if `nightly` is set as well. | 33 | # Implement embedded-hal-async traits if `nightly` is set as well. |
| @@ -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..87e16f0eb --- /dev/null +++ b/embassy-rp/src/uart/buffered.rs | |||
| @@ -0,0 +1,489 @@ | |||
| 1 | use core::future::{poll_fn, Future}; | ||
| 2 | use core::task::{Poll, Waker}; | ||
| 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 | |||
| 9 | use super::*; | ||
| 10 | |||
| 11 | pub struct State<'d, T: Instance>(StateStorage<FullStateInner<'d, T>>); | ||
| 12 | impl<'d, T: Instance> State<'d, T> { | ||
| 13 | pub const fn new() -> Self { | ||
| 14 | Self(StateStorage::new()) | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 18 | pub struct RxState<'d, T: Instance>(StateStorage<RxStateInner<'d, T>>); | ||
| 19 | impl<'d, T: Instance> RxState<'d, T> { | ||
| 20 | pub const fn new() -> Self { | ||
| 21 | Self(StateStorage::new()) | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | pub struct TxState<'d, T: Instance>(StateStorage<TxStateInner<'d, T>>); | ||
| 26 | impl<'d, T: Instance> TxState<'d, T> { | ||
| 27 | pub const fn new() -> Self { | ||
| 28 | Self(StateStorage::new()) | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | struct RxStateInner<'d, T: Instance> { | ||
| 33 | phantom: PhantomData<&'d mut T>, | ||
| 34 | |||
| 35 | waker: WakerRegistration, | ||
| 36 | buf: RingBuffer<'d>, | ||
| 37 | } | ||
| 38 | |||
| 39 | struct TxStateInner<'d, T: Instance> { | ||
| 40 | phantom: PhantomData<&'d mut T>, | ||
| 41 | |||
| 42 | waker: WakerRegistration, | ||
| 43 | buf: RingBuffer<'d>, | ||
| 44 | } | ||
| 45 | |||
| 46 | struct FullStateInner<'d, T: Instance> { | ||
| 47 | rx: RxStateInner<'d, T>, | ||
| 48 | tx: TxStateInner<'d, T>, | ||
| 49 | } | ||
| 50 | |||
| 51 | unsafe impl<'d, T: Instance> Send for RxStateInner<'d, T> {} | ||
| 52 | unsafe impl<'d, T: Instance> Sync for RxStateInner<'d, T> {} | ||
| 53 | |||
| 54 | unsafe impl<'d, T: Instance> Send for TxStateInner<'d, T> {} | ||
| 55 | unsafe impl<'d, T: Instance> Sync for TxStateInner<'d, T> {} | ||
| 56 | |||
| 57 | unsafe impl<'d, T: Instance> Send for FullStateInner<'d, T> {} | ||
| 58 | unsafe impl<'d, T: Instance> Sync for FullStateInner<'d, T> {} | ||
| 59 | |||
| 60 | pub struct BufferedUart<'d, T: Instance> { | ||
| 61 | inner: PeripheralMutex<'d, FullStateInner<'d, T>>, | ||
| 62 | } | ||
| 63 | |||
| 64 | pub struct BufferedUartRx<'d, T: Instance> { | ||
| 65 | inner: PeripheralMutex<'d, RxStateInner<'d, T>>, | ||
| 66 | } | ||
| 67 | |||
| 68 | pub struct BufferedUartTx<'d, T: Instance> { | ||
| 69 | inner: PeripheralMutex<'d, TxStateInner<'d, T>>, | ||
| 70 | } | ||
| 71 | |||
| 72 | impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} | ||
| 73 | impl<'d, T: Instance> Unpin for BufferedUartRx<'d, T> {} | ||
| 74 | impl<'d, T: Instance> Unpin for BufferedUartTx<'d, T> {} | ||
| 75 | |||
| 76 | impl<'d, T: Instance> BufferedUart<'d, T> { | ||
| 77 | pub fn new<M: Mode>( | ||
| 78 | state: &'d mut State<'d, T>, | ||
| 79 | _uart: Uart<'d, T, M>, | ||
| 80 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 81 | tx_buffer: &'d mut [u8], | ||
| 82 | rx_buffer: &'d mut [u8], | ||
| 83 | ) -> BufferedUart<'d, T> { | ||
| 84 | into_ref!(irq); | ||
| 85 | |||
| 86 | let r = T::regs(); | ||
| 87 | unsafe { | ||
| 88 | r.uartimsc().modify(|w| { | ||
| 89 | w.set_rxim(true); | ||
| 90 | w.set_rtim(true); | ||
| 91 | w.set_txim(true); | ||
| 92 | }); | ||
| 93 | } | ||
| 94 | |||
| 95 | Self { | ||
| 96 | inner: PeripheralMutex::new(irq, &mut state.0, move || FullStateInner { | ||
| 97 | tx: TxStateInner { | ||
| 98 | phantom: PhantomData, | ||
| 99 | waker: WakerRegistration::new(), | ||
| 100 | buf: RingBuffer::new(tx_buffer), | ||
| 101 | }, | ||
| 102 | rx: RxStateInner { | ||
| 103 | phantom: PhantomData, | ||
| 104 | waker: WakerRegistration::new(), | ||
| 105 | buf: RingBuffer::new(rx_buffer), | ||
| 106 | }, | ||
| 107 | }), | ||
| 108 | } | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | impl<'d, T: Instance> BufferedUartRx<'d, T> { | ||
| 113 | pub fn new<M: Mode>( | ||
| 114 | state: &'d mut RxState<'d, T>, | ||
| 115 | _uart: UartRx<'d, T, M>, | ||
| 116 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 117 | rx_buffer: &'d mut [u8], | ||
| 118 | ) -> BufferedUartRx<'d, T> { | ||
| 119 | into_ref!(irq); | ||
| 120 | |||
| 121 | let r = T::regs(); | ||
| 122 | unsafe { | ||
| 123 | r.uartimsc().modify(|w| { | ||
| 124 | w.set_rxim(true); | ||
| 125 | w.set_rtim(true); | ||
| 126 | }); | ||
| 127 | } | ||
| 128 | |||
| 129 | Self { | ||
| 130 | inner: PeripheralMutex::new(irq, &mut state.0, move || RxStateInner { | ||
| 131 | phantom: PhantomData, | ||
| 132 | |||
| 133 | buf: RingBuffer::new(rx_buffer), | ||
| 134 | waker: WakerRegistration::new(), | ||
| 135 | }), | ||
| 136 | } | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | impl<'d, T: Instance> BufferedUartTx<'d, T> { | ||
| 141 | pub fn new<M: Mode>( | ||
| 142 | state: &'d mut TxState<'d, T>, | ||
| 143 | _uart: UartTx<'d, T, M>, | ||
| 144 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 145 | tx_buffer: &'d mut [u8], | ||
| 146 | ) -> BufferedUartTx<'d, T> { | ||
| 147 | into_ref!(irq); | ||
| 148 | |||
| 149 | let r = T::regs(); | ||
| 150 | unsafe { | ||
| 151 | r.uartimsc().modify(|w| { | ||
| 152 | w.set_txim(true); | ||
| 153 | }); | ||
| 154 | } | ||
| 155 | |||
| 156 | Self { | ||
| 157 | inner: PeripheralMutex::new(irq, &mut state.0, move || TxStateInner { | ||
| 158 | phantom: PhantomData, | ||
| 159 | |||
| 160 | buf: RingBuffer::new(tx_buffer), | ||
| 161 | waker: WakerRegistration::new(), | ||
| 162 | }), | ||
| 163 | } | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | impl<'d, T: Instance> PeripheralState for FullStateInner<'d, T> | ||
| 168 | where | ||
| 169 | Self: 'd, | ||
| 170 | { | ||
| 171 | type Interrupt = T::Interrupt; | ||
| 172 | fn on_interrupt(&mut self) { | ||
| 173 | self.rx.on_interrupt(); | ||
| 174 | self.tx.on_interrupt(); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | impl<'d, T: Instance> RxStateInner<'d, T> | ||
| 179 | where | ||
| 180 | Self: 'd, | ||
| 181 | { | ||
| 182 | fn read(&mut self, buf: &mut [u8], waker: &Waker) -> (Poll<Result<usize, Error>>, bool) { | ||
| 183 | // We have data ready in buffer? Return it. | ||
| 184 | let mut do_pend = false; | ||
| 185 | let data = self.buf.pop_buf(); | ||
| 186 | if !data.is_empty() { | ||
| 187 | let len = data.len().min(buf.len()); | ||
| 188 | buf[..len].copy_from_slice(&data[..len]); | ||
| 189 | |||
| 190 | if self.buf.is_full() { | ||
| 191 | do_pend = true; | ||
| 192 | } | ||
| 193 | self.buf.pop(len); | ||
| 194 | |||
| 195 | return (Poll::Ready(Ok(len)), do_pend); | ||
| 196 | } | ||
| 197 | |||
| 198 | self.waker.register(waker); | ||
| 199 | (Poll::Pending, do_pend) | ||
| 200 | } | ||
| 201 | |||
| 202 | fn fill_buf<'a>(&mut self, waker: &Waker) -> Poll<Result<&'a [u8], Error>> { | ||
| 203 | // We have data ready in buffer? Return it. | ||
| 204 | let buf = self.buf.pop_buf(); | ||
| 205 | if !buf.is_empty() { | ||
| 206 | let buf: &[u8] = buf; | ||
| 207 | // Safety: buffer lives as long as uart | ||
| 208 | let buf: &[u8] = unsafe { core::mem::transmute(buf) }; | ||
| 209 | return Poll::Ready(Ok(buf)); | ||
| 210 | } | ||
| 211 | |||
| 212 | self.waker.register(waker); | ||
| 213 | Poll::Pending | ||
| 214 | } | ||
| 215 | |||
| 216 | fn consume(&mut self, amt: usize) -> bool { | ||
| 217 | let full = self.buf.is_full(); | ||
| 218 | self.buf.pop(amt); | ||
| 219 | full | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | impl<'d, T: Instance> PeripheralState for RxStateInner<'d, T> | ||
| 224 | where | ||
| 225 | Self: 'd, | ||
| 226 | { | ||
| 227 | type Interrupt = T::Interrupt; | ||
| 228 | fn on_interrupt(&mut self) { | ||
| 229 | let r = T::regs(); | ||
| 230 | unsafe { | ||
| 231 | let ris = r.uartris().read(); | ||
| 232 | // Clear interrupt flags | ||
| 233 | r.uarticr().modify(|w| { | ||
| 234 | w.set_rxic(true); | ||
| 235 | w.set_rtic(true); | ||
| 236 | }); | ||
| 237 | |||
| 238 | if ris.peris() { | ||
| 239 | warn!("Parity error"); | ||
| 240 | r.uarticr().modify(|w| { | ||
| 241 | w.set_peic(true); | ||
| 242 | }); | ||
| 243 | } | ||
| 244 | if ris.feris() { | ||
| 245 | warn!("Framing error"); | ||
| 246 | r.uarticr().modify(|w| { | ||
| 247 | w.set_feic(true); | ||
| 248 | }); | ||
| 249 | } | ||
| 250 | if ris.beris() { | ||
| 251 | warn!("Break error"); | ||
| 252 | r.uarticr().modify(|w| { | ||
| 253 | w.set_beic(true); | ||
| 254 | }); | ||
| 255 | } | ||
| 256 | if ris.oeris() { | ||
| 257 | warn!("Overrun error"); | ||
| 258 | r.uarticr().modify(|w| { | ||
| 259 | w.set_oeic(true); | ||
| 260 | }); | ||
| 261 | } | ||
| 262 | |||
| 263 | if !r.uartfr().read().rxfe() { | ||
| 264 | let buf = self.buf.push_buf(); | ||
| 265 | if !buf.is_empty() { | ||
| 266 | buf[0] = r.uartdr().read().data(); | ||
| 267 | self.buf.push(1); | ||
| 268 | } else { | ||
| 269 | warn!("RX buffer full, discard received byte"); | ||
| 270 | } | ||
| 271 | |||
| 272 | if self.buf.is_full() { | ||
| 273 | self.waker.wake(); | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | if ris.rtris() { | ||
| 278 | self.waker.wake(); | ||
| 279 | }; | ||
| 280 | } | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | impl<'d, T: Instance> TxStateInner<'d, T> | ||
| 285 | where | ||
| 286 | Self: 'd, | ||
| 287 | { | ||
| 288 | fn write(&mut self, buf: &[u8], waker: &Waker) -> (Poll<Result<usize, Error>>, bool) { | ||
| 289 | let empty = self.buf.is_empty(); | ||
| 290 | let tx_buf = self.buf.push_buf(); | ||
| 291 | if tx_buf.is_empty() { | ||
| 292 | self.waker.register(waker); | ||
| 293 | return (Poll::Pending, empty); | ||
| 294 | } | ||
| 295 | |||
| 296 | let n = core::cmp::min(tx_buf.len(), buf.len()); | ||
| 297 | tx_buf[..n].copy_from_slice(&buf[..n]); | ||
| 298 | self.buf.push(n); | ||
| 299 | |||
| 300 | (Poll::Ready(Ok(n)), empty) | ||
| 301 | } | ||
| 302 | |||
| 303 | fn flush(&mut self, waker: &Waker) -> Poll<Result<(), Error>> { | ||
| 304 | if !self.buf.is_empty() { | ||
| 305 | self.waker.register(waker); | ||
| 306 | return Poll::Pending; | ||
| 307 | } | ||
| 308 | |||
| 309 | Poll::Ready(Ok(())) | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | impl<'d, T: Instance> PeripheralState for TxStateInner<'d, T> | ||
| 314 | where | ||
| 315 | Self: 'd, | ||
| 316 | { | ||
| 317 | type Interrupt = T::Interrupt; | ||
| 318 | fn on_interrupt(&mut self) { | ||
| 319 | let r = T::regs(); | ||
| 320 | unsafe { | ||
| 321 | let buf = self.buf.pop_buf(); | ||
| 322 | if !buf.is_empty() { | ||
| 323 | r.uartimsc().modify(|w| { | ||
| 324 | w.set_txim(true); | ||
| 325 | }); | ||
| 326 | r.uartdr().write(|w| w.set_data(buf[0].into())); | ||
| 327 | self.buf.pop(1); | ||
| 328 | self.waker.wake(); | ||
| 329 | } else { | ||
| 330 | // Disable interrupt until we have something to transmit again | ||
| 331 | r.uartimsc().modify(|w| { | ||
| 332 | w.set_txim(false); | ||
| 333 | }); | ||
| 334 | } | ||
| 335 | } | ||
| 336 | } | ||
| 337 | } | ||
| 338 | |||
| 339 | impl embedded_io::Error for Error { | ||
| 340 | fn kind(&self) -> embedded_io::ErrorKind { | ||
| 341 | embedded_io::ErrorKind::Other | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | impl<'d, T: Instance> embedded_io::Io for BufferedUart<'d, T> { | ||
| 346 | type Error = Error; | ||
| 347 | } | ||
| 348 | |||
| 349 | impl<'d, T: Instance> embedded_io::Io for BufferedUartRx<'d, T> { | ||
| 350 | type Error = Error; | ||
| 351 | } | ||
| 352 | |||
| 353 | impl<'d, T: Instance> embedded_io::Io for BufferedUartTx<'d, T> { | ||
| 354 | type Error = Error; | ||
| 355 | } | ||
| 356 | |||
| 357 | impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { | ||
| 358 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 359 | where | ||
| 360 | Self: 'a; | ||
| 361 | |||
| 362 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 363 | poll_fn(move |cx| { | ||
| 364 | let (res, do_pend) = self.inner.with(|state| { | ||
| 365 | compiler_fence(Ordering::SeqCst); | ||
| 366 | state.rx.read(buf, cx.waker()) | ||
| 367 | }); | ||
| 368 | |||
| 369 | if do_pend { | ||
| 370 | self.inner.pend(); | ||
| 371 | } | ||
| 372 | |||
| 373 | res | ||
| 374 | }) | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 378 | impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUartRx<'d, T> { | ||
| 379 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 380 | where | ||
| 381 | Self: 'a; | ||
| 382 | |||
| 383 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 384 | poll_fn(move |cx| { | ||
| 385 | let (res, do_pend) = self.inner.with(|state| { | ||
| 386 | compiler_fence(Ordering::SeqCst); | ||
| 387 | state.read(buf, cx.waker()) | ||
| 388 | }); | ||
| 389 | |||
| 390 | if do_pend { | ||
| 391 | self.inner.pend(); | ||
| 392 | } | ||
| 393 | |||
| 394 | res | ||
| 395 | }) | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> { | ||
| 400 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> | ||
| 401 | where | ||
| 402 | Self: 'a; | ||
| 403 | |||
| 404 | fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { | ||
| 405 | poll_fn(move |cx| { | ||
| 406 | self.inner.with(|state| { | ||
| 407 | compiler_fence(Ordering::SeqCst); | ||
| 408 | state.rx.fill_buf(cx.waker()) | ||
| 409 | }) | ||
| 410 | }) | ||
| 411 | } | ||
| 412 | |||
| 413 | fn consume(&mut self, amt: usize) { | ||
| 414 | let signal = self.inner.with(|state| state.rx.consume(amt)); | ||
| 415 | if signal { | ||
| 416 | self.inner.pend(); | ||
| 417 | } | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUartRx<'d, T> { | ||
| 422 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> | ||
| 423 | where | ||
| 424 | Self: 'a; | ||
| 425 | |||
| 426 | fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { | ||
| 427 | poll_fn(move |cx| { | ||
| 428 | self.inner.with(|state| { | ||
| 429 | compiler_fence(Ordering::SeqCst); | ||
| 430 | state.fill_buf(cx.waker()) | ||
| 431 | }) | ||
| 432 | }) | ||
| 433 | } | ||
| 434 | |||
| 435 | fn consume(&mut self, amt: usize) { | ||
| 436 | let signal = self.inner.with(|state| state.consume(amt)); | ||
| 437 | if signal { | ||
| 438 | self.inner.pend(); | ||
| 439 | } | ||
| 440 | } | ||
| 441 | } | ||
| 442 | |||
| 443 | impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { | ||
| 444 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 445 | where | ||
| 446 | Self: 'a; | ||
| 447 | |||
| 448 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 449 | poll_fn(move |cx| { | ||
| 450 | let (poll, empty) = self.inner.with(|state| state.tx.write(buf, cx.waker())); | ||
| 451 | if empty { | ||
| 452 | self.inner.pend(); | ||
| 453 | } | ||
| 454 | poll | ||
| 455 | }) | ||
| 456 | } | ||
| 457 | |||
| 458 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | ||
| 459 | where | ||
| 460 | Self: 'a; | ||
| 461 | |||
| 462 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 463 | poll_fn(move |cx| self.inner.with(|state| state.tx.flush(cx.waker()))) | ||
| 464 | } | ||
| 465 | } | ||
| 466 | |||
| 467 | impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T> { | ||
| 468 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 469 | where | ||
| 470 | Self: 'a; | ||
| 471 | |||
| 472 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 473 | poll_fn(move |cx| { | ||
| 474 | let (poll, empty) = self.inner.with(|state| state.write(buf, cx.waker())); | ||
| 475 | if empty { | ||
| 476 | self.inner.pend(); | ||
| 477 | } | ||
| 478 | poll | ||
| 479 | }) | ||
| 480 | } | ||
| 481 | |||
| 482 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | ||
| 483 | where | ||
| 484 | Self: 'a; | ||
| 485 | |||
| 486 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 487 | poll_fn(move |cx| self.inner.with(|state| state.flush(cx.waker()))) | ||
| 488 | } | ||
| 489 | } | ||
diff --git a/embassy-rp/src/uart.rs b/embassy-rp/src/uart/mod.rs index 987b716b4..d9285ee51 100644 --- a/embassy-rp/src/uart.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -346,6 +346,11 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { | |||
| 346 | w.set_fen(true); | 346 | w.set_fen(true); |
| 347 | }); | 347 | }); |
| 348 | 348 | ||
| 349 | r.uartifls().write(|w| { | ||
| 350 | w.set_rxiflsel(0b000); | ||
| 351 | w.set_txiflsel(0b000); | ||
| 352 | }); | ||
| 353 | |||
| 349 | r.uartcr().write(|w| { | 354 | r.uartcr().write(|w| { |
| 350 | w.set_uarten(true); | 355 | w.set_uarten(true); |
| 351 | w.set_rxe(true); | 356 | w.set_rxe(true); |
| @@ -475,6 +480,75 @@ mod eh1 { | |||
| 475 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> { | 480 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> { |
| 476 | type Error = Error; | 481 | type Error = Error; |
| 477 | } | 482 | } |
| 483 | |||
| 484 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for UartRx<'d, T, M> { | ||
| 485 | fn read(&mut self) -> nb::Result<u8, Self::Error> { | ||
| 486 | let r = T::regs(); | ||
| 487 | unsafe { | ||
| 488 | let dr = r.uartdr().read(); | ||
| 489 | |||
| 490 | if dr.oe() { | ||
| 491 | Err(nb::Error::Other(Error::Overrun)) | ||
| 492 | } else if dr.be() { | ||
| 493 | Err(nb::Error::Other(Error::Break)) | ||
| 494 | } else if dr.pe() { | ||
| 495 | Err(nb::Error::Other(Error::Parity)) | ||
| 496 | } else if dr.fe() { | ||
| 497 | Err(nb::Error::Other(Error::Framing)) | ||
| 498 | } else if dr.fe() { | ||
| 499 | Ok(dr.data()) | ||
| 500 | } else { | ||
| 501 | Err(nb::Error::WouldBlock) | ||
| 502 | } | ||
| 503 | } | ||
| 504 | } | ||
| 505 | } | ||
| 506 | |||
| 507 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for UartTx<'d, T, M> { | ||
| 508 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 509 | self.blocking_write(buffer) | ||
| 510 | } | ||
| 511 | |||
| 512 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 513 | self.blocking_flush() | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for UartTx<'d, T, M> { | ||
| 518 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | ||
| 519 | self.blocking_write(&[char]).map_err(nb::Error::Other) | ||
| 520 | } | ||
| 521 | |||
| 522 | fn flush(&mut self) -> nb::Result<(), Self::Error> { | ||
| 523 | self.blocking_flush().map_err(nb::Error::Other) | ||
| 524 | } | ||
| 525 | } | ||
| 526 | |||
| 527 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for Uart<'d, T, M> { | ||
| 528 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { | ||
| 529 | embedded_hal_02::serial::Read::read(&mut self.rx) | ||
| 530 | } | ||
| 531 | } | ||
| 532 | |||
| 533 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for Uart<'d, T, M> { | ||
| 534 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 535 | self.blocking_write(buffer) | ||
| 536 | } | ||
| 537 | |||
| 538 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 539 | self.blocking_flush() | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for Uart<'d, T, M> { | ||
| 544 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | ||
| 545 | self.blocking_write(&[char]).map_err(nb::Error::Other) | ||
| 546 | } | ||
| 547 | |||
| 548 | fn flush(&mut self) -> nb::Result<(), Self::Error> { | ||
| 549 | self.blocking_flush().map_err(nb::Error::Other) | ||
| 550 | } | ||
| 551 | } | ||
| 478 | } | 552 | } |
| 479 | 553 | ||
| 480 | #[cfg(all( | 554 | #[cfg(all( |
| @@ -532,6 +606,11 @@ mod eha { | |||
| 532 | } | 606 | } |
| 533 | } | 607 | } |
| 534 | 608 | ||
| 609 | #[cfg(feature = "nightly")] | ||
| 610 | mod buffered; | ||
| 611 | #[cfg(feature = "nightly")] | ||
| 612 | pub use buffered::*; | ||
| 613 | |||
| 535 | mod sealed { | 614 | mod sealed { |
| 536 | use super::*; | 615 | use super::*; |
| 537 | 616 | ||
| @@ -541,6 +620,8 @@ mod sealed { | |||
| 541 | const TX_DREQ: u8; | 620 | const TX_DREQ: u8; |
| 542 | const RX_DREQ: u8; | 621 | const RX_DREQ: u8; |
| 543 | 622 | ||
| 623 | type Interrupt: crate::interrupt::Interrupt; | ||
| 624 | |||
| 544 | fn regs() -> pac::uart::Uart; | 625 | fn regs() -> pac::uart::Uart; |
| 545 | } | 626 | } |
| 546 | pub trait TxPin<T: Instance> {} | 627 | pub trait TxPin<T: Instance> {} |
| @@ -572,6 +653,8 @@ macro_rules! impl_instance { | |||
| 572 | const TX_DREQ: u8 = $tx_dreq; | 653 | const TX_DREQ: u8 = $tx_dreq; |
| 573 | const RX_DREQ: u8 = $rx_dreq; | 654 | const RX_DREQ: u8 = $rx_dreq; |
| 574 | 655 | ||
| 656 | type Interrupt = crate::interrupt::$irq; | ||
| 657 | |||
| 575 | fn regs() -> pac::uart::Uart { | 658 | fn regs() -> pac::uart::Uart { |
| 576 | pac::$inst | 659 | pac::$inst |
| 577 | } | 660 | } |
| @@ -580,8 +663,8 @@ macro_rules! impl_instance { | |||
| 580 | }; | 663 | }; |
| 581 | } | 664 | } |
| 582 | 665 | ||
| 583 | impl_instance!(UART0, UART0, 20, 21); | 666 | impl_instance!(UART0, UART0_IRQ, 20, 21); |
| 584 | impl_instance!(UART1, UART1, 22, 23); | 667 | impl_instance!(UART1, UART1_IRQ, 22, 23); |
| 585 | 668 | ||
| 586 | pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} | 669 | pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} |
| 587 | pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} | 670 | pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} |
diff --git a/tests/rp/.cargo/config.toml b/tests/rp/.cargo/config.toml index 0330025e4..9611db3a0 100644 --- a/tests/rp/.cargo/config.toml +++ b/tests/rp/.cargo/config.toml | |||
| @@ -3,7 +3,7 @@ build-std = ["core"] | |||
| 3 | build-std-features = ["panic_immediate_abort"] | 3 | build-std-features = ["panic_immediate_abort"] |
| 4 | 4 | ||
| 5 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | 5 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] |
| 6 | #runner = "teleprobe client run --target bluepill-stm32f103c8 --elf" | 6 | #runner = "teleprobe client run --target rpi-pico --elf" |
| 7 | runner = "teleprobe local run --chip RP2040 --elf" | 7 | runner = "teleprobe local run --chip RP2040 --elf" |
| 8 | 8 | ||
| 9 | rustflags = [ | 9 | rustflags = [ |
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 7e2717ddf..503373759 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml | |||
| @@ -20,6 +20,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } | |||
| 20 | embedded-hal-async = { version = "0.1.0-alpha.1" } | 20 | embedded-hal-async = { version = "0.1.0-alpha.1" } |
| 21 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } | 21 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } |
| 22 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 22 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 23 | embedded-io = { version = "0.3.0", features = ["async"] } | ||
| 23 | 24 | ||
| 24 | [profile.dev] | 25 | [profile.dev] |
| 25 | debug = 2 | 26 | debug = 2 |
diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs new file mode 100644 index 000000000..9cc20bb98 --- /dev/null +++ b/tests/rp/src/bin/uart_buffered.rs | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::{assert_eq, *}; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::interrupt; | ||
| 8 | use embassy_rp::uart::{BufferedUart, Config, State, Uart}; | ||
| 9 | use embedded_io::asynch::{Read, Write}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | let p = embassy_rp::init(Default::default()); | ||
| 15 | info!("Hello World!"); | ||
| 16 | |||
| 17 | let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0); | ||
| 18 | |||
| 19 | let config = Config::default(); | ||
| 20 | let uart = Uart::new_blocking(uart, tx, rx, config); | ||
| 21 | |||
| 22 | let irq = interrupt::take!(UART0_IRQ); | ||
| 23 | let tx_buf = &mut [0u8; 16]; | ||
| 24 | let rx_buf = &mut [0u8; 16]; | ||
| 25 | let mut state = State::new(); | ||
| 26 | let mut uart = BufferedUart::new(&mut state, uart, irq, tx_buf, rx_buf); | ||
| 27 | |||
| 28 | // Make sure we send more bytes than fits in the FIFO, to test the actual | ||
| 29 | // bufferedUart. | ||
| 30 | |||
| 31 | let data = [ | ||
| 32 | 1_u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, | ||
| 33 | 30, 31, 32, | ||
| 34 | ]; | ||
| 35 | uart.write_all(&data).await.unwrap(); | ||
| 36 | info!("Done writing"); | ||
| 37 | |||
| 38 | let mut buf = [0; 32]; | ||
| 39 | uart.read_exact(&mut buf).await.unwrap(); | ||
| 40 | assert_eq!(buf, data); | ||
| 41 | |||
| 42 | info!("Test OK"); | ||
| 43 | cortex_m::asm::bkpt(); | ||
| 44 | } | ||
