diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-12-16 07:44:40 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-12-16 07:44:40 +0000 |
| commit | 5df16c6793a3730535ac91af8133ff744d76fad5 (patch) | |
| tree | efe5218718aa6115d472aa00b8611c8bb5510078 | |
| parent | d5a3064c2c20b4a9515e5322bb9a74724ebcf7c9 (diff) | |
| parent | 0642eec01e23d9037e21186cfb0c169e56f9a161 (diff) | |
Merge #544
544: Introduces split on the nRF Uarte r=Dirbaio a=huntc
A new `split` method is introduced such that the Uarte tx and rx can be used from separate tasks. An MPSC is used in an example to illustrate how data may be passed between these tasks.
The approach taken within the `Uarte` struct is to split into tx and rx fields on calling `Uarte::new`. These fields are returned given a call to `Uarte::split`, but otherwise, if that call isn't made, then the API remains as it was before.
Here's a snippet from a new example introduced:
```rust
#[embassy::main]
async fn main(spawner: Spawner, p: Peripherals) {
// ...
let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, NoPin, NoPin, config);
let (mut tx, rx) = uart.split();
// ...
// Spawn a task responsible purely for reading
unwrap!(spawner.spawn(reader(rx, s)));
// ...
// Continue reading in this main task and write
// back out the buffer we receive from the read
// task.
loop {
if let Some(buf) = r.recv().await {
info!("writing...");
unwrap!(tx.write(&buf).await);
}
}
}
#[embassy::task]
async fn reader(mut rx: UarteRx<'static, UARTE0>, s: Sender<'static, Noop, [u8; 8], 1>) {
let mut buf = [0; 8];
loop {
info!("reading...");
unwrap!(rx.read(&mut buf).await);
unwrap!(s.send(buf).await);
}
}
```
Co-authored-by: huntc <[email protected]>
| -rw-r--r-- | embassy-nrf/src/uarte.rs | 215 | ||||
| -rw-r--r-- | examples/nrf/src/bin/uart_split.rs | 68 |
2 files changed, 220 insertions, 63 deletions
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index ff781cabd..17417c0e2 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs | |||
| @@ -54,6 +54,20 @@ impl Default for Config { | |||
| 54 | /// Interface to the UARTE peripheral | 54 | /// Interface to the UARTE peripheral |
| 55 | pub struct Uarte<'d, T: Instance> { | 55 | pub struct Uarte<'d, T: Instance> { |
| 56 | phantom: PhantomData<&'d mut T>, | 56 | phantom: PhantomData<&'d mut T>, |
| 57 | tx: UarteTx<'d, T>, | ||
| 58 | rx: UarteRx<'d, T>, | ||
| 59 | } | ||
| 60 | |||
| 61 | /// Transmitter interface to the UARTE peripheral obtained | ||
| 62 | /// via [Uarte]::split. | ||
| 63 | pub struct UarteTx<'d, T: Instance> { | ||
| 64 | phantom: PhantomData<&'d mut T>, | ||
| 65 | } | ||
| 66 | |||
| 67 | /// Receiver interface to the UARTE peripheral obtained | ||
| 68 | /// via [Uarte]::split. | ||
| 69 | pub struct UarteRx<'d, T: Instance> { | ||
| 70 | phantom: PhantomData<&'d mut T>, | ||
| 57 | } | 71 | } |
| 58 | 72 | ||
| 59 | impl<'d, T: Instance> Uarte<'d, T> { | 73 | impl<'d, T: Instance> Uarte<'d, T> { |
| @@ -119,11 +133,24 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 119 | apply_workaround_for_enable_anomaly(&r); | 133 | apply_workaround_for_enable_anomaly(&r); |
| 120 | r.enable.write(|w| w.enable().enabled()); | 134 | r.enable.write(|w| w.enable().enabled()); |
| 121 | 135 | ||
| 136 | let s = T::state(); | ||
| 137 | |||
| 138 | s.tx_rx_refcount.store(2, Ordering::Relaxed); | ||
| 139 | |||
| 122 | Self { | 140 | Self { |
| 123 | phantom: PhantomData, | 141 | phantom: PhantomData, |
| 142 | tx: UarteTx::new(), | ||
| 143 | rx: UarteRx::new(), | ||
| 124 | } | 144 | } |
| 125 | } | 145 | } |
| 126 | 146 | ||
| 147 | /// Split the Uarte into a transmitter and receiver, which is | ||
| 148 | /// particuarly useful when having two tasks correlating to | ||
| 149 | /// transmitting and receiving. | ||
| 150 | pub fn split(self) -> (UarteTx<'d, T>, UarteRx<'d, T>) { | ||
| 151 | (self.tx, self.rx) | ||
| 152 | } | ||
| 153 | |||
| 127 | fn on_interrupt(_: *mut ()) { | 154 | fn on_interrupt(_: *mut ()) { |
| 128 | let r = T::regs(); | 155 | let r = T::regs(); |
| 129 | let s = T::state(); | 156 | let s = T::state(); |
| @@ -139,72 +166,72 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 139 | } | 166 | } |
| 140 | } | 167 | } |
| 141 | 168 | ||
| 142 | impl<'a, T: Instance> Drop for Uarte<'a, T> { | 169 | impl<'d, T: Instance> Read for Uarte<'d, T> { |
| 143 | fn drop(&mut self) { | 170 | #[rustfmt::skip] |
| 144 | info!("uarte drop"); | 171 | type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), TraitError>> + 'a; |
| 145 | |||
| 146 | let r = T::regs(); | ||
| 147 | |||
| 148 | let did_stoprx = r.events_rxstarted.read().bits() != 0; | ||
| 149 | let did_stoptx = r.events_txstarted.read().bits() != 0; | ||
| 150 | info!("did_stoprx {} did_stoptx {}", did_stoprx, did_stoptx); | ||
| 151 | 172 | ||
| 152 | // Wait for rxto or txstopped, if needed. | 173 | fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { |
| 153 | while (did_stoprx && r.events_rxto.read().bits() == 0) | 174 | self.rx.read(rx_buffer) |
| 154 | || (did_stoptx && r.events_txstopped.read().bits() == 0) | 175 | } |
| 155 | {} | 176 | } |
| 156 | 177 | ||
| 157 | // Finally we can disable! | 178 | impl<'d, T: Instance> Write for Uarte<'d, T> { |
| 158 | r.enable.write(|w| w.enable().disabled()); | 179 | #[rustfmt::skip] |
| 180 | type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), TraitError>> + 'a; | ||
| 159 | 181 | ||
| 160 | gpio::deconfigure_pin(r.psel.rxd.read().bits()); | 182 | fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { |
| 161 | gpio::deconfigure_pin(r.psel.txd.read().bits()); | 183 | self.tx.write(tx_buffer) |
| 162 | gpio::deconfigure_pin(r.psel.rts.read().bits()); | 184 | } |
| 163 | gpio::deconfigure_pin(r.psel.cts.read().bits()); | 185 | } |
| 164 | 186 | ||
| 165 | info!("uarte drop: done"); | 187 | impl<'d, T: Instance> UarteTx<'d, T> { |
| 188 | pub fn new() -> Self { | ||
| 189 | Self { | ||
| 190 | phantom: PhantomData, | ||
| 191 | } | ||
| 166 | } | 192 | } |
| 167 | } | 193 | } |
| 168 | 194 | ||
| 169 | impl<'d, T: Instance> Read for Uarte<'d, T> { | 195 | impl<'d, T: Instance> Write for UarteTx<'d, T> { |
| 170 | #[rustfmt::skip] | 196 | #[rustfmt::skip] |
| 171 | type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), TraitError>> + 'a; | 197 | type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), TraitError>> + 'a; |
| 172 | 198 | ||
| 173 | fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { | 199 | fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { |
| 174 | async move { | 200 | async move { |
| 175 | let ptr = rx_buffer.as_ptr(); | 201 | let ptr = tx_buffer.as_ptr(); |
| 176 | let len = rx_buffer.len(); | 202 | let len = tx_buffer.len(); |
| 177 | assert!(len <= EASY_DMA_SIZE); | 203 | assert!(len <= EASY_DMA_SIZE); |
| 204 | // TODO: panic if buffer is not in SRAM | ||
| 178 | 205 | ||
| 179 | let r = T::regs(); | 206 | let r = T::regs(); |
| 180 | let s = T::state(); | 207 | let s = T::state(); |
| 181 | 208 | ||
| 182 | let drop = OnDrop::new(move || { | 209 | let drop = OnDrop::new(move || { |
| 183 | info!("read drop: stopping"); | 210 | info!("write drop: stopping"); |
| 184 | |||
| 185 | r.intenclr.write(|w| w.endrx().clear()); | ||
| 186 | r.events_rxto.reset(); | ||
| 187 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||
| 188 | 211 | ||
| 189 | while r.events_endrx.read().bits() == 0 {} | 212 | r.intenclr.write(|w| w.endtx().clear()); |
| 213 | r.events_txstopped.reset(); | ||
| 214 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | ||
| 190 | 215 | ||
| 191 | info!("read drop: stopped"); | 216 | // TX is stopped almost instantly, spinning is fine. |
| 217 | while r.events_endtx.read().bits() == 0 {} | ||
| 218 | info!("write drop: stopped"); | ||
| 192 | }); | 219 | }); |
| 193 | 220 | ||
| 194 | r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | 221 | r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); |
| 195 | r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | 222 | r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); |
| 196 | 223 | ||
| 197 | r.events_endrx.reset(); | 224 | r.events_endtx.reset(); |
| 198 | r.intenset.write(|w| w.endrx().set()); | 225 | r.intenset.write(|w| w.endtx().set()); |
| 199 | 226 | ||
| 200 | compiler_fence(Ordering::SeqCst); | 227 | compiler_fence(Ordering::SeqCst); |
| 201 | 228 | ||
| 202 | trace!("startrx"); | 229 | trace!("starttx"); |
| 203 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | 230 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); |
| 204 | 231 | ||
| 205 | poll_fn(|cx| { | 232 | poll_fn(|cx| { |
| 206 | s.endrx_waker.register(cx.waker()); | 233 | s.endtx_waker.register(cx.waker()); |
| 207 | if r.events_endrx.read().bits() != 0 { | 234 | if r.events_endtx.read().bits() != 0 { |
| 208 | return Poll::Ready(()); | 235 | return Poll::Ready(()); |
| 209 | } | 236 | } |
| 210 | Poll::Pending | 237 | Poll::Pending |
| @@ -212,7 +239,7 @@ impl<'d, T: Instance> Read for Uarte<'d, T> { | |||
| 212 | .await; | 239 | .await; |
| 213 | 240 | ||
| 214 | compiler_fence(Ordering::SeqCst); | 241 | compiler_fence(Ordering::SeqCst); |
| 215 | r.events_rxstarted.reset(); | 242 | r.events_txstarted.reset(); |
| 216 | drop.defuse(); | 243 | drop.defuse(); |
| 217 | 244 | ||
| 218 | Ok(()) | 245 | Ok(()) |
| @@ -220,46 +247,71 @@ impl<'d, T: Instance> Read for Uarte<'d, T> { | |||
| 220 | } | 247 | } |
| 221 | } | 248 | } |
| 222 | 249 | ||
| 223 | impl<'d, T: Instance> Write for Uarte<'d, T> { | 250 | impl<'a, T: Instance> Drop for UarteTx<'a, T> { |
| 251 | fn drop(&mut self) { | ||
| 252 | info!("uarte tx drop"); | ||
| 253 | |||
| 254 | let r = T::regs(); | ||
| 255 | |||
| 256 | let did_stoptx = r.events_txstarted.read().bits() != 0; | ||
| 257 | info!("did_stoptx {}", did_stoptx); | ||
| 258 | |||
| 259 | // Wait for txstopped, if needed. | ||
| 260 | while did_stoptx && r.events_txstopped.read().bits() == 0 {} | ||
| 261 | |||
| 262 | let s = T::state(); | ||
| 263 | |||
| 264 | drop_tx_rx(&r, &s); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | impl<'d, T: Instance> UarteRx<'d, T> { | ||
| 269 | pub fn new() -> Self { | ||
| 270 | Self { | ||
| 271 | phantom: PhantomData, | ||
| 272 | } | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | impl<'d, T: Instance> Read for UarteRx<'d, T> { | ||
| 224 | #[rustfmt::skip] | 277 | #[rustfmt::skip] |
| 225 | type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), TraitError>> + 'a; | 278 | type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), TraitError>> + 'a; |
| 226 | 279 | ||
| 227 | fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { | 280 | fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { |
| 228 | async move { | 281 | async move { |
| 229 | let ptr = tx_buffer.as_ptr(); | 282 | let ptr = rx_buffer.as_ptr(); |
| 230 | let len = tx_buffer.len(); | 283 | let len = rx_buffer.len(); |
| 231 | assert!(len <= EASY_DMA_SIZE); | 284 | assert!(len <= EASY_DMA_SIZE); |
| 232 | // TODO: panic if buffer is not in SRAM | ||
| 233 | 285 | ||
| 234 | let r = T::regs(); | 286 | let r = T::regs(); |
| 235 | let s = T::state(); | 287 | let s = T::state(); |
| 236 | 288 | ||
| 237 | let drop = OnDrop::new(move || { | 289 | let drop = OnDrop::new(move || { |
| 238 | info!("write drop: stopping"); | 290 | info!("read drop: stopping"); |
| 239 | 291 | ||
| 240 | r.intenclr.write(|w| w.endtx().clear()); | 292 | r.intenclr.write(|w| w.endrx().clear()); |
| 241 | r.events_txstopped.reset(); | 293 | r.events_rxto.reset(); |
| 242 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | 294 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); |
| 243 | 295 | ||
| 244 | // TX is stopped almost instantly, spinning is fine. | 296 | while r.events_endrx.read().bits() == 0 {} |
| 245 | while r.events_endtx.read().bits() == 0 {} | 297 | |
| 246 | info!("write drop: stopped"); | 298 | info!("read drop: stopped"); |
| 247 | }); | 299 | }); |
| 248 | 300 | ||
| 249 | r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | 301 | r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); |
| 250 | r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | 302 | r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); |
| 251 | 303 | ||
| 252 | r.events_endtx.reset(); | 304 | r.events_endrx.reset(); |
| 253 | r.intenset.write(|w| w.endtx().set()); | 305 | r.intenset.write(|w| w.endrx().set()); |
| 254 | 306 | ||
| 255 | compiler_fence(Ordering::SeqCst); | 307 | compiler_fence(Ordering::SeqCst); |
| 256 | 308 | ||
| 257 | trace!("starttx"); | 309 | trace!("startrx"); |
| 258 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | 310 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); |
| 259 | 311 | ||
| 260 | poll_fn(|cx| { | 312 | poll_fn(|cx| { |
| 261 | s.endtx_waker.register(cx.waker()); | 313 | s.endrx_waker.register(cx.waker()); |
| 262 | if r.events_endtx.read().bits() != 0 { | 314 | if r.events_endrx.read().bits() != 0 { |
| 263 | return Poll::Ready(()); | 315 | return Poll::Ready(()); |
| 264 | } | 316 | } |
| 265 | Poll::Pending | 317 | Poll::Pending |
| @@ -267,7 +319,7 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { | |||
| 267 | .await; | 319 | .await; |
| 268 | 320 | ||
| 269 | compiler_fence(Ordering::SeqCst); | 321 | compiler_fence(Ordering::SeqCst); |
| 270 | r.events_txstarted.reset(); | 322 | r.events_rxstarted.reset(); |
| 271 | drop.defuse(); | 323 | drop.defuse(); |
| 272 | 324 | ||
| 273 | Ok(()) | 325 | Ok(()) |
| @@ -275,6 +327,24 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { | |||
| 275 | } | 327 | } |
| 276 | } | 328 | } |
| 277 | 329 | ||
| 330 | impl<'a, T: Instance> Drop for UarteRx<'a, T> { | ||
| 331 | fn drop(&mut self) { | ||
| 332 | info!("uarte rx drop"); | ||
| 333 | |||
| 334 | let r = T::regs(); | ||
| 335 | |||
| 336 | let did_stoprx = r.events_rxstarted.read().bits() != 0; | ||
| 337 | info!("did_stoprx {}", did_stoprx); | ||
| 338 | |||
| 339 | // Wait for rxto, if needed. | ||
| 340 | while did_stoprx && r.events_rxto.read().bits() == 0 {} | ||
| 341 | |||
| 342 | let s = T::state(); | ||
| 343 | |||
| 344 | drop_tx_rx(&r, &s); | ||
| 345 | } | ||
| 346 | } | ||
| 347 | |||
| 278 | #[cfg(not(any(feature = "_nrf9160", feature = "nrf5340")))] | 348 | #[cfg(not(any(feature = "_nrf9160", feature = "nrf5340")))] |
| 279 | pub(in crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) { | 349 | pub(in crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) { |
| 280 | // Do nothing | 350 | // Do nothing |
| @@ -328,6 +398,21 @@ pub(in crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::Reg | |||
| 328 | } | 398 | } |
| 329 | } | 399 | } |
| 330 | 400 | ||
| 401 | pub(in crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &sealed::State) { | ||
| 402 | if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 { | ||
| 403 | // Finally we can disable, and we do so for the peripheral | ||
| 404 | // i.e. not just rx concerns. | ||
| 405 | r.enable.write(|w| w.enable().disabled()); | ||
| 406 | |||
| 407 | gpio::deconfigure_pin(r.psel.rxd.read().bits()); | ||
| 408 | gpio::deconfigure_pin(r.psel.txd.read().bits()); | ||
| 409 | gpio::deconfigure_pin(r.psel.rts.read().bits()); | ||
| 410 | gpio::deconfigure_pin(r.psel.cts.read().bits()); | ||
| 411 | |||
| 412 | info!("uarte tx and rx drop: done"); | ||
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 331 | /// Interface to an UARTE peripheral that uses an additional timer and two PPI channels, | 416 | /// Interface to an UARTE peripheral that uses an additional timer and two PPI channels, |
| 332 | /// allowing it to implement the ReadUntilIdle trait. | 417 | /// allowing it to implement the ReadUntilIdle trait. |
| 333 | pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> { | 418 | pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> { |
| @@ -487,6 +572,8 @@ impl<'d, U: Instance, T: TimerInstance> Write for UarteWithIdle<'d, U, T> { | |||
| 487 | } | 572 | } |
| 488 | 573 | ||
| 489 | pub(crate) mod sealed { | 574 | pub(crate) mod sealed { |
| 575 | use core::sync::atomic::AtomicU8; | ||
| 576 | |||
| 490 | use embassy::waitqueue::AtomicWaker; | 577 | use embassy::waitqueue::AtomicWaker; |
| 491 | 578 | ||
| 492 | use super::*; | 579 | use super::*; |
| @@ -494,12 +581,14 @@ pub(crate) mod sealed { | |||
| 494 | pub struct State { | 581 | pub struct State { |
| 495 | pub endrx_waker: AtomicWaker, | 582 | pub endrx_waker: AtomicWaker, |
| 496 | pub endtx_waker: AtomicWaker, | 583 | pub endtx_waker: AtomicWaker, |
| 584 | pub tx_rx_refcount: AtomicU8, | ||
| 497 | } | 585 | } |
| 498 | impl State { | 586 | impl State { |
| 499 | pub const fn new() -> Self { | 587 | pub const fn new() -> Self { |
| 500 | Self { | 588 | Self { |
| 501 | endrx_waker: AtomicWaker::new(), | 589 | endrx_waker: AtomicWaker::new(), |
| 502 | endtx_waker: AtomicWaker::new(), | 590 | endtx_waker: AtomicWaker::new(), |
| 591 | tx_rx_refcount: AtomicU8::new(0), | ||
| 503 | } | 592 | } |
| 504 | } | 593 | } |
| 505 | } | 594 | } |
diff --git a/examples/nrf/src/bin/uart_split.rs b/examples/nrf/src/bin/uart_split.rs new file mode 100644 index 000000000..4b5dbb21f --- /dev/null +++ b/examples/nrf/src/bin/uart_split.rs | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | #[path = "../example_common.rs"] | ||
| 6 | mod example_common; | ||
| 7 | use embassy::blocking_mutex::kind::Noop; | ||
| 8 | use embassy::channel::mpsc::{self, Channel, Sender}; | ||
| 9 | use embassy::util::Forever; | ||
| 10 | use embassy_nrf::peripherals::UARTE0; | ||
| 11 | use embassy_nrf::uarte::UarteRx; | ||
| 12 | use example_common::*; | ||
| 13 | |||
| 14 | use embassy::executor::Spawner; | ||
| 15 | use embassy::traits::uart::{Read, Write}; | ||
| 16 | use embassy_nrf::gpio::NoPin; | ||
| 17 | use embassy_nrf::{interrupt, uarte, Peripherals}; | ||
| 18 | |||
| 19 | static CHANNEL: Forever<Channel<Noop, [u8; 8], 1>> = Forever::new(); | ||
| 20 | |||
| 21 | #[embassy::main] | ||
| 22 | async fn main(spawner: Spawner, p: Peripherals) { | ||
| 23 | let mut config = uarte::Config::default(); | ||
| 24 | config.parity = uarte::Parity::EXCLUDED; | ||
| 25 | config.baudrate = uarte::Baudrate::BAUD115200; | ||
| 26 | |||
| 27 | let irq = interrupt::take!(UARTE0_UART0); | ||
| 28 | let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, NoPin, NoPin, config); | ||
| 29 | let (mut tx, rx) = uart.split(); | ||
| 30 | |||
| 31 | let c = CHANNEL.put(Channel::new()); | ||
| 32 | let (s, mut r) = mpsc::split(c); | ||
| 33 | |||
| 34 | info!("uarte initialized!"); | ||
| 35 | |||
| 36 | // Spawn a task responsible purely for reading | ||
| 37 | |||
| 38 | unwrap!(spawner.spawn(reader(rx, s))); | ||
| 39 | |||
| 40 | // Message must be in SRAM | ||
| 41 | { | ||
| 42 | let mut buf = [0; 23]; | ||
| 43 | buf.copy_from_slice(b"Type 8 chars to echo!\r\n"); | ||
| 44 | |||
| 45 | unwrap!(tx.write(&buf).await); | ||
| 46 | info!("wrote hello in uart!"); | ||
| 47 | } | ||
| 48 | |||
| 49 | // Continue reading in this main task and write | ||
| 50 | // back out the buffer we receive from the read | ||
| 51 | // task. | ||
| 52 | loop { | ||
| 53 | if let Some(buf) = r.recv().await { | ||
| 54 | info!("writing..."); | ||
| 55 | unwrap!(tx.write(&buf).await); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | #[embassy::task] | ||
| 61 | async fn reader(mut rx: UarteRx<'static, UARTE0>, s: Sender<'static, Noop, [u8; 8], 1>) { | ||
| 62 | let mut buf = [0; 8]; | ||
| 63 | loop { | ||
| 64 | info!("reading..."); | ||
| 65 | unwrap!(rx.read(&mut buf).await); | ||
| 66 | unwrap!(s.send(buf).await); | ||
| 67 | } | ||
| 68 | } | ||
