Skip to content

Commit 4ed85a5

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 19e332c commit 4ed85a5

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
@@ -371,11 +371,16 @@ where
371371
)
372372
}
373373

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

@@ -405,6 +410,8 @@ pub struct Pins {
405410

406411
#[derive(Debug)]
407412
pub enum Error {
413+
TxBufferTooSmall,
414+
RxBufferTooSmall,
408415
TxBufferTooLong,
409416
RxBufferTooLong,
410417
Transmit,
@@ -440,40 +447,46 @@ mod _uarte1 {
440447
}
441448

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

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

454-
impl<T> UarteTx<T>
461+
impl<'a, T> UarteTx<'a, T>
455462
where
456463
T: Instance,
457464
{
458-
fn new() -> UarteTx<T> {
459-
let tx = UarteTx {
460-
_marker: core::marker::PhantomData,
461-
tx_buf: [0; 1],
462-
};
463-
tx
465+
fn new(tx_buf: &'a mut [u8]) -> Result<UarteTx<'a, T>, Error> {
466+
if tx_buf.len() > 0 {
467+
Ok(UarteTx {
468+
_marker: core::marker::PhantomData,
469+
tx_buf,
470+
})
471+
} else {
472+
Err(Error::TxBufferTooSmall)
473+
}
464474
}
465475
}
466476

467-
impl<T> UarteRx<T>
477+
impl<'a, T> UarteRx<'a, T>
468478
where
469479
T: Instance,
470480
{
471-
fn new() -> UarteRx<T> {
472-
let rx = UarteRx {
473-
_marker: core::marker::PhantomData,
474-
rx_buf: [0; 1],
475-
};
476-
rx
481+
fn new(rx_buf: &'a mut [u8]) -> Result<UarteRx<'a, T>, Error> {
482+
if rx_buf.len() > 0 {
483+
Ok(UarteRx {
484+
_marker: core::marker::PhantomData,
485+
rx_buf,
486+
})
487+
} else {
488+
Err(Error::RxBufferTooSmall)
489+
}
477490
}
478491
}
479492

@@ -484,7 +497,7 @@ pub mod serial {
484497
use embedded_hal::serial;
485498
use nb;
486499

487-
impl<T> serial::Write<u8> for UarteTx<T>
500+
impl<'a, T> serial::Write<u8> for UarteTx<'a, T>
488501
where
489502
T: Instance,
490503
{
@@ -502,8 +515,7 @@ pub mod serial {
502515
} else {
503516
// Start a new transmission, copy value into transmit buffer.
504517

505-
let tx_buffer = &mut self.tx_buf;
506-
tx_buffer[0] = b;
518+
self.tx_buf[0] = b;
507519

508520
// Conservative compiler fence to prevent optimizations that do not
509521
// take in to account actions by DMA. The fence has been placed here,
@@ -522,18 +534,13 @@ pub mod serial {
522534
uarte
523535
.txd
524536
.ptr
525-
.write(|w| unsafe { w.ptr().bits(tx_buffer.as_ptr() as u32) });
537+
.write(|w| unsafe { w.ptr().bits(self.tx_buf.as_ptr() as u32) });
526538

527-
// We're giving it the length of the buffer, so no danger of
528-
// accessing invalid memory. We have verified that the length of the
529-
// buffer fits in an `u8`, so the cast to `u8` is also fine.
539+
// We're giving it a length of 1 to transmit 1 byte at a time.
530540
//
531541
// The MAXCNT field is 8 bits wide and accepts the full range of
532542
// values.
533-
uarte
534-
.txd
535-
.maxcnt
536-
.write(|w| unsafe { w.maxcnt().bits(tx_buffer.len() as _) });
543+
uarte.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(1) });
537544

538545
// Start UARTE Transmit transaction.
539546
// `1` is a valid value to write to task registers.
@@ -577,7 +584,7 @@ pub mod serial {
577584
}
578585
}
579586

580-
impl<T> core::fmt::Write for UarteTx<T>
587+
impl<'a, T> core::fmt::Write for UarteTx<'a, T>
581588
where
582589
T: Instance,
583590
{
@@ -589,7 +596,7 @@ pub mod serial {
589596
}
590597
}
591598

592-
impl<T> serial::Read<u8> for UarteRx<T>
599+
impl<'a, T> serial::Read<u8> for UarteRx<'a, T>
593600
where
594601
T: Instance,
595602
{
@@ -615,26 +622,20 @@ pub mod serial {
615622
}
616623
Ok(b)
617624
} else {
618-
let rx_buf = &mut self.rx_buf;
619-
620625
// We're giving the register a pointer to the rx buffer.
621626
//
622627
// The PTR field is a full 32 bits wide and accepts the full range
623628
// of values.
624629
uarte
625630
.rxd
626631
.ptr
627-
.write(|w| unsafe { w.ptr().bits(rx_buf.as_ptr() as u32) });
632+
.write(|w| unsafe { w.ptr().bits(self.rx_buf.as_ptr() as u32) });
628633

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

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

0 commit comments

Comments
 (0)