From ede53457a9d37ac62221d18cbfcca459e58ced94 Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Tue, 13 Aug 2019 14:19:05 -0400 Subject: Basic, and somewhat broken, UARTE1 handling. Using this for serial output from the Trinket M0. Currently it needs to fill up a DMA buffer before we get any output, and it seems like some data is being lost. But at least its not garbled, so there's nothing wrong with the UART device setup. --- ble/src/main.rs | 53 +++++++++++++++++++++++++++++----- ble/src/uarte1.rs | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 ble/src/uarte1.rs diff --git a/ble/src/main.rs b/ble/src/main.rs index 2da6de9..3c98b7e 100644 --- a/ble/src/main.rs +++ b/ble/src/main.rs @@ -7,13 +7,13 @@ mod i2c; mod logger; mod macros; mod rtc; +mod uarte1; use clint::HandlerArray; -use core::fmt::Write; use core::mem; use cortex_m::asm::wfi; use cortex_m_rt::{entry, exception, ExceptionFrame}; -use log::{info, trace, LevelFilter}; +use log::{info, LevelFilter}; #[allow(unused_imports)] extern crate panic_semihosting; @@ -33,7 +33,6 @@ const I2C_ADDR: u8 = 4; // TODO: // * set up serial reader for trinket -// * set up i²c interface for keyboard reports // * and, finally, bluetooth // Interrupt handler table. @@ -53,7 +52,7 @@ fn main() -> ! { let mut nvic = nrf52.NVIC; let mut rtc_handler = rtc::setup(Rtc::new(nrf52.RTC0), Clocks::new(nrf52.CLOCK)); - let mut twis_handler = i2c::setup(Twis::new( + let (mut twis_reader, mut twis_handler) = i2c::setup(Twis::new( I2C_ADDR, nrf52.TWIS0, twis::Pins { @@ -68,27 +67,62 @@ fn main() -> ! { .into_push_pull_output(Level::High) .degrade(); let rxp = nrf52.pins.P0_25.into_floating_input().degrade(); - let mut uarte1 = uarte1(nrf52.UARTE1, txp, rxp); + let uarte1 = uarte1(nrf52.UARTE1, txp, rxp); + let (mut uarte1_reader, mut uarte1_handler) = uarte1::setup(uarte1); HANDLERS.with_overrides(|hs| { hs.register(0, &mut rtc_handler); nvic.enable(Interrupt::RTC0); hs.register(1, &mut twis_handler); nvic.enable(Interrupt::SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); + hs.register(2, &mut uarte1_handler); + nvic.enable(Interrupt::UARTE1); info!("Bootstrap complete."); let mut last_tick = rtc::millis(); last_tick -= last_tick % 1024; + let mut buf: [u8; 256] = [0; 256]; loop { let tick = rtc::millis(); if tick >= last_tick + 1024 { last_tick = tick; last_tick -= last_tick % 1024; - trace!("."); - write!(uarte1, "!").expect("uarte1 write"); } + 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]); + } + + 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; + } + info!( + "serial - {}: {}", + i, + core::str::from_utf8(&buf[0..i]).expect("utf8conv") + ); + } wfi(); } }); @@ -132,3 +166,8 @@ fn RTC0() { fn SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0() { HANDLERS.call(1); } + +#[interrupt] +fn UARTE1() { + HANDLERS.call(2); +} diff --git a/ble/src/uarte1.rs b/ble/src/uarte1.rs new file mode 100644 index 0000000..61d631e --- /dev/null +++ b/ble/src/uarte1.rs @@ -0,0 +1,85 @@ +use log::info; +use nrf52840_hal::uarte::{self, Uarte}; +use starb::{Reader, RingBuffer, Writer}; + +static mut RB: RingBuffer = RingBuffer::new(0); + +pub fn setup(mut uarte: Uarte) -> (Reader<'static, u8>, impl FnMut()) +where + I: uarte::Instance, +{ + uarte.0.intenset.write(|w| { + w.endrx().set_bit(); + w.error().set_bit(); + w.rxto().set_bit(); + 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 _) }); + uarte + .0 + .rxd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(buf.len() 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); + (rbr, cl) +} + +fn handler(uarte: &mut Uarte, writer: &mut Writer, buf: &mut [u8]) +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(); + } + + // 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 _) }); + + // restart the read. + uarte.0.tasks_startrx.write(|w| w.tasks_startrx().set_bit()); + } 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()); + } 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"); + } else if uarte + .0 + .events_rxstarted + .read() + .events_rxstarted() + .bit_is_set() + { + uarte + .0 + .events_rxstarted + .write(|w| w.events_rxstarted().clear_bit()); + info!("rxstarted"); + } +} -- cgit v1.2.3