nrf52-bin-logger 0.2.0

A binary protocol for UARTE logging on the nRF52
////////////////////////////////////////////////////////////////////////
// These functions are taken from nrf52-hal. This is because
// they are private functions (rightly so), but we need this
// behavior to enable non-blocking reading to the ping pong
// buffers


use nrf52832_hal::{nrf52832_pac::UARTE0};
use core::sync::atomic::{compiler_fence, Ordering::SeqCst};

/// Start a UARTE read transaction by setting the control
/// values and triggering a read task
pub(crate) fn start_read(rx_buffer: &mut [u8]) -> Result<(), nrf52832_hal::uarte::Error> {
    let periph = unsafe { &*UARTE0::ptr() };

    // This is overly restrictive. See (similar SPIM issue):
    // https://github.com/nrf-rs/nrf52/issues/17
    if rx_buffer.len() > u8::max_value() as usize {
        return Err(nrf52832_hal::uarte::Error::TxBufferTooLong);
    }

    // Conservative compiler fence to prevent optimizations that do not
    // take in to account actions by DMA. The fence has been placed here,
    // before any DMA action has started
    compiler_fence(SeqCst);

    // Set up the DMA read
    periph.rxd.ptr.write(|w|
        // We're giving the register a pointer to the stack. Since we're
        // waiting for the UARTE transaction to end before this stack pointer
        // becomes invalid, there's nothing wrong here.
        //
        // The PTR field is a full 32 bits wide and accepts the full range
        // of values.
        unsafe { w.ptr().bits(rx_buffer.as_ptr() as u32) });
    periph.rxd.maxcnt.write(|w|
        // We're giving it the length of the buffer, so no danger of
        // accessing invalid memory. We have verified that the length of the
        // buffer fits in an `u8`, so the cast to `u8` is also fine.
        //
        // The MAXCNT field is at least 8 bits wide and accepts the full
        // range of values.
        unsafe { w.maxcnt().bits(rx_buffer.len() as _) });

    // Start UARTE Receive transaction
    periph.tasks_startrx.write(|w|
        // `1` is a valid value to write to task registers.
        unsafe { w.bits(1) });

    Ok(())
}

/// Finalize a UARTE read transaction by clearing the event
pub(crate) fn finalize_read() {
    let periph = unsafe { &*UARTE0::ptr() };

    // Reset the event, otherwise it will always read `1` from now on.
    periph.events_endrx.write(|w| w);

    // Conservative compiler fence to prevent optimizations that do not
    // take in to account actions by DMA. The fence has been placed here,
    // after all possible DMA actions have completed
    compiler_fence(SeqCst);
}