Skip to content

Commit c4b7318

Browse files
committed
Pass TX and RX buffers to split() to ensure move of UartTx and UartRx does not affect memory location for DMA.
1 parent 64a00e5 commit c4b7318

File tree

1 file changed

+46
-45
lines changed

1 file changed

+46
-45
lines changed

nrf-hal-common/src/uarte.rs

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -373,11 +373,16 @@ where
373373
)
374374
}
375375

376-
// Split into implementations of embedded_hal::serial traits
377-
pub fn split(self) -> (UarteTx<T>, UarteRx<T>) {
378-
let tx = UarteTx::new();
379-
let rx = UarteRx::new();
380-
(tx, rx)
376+
// Split into implementations of embedded_hal::serial traits. The buffers passed here must outlive any DMA transfers
377+
// that are initiated by the UartTx and UartRx.
378+
pub fn split<'a>(
379+
self,
380+
tx_buf: &'a mut [u8],
381+
rx_buf: &'a mut [u8],
382+
) -> Result<(UarteTx<'a, T>, UarteRx<'a, T>), Error> {
383+
let tx = UarteTx::new(tx_buf)?;
384+
let rx = UarteRx::new(rx_buf)?;
385+
Ok((tx, rx))
381386
}
382387
}
383388

@@ -407,6 +412,8 @@ pub struct Pins {
407412

408413
#[derive(Debug)]
409414
pub enum Error {
415+
TxBufferTooSmall,
416+
RxBufferTooSmall,
410417
TxBufferTooLong,
411418
RxBufferTooLong,
412419
Transmit,
@@ -442,40 +449,46 @@ mod _uarte1 {
442449
}
443450

444451
/// Interface for the TX part of a UART instance that can be used independently of the RX part.
445-
pub struct UarteTx<T> {
452+
pub struct UarteTx<'a, T> {
446453
_marker: core::marker::PhantomData<T>,
447-
tx_buf: [u8; 1],
454+
tx_buf: &'a mut [u8],
448455
}
449456

450457
/// Interface for the RX part of a UART instance that can be used independently of the TX part.
451-
pub struct UarteRx<T> {
458+
pub struct UarteRx<'a, T> {
452459
_marker: core::marker::PhantomData<T>,
453-
rx_buf: [u8; 1],
460+
rx_buf: &'a mut [u8],
454461
}
455462

456-
impl<T> UarteTx<T>
463+
impl<'a, T> UarteTx<'a, T>
457464
where
458465
T: Instance,
459466
{
460-
fn new() -> UarteTx<T> {
461-
let tx = UarteTx {
462-
_marker: core::marker::PhantomData,
463-
tx_buf: [0; 1],
464-
};
465-
tx
467+
fn new(tx_buf: &'a mut [u8]) -> Result<UarteTx<'a, T>, Error> {
468+
if tx_buf.len() > 0 {
469+
Ok(UarteTx {
470+
_marker: core::marker::PhantomData,
471+
tx_buf,
472+
})
473+
} else {
474+
Err(Error::TxBufferTooSmall)
475+
}
466476
}
467477
}
468478

469-
impl<T> UarteRx<T>
479+
impl<'a, T> UarteRx<'a, T>
470480
where
471481
T: Instance,
472482
{
473-
fn new() -> UarteRx<T> {
474-
let rx = UarteRx {
475-
_marker: core::marker::PhantomData,
476-
rx_buf: [0; 1],
477-
};
478-
rx
483+
fn new(rx_buf: &'a mut [u8]) -> Result<UarteRx<'a, T>, Error> {
484+
if rx_buf.len() > 0 {
485+
Ok(UarteRx {
486+
_marker: core::marker::PhantomData,
487+
rx_buf,
488+
})
489+
} else {
490+
Err(Error::RxBufferTooSmall)
491+
}
479492
}
480493
}
481494

@@ -486,7 +499,7 @@ pub mod serial {
486499
use embedded_hal::serial;
487500
use nb;
488501

489-
impl<T> serial::Write<u8> for UarteTx<T>
502+
impl<'a, T> serial::Write<u8> for UarteTx<'a, T>
490503
where
491504
T: Instance,
492505
{
@@ -504,8 +517,7 @@ pub mod serial {
504517
} else {
505518
// Start a new transmission, copy value into transmit buffer.
506519

507-
let tx_buffer = &mut self.tx_buf;
508-
tx_buffer[0] = b;
520+
self.tx_buf[0] = b;
509521

510522
// Conservative compiler fence to prevent optimizations that do not
511523
// take in to account actions by DMA. The fence has been placed here,
@@ -524,18 +536,13 @@ pub mod serial {
524536
uarte
525537
.txd
526538
.ptr
527-
.write(|w| unsafe { w.ptr().bits(tx_buffer.as_ptr() as u32) });
539+
.write(|w| unsafe { w.ptr().bits(self.tx_buf.as_ptr() as u32) });
528540

529-
// We're giving it the length of the buffer, so no danger of
530-
// accessing invalid memory. We have verified that the length of the
531-
// buffer fits in an `u8`, so the cast to `u8` is also fine.
541+
// We're giving it a length of 1 to transmit 1 byte at a time.
532542
//
533543
// The MAXCNT field is 8 bits wide and accepts the full range of
534544
// values.
535-
uarte
536-
.txd
537-
.maxcnt
538-
.write(|w| unsafe { w.maxcnt().bits(tx_buffer.len() as _) });
545+
uarte.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(1) });
539546

540547
// Start UARTE Transmit transaction.
541548
// `1` is a valid value to write to task registers.
@@ -579,7 +586,7 @@ pub mod serial {
579586
}
580587
}
581588

582-
impl<T> core::fmt::Write for UarteTx<T>
589+
impl<'a, T> core::fmt::Write for UarteTx<'a, T>
583590
where
584591
T: Instance,
585592
{
@@ -591,7 +598,7 @@ pub mod serial {
591598
}
592599
}
593600

594-
impl<T> serial::Read<u8> for UarteRx<T>
601+
impl<'a, T> serial::Read<u8> for UarteRx<'a, T>
595602
where
596603
T: Instance,
597604
{
@@ -617,26 +624,20 @@ pub mod serial {
617624
}
618625
Ok(b)
619626
} else {
620-
let rx_buf = &mut self.rx_buf;
621-
622627
// We're giving the register a pointer to the rx buffer.
623628
//
624629
// The PTR field is a full 32 bits wide and accepts the full range
625630
// of values.
626631
uarte
627632
.rxd
628633
.ptr
629-
.write(|w| unsafe { w.ptr().bits(rx_buf.as_ptr() as u32) });
634+
.write(|w| unsafe { w.ptr().bits(self.rx_buf.as_ptr() as u32) });
630635

631-
// We're giving it the length of the buffer, so no danger of
632-
// accessing invalid memory.
636+
// We're giving it a length of 1 to read only 1 byte.
633637
//
634638
// The MAXCNT field is at least 8 bits wide and accepts the full
635639
// range of values.
636-
uarte
637-
.rxd
638-
.maxcnt
639-
.write(|w| unsafe { w.maxcnt().bits(rx_buf.len() as _) });
640+
uarte.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(1) });
640641

641642
// Start UARTE Receive transaction.
642643
// `1` is a valid value to write to task registers.

0 commit comments

Comments
 (0)