aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2021-05-10 15:45:40 +0200
committerDario Nieuwenhuis <[email protected]>2021-05-10 23:06:25 +0200
commitdda338cedb6b82a8d7cd75d18a8ebc6dfd46f53a (patch)
tree4d5a23026b83597b4aa45a2ec1f55b5f5de2b1fb
parent040fffd667f8bdc089df828783aa0a76a06d4b5a (diff)
Add implementation of ReadUntilIdle for nRF UART
Add type UarteWithIdle that implements Read, Write and ReadUntilIdle traits. The type uses a timer + 2 PPI channels internally, triggered on RTXSTARTED event.
-rw-r--r--embassy-nrf/src/uarte.rs159
1 files changed, 158 insertions, 1 deletions
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index a02f7c347..0f574ba36 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -5,7 +5,7 @@ use core::marker::PhantomData;
5use core::sync::atomic::{compiler_fence, Ordering}; 5use core::sync::atomic::{compiler_fence, Ordering};
6use core::task::Poll; 6use core::task::Poll;
7use embassy::interrupt::InterruptExt; 7use embassy::interrupt::InterruptExt;
8use embassy::traits::uart::{Error, Read, Write}; 8use embassy::traits::uart::{Error, Read, ReadUntilIdle, Write};
9use embassy::util::{AtomicWaker, OnDrop, Unborrow}; 9use embassy::util::{AtomicWaker, OnDrop, Unborrow};
10use embassy_extras::unborrow; 10use embassy_extras::unborrow;
11use futures::future::poll_fn; 11use futures::future::poll_fn;
@@ -17,7 +17,9 @@ use crate::interrupt;
17use crate::interrupt::Interrupt; 17use crate::interrupt::Interrupt;
18use crate::pac; 18use crate::pac;
19use crate::peripherals; 19use crate::peripherals;
20use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
20use crate::target_constants::EASY_DMA_SIZE; 21use crate::target_constants::EASY_DMA_SIZE;
22use crate::timer::Instance as TimerInstance;
21 23
22// Re-export SVD variants to allow user to directly set values. 24// Re-export SVD variants to allow user to directly set values.
23pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; 25pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
@@ -281,6 +283,161 @@ impl<'d, T: Instance> Write for Uarte<'d, T> {
281 } 283 }
282} 284}
283 285
286/// Interface to an UARTE peripheral that uses timers and PPI to emulate
287/// ReadUntilIdle.
288pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> {
289 uarte: Uarte<'d, U>,
290 timer: T,
291 _ppi_ch1: Ppi<'d, AnyConfigurableChannel>,
292 _ppi_ch2: Ppi<'d, AnyConfigurableChannel>,
293}
294
295impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> {
296 /// Creates the interface to a UARTE instance.
297 /// Sets the baud rate, parity and assigns the pins to the UARTE peripheral.
298 ///
299 /// # Safety
300 ///
301 /// The returned API is safe unless you use `mem::forget` (or similar safe mechanisms)
302 /// on stack allocated buffers which which have been passed to [`send()`](Uarte::send)
303 /// or [`receive`](Uarte::receive).
304 #[allow(unused_unsafe)]
305 pub unsafe fn new(
306 uarte: impl Unborrow<Target = U> + 'd,
307 timer: impl Unborrow<Target = T> + 'd,
308 ppi_ch1: impl Unborrow<Target = impl ConfigurableChannel> + 'd,
309 ppi_ch2: impl Unborrow<Target = impl ConfigurableChannel> + 'd,
310 irq: impl Unborrow<Target = U::Interrupt> + 'd,
311 rxd: impl Unborrow<Target = impl GpioPin> + 'd,
312 txd: impl Unborrow<Target = impl GpioPin> + 'd,
313 cts: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
314 rts: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
315 config: Config,
316 ) -> Self {
317 let baudrate = config.baudrate;
318 let uarte = Uarte::new(uarte, irq, rxd, txd, cts, rts, config);
319
320 unborrow!(timer, ppi_ch1, ppi_ch2);
321
322 let r = U::regs();
323 let rt = timer.regs();
324
325 // BAUDRATE register values are `baudrate * 2^32 / 16000000`
326 // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values
327 //
328 // We want to stop RX if line is idle for 2 bytes worth of time
329 // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit)
330 // This gives us the amount of 16M ticks for 20 bits.
331 let timeout = 0x8000_0000 / (baudrate as u32 / 40);
332
333 rt.tasks_stop.write(|w| unsafe { w.bits(1) });
334 rt.bitmode.write(|w| w.bitmode()._32bit());
335 rt.prescaler.write(|w| unsafe { w.prescaler().bits(0) });
336 rt.cc[0].write(|w| unsafe { w.bits(timeout) });
337 rt.mode.write(|w| w.mode().timer());
338 rt.shorts.write(|w| {
339 w.compare0_clear().set_bit();
340 w.compare0_stop().set_bit();
341 w
342 });
343
344 let mut ppi_ch1 = Ppi::new(ppi_ch1.degrade_configurable());
345 ppi_ch1.set_event(Event::from_reg(&r.events_rxstarted));
346 ppi_ch1.set_task(Task::from_reg(&rt.tasks_clear));
347 ppi_ch1.set_fork_task(Task::from_reg(&rt.tasks_start));
348 ppi_ch1.enable();
349
350 let mut ppi_ch2 = Ppi::new(ppi_ch2.degrade_configurable());
351 ppi_ch2.set_event(Event::from_reg(&rt.events_compare[0]));
352 ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx));
353 ppi_ch2.enable();
354
355 Self {
356 uarte,
357 timer,
358 _ppi_ch1: ppi_ch1,
359 _ppi_ch2: ppi_ch2,
360 }
361 }
362}
363
364impl<'d, U: Instance, T: TimerInstance> ReadUntilIdle for UarteWithIdle<'d, U, T> {
365 #[rustfmt::skip]
366 type ReadUntilIdleFuture<'a> where Self: 'a = impl Future<Output = Result<usize, Error>> + 'a;
367 fn read_until_idle<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadUntilIdleFuture<'a> {
368 async move {
369 let ptr = rx_buffer.as_ptr();
370 let len = rx_buffer.len();
371 assert!(len <= EASY_DMA_SIZE);
372
373 let r = U::regs();
374 let s = U::state();
375
376 let rt = self.timer.regs();
377
378 let drop = OnDrop::new(move || {
379 info!("read drop: stopping");
380
381 rt.tasks_stop.write(|w| unsafe { w.bits(1) });
382
383 r.intenclr.write(|w| w.endrx().clear());
384 r.events_rxto.reset();
385 r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
386
387 while r.events_endrx.read().bits() == 0 {}
388
389 info!("read drop: stopped");
390 });
391
392 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
393 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
394
395 r.events_endrx.reset();
396 r.intenset.write(|w| w.endrx().set());
397
398 compiler_fence(Ordering::SeqCst);
399
400 trace!("startrx");
401 r.tasks_startrx.write(|w| unsafe { w.bits(1) });
402
403 let n: usize = poll_fn(|cx| {
404 s.endrx_waker.register(cx.waker());
405 if r.events_endrx.read().bits() != 0 {
406 let n: usize = r.rxd.amount.read().amount().bits() as usize;
407 return Poll::Ready(n);
408 }
409 Poll::Pending
410 })
411 .await;
412
413 compiler_fence(Ordering::SeqCst);
414 r.events_rxstarted.reset();
415 // Stop timer
416 rt.tasks_stop.write(|w| unsafe { w.bits(1) });
417 drop.defuse();
418
419 Ok(n)
420 }
421 }
422}
423
424impl<'d, U: Instance, T: TimerInstance> Read for UarteWithIdle<'d, U, T> {
425 #[rustfmt::skip]
426 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a;
427 fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
428 self.uarte.read(rx_buffer)
429 }
430}
431
432impl<'d, U: Instance, T: TimerInstance> Write for UarteWithIdle<'d, U, T> {
433 #[rustfmt::skip]
434 type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Error>> + 'a;
435
436 fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> {
437 self.uarte.write(tx_buffer)
438 }
439}
440
284mod sealed { 441mod sealed {
285 use super::*; 442 use super::*;
286 443