From 852c73760589e663e484c1783bd5b73c7df6907c Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Tue, 13 Aug 2019 20:35:16 -0400 Subject: Use bulk starb read/write operations. This should speed things up a bit, but, unfortunately, doesn't solve my serial1 problems. --- ble/src/i2c.rs | 8 ++-- ble/src/logger.rs | 26 ++++-------- ble/src/main.rs | 38 +++++------------ ble/src/uarte1.rs | 119 +++++++++++++++++++++++++++++++++++++++++------------- 4 files changed, 111 insertions(+), 80 deletions(-) (limited to 'ble/src') diff --git a/ble/src/i2c.rs b/ble/src/i2c.rs index 0f7fe5e..b5a5114 100644 --- a/ble/src/i2c.rs +++ b/ble/src/i2c.rs @@ -39,11 +39,9 @@ where let mut buf: [u8; 255] = [0; 255]; match twis.read(&mut buf) { Ok(len) => { - for b in &buf[0..len] { - // Ignore unshift errors for now, as I don't think - // there's much we can do about it. - writer.unshift(*b).ok(); - } + // Ignore unshift overflow for now, as I don't think + // there's much we can do about it. + writer.unshift_from(&buf[0..len]); trace!("write done"); } Err(e) => error!("{:?}", e), diff --git a/ble/src/logger.rs b/ble/src/logger.rs index f102b74..b4167b2 100644 --- a/ble/src/logger.rs +++ b/ble/src/logger.rs @@ -2,6 +2,7 @@ use crate::rtc; use core::cell::UnsafeCell; use core::fmt::{self, Write}; +use core::mem::MaybeUninit; use log::{Metadata, Record}; use nrf52840_hal::{target::UARTE0, uarte, Uarte}; use starb::{Reader, RingBuffer, Writer}; @@ -22,12 +23,9 @@ impl<'a> JoinedRingBuffer<'a> { impl fmt::Write for JoinedRingBuffer<'_> { fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { - for b in s.bytes() { - if let Err(_) = self.lbw.unshift(b) { - // Ignore buffer full errors for logging. - return Ok(()); - } - } + // Drop anything that couldn't fit on the ground so we don't + // back up. + self.lbw.unshift_from(s.as_bytes()); Ok(()) } } @@ -94,20 +92,12 @@ where } fn flush(&self) { - // Unsafe due to mutable static. We can only deal with the - // tail position of the buffer here to keep things safe. let jrb = unsafe { &mut JRB }; - if jrb.lbr.is_empty() { - return; - } - let writer = unsafe { &mut (*self.writer.get()) }; - while let Some(b) = jrb.lbr.shift() { - // TODO: The UARTE peripheral uses DMA to send a bunch of - // stuff at speed, in hardware. It would be nice to use - // it, but we can't just take a slice of the ring buffer, - // since we don't know about its internal structure here. - writer.w.write(&[b]).expect("writing log"); + let mut buf: [u8; 256] = unsafe { MaybeUninit::<[u8; 256]>::uninit().assume_init() }; + let len = jrb.lbr.shift_into(&mut buf); + if len > 0 { + writer.w.write(&buf[0..len]).expect("writing log") } } } diff --git a/ble/src/main.rs b/ble/src/main.rs index 3c98b7e..71e3b82 100644 --- a/ble/src/main.rs +++ b/ble/src/main.rs @@ -90,38 +90,20 @@ fn main() -> ! { last_tick -= last_tick % 1024; } - if !twis_reader.is_empty() { - let mut i = 0; - for b in &mut twis_reader { - if i == buf.len() { - info!("i²c data: {:?}", &buf[0..i]); - i = 0; - } - buf[i] = b; - i += 1; - } - info!("i²c data: {:?}", &buf[0..i]); + let mut len = twis_reader.shift_into(&mut buf); + while len > 0 { + info!("i²c data: {:?}", &buf[0..len]); + len = twis_reader.shift_into(&mut buf); } - if !uarte1_reader.is_empty() { - let mut i = 0; - for b in &mut uarte1_reader { - if i == buf.len() { - info!( - "serial - {}: {}", - i, - core::str::from_utf8(&buf[0..i]).expect("utf8conv") - ); - i = 0; - } - buf[i] = b; - i += 1; - } + let mut len = uarte1_reader.shift_into(&mut buf); + while len > 0 { info!( - "serial - {}: {}", - i, - core::str::from_utf8(&buf[0..i]).expect("utf8conv") + "serial {}: {}", + len, + core::str::from_utf8(&buf[0..len]).expect("utf8conv") ); + len = uarte1_reader.shift_into(&mut buf); } wfi(); } diff --git a/ble/src/uarte1.rs b/ble/src/uarte1.rs index 61d631e..1afce29 100644 --- a/ble/src/uarte1.rs +++ b/ble/src/uarte1.rs @@ -4,6 +4,42 @@ use starb::{Reader, RingBuffer, Writer}; static mut RB: RingBuffer = RingBuffer::new(0); +const BUFLEN: usize = 128; + +struct DoubleBuffer { + bank0: [u8; BUFLEN], + bank1: [u8; BUFLEN], + is_bank0: bool, +} +impl DoubleBuffer { + const fn new() -> Self { + Self { + bank0: [0; BUFLEN], + bank1: [0; BUFLEN], + is_bank0: true, + } + } + + fn cur_ptr(&mut self) -> *mut u8 { + if self.is_bank0 { + self.bank0.as_mut_ptr() + } else { + self.bank1.as_mut_ptr() + } + } + + fn next_ptr(&mut self) -> *mut u8 { + self.is_bank0 = !self.is_bank0; + if self.is_bank0 { + self.bank1.as_mut_ptr() + } else { + self.bank0.as_mut_ptr() + } + } +} + +static mut DBL_BUFF: DoubleBuffer = DoubleBuffer::new(); + pub fn setup(mut uarte: Uarte) -> (Reader<'static, u8>, impl FnMut()) where I: uarte::Instance, @@ -15,60 +51,73 @@ where w.rxstarted().set_bit() }); - let mut buf: [u8; 255] = [0; 255]; - uarte - .0 - .rxd - .ptr - .write(|w| unsafe { w.ptr().bits(buf.as_mut_ptr() as _) }); + let ptr = unsafe { DBL_BUFF.next_ptr() }; + info!("setting up dma: p: {:x}, maxcnt: {}", ptr as u32, BUFLEN); + uarte.0.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); uarte .0 .rxd .maxcnt - .write(|w| unsafe { w.maxcnt().bits(buf.len() as _) }); + .write(|w| unsafe { w.maxcnt().bits(BUFLEN as _) }); uarte.0.tasks_startrx.write(|w| w.tasks_startrx().set_bit()); let (rbr, mut rbw) = unsafe { RB.split() }; // start rx into a buffer. it would be nice if we could do this // with rxrdy or something like i2c does. - let cl = move || handler(&mut uarte, &mut rbw, &mut buf); + let cl = move || handler(&mut uarte, &mut rbw); (rbr, cl) } -fn handler(uarte: &mut Uarte, writer: &mut Writer, buf: &mut [u8]) +fn handler(uarte: &mut Uarte, writer: &mut Writer) where I: uarte::Instance, { if uarte.0.events_endrx.read().events_endrx().bit_is_set() { uarte.0.events_endrx.write(|w| w.events_endrx().clear_bit()); - // Copy DMA buffer to ring buffer. - let len = uarte.0.rxd.amount.read().amount().bits(); - info!("endrx - {}", len); - for i in 0..len { - writer.unshift(buf[i as usize]).ok(); + // The buffer should be swapped from the RXSTARTED event, so + // we can restart the read immediately. + let optr = uarte.0.rxd.ptr.read().ptr().bits(); + let ptr = unsafe { DBL_BUFF.cur_ptr() as u32 }; + /* + if optr == ptr { + uarte + .0 + .rxd + .ptr + .write(|w| unsafe { w.ptr().bits(DBL_BUFF.next_ptr() as _) }); } + */ + uarte.0.tasks_startrx.write(|w| w.tasks_startrx().set_bit()); - // Reset the DMA buffer. TODO: this is probably unneccesary. - uarte - .0 - .rxd - .ptr - .write(|w| unsafe { w.ptr().bits(buf.as_mut_ptr() as _) }); - uarte - .0 - .rxd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(buf.len() as _) }); + // Copy DMA buffer to ring buffer. + let len = uarte.0.rxd.amount.read().amount().bits(); + let mc = uarte.0.rxd.maxcnt.read().maxcnt().bits(); + info!( + "endrx - l: {}, p: {:x}, mc: {}, b: {:x}", + len, optr, mc, ptr + ); + flush_buf(writer, unsafe { DBL_BUFF.cur_ptr() }, len.into()); - // restart the read. - uarte.0.tasks_startrx.write(|w| w.tasks_startrx().set_bit()); + /* + uarte + .0 + .rxd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(BUFLEN as _) }); + */ } else if uarte.0.events_error.read().events_error().bit_is_set() { uarte.0.events_error.write(|w| w.events_error().clear_bit()); - info!("error: {:b}", uarte.0.errorsrc.read().bits()); + + let len = uarte.0.rxd.amount.read().amount().bits(); + info!("error: {:b} {}b", uarte.0.errorsrc.read().bits(), len,); } else if uarte.0.events_rxto.read().events_rxto().bit_is_set() { uarte.0.events_rxto.write(|w| w.events_rxto().clear_bit()); - info!("rxto"); + + let len = uarte.0.rxd.amount.read().amount().bits(); + info!("rxto - {}", len); + flush_buf(writer, unsafe { DBL_BUFF.cur_ptr() }, len.into()); + uarte.0.tasks_flushrx.write(|w| w.tasks_flushrx().set_bit()); } else if uarte .0 .events_rxstarted @@ -81,5 +130,17 @@ where .events_rxstarted .write(|w| w.events_rxstarted().clear_bit()); info!("rxstarted"); + + // Swap to the next buffer as soon as the transfer starts to + // try and lose as little data as possible. + let ptr = unsafe { DBL_BUFF.next_ptr() }; + uarte.0.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); } } + +fn flush_buf(writer: &mut Writer, ptr: *mut u8, len: usize) { + let buf = unsafe { core::slice::from_raw_parts(ptr, len) }; + info!("flush start"); + writer.unshift_from(buf); + info!("flush end"); +} -- cgit v1.2.3