From 7233780945407f4168caeaa350e93359e5890e33 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 2 May 2019 10:16:51 +0200 Subject: [PATCH 01/44] Added interrupt driven UARTE --- nrf52-hal-common/Cargo.toml | 4 + nrf52-hal-common/src/uarte.rs | 342 +++++++++++++++++++++++++++++----- 2 files changed, 295 insertions(+), 51 deletions(-) diff --git a/nrf52-hal-common/Cargo.toml b/nrf52-hal-common/Cargo.toml index 26f4e38c..9c09c196 100644 --- a/nrf52-hal-common/Cargo.toml +++ b/nrf52-hal-common/Cargo.toml @@ -22,6 +22,10 @@ nb = "0.1.1" fpa = "0.1.0" rand_core = "0.4.0" +[dependencies.heapless] +version = "0.4.3" +features = ["min-const-fn"] + [dependencies.void] default-features = false version = "1.0.2" diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index a2804f65..8071b1f5 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -4,9 +4,9 @@ //! //! - nrf52832: Section 35 //! - nrf52840: Section 6.34 +use core::fmt; use core::ops::Deref; use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; -use core::fmt; #[cfg(feature="9160")] use crate::target::{ @@ -21,23 +21,19 @@ use crate::target::{ UARTE0, }; -use crate::target_constants::EASY_DMA_SIZE; +use crate::gpio::{Floating, Input, Output, Pin, PushPull}; use crate::prelude::*; -use crate::gpio::{ - Pin, - Output, - PushPull, - Input, - Floating, -}; +use crate::target_constants::EASY_DMA_SIZE; use crate::timer::{self, Timer}; - -// Re-export SVD variants to allow user to directly set values -pub use uarte0::{ - baudrate::BAUDRATEW as Baudrate, - config::PARITYW as Parity, +use heapless::{ + consts::*, + pool, + pool::singleton::{Box, Pool}, + spsc::{Consumer, Queue}, }; +// Re-export SVD variants to allow user to directly set values +pub use crate::target::uarte0::{baudrate::BAUDRATEW as Baudrate, config::PARITYW as Parity}; /// Interface to a UARTE instance /// @@ -49,7 +45,10 @@ pub use uarte0::{ /// - nrf52840: Section 6.1.2 pub struct Uarte(T); -impl Uarte where T: Instance { +impl Uarte +where + T: Instance, +{ pub fn new(uarte: T, mut pins: Pins, parity: Parity, baudrate: Baudrate) -> Self { // Select pins uarte.psel.rxd.write(|w| { @@ -90,21 +89,16 @@ impl Uarte where T: Instance { }); // Enable UARTE instance - uarte.enable.write(|w| - w.enable().enabled() - ); + uarte.enable.write(|w| w.enable().enabled()); // Configure let hardware_flow_control = pins.rts.is_some() && pins.cts.is_some(); - uarte.config.write(|w| - w.hwfc().bit(hardware_flow_control) - .parity().variant(parity) - ); + uarte + .config + .write(|w| w.hwfc().bit(hardware_flow_control).parity().variant(parity)); // Configure frequency - uarte.baudrate.write(|w| - w.baudrate().variant(baudrate) - ); + uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); Uarte(uarte) } @@ -115,11 +109,7 @@ impl Uarte where T: Instance { /// /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. - pub fn write(&mut self, - tx_buffer : &[u8], - ) - -> Result<(), Error> - { + pub fn write(&mut self, tx_buffer: &[u8]) -> Result<(), Error> { if tx_buffer.len() > EASY_DMA_SIZE { return Err(Error::TxBufferTooLong); } @@ -146,8 +136,7 @@ impl Uarte where T: Instance { // // The PTR field is a full 32 bits wide and accepts the full range // of values. - unsafe { w.ptr().bits(tx_buffer.as_ptr() as u32) } - ); + unsafe { w.ptr().bits(tx_buffer.as_ptr() as u32) }); self.0.txd.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 @@ -197,11 +186,7 @@ impl Uarte where T: Instance { /// until the buffer is full. /// /// The buffer must have a length of at most 255 bytes - pub fn read(&mut self, - rx_buffer : &mut [u8], - ) - -> Result<(), Error> - { + pub fn read(&mut self, rx_buffer: &mut [u8]) -> Result<(), Error> { self.start_read(rx_buffer)?; // Wait for transmission to end @@ -234,8 +219,10 @@ impl Uarte where T: Instance { &mut self, rx_buffer: &mut [u8], timer: &mut Timer, - cycles: u32 - ) -> Result<(), Error> where I: timer::Instance + cycles: u32, + ) -> Result<(), Error> + where + I: timer::Instance, { // Start the read self.start_read(rx_buffer)?; @@ -298,8 +285,7 @@ impl Uarte where T: Instance { // // 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) } - ); + unsafe { w.ptr().bits(rx_buffer.as_ptr() as u32) }); self.0.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 @@ -331,8 +317,7 @@ impl Uarte where T: Instance { /// Stop an unfinished UART read transaction and flush FIFO to DMA buffer fn cancel_read(&mut self) { // Stop reception - self.0.tasks_stoprx.write(|w| - unsafe { w.bits(1) }); + self.0.tasks_stoprx.write(|w| unsafe { w.bits(1) }); // Wait for the reception to have stopped while self.0.events_rxto.read().bits() == 0 {} @@ -341,8 +326,7 @@ impl Uarte where T: Instance { self.0.events_rxto.write(|w| w); // Ask UART to flush FIFO to DMA buffer - self.0.tasks_flushrx.write(|w| - unsafe { w.bits(1) }); + self.0.tasks_flushrx.write(|w| unsafe { w.bits(1) }); // Wait for the flush to complete. while self.0.events_endrx.read().bits() == 0 {} @@ -354,9 +338,257 @@ impl Uarte where T: Instance { pub fn free(self) -> T { self.0 } + + /// Splits the UARTE into a transmitter and receiver for interrupt driven use + /// + /// In needs a `Queue` to place received DMA chunks, and a `Consumer` to place DMA chunks to + /// send + /// + /// Note: The act of splitting might not be needed on the nRF52 chips, as they map to the same + /// interrupt in the end. Kept as a split for now, but might be merged in the future. + pub fn split( + self, + rxq: Queue, U2>, + txc: Consumer<'static, Box, TXQSize>, + ) -> (UarteRX, UarteTX) { + let mut rx = UarteRX::::new(rxq); + rx.enable_interrupts(); + rx.prepare_read().unwrap(); + rx.start_read(); + + let tx = UarteTX::::new(txc); + tx.enable_interrupts(); + (rx, tx) + } } -impl fmt::Write for Uarte where T: Instance { +/// DMA block size +pub const DMA_SIZE: usize = 16; +pool!(DMAPool: [u8; DMA_SIZE]); + +/// UARTE RX part, used in interrupt driven contexts +pub struct UarteRX { + rxq: Queue, U2>, // double buffering of DMA chunks + _marker: core::marker::PhantomData, +} + +/// Receive error in interrupt driven context +#[derive(Debug)] +pub enum RXError { + /// Out of memory error, global pool is depleted + /// + /// Potential causes: + /// 1. User code is saving the `Box` (and not dropping them) + /// 2. User code running `mem::forget` on the `Box` + /// 3. The pool is too small for the use case + OOM, +} + +impl UarteRX +where + T: Instance, +{ + /// Construct new UARTE RX, hidden from users - used internally + fn new(rxq: Queue, U2>) -> Self { + Self { + rxq, + _marker: core::marker::PhantomData, + } + } + + /// Used internally to set up the proper interrupts + fn enable_interrupts(&self) { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; + + uarte + .inten + .modify(|_, w| w.endrx().set_bit().rxstarted().set_bit()); + } + + /// Start a UARTE read transaction + fn start_read(&mut self) { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; + + // Start UARTE Receive transaction + uarte.tasks_startrx.write(|w| + // `1` is a valid value to write to task registers. + unsafe { w.bits(1) }); + } + + /// Prepare UARTE read transaction + fn prepare_read(&mut self) -> Result<(), RXError> { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; + + let b = DMAPool::alloc().ok_or(RXError::OOM)?.freeze(); + compiler_fence(SeqCst); + + // setup start address + uarte + .rxd + .ptr + .write(|w| unsafe { w.ptr().bits(b.as_ptr() as u32) }); + // setup length + uarte + .rxd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(b.len() as _) }); + + if self.rxq.enqueue(b).is_err() { + panic!("Internal driver error, RX Queue Overflow"); + } else { + Ok(()) + } + } + + /// Main entry point for the RX driver - Must be called from the corresponding UARTE Interrupt + /// handler/task. + /// + /// Will return: + /// 1. `Ok(Some(Box))` if data was received + /// 2. `Ok(None)` if there was no data, i.e. UARTE interrupt was due to other events + /// 3. `Err(RXError::OOM)` if the memory pool was depleted, see `RXError` for mitigations + pub fn process_interrupt(&mut self) -> Result>, RXError> { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; + + // check if dma rx transaction has started + if uarte.events_rxstarted.read().bits() == 1 { + // DMA transaction has started + self.prepare_read()?; + + // Reset the event, otherwise it will always read `1` from now on. + uarte.events_rxstarted.write(|w| w); + } + + // check id dma transaction finished + if uarte.events_endrx.read().bits() == 1 { + // our transaction has finished + if let Some(ret_b) = self.rxq.dequeue() { + // Reset the event, otherwise it will always read `1` from now on. + uarte.events_endrx.write(|w| w); + + self.start_read(); + + return Ok(Some(ret_b)); // ok to return, rx started will be caught later + } else { + panic!("Internal driver error, RX Queue Underflow"); + } + } + + // the interrupt was not RXSTARTED or ENDRX, so no action + Ok(None) + } +} + +/// A transmit queue size of 4 `DMAPool` chunks for now +pub type TXQSize = U4; + +/// UARTE TX part, used in interrupt driven contexts +pub struct UarteTX { + txc: Consumer<'static, Box, TXQSize>, // chunks to transmit + current: Option>, + _marker: core::marker::PhantomData, +} + +impl UarteTX +where + T: Instance, +{ + /// Construct new UARTE TX, hidden from users - used internally + fn new(txc: Consumer<'static, Box, TXQSize>) -> Self { + Self { + txc, + current: None, + _marker: core::marker::PhantomData, + } + } + + /// Used internally to set up the proper interrupts + fn enable_interrupts(&self) { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; + + uarte.inten.modify(|_, w| w.endtx().set_bit()); + } + + /// Sets up the UARTE to send DMA chunk + fn start_write(&mut self, b: Box) { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; + + compiler_fence(SeqCst); + + // setup start address + uarte + .txd + .ptr + .write(|w| unsafe { w.ptr().bits(b.as_ptr() as u32) }); + + // setup length + uarte + .txd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(b.len() as _) }); + + // Start UARTE transmit transaction + uarte.tasks_starttx.write(|w| unsafe { w.bits(1) }); + self.current = Some(b); // drops the previous current package + } + + /// Main entry point for the TX driver - Must be called from the corresponding UARTE Interrupt + /// handler/task. + pub fn process_interrupt(&mut self) { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; + + // ENDTX event? (DMA transaction finished) + if uarte.events_endtx.read().bits() == 1 { + // our transaction has finished + match self.txc.dequeue() { + None => { + // a ENDTX without an started transaction is an error + if self.current.is_none() { + panic!("Internal error, ENDTX without current transaction.") + } + // we don't have any more to send, so drop the current buffer + self.current = None; + } + Some(b) => { + self.start_write(b); + } + } + + // Reset the event, otherwise it will always read `1` from now on. + uarte.events_endtx.write(|w| w); + } else { + if self.current.is_none() { + match self.txc.dequeue() { + Some(b) => + // we were idle, so start a new transaction + { + self.start_write(b) + } + None => (), + } + } + } + } +} + +impl fmt::Write for Uarte +where + T: Instance, +{ fn write_str(&mut self, s: &str) -> fmt::Result { // Copy all data into an on-stack buffer so we never try to EasyDMA from // flash @@ -377,7 +609,6 @@ pub struct Pins { pub rts: Option>>, } - #[derive(Debug)] pub enum Error { TxBufferTooLong, @@ -388,10 +619,19 @@ pub enum Error { BufferNotInRAM, } +pub trait Instance: Deref { + fn ptr() -> *const uarte0::RegisterBlock; +} -pub trait Instance: Deref {} - -impl Instance for UARTE0 {} +impl Instance for UARTE0 { + fn ptr() -> *const uarte0::RegisterBlock { + UARTE0::ptr() + } +} #[cfg(feature="9160")] -impl Instance for UARTE1 {} +impl Instance for UARTE1 { + fn ptr() -> *const uarte0::RegisterBlock { + UARTE1::ptr() + } +} From dce32c34516070c62aabd3d8d3c689751af055e6 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 2 May 2019 22:06:30 +0200 Subject: [PATCH 02/44] Updated heapless dep, added missing exports --- nrf52-hal-common/Cargo.toml | 2 +- nrf52-hal-common/src/lib.rs | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/nrf52-hal-common/Cargo.toml b/nrf52-hal-common/Cargo.toml index 9c09c196..23e449e7 100644 --- a/nrf52-hal-common/Cargo.toml +++ b/nrf52-hal-common/Cargo.toml @@ -23,7 +23,7 @@ fpa = "0.1.0" rand_core = "0.4.0" [dependencies.heapless] -version = "0.4.3" +version = "0.4.4" features = ["min-const-fn"] [dependencies.void] diff --git a/nrf52-hal-common/src/lib.rs b/nrf52-hal-common/src/lib.rs index d2ab31b5..a490bb51 100644 --- a/nrf52-hal-common/src/lib.rs +++ b/nrf52-hal-common/src/lib.rs @@ -58,8 +58,7 @@ pub mod target_constants { /// Does this slice reside entirely within RAM? pub(crate) fn slice_in_ram(slice: &[u8]) -> bool { let ptr = slice.as_ptr() as usize; - ptr >= target_constants::SRAM_LOWER && - (ptr + slice.len()) < target_constants::SRAM_UPPER + ptr >= target_constants::SRAM_LOWER && (ptr + slice.len()) < target_constants::SRAM_UPPER } /// A handy structure for converting rust slices into ptr and len pairs @@ -72,10 +71,7 @@ pub(crate) struct DmaSlice { impl DmaSlice { pub fn null() -> Self { - Self { - ptr: 0, - len: 0, - } + Self { ptr: 0, len: 0 } } pub fn from_slice(slice: &[u8]) -> Self { @@ -95,4 +91,4 @@ pub use crate::saadc::Saadc; pub use crate::spim::Spim; pub use crate::timer::Timer; pub use crate::twim::Twim; -pub use crate::uarte::Uarte; +pub use crate::uarte::{DMAPool, RXError, TXQSize, Uarte, UarteRX, UarteTX, DMA_SIZE}; From 4fcd3bfe503c008e0b5f204f3ec8b9450e70e315 Mon Sep 17 00:00:00 2001 From: Per Date: Fri, 3 May 2019 12:37:53 +0200 Subject: [PATCH 03/44] transmit queue generic over size S --- nrf52-hal-common/src/lib.rs | 5 ++-- nrf52-hal-common/src/uarte.rs | 49 +++++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/nrf52-hal-common/src/lib.rs b/nrf52-hal-common/src/lib.rs index a490bb51..ca8f1a9a 100644 --- a/nrf52-hal-common/src/lib.rs +++ b/nrf52-hal-common/src/lib.rs @@ -58,7 +58,8 @@ pub mod target_constants { /// Does this slice reside entirely within RAM? pub(crate) fn slice_in_ram(slice: &[u8]) -> bool { let ptr = slice.as_ptr() as usize; - ptr >= target_constants::SRAM_LOWER && (ptr + slice.len()) < target_constants::SRAM_UPPER + ptr >= target_constants::SRAM_LOWER + && (ptr + slice.len()) < target_constants::SRAM_UPPER } /// A handy structure for converting rust slices into ptr and len pairs @@ -91,4 +92,4 @@ pub use crate::saadc::Saadc; pub use crate::spim::Spim; pub use crate::timer::Timer; pub use crate::twim::Twim; -pub use crate::uarte::{DMAPool, RXError, TXQSize, Uarte, UarteRX, UarteTX, DMA_SIZE}; +pub use crate::uarte::{DMAPool, RXError, Uarte, UarteRX, UarteTX, DMA_SIZE}; diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 8071b1f5..d2513a21 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -30,10 +30,13 @@ use heapless::{ pool, pool::singleton::{Box, Pool}, spsc::{Consumer, Queue}, + ArrayLength, }; // Re-export SVD variants to allow user to directly set values -pub use crate::target::uarte0::{baudrate::BAUDRATEW as Baudrate, config::PARITYW as Parity}; +pub use crate::target::uarte0::{ + baudrate::BAUDRATEW as Baudrate, config::PARITYW as Parity, +}; /// Interface to a UARTE instance /// @@ -49,7 +52,12 @@ impl Uarte where T: Instance, { - pub fn new(uarte: T, mut pins: Pins, parity: Parity, baudrate: Baudrate) -> Self { + pub fn new( + uarte: T, + mut pins: Pins, + parity: Parity, + baudrate: Baudrate, + ) -> Self { // Select pins uarte.psel.rxd.write(|w| { let w = unsafe { w.pin().bits(pins.rxd.pin) }; @@ -93,9 +101,9 @@ where // Configure let hardware_flow_control = pins.rts.is_some() && pins.cts.is_some(); - uarte - .config - .write(|w| w.hwfc().bit(hardware_flow_control).parity().variant(parity)); + uarte.config.write(|w| { + w.hwfc().bit(hardware_flow_control).parity().variant(parity) + }); // Configure frequency uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); @@ -346,17 +354,20 @@ where /// /// Note: The act of splitting might not be needed on the nRF52 chips, as they map to the same /// interrupt in the end. Kept as a split for now, but might be merged in the future. - pub fn split( + pub fn split( self, rxq: Queue, U2>, - txc: Consumer<'static, Box, TXQSize>, - ) -> (UarteRX, UarteTX) { + txc: Consumer<'static, Box, S>, + ) -> (UarteRX, UarteTX) + where + S: ArrayLength>, + { let mut rx = UarteRX::::new(rxq); rx.enable_interrupts(); rx.prepare_read().unwrap(); rx.start_read(); - let tx = UarteTX::::new(txc); + let tx = UarteTX::::new(txc); tx.enable_interrupts(); (rx, tx) } @@ -453,7 +464,9 @@ where /// 1. `Ok(Some(Box))` if data was received /// 2. `Ok(None)` if there was no data, i.e. UARTE interrupt was due to other events /// 3. `Err(RXError::OOM)` if the memory pool was depleted, see `RXError` for mitigations - pub fn process_interrupt(&mut self) -> Result>, RXError> { + pub fn process_interrupt( + &mut self, + ) -> Result>, RXError> { // This operation is safe due to type-state programming guaranteeing that the RX and TX are // unique within the driver let uarte = unsafe { &*T::ptr() }; @@ -487,22 +500,24 @@ where } } -/// A transmit queue size of 4 `DMAPool` chunks for now -pub type TXQSize = U4; - /// UARTE TX part, used in interrupt driven contexts -pub struct UarteTX { - txc: Consumer<'static, Box, TXQSize>, // chunks to transmit +/// S is the queue length, can be U3, U4 etc. +pub struct UarteTX +where + S: ArrayLength>, +{ + txc: Consumer<'static, Box, S>, // chunks to transmit current: Option>, _marker: core::marker::PhantomData, } -impl UarteTX +impl UarteTX where T: Instance, + S: ArrayLength>, { /// Construct new UARTE TX, hidden from users - used internally - fn new(txc: Consumer<'static, Box, TXQSize>) -> Self { + fn new(txc: Consumer<'static, Box, S>) -> Self { Self { txc, current: None, From 42e20395f6c5f117b37621164af1de980117ff1f Mon Sep 17 00:00:00 2001 From: Per Lindgren Date: Sun, 5 May 2019 01:22:11 +0200 Subject: [PATCH 04/44] DMA_SIZE now parametrised --- nrf52-hal-common/Cargo.toml | 8 +++++ nrf52-hal-common/src/uarte.rs | 68 +++++++++++++++++++++++++++-------- nrf52810-hal/Cargo.toml | 13 ++++++- nrf52832-hal/Cargo.toml | 13 +++++-- nrf52840-hal/Cargo.toml | 12 ++++++- 5 files changed, 95 insertions(+), 19 deletions(-) diff --git a/nrf52-hal-common/Cargo.toml b/nrf52-hal-common/Cargo.toml index 23e449e7..faa83502 100644 --- a/nrf52-hal-common/Cargo.toml +++ b/nrf52-hal-common/Cargo.toml @@ -62,3 +62,11 @@ default = ["52832"] 52832 = ["nrf52832-pac"] 52840 = ["nrf52840-pac"] 9160 = ["nrf9160-pac"] +POOL = [] +DMA_SIZE_4 = [] +DMA_SIZE_8 = [] +DMA_SIZE_16 = [] +DMA_SIZE_32 = [] +DMA_SIZE_64 = [] +DMA_SIZE_128 = [] +DMA_SIZE_256 = [] diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index d2513a21..38fed3e6 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -34,9 +34,7 @@ use heapless::{ }; // Re-export SVD variants to allow user to directly set values -pub use crate::target::uarte0::{ - baudrate::BAUDRATEW as Baudrate, config::PARITYW as Parity, -}; +pub use crate::target::uarte0::{baudrate::BAUDRATEW as Baudrate, config::PARITYW as Parity}; /// Interface to a UARTE instance /// @@ -52,12 +50,7 @@ impl Uarte where T: Instance, { - pub fn new( - uarte: T, - mut pins: Pins, - parity: Parity, - baudrate: Baudrate, - ) -> Self { + pub fn new(uarte: T, mut pins: Pins, parity: Parity, baudrate: Baudrate) -> Self { // Select pins uarte.psel.rxd.write(|w| { let w = unsafe { w.pin().bits(pins.rxd.pin) }; @@ -101,9 +94,9 @@ where // Configure let hardware_flow_control = pins.rts.is_some() && pins.cts.is_some(); - uarte.config.write(|w| { - w.hwfc().bit(hardware_flow_control).parity().variant(parity) - }); + uarte + .config + .write(|w| w.hwfc().bit(hardware_flow_control).parity().variant(parity)); // Configure frequency uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); @@ -374,7 +367,54 @@ where } /// DMA block size +/// Defaults to DMA_SIZE = 16 if not explicitly set +#[cfg(not(any( + feature = "DMA_SIZE_4", + feature = "DMA_SIZE_8", + feature = "DMA_SIZE_16", + feature = "DMA_SIZE_32", + feature = "DMA_SIZE_64", + feature = "DMA_SIZE_128", + feature = "DMA_SIZE_256" +)))] +pub const DMA_SIZE: usize = 16; + +#[cfg(feature = "DMA_SIZE_4")] +pub const DMA_SIZE: usize = 4; + +#[cfg(feature = "DMA_SIZE_8")] +pub const DMA_SIZE: usize = 8; + +#[cfg(feature = "DMA_SIZE_16")] pub const DMA_SIZE: usize = 16; + +#[cfg(feature = "DMA_SIZE_32")] +pub const DMA_SIZE: usize = 32; + +#[cfg(feature = "DMA_SIZE_64")] +pub const DMA_SIZE: usize = 64; + +#[cfg(feature = "DMA_SIZE_128")] +pub const DMA_SIZE: usize = 128; + +// Currently causes internal OOM, needs fixing +#[cfg(feature = "DMA_SIZE_256")] +pub const DMA_SIZE: usize = 256; + +// An alternative solution to the above is to define the DMA_SIZE +// in a separate (default) crate, which can be overridden +// by a patch in the user Cargo.toml, pointing to +// a local crate with the user defined DMA_SIZE constant. +// What would you prefer? + +// The DMA implementation shuld be hidden behind a feature POOL +// This likely requires a mod {} around the related code +// or the non-ergonomic repetition of the gate. +// Is there a better solution? +// +// The reason to have a POOL gate is that we don't want the POOL +// to cause memory OH if not used by the application + pool!(DMAPool: [u8; DMA_SIZE]); /// UARTE RX part, used in interrupt driven contexts @@ -464,9 +504,7 @@ where /// 1. `Ok(Some(Box))` if data was received /// 2. `Ok(None)` if there was no data, i.e. UARTE interrupt was due to other events /// 3. `Err(RXError::OOM)` if the memory pool was depleted, see `RXError` for mitigations - pub fn process_interrupt( - &mut self, - ) -> Result>, RXError> { + pub fn process_interrupt(&mut self) -> Result>, RXError> { // This operation is safe due to type-state programming guaranteeing that the RX and TX are // unique within the driver let uarte = unsafe { &*T::ptr() }; diff --git a/nrf52810-hal/Cargo.toml b/nrf52810-hal/Cargo.toml index 67ca9e9f..405acf45 100644 --- a/nrf52810-hal/Cargo.toml +++ b/nrf52810-hal/Cargo.toml @@ -41,4 +41,15 @@ version = "0.2.1" [features] doc = [] rt = ["nrf52810-pac/rt"] -default = ["rt"] +default = ["rt", "POOL"] +POOL = ["nrf52-hal-common/POOL"] +DMA_SIZE_4 = ["nrf52-hal-common/DMA_SIZE_4"] +DMA_SIZE_8 = ["nrf52-hal-common/DMA_SIZE_8"] +DMA_SIZE_16 = ["nrf52-hal-common/DMA_SIZE_16"] +DMA_SIZE_32 = ["nrf52-hal-common/DMA_SIZE_32"] +DMA_SIZE_64 = ["nrf52-hal-common/DMA_SIZE_64"] +DMA_SIZE_128 = ["nrf52-hal-common/DMA_SIZE_128"] +DMA_SIZE_256 = ["nrf52-hal-common/DMA_SIZE_256"] + + + diff --git a/nrf52832-hal/Cargo.toml b/nrf52832-hal/Cargo.toml index ea141117..78d21f5f 100644 --- a/nrf52832-hal/Cargo.toml +++ b/nrf52832-hal/Cargo.toml @@ -42,8 +42,17 @@ doc = [] rt = ["nrf52832-pac/rt"] xxAA-package = [] xxAB-package = [] +POOL = ["nrf52-hal-common/POOL"] +DMA_SIZE_4 = ["nrf52-hal-common/DMA_SIZE_4"] +DMA_SIZE_8 = ["nrf52-hal-common/DMA_SIZE_8"] +DMA_SIZE_16 = ["nrf52-hal-common/DMA_SIZE_16"] +DMA_SIZE_32 = ["nrf52-hal-common/DMA_SIZE_32"] +DMA_SIZE_64 = ["nrf52-hal-common/DMA_SIZE_64"] +DMA_SIZE_128 = ["nrf52-hal-common/DMA_SIZE_128"] +DMA_SIZE_256 = ["nrf52-hal-common/DMA_SIZE_256"] + # Note: We use the xxAB package because it has the least amount of available resources. # However, most users will want to use the xxAA package. -default = ["rt", "xxAB-package"] - +# If disabling default features, "POOL" and "DMA_SIZE_XX" should be manually set. +default = ["rt", "xxAB-package", "POOL"] diff --git a/nrf52840-hal/Cargo.toml b/nrf52840-hal/Cargo.toml index b22a03d9..bb9486c7 100644 --- a/nrf52840-hal/Cargo.toml +++ b/nrf52840-hal/Cargo.toml @@ -42,5 +42,15 @@ version = "0.2.1" [features] doc = [] rt = ["nrf52840-pac/rt"] -default = ["rt"] +default = ["rt", "POOL"] +POOL = ["nrf52-hal-common/POOL"] +DMA_SIZE_4 = ["nrf52-hal-common/DMA_SIZE_4"] +DMA_SIZE_8 = ["nrf52-hal-common/DMA_SIZE_8"] +DMA_SIZE_16 = ["nrf52-hal-common/DMA_SIZE_16"] +DMA_SIZE_32 = ["nrf52-hal-common/DMA_SIZE_32"] +DMA_SIZE_64 = ["nrf52-hal-common/DMA_SIZE_64"] +DMA_SIZE_128 = ["nrf52-hal-common/DMA_SIZE_128"] +DMA_SIZE_256 = ["nrf52-hal-common/DMA_SIZE_256"] + + From c64c41df863c03c76497ae57cf588cc906094fa0 Mon Sep 17 00:00:00 2001 From: Jacob Rosenthal Date: Mon, 15 Jul 2019 16:11:42 -0700 Subject: [PATCH 05/44] uarte interrupt example from https://github.com/korken89/rtfm_workshop/blob/7a153023d4c7923e058126ae6bd12f9ce7639098/examples/pool.rs --- Cargo.toml | 1 + examples/rtfm-demo/Cargo.toml | 2 +- examples/rtfm-uarte-interrupts/.gdbinit | 10 ++ examples/rtfm-uarte-interrupts/Cargo.toml | 33 ++++++ examples/rtfm-uarte-interrupts/src/main.rs | 114 +++++++++++++++++++++ nrf52-hal-common/Cargo.toml | 3 +- 6 files changed, 160 insertions(+), 3 deletions(-) create mode 100644 examples/rtfm-uarte-interrupts/.gdbinit create mode 100644 examples/rtfm-uarte-interrupts/Cargo.toml create mode 100644 examples/rtfm-uarte-interrupts/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index e6c2c980..64936b4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "nrf52840-hal", "nrf9160-hal", "examples/rtfm-demo", + "examples/rtfm-uarte-interrupts", "examples/spi-demo", "examples/twi-ssd1306", ] diff --git a/examples/rtfm-demo/Cargo.toml b/examples/rtfm-demo/Cargo.toml index 4d4ce3da..35120e35 100644 --- a/examples/rtfm-demo/Cargo.toml +++ b/examples/rtfm-demo/Cargo.toml @@ -5,7 +5,7 @@ authors = ["James Munns "] edition = "2018" [dependencies] -cortex-m-rtfm = "0.4.3" +cortex-m-rtfm = { git = "https://github.com/japaric/cortex-m-rtfm.git"} panic-semihosting = "0.5.1" cortex-m-semihosting = "0.3.3" diff --git a/examples/rtfm-uarte-interrupts/.gdbinit b/examples/rtfm-uarte-interrupts/.gdbinit new file mode 100644 index 00000000..ec068055 --- /dev/null +++ b/examples/rtfm-uarte-interrupts/.gdbinit @@ -0,0 +1,10 @@ +set remotetimeout 60000 +target remote :2331 +set arm force-mode thumb + +# Uncomment to enable semihosting, when necessary +monitor semihosting enable + +layout split +monitor reset +load diff --git a/examples/rtfm-uarte-interrupts/Cargo.toml b/examples/rtfm-uarte-interrupts/Cargo.toml new file mode 100644 index 00000000..749c102e --- /dev/null +++ b/examples/rtfm-uarte-interrupts/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "rtfm-uarte-interrupts" +version = "0.1.0" +authors = ["James Munns "] +edition = "2018" + +[dependencies] +cortex-m-rtfm = { git = "https://github.com/japaric/cortex-m-rtfm.git"} +panic-semihosting = "0.5.1" +cortex-m-semihosting = "0.3.3" +heapless = ">= 0.5.0" + +[dependencies.nrf52810-hal] +version = "0.8.0" +path = "../../nrf52810-hal" +optional = true + +[dependencies.nrf52832-hal] +version = "0.8.0" +path = "../../nrf52832-hal" +optional = true +features = ["rt", "xxAB-package", "POOL"] + +[dependencies.nrf52840-hal] +version = "0.8.0" +path = "../../nrf52840-hal" +optional = true + +[features] +52810 = ["nrf52810-hal"] +52832 = ["nrf52832-hal"] +52840 = ["nrf52840-hal"] +default = ["52832"] diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs new file mode 100644 index 00000000..4be0da62 --- /dev/null +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -0,0 +1,114 @@ +#![no_main] +#![no_std] + +// panic handler +extern crate panic_semihosting; + +use cortex_m_semihosting::hprintln; + +use nrf52832_hal as hal; + +use hal::gpio::{p0, Level}; +use hal::target::{interrupt, UARTE0}; +use hal::{uarte, Uarte}; +use hal::{DMAPool, RXError, UarteRX, UarteTX, DMA_SIZE}; + +use heapless::{ + consts::U4, + pool::singleton::Box, + pool::singleton::Pool, + spsc::{Producer, Queue}, +}; + +use rtfm::app; + +const NR_PACKAGES: usize = 10; +const DMA_MEM: usize = DMA_SIZE * NR_PACKAGES + 16; + +//not sure about U4 +type TXQSize = U4; + +#[app(device = crate::hal::target)] +const APP: () = { + static mut RX: UarteRX = (); + //not sure about u4 + static mut TX: UarteTX = (); + static mut PRODUCER: Producer<'static, Box, TXQSize> = (); + + #[init(spawn = [])] + fn init(c: init::Context) -> init::LateResources { + // for the actual DMA buffers + static mut MEMORY: [u8; DMA_MEM] = [0; DMA_MEM]; + // for the producer/consumer of TX + static mut TX_RB: Option, TXQSize>> = None; + + hprintln!("init").unwrap(); + // move MEMORY to P (the DMA buffer allocator) + DMAPool::grow(MEMORY); + + let port0 = p0::Parts::new(c.device.P0); + + let uarte0 = Uarte::new( + c.device.UARTE0, + uarte::Pins { + txd: port0.p0_06.into_push_pull_output(Level::High).degrade(), + rxd: port0.p0_08.into_floating_input().degrade(), + cts: None, + rts: None, + }, + uarte::Parity::EXCLUDED, + uarte::Baudrate::BAUD115200, + ); + + *TX_RB = Some(Queue::new()); + let (txp, txc) = TX_RB.as_mut().unwrap().split(); + let (rx, tx) = uarte0.split(Queue::new(), txc); + + init::LateResources { + RX: rx, + TX: tx, + PRODUCER: txp, + } + } + + // // we can get Box

us being now the owner + #[task(capacity = 2, resources = [PRODUCER])] + fn printer(c: printer::Context, data: Box) { + // enqueue a test message + // let mut b = DMAPool::alloc().unwrap().freeze(); + // b.copy_from_slice(&[0, 1, 2, 3]); + + // hprintln!("{:?}", &data).unwrap(); + // just do the buffer dance without copying + c.resources.PRODUCER.enqueue(data).unwrap(); + rtfm::pend(interrupt::UARTE0_UART0); + } + + #[task] + fn rx_error(_: rx_error::Context, err: RXError) { + hprintln!("rx_error {:?}", err).unwrap(); + } + + #[interrupt(priority = 2, resources = [RX, TX], spawn = [printer, rx_error])] + fn UARTE0_UART0(c: UARTE0_UART0::Context) { + // probe RX + match c.resources.RX.process_interrupt() { + Ok(Some(b)) => { + // delegate data to printer + match c.spawn.printer(b) { + Err(_) => c.spawn.rx_error(RXError::OOM).unwrap(), + _ => (), + }; + } + Ok(None) => (), // no + Err(err) => c.spawn.rx_error(err).unwrap(), + } + + c.resources.TX.process_interrupt(); + } + + extern "C" { + fn SWI1_EGU1(); + fn SWI2_EGU2(); + } +}; diff --git a/nrf52-hal-common/Cargo.toml b/nrf52-hal-common/Cargo.toml index faa83502..494d6ead 100644 --- a/nrf52-hal-common/Cargo.toml +++ b/nrf52-hal-common/Cargo.toml @@ -23,8 +23,7 @@ fpa = "0.1.0" rand_core = "0.4.0" [dependencies.heapless] -version = "0.4.4" -features = ["min-const-fn"] +version = "0.5.0" [dependencies.void] default-features = false From afda33b5ad71eb43a6435b1efe9714159ba574a4 Mon Sep 17 00:00:00 2001 From: Jacob Rosenthal Date: Tue, 16 Jul 2019 12:30:18 -0700 Subject: [PATCH 06/44] add missing .cargo for rtfm-uarte-interrupts example --- examples/rtfm-uarte-interrupts/.cargo/config | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 examples/rtfm-uarte-interrupts/.cargo/config diff --git a/examples/rtfm-uarte-interrupts/.cargo/config b/examples/rtfm-uarte-interrupts/.cargo/config new file mode 100644 index 00000000..90b5200a --- /dev/null +++ b/examples/rtfm-uarte-interrupts/.cargo/config @@ -0,0 +1,2 @@ +[target.thumbv7em-none-eabihf] +runner = "arm-none-eabi-gdb -tui" From ccc77d6c824370c38d48b11b6128c9388a65cb44 Mon Sep 17 00:00:00 2001 From: Jacob Rosenthal Date: Tue, 30 Jul 2019 19:00:10 -0700 Subject: [PATCH 07/44] default build target --- examples/rtfm-uarte-interrupts/.cargo/config | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/rtfm-uarte-interrupts/.cargo/config b/examples/rtfm-uarte-interrupts/.cargo/config index 90b5200a..64e3ce85 100644 --- a/examples/rtfm-uarte-interrupts/.cargo/config +++ b/examples/rtfm-uarte-interrupts/.cargo/config @@ -1,2 +1,5 @@ [target.thumbv7em-none-eabihf] runner = "arm-none-eabi-gdb -tui" + +[build] +target = "thumbv7em-none-eabihf" From 3eb1cae302547e566d5380e4ee116757bf3c81ad Mon Sep 17 00:00:00 2001 From: Jacob Rosenthal Date: Sat, 3 Aug 2019 22:06:36 -0700 Subject: [PATCH 08/44] fix to original example --- examples/rtfm-uarte-interrupts/src/main.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index 4be0da62..b7cc9278 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -14,7 +14,7 @@ use hal::{uarte, Uarte}; use hal::{DMAPool, RXError, UarteRX, UarteTX, DMA_SIZE}; use heapless::{ - consts::U4, + consts::U3, pool::singleton::Box, pool::singleton::Pool, spsc::{Producer, Queue}, @@ -25,14 +25,12 @@ use rtfm::app; const NR_PACKAGES: usize = 10; const DMA_MEM: usize = DMA_SIZE * NR_PACKAGES + 16; -//not sure about U4 -type TXQSize = U4; +type TXQSize = U3; #[app(device = crate::hal::target)] const APP: () = { static mut RX: UarteRX = (); - //not sure about u4 - static mut TX: UarteTX = (); + static mut TX: UarteTX = (); static mut PRODUCER: Producer<'static, Box, TXQSize> = (); #[init(spawn = [])] @@ -48,6 +46,7 @@ const APP: () = { let port0 = p0::Parts::new(c.device.P0); + //adafruit nrf52 le let uarte0 = Uarte::new( c.device.UARTE0, uarte::Pins { From 65f56b2ceb80aa20cbf1bb8ba0ad3b788e8dfbaf Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Wed, 7 Aug 2019 15:52:08 +0200 Subject: [PATCH 09/44] Use release RTFM version --- examples/rtfm-demo/Cargo.toml | 2 +- examples/rtfm-uarte-interrupts/Cargo.toml | 2 +- examples/rtfm-uarte-interrupts/src/main.rs | 29 +++++++++++----------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/examples/rtfm-demo/Cargo.toml b/examples/rtfm-demo/Cargo.toml index 35120e35..269d5204 100644 --- a/examples/rtfm-demo/Cargo.toml +++ b/examples/rtfm-demo/Cargo.toml @@ -5,7 +5,7 @@ authors = ["James Munns "] edition = "2018" [dependencies] -cortex-m-rtfm = { git = "https://github.com/japaric/cortex-m-rtfm.git"} +cortex-m-rtfm = "0.4" panic-semihosting = "0.5.1" cortex-m-semihosting = "0.3.3" diff --git a/examples/rtfm-uarte-interrupts/Cargo.toml b/examples/rtfm-uarte-interrupts/Cargo.toml index 749c102e..00d6132d 100644 --- a/examples/rtfm-uarte-interrupts/Cargo.toml +++ b/examples/rtfm-uarte-interrupts/Cargo.toml @@ -5,7 +5,7 @@ authors = ["James Munns "] edition = "2018" [dependencies] -cortex-m-rtfm = { git = "https://github.com/japaric/cortex-m-rtfm.git"} +cortex-m-rtfm = "0.4" panic-semihosting = "0.5.1" cortex-m-semihosting = "0.3.3" heapless = ">= 0.5.0" diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index b7cc9278..eb1f0175 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -34,21 +34,21 @@ const APP: () = { static mut PRODUCER: Producer<'static, Box, TXQSize> = (); #[init(spawn = [])] - fn init(c: init::Context) -> init::LateResources { + fn init() -> init::LateResources { // for the actual DMA buffers static mut MEMORY: [u8; DMA_MEM] = [0; DMA_MEM]; // for the producer/consumer of TX - static mut TX_RB: Option, TXQSize>> = None; + static mut TX_RB: Queue, TXQSize> = Queue(heapless::i::Queue::new()); hprintln!("init").unwrap(); // move MEMORY to P (the DMA buffer allocator) DMAPool::grow(MEMORY); - let port0 = p0::Parts::new(c.device.P0); + let port0 = p0::Parts::new(device.P0); //adafruit nrf52 le let uarte0 = Uarte::new( - c.device.UARTE0, + device.UARTE0, uarte::Pins { txd: port0.p0_06.into_push_pull_output(Level::High).degrade(), rxd: port0.p0_08.into_floating_input().degrade(), @@ -59,8 +59,7 @@ const APP: () = { uarte::Baudrate::BAUD115200, ); - *TX_RB = Some(Queue::new()); - let (txp, txc) = TX_RB.as_mut().unwrap().split(); + let (txp, txc) = TX_RB.split(); let (rx, tx) = uarte0.split(Queue::new(), txc); init::LateResources { @@ -72,38 +71,38 @@ const APP: () = { // // we can get Box

us being now the owner #[task(capacity = 2, resources = [PRODUCER])] - fn printer(c: printer::Context, data: Box) { + fn printer(data: Box) { // enqueue a test message // let mut b = DMAPool::alloc().unwrap().freeze(); // b.copy_from_slice(&[0, 1, 2, 3]); // hprintln!("{:?}", &data).unwrap(); // just do the buffer dance without copying - c.resources.PRODUCER.enqueue(data).unwrap(); + resources.PRODUCER.enqueue(data).unwrap(); rtfm::pend(interrupt::UARTE0_UART0); } #[task] - fn rx_error(_: rx_error::Context, err: RXError) { + fn rx_error(err: RXError) { hprintln!("rx_error {:?}", err).unwrap(); } #[interrupt(priority = 2, resources = [RX, TX], spawn = [printer, rx_error])] - fn UARTE0_UART0(c: UARTE0_UART0::Context) { + fn UARTE0_UART0() { // probe RX - match c.resources.RX.process_interrupt() { + match resources.RX.process_interrupt() { Ok(Some(b)) => { // delegate data to printer - match c.spawn.printer(b) { - Err(_) => c.spawn.rx_error(RXError::OOM).unwrap(), + match spawn.printer(b) { + Err(_) => spawn.rx_error(RXError::OOM).unwrap(), _ => (), }; } Ok(None) => (), // no - Err(err) => c.spawn.rx_error(err).unwrap(), + Err(err) => spawn.rx_error(err).unwrap(), } - c.resources.TX.process_interrupt(); + resources.TX.process_interrupt(); } extern "C" { From 9e21101e89c331db395b5d1f9d825c317e2fac60 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Wed, 7 Aug 2019 16:02:57 +0200 Subject: [PATCH 10/44] Added plumbing for timeout Timer in UARTE Added same ptr extension to Timers Instance as we have on UARTE --- examples/rtfm-uarte-interrupts/src/main.rs | 8 +++++--- nrf52-hal-common/src/timer.rs | 7 +++++-- nrf52-hal-common/src/uarte.rs | 24 ++++++++++++++++------ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index eb1f0175..35c33adb 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -9,7 +9,8 @@ use cortex_m_semihosting::hprintln; use nrf52832_hal as hal; use hal::gpio::{p0, Level}; -use hal::target::{interrupt, UARTE0}; +use hal::target::{interrupt, TIMER0, UARTE0}; +use hal::timer::*; use hal::{uarte, Uarte}; use hal::{DMAPool, RXError, UarteRX, UarteTX, DMA_SIZE}; @@ -29,7 +30,7 @@ type TXQSize = U3; #[app(device = crate::hal::target)] const APP: () = { - static mut RX: UarteRX = (); + static mut RX: UarteRX = (); static mut TX: UarteTX = (); static mut PRODUCER: Producer<'static, Box, TXQSize> = (); @@ -59,8 +60,9 @@ const APP: () = { uarte::Baudrate::BAUD115200, ); + let timer = Timer::new(device.TIMER0); let (txp, txc) = TX_RB.split(); - let (rx, tx) = uarte0.split(Queue::new(), txc); + let (rx, tx) = uarte0.split(Queue::new(), txc, timer); init::LateResources { RX: rx, diff --git a/nrf52-hal-common/src/timer.rs b/nrf52-hal-common/src/timer.rs index 6f8dc1ef..280200aa 100644 --- a/nrf52-hal-common/src/timer.rs +++ b/nrf52-hal-common/src/timer.rs @@ -17,7 +17,6 @@ use void::{unreachable, Void}; #[cfg(any(feature = "52832", feature = "52840"))] use crate::target::{TIMER3, TIMER4}; - /// Interface to a TIMER instance /// /// Right now, this is a very basic interface. The timer will always be @@ -178,11 +177,11 @@ where } } - /// Implemented by all `TIMER` instances pub trait Instance: Deref { /// This interrupt associated with this RTC instance const INTERRUPT: Interrupt; + fn ptr() -> *const timer0::RegisterBlock; } macro_rules! impl_instance { @@ -190,6 +189,10 @@ macro_rules! impl_instance { $( impl Instance for $name { const INTERRUPT: Interrupt = Interrupt::$name; + + fn ptr() -> *const timer0::RegisterBlock { + $name::ptr() + } } )* } diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 38fed3e6..28a5c394 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -347,15 +347,24 @@ where /// /// Note: The act of splitting might not be needed on the nRF52 chips, as they map to the same /// interrupt in the end. Kept as a split for now, but might be merged in the future. - pub fn split( + pub fn split( self, rxq: Queue, U2>, txc: Consumer<'static, Box, S>, - ) -> (UarteRX, UarteTX) + timer: Timer, + ) -> (UarteRX, UarteTX) where S: ArrayLength>, + I: timer::Instance, { - let mut rx = UarteRX::::new(rxq); + // This operation is safe due to type-state programming guaranteeing that the Timer is + // unique within the driver + let timer_reg = unsafe { &*I::ptr() }; + + // Enable COMPARE0 interrupt + timer_reg.intenset.modify(|_, w| w.compare0().set()); + + let mut rx = UarteRX::::new(rxq, timer); rx.enable_interrupts(); rx.prepare_read().unwrap(); rx.start_read(); @@ -418,8 +427,9 @@ pub const DMA_SIZE: usize = 256; pool!(DMAPool: [u8; DMA_SIZE]); /// UARTE RX part, used in interrupt driven contexts -pub struct UarteRX { +pub struct UarteRX { rxq: Queue, U2>, // double buffering of DMA chunks + timer: Timer, // Timer for handling timeouts _marker: core::marker::PhantomData, } @@ -435,14 +445,16 @@ pub enum RXError { OOM, } -impl UarteRX +impl UarteRX where T: Instance, + I: timer::Instance, { /// Construct new UARTE RX, hidden from users - used internally - fn new(rxq: Queue, U2>) -> Self { + fn new(rxq: Queue, U2>, timer: Timer) -> Self { Self { rxq, + timer, _marker: core::marker::PhantomData, } } From 552035a4e3a15a8ac6a55944a855dbc937b60608 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Wed, 7 Aug 2019 16:40:49 +0200 Subject: [PATCH 11/44] Fixed so there is an extra way to enable the timers interrupts No need for the ptr trickery --- examples/rtfm-uarte-interrupts/src/main.rs | 2 +- nrf52-hal-common/src/timer.rs | 16 +++++++++++----- nrf52-hal-common/src/uarte.rs | 7 ++++--- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index 35c33adb..d5eb26d6 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -60,7 +60,7 @@ const APP: () = { uarte::Baudrate::BAUD115200, ); - let timer = Timer::new(device.TIMER0); + let mut timer = Timer::new(device.TIMER0); let (txp, txc) = TX_RB.split(); let (rx, tx) = uarte0.split(Queue::new(), txc, timer); diff --git a/nrf52-hal-common/src/timer.rs b/nrf52-hal-common/src/timer.rs index 280200aa..146800d5 100644 --- a/nrf52-hal-common/src/timer.rs +++ b/nrf52-hal-common/src/timer.rs @@ -55,6 +55,17 @@ where self.0.cc[1].read().bits() } + /// Enables the interrupt for this timer, external NVIC modification + /// + /// Enables an interrupt that is fired when the timer reaches the value that + /// is given as an argument to `start`. + pub(crate) fn enable_interrupt_generation(&mut self) { + // As of this writing, the timer code only uses + // `cc[0]`/`events_compare[0]`. If the code is extended to use other + // compare registers, the following needs to be adapted. + self.0.intenset.modify(|_, w| w.compare0().set()); + } + /// Enables the interrupt for this timer /// /// Enables an interrupt that is fired when the timer reaches the value that @@ -181,7 +192,6 @@ where pub trait Instance: Deref { /// This interrupt associated with this RTC instance const INTERRUPT: Interrupt; - fn ptr() -> *const timer0::RegisterBlock; } macro_rules! impl_instance { @@ -189,10 +199,6 @@ macro_rules! impl_instance { $( impl Instance for $name { const INTERRUPT: Interrupt = Interrupt::$name; - - fn ptr() -> *const timer0::RegisterBlock { - $name::ptr() - } } )* } diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 28a5c394..d8de8c80 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -351,7 +351,7 @@ where self, rxq: Queue, U2>, txc: Consumer<'static, Box, S>, - timer: Timer, + mut timer: Timer, ) -> (UarteRX, UarteTX) where S: ArrayLength>, @@ -359,10 +359,11 @@ where { // This operation is safe due to type-state programming guaranteeing that the Timer is // unique within the driver - let timer_reg = unsafe { &*I::ptr() }; + //let timer_reg = unsafe { &*I::ptr() }; // Enable COMPARE0 interrupt - timer_reg.intenset.modify(|_, w| w.compare0().set()); + //timer_reg.intenset.modify(|_, w| w.compare0().set()); + timer.enable_interrupt_generation(); let mut rx = UarteRX::::new(rxq, timer); rx.enable_interrupts(); From ad0d255bd074f2f56566a8143693def51ecea655 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Wed, 7 Aug 2019 17:04:02 +0200 Subject: [PATCH 12/44] Timeout almost done, need to handle non full packets being read --- examples/rtfm-uarte-interrupts/src/main.rs | 2 +- nrf52-hal-common/src/timer.rs | 13 ++++++ nrf52-hal-common/src/uarte.rs | 52 ++++++++++++++++++++-- 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index d5eb26d6..35c33adb 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -60,7 +60,7 @@ const APP: () = { uarte::Baudrate::BAUD115200, ); - let mut timer = Timer::new(device.TIMER0); + let timer = Timer::new(device.TIMER0); let (txp, txc) = TX_RB.split(); let (rx, tx) = uarte0.split(Queue::new(), txc, timer); diff --git a/nrf52-hal-common/src/timer.rs b/nrf52-hal-common/src/timer.rs index 146800d5..12ba8d98 100644 --- a/nrf52-hal-common/src/timer.rs +++ b/nrf52-hal-common/src/timer.rs @@ -66,6 +66,19 @@ where self.0.intenset.modify(|_, w| w.compare0().set()); } + /// Clears the interrupt for this timer, external NVIC modification + /// + /// Enables an interrupt that is fired when the timer reaches the value that + /// is given as an argument to `start`. + pub(crate) fn clear_interrupt(&mut self) { + // As of this writing, the timer code only uses + // `cc[0]`/`events_compare[0]`. If the code is extended to use other + // compare registers, the following needs to be adapted. + + // Reset the event, otherwise it will always read `1` from now on. + self.0.events_compare[0].write(|w| w); + } + /// Enables the interrupt for this timer /// /// Enables an interrupt that is fired when the timer reaches the value that diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index d8de8c80..ab921430 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -24,7 +24,10 @@ use crate::target::{ use crate::gpio::{Floating, Input, Output, Pin, PushPull}; use crate::prelude::*; use crate::target_constants::EASY_DMA_SIZE; + use crate::timer::{self, Timer}; +use embedded_hal::timer::{Cancel, CountDown}; + use heapless::{ consts::*, pool, @@ -466,9 +469,16 @@ where // unique within the driver let uarte = unsafe { &*T::ptr() }; - uarte - .inten - .modify(|_, w| w.endrx().set_bit().rxstarted().set_bit()); + uarte.inten.modify(|_, w| { + w.endrx() + .set_bit() + .rxstarted() + .set_bit() + .rxto() + .set_bit() + .rxdrdy() + .set_bit() + }); } /// Start a UARTE read transaction @@ -510,6 +520,21 @@ where } } + /// Timeout handling for the RX driver - Must be called from the corresponding TIMERx Interrupt + /// handler/task. + pub fn process_timeout(&mut self) { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; + + self.timer.clear_interrupt(); + + // Stop UARTE Receive transaction to generate the Timeout Event + uarte.tasks_stoprx.write(|w| + // `1` is a valid value to write to task registers. + unsafe { w.bits(1) }); + } + /// Main entry point for the RX driver - Must be called from the corresponding UARTE Interrupt /// handler/task. /// @@ -522,6 +547,22 @@ where // unique within the driver let uarte = unsafe { &*T::ptr() }; + if uarte.events_rxdrdy.read().bits() == 1 { + self.timer.cancel().unwrap(); // Never fails + self.timer.start(1000_u32); // 1 ms for now + + // Reset the event, otherwise it will always read `1` from now on. + uarte.events_rxdrdy.write(|w| w); + } + + if uarte.events_rxto.read().bits() == 1 { + // Ask UART to flush FIFO to DMA buffer + uarte.tasks_flushrx.write(|w| unsafe { w.bits(1) }); + + // Reset the event, otherwise it will always read `1` from now on. + uarte.events_rxto.write(|w| w); + } + // check if dma rx transaction has started if uarte.events_rxstarted.read().bits() == 1 { // DMA transaction has started @@ -531,8 +572,11 @@ where uarte.events_rxstarted.write(|w| w); } - // check id dma transaction finished + // check if dma transaction finished if uarte.events_endrx.read().bits() == 1 { + // TODO: Add handling for the true number of bytes received + self.timer.cancel().unwrap(); // Never fails + // our transaction has finished if let Some(ret_b) = self.rxq.dequeue() { // Reset the event, otherwise it will always read `1` from now on. From 7ea8d884ad0f51e9a286efb6c723a5ef88a78284 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 8 Aug 2019 11:36:35 +0200 Subject: [PATCH 13/44] Now working with sizes of packets added --- nrf52-hal-common/Cargo.toml | 2 +- nrf52-hal-common/src/lib.rs | 5 +- nrf52-hal-common/src/timer.rs | 2 - nrf52-hal-common/src/uarte.rs | 108 +++++++++++++++++++++++++--------- 4 files changed, 84 insertions(+), 33 deletions(-) diff --git a/nrf52-hal-common/Cargo.toml b/nrf52-hal-common/Cargo.toml index 494d6ead..748687bc 100644 --- a/nrf52-hal-common/Cargo.toml +++ b/nrf52-hal-common/Cargo.toml @@ -68,4 +68,4 @@ DMA_SIZE_16 = [] DMA_SIZE_32 = [] DMA_SIZE_64 = [] DMA_SIZE_128 = [] -DMA_SIZE_256 = [] +DMA_SIZE_255 = [] diff --git a/nrf52-hal-common/src/lib.rs b/nrf52-hal-common/src/lib.rs index ca8f1a9a..4ade8995 100644 --- a/nrf52-hal-common/src/lib.rs +++ b/nrf52-hal-common/src/lib.rs @@ -58,8 +58,7 @@ pub mod target_constants { /// Does this slice reside entirely within RAM? pub(crate) fn slice_in_ram(slice: &[u8]) -> bool { let ptr = slice.as_ptr() as usize; - ptr >= target_constants::SRAM_LOWER - && (ptr + slice.len()) < target_constants::SRAM_UPPER + ptr >= target_constants::SRAM_LOWER && (ptr + slice.len()) < target_constants::SRAM_UPPER } /// A handy structure for converting rust slices into ptr and len pairs @@ -92,4 +91,4 @@ pub use crate::saadc::Saadc; pub use crate::spim::Spim; pub use crate::timer::Timer; pub use crate::twim::Twim; -pub use crate::uarte::{DMAPool, RXError, Uarte, UarteRX, UarteTX, DMA_SIZE}; +pub use crate::uarte::{DMAPool, DMAPoolNode, RXError, Uarte, UarteRX, UarteTX, DMA_SIZE}; diff --git a/nrf52-hal-common/src/timer.rs b/nrf52-hal-common/src/timer.rs index 12ba8d98..cfe0105f 100644 --- a/nrf52-hal-common/src/timer.rs +++ b/nrf52-hal-common/src/timer.rs @@ -55,8 +55,6 @@ where self.0.cc[1].read().bits() } - /// Enables the interrupt for this timer, external NVIC modification - /// /// Enables an interrupt that is fired when the timer reaches the value that /// is given as an argument to `start`. pub(crate) fn enable_interrupt_generation(&mut self) { diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index ab921430..13f43ee4 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -26,7 +26,7 @@ use crate::prelude::*; use crate::target_constants::EASY_DMA_SIZE; use crate::timer::{self, Timer}; -use embedded_hal::timer::{Cancel, CountDown}; +use embedded_hal::timer::Cancel; use heapless::{ consts::*, @@ -352,23 +352,14 @@ where /// interrupt in the end. Kept as a split for now, but might be merged in the future. pub fn split( self, - rxq: Queue, U2>, txc: Consumer<'static, Box, S>, - mut timer: Timer, + timer: Timer, ) -> (UarteRX, UarteTX) where S: ArrayLength>, I: timer::Instance, { - // This operation is safe due to type-state programming guaranteeing that the Timer is - // unique within the driver - //let timer_reg = unsafe { &*I::ptr() }; - - // Enable COMPARE0 interrupt - //timer_reg.intenset.modify(|_, w| w.compare0().set()); - timer.enable_interrupt_generation(); - - let mut rx = UarteRX::::new(rxq, timer); + let mut rx = UarteRX::::new(timer); rx.enable_interrupts(); rx.prepare_read().unwrap(); rx.start_read(); @@ -411,8 +402,9 @@ pub const DMA_SIZE: usize = 64; pub const DMA_SIZE: usize = 128; // Currently causes internal OOM, needs fixing -#[cfg(feature = "DMA_SIZE_256")] -pub const DMA_SIZE: usize = 256; +// Maximum DMA size is 255 of the UARTE peripheral, see `MAXCNT` for details +#[cfg(feature = "DMA_SIZE_255")] +pub const DMA_SIZE: usize = 255; // An alternative solution to the above is to define the DMA_SIZE // in a separate (default) crate, which can be overridden @@ -427,8 +419,58 @@ pub const DMA_SIZE: usize = 256; // // The reason to have a POOL gate is that we don't want the POOL // to cause memory OH if not used by the application +#[derive(Debug)] +pub struct DMAPoolNode { + len: u8, + buf: [u8; DMA_SIZE], +} + +impl DMAPoolNode { + pub fn new() -> Self { + Self { + len: 0, + buf: [0; DMA_SIZE], + } + } + + pub fn write(&mut self, buf: &[u8]) -> usize { + if buf.len() > DMA_SIZE { + self.len = DMA_SIZE as u8; + } else { + self.len = buf.len() as u8; + } + + let internal_buffer = &mut self.buf[..self.len as usize]; + internal_buffer.copy_from_slice(&buf[..self.len as usize]); + + return self.len as usize; + } + + pub fn read(&self) -> &[u8] { + &self.buf[..self.len as usize] + } + + pub fn len(&self) -> usize { + self.len as usize + } + + fn set_len(&mut self, len: u8) { + self.len = len; + } + + fn max_len(&self) -> usize { + DMA_SIZE + } + + fn buffer_address(&self) -> u32 { + self.buf.as_ptr() as u32 + } +} -pool!(DMAPool: [u8; DMA_SIZE]); +pool!( + #[allow(non_upper_case_globals)] + DMAPool: DMAPoolNode +); /// UARTE RX part, used in interrupt driven contexts pub struct UarteRX { @@ -455,16 +497,16 @@ where I: timer::Instance, { /// Construct new UARTE RX, hidden from users - used internally - fn new(rxq: Queue, U2>, timer: Timer) -> Self { + fn new(timer: Timer) -> Self { Self { - rxq, + rxq: Queue::new(), timer, _marker: core::marker::PhantomData, } } /// Used internally to set up the proper interrupts - fn enable_interrupts(&self) { + fn enable_interrupts(&mut self) { // This operation is safe due to type-state programming guaranteeing that the RX and TX are // unique within the driver let uarte = unsafe { &*T::ptr() }; @@ -479,6 +521,8 @@ where .rxdrdy() .set_bit() }); + + self.timer.enable_interrupt_generation(); } /// Start a UARTE read transaction @@ -499,19 +543,23 @@ where // unique within the driver let uarte = unsafe { &*T::ptr() }; - let b = DMAPool::alloc().ok_or(RXError::OOM)?.freeze(); + let b = DMAPool::alloc() + .ok_or(RXError::OOM)? + .init(DMAPoolNode::new()); // TODO: Find a way to not need new, the zeroing of the + // internal buffer is unnecessary + compiler_fence(SeqCst); // setup start address uarte .rxd .ptr - .write(|w| unsafe { w.ptr().bits(b.as_ptr() as u32) }); + .write(|w| unsafe { w.ptr().bits(b.buffer_address()) }); // setup length uarte .rxd .maxcnt - .write(|w| unsafe { w.maxcnt().bits(b.len() as _) }); + .write(|w| unsafe { w.maxcnt().bits(b.max_len() as _) }); if self.rxq.enqueue(b).is_err() { panic!("Internal driver error, RX Queue Overflow"); @@ -522,11 +570,12 @@ where /// Timeout handling for the RX driver - Must be called from the corresponding TIMERx Interrupt /// handler/task. - pub fn process_timeout(&mut self) { + pub fn process_timeout_interrupt(&mut self) { // This operation is safe due to type-state programming guaranteeing that the RX and TX are // unique within the driver let uarte = unsafe { &*T::ptr() }; + // Reset the event, otherwise it will always read `1` from now on. self.timer.clear_interrupt(); // Stop UARTE Receive transaction to generate the Timeout Event @@ -547,16 +596,17 @@ where // unique within the driver let uarte = unsafe { &*T::ptr() }; + // Handles the byte timeout timer if uarte.events_rxdrdy.read().bits() == 1 { self.timer.cancel().unwrap(); // Never fails - self.timer.start(1000_u32); // 1 ms for now + self.timer.start(1000_u32); // 1 ms timeout for now // Reset the event, otherwise it will always read `1` from now on. uarte.events_rxdrdy.write(|w| w); } if uarte.events_rxto.read().bits() == 1 { - // Ask UART to flush FIFO to DMA buffer + // Tell UARTE to flush FIFO to DMA buffer uarte.tasks_flushrx.write(|w| unsafe { w.bits(1) }); // Reset the event, otherwise it will always read `1` from now on. @@ -574,11 +624,15 @@ where // check if dma transaction finished if uarte.events_endrx.read().bits() == 1 { - // TODO: Add handling for the true number of bytes received self.timer.cancel().unwrap(); // Never fails // our transaction has finished - if let Some(ret_b) = self.rxq.dequeue() { + if let Some(mut ret_b) = self.rxq.dequeue() { + // Read the true number of bytes and set the correct length of the packet before + // returning it + let bytes_read = uarte.rxd.amount.read().bits() as u8; + ret_b.set_len(bytes_read); + // Reset the event, otherwise it will always read `1` from now on. uarte.events_endrx.write(|w| w); @@ -641,7 +695,7 @@ where uarte .txd .ptr - .write(|w| unsafe { w.ptr().bits(b.as_ptr() as u32) }); + .write(|w| unsafe { w.ptr().bits(b.buffer_address()) }); // setup length uarte From d36946ee81334c2c885ce5161377ed58f0c6af2a Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 8 Aug 2019 11:39:23 +0200 Subject: [PATCH 14/44] Added check for 0 sized chunks being sent --- nrf52-hal-common/src/uarte.rs | 38 +++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 13f43ee4..8584f519 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -689,23 +689,27 @@ where // unique within the driver let uarte = unsafe { &*T::ptr() }; - compiler_fence(SeqCst); - - // setup start address - uarte - .txd - .ptr - .write(|w| unsafe { w.ptr().bits(b.buffer_address()) }); - - // setup length - uarte - .txd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(b.len() as _) }); - - // Start UARTE transmit transaction - uarte.tasks_starttx.write(|w| unsafe { w.bits(1) }); - self.current = Some(b); // drops the previous current package + if b.len() == 0 { + return; + } else { + compiler_fence(SeqCst); + + // setup start address + uarte + .txd + .ptr + .write(|w| unsafe { w.ptr().bits(b.buffer_address()) }); + + // setup length + uarte + .txd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(b.len() as _) }); + + // Start UARTE transmit transaction + uarte.tasks_starttx.write(|w| unsafe { w.bits(1) }); + self.current = Some(b); // drops the previous current package + } } /// Main entry point for the TX driver - Must be called from the corresponding UARTE Interrupt From 8593b58c53f355414640051cd56510f738d9d9db Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 8 Aug 2019 11:40:31 +0200 Subject: [PATCH 15/44] Cleanup of chunk check --- nrf52-hal-common/src/uarte.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 8584f519..7483f481 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -689,9 +689,8 @@ where // unique within the driver let uarte = unsafe { &*T::ptr() }; - if b.len() == 0 { - return; - } else { + // Only send if the DMA chunk has data, else drop the `Box` + if b.len() > 0 { compiler_fence(SeqCst); // setup start address From 4229a188908b4a80272b8ac50d7c560d14ac7700 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 8 Aug 2019 11:46:41 +0200 Subject: [PATCH 16/44] Handle DMA pool inside the driver --- nrf52-hal-common/src/lib.rs | 2 +- nrf52-hal-common/src/uarte.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/nrf52-hal-common/src/lib.rs b/nrf52-hal-common/src/lib.rs index 4ade8995..28f3e2ae 100644 --- a/nrf52-hal-common/src/lib.rs +++ b/nrf52-hal-common/src/lib.rs @@ -91,4 +91,4 @@ pub use crate::saadc::Saadc; pub use crate::spim::Spim; pub use crate::timer::Timer; pub use crate::twim::Twim; -pub use crate::uarte::{DMAPool, DMAPoolNode, RXError, Uarte, UarteRX, UarteTX, DMA_SIZE}; +pub use crate::uarte::{DMAPool, DMAPoolNode, RXError, Uarte, UarteRX, UarteTX}; diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 7483f481..7aac719b 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -354,11 +354,18 @@ where self, txc: Consumer<'static, Box, S>, timer: Timer, + dma_pool_memory: &'static mut [u8], ) -> (UarteRX, UarteTX) where S: ArrayLength>, I: timer::Instance, { + debug_assert!( + dma_pool_memory.len() >= core::mem::size_of::() * 2, + "The memory pool needs at least space for 2 `DMAPoolNode`s" + ); + DMAPool::grow(dma_pool_memory); + let mut rx = UarteRX::::new(timer); rx.enable_interrupts(); rx.prepare_read().unwrap(); From cdea379b16082ba48af0800d86724cca492e776e Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 8 Aug 2019 12:14:10 +0200 Subject: [PATCH 17/44] Updated timeout to 10 ms --- nrf52-hal-common/src/uarte.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 7aac719b..17e073cb 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -606,7 +606,7 @@ where // Handles the byte timeout timer if uarte.events_rxdrdy.read().bits() == 1 { self.timer.cancel().unwrap(); // Never fails - self.timer.start(1000_u32); // 1 ms timeout for now + self.timer.start(10_000_u32); // 10 ms timeout for now // Reset the event, otherwise it will always read `1` from now on. uarte.events_rxdrdy.write(|w| w); From a7d470a977d7799237631626bff3ec804c96af2f Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 8 Aug 2019 12:21:26 +0200 Subject: [PATCH 18/44] Renaming to better describing names --- nrf52-hal-common/Cargo.toml | 14 ++--- nrf52-hal-common/src/lib.rs | 2 +- nrf52-hal-common/src/uarte.rs | 106 +++++++++++++++++----------------- nrf52810-hal/Cargo.toml | 14 ++--- nrf52832-hal/Cargo.toml | 14 ++--- nrf52840-hal/Cargo.toml | 14 ++--- 6 files changed, 82 insertions(+), 82 deletions(-) diff --git a/nrf52-hal-common/Cargo.toml b/nrf52-hal-common/Cargo.toml index 748687bc..e2e8a10a 100644 --- a/nrf52-hal-common/Cargo.toml +++ b/nrf52-hal-common/Cargo.toml @@ -62,10 +62,10 @@ default = ["52832"] 52840 = ["nrf52840-pac"] 9160 = ["nrf9160-pac"] POOL = [] -DMA_SIZE_4 = [] -DMA_SIZE_8 = [] -DMA_SIZE_16 = [] -DMA_SIZE_32 = [] -DMA_SIZE_64 = [] -DMA_SIZE_128 = [] -DMA_SIZE_255 = [] +UARTE_DMA_SIZE_4 = [] +UARTE_DMA_SIZE_8 = [] +UARTE_DMA_SIZE_16 = [] +UARTE_DMA_SIZE_32 = [] +UARTE_DMA_SIZE_64 = [] +UARTE_DMA_SIZE_128 = [] +UARTE_DMA_SIZE_255 = [] diff --git a/nrf52-hal-common/src/lib.rs b/nrf52-hal-common/src/lib.rs index 28f3e2ae..50b7856d 100644 --- a/nrf52-hal-common/src/lib.rs +++ b/nrf52-hal-common/src/lib.rs @@ -91,4 +91,4 @@ pub use crate::saadc::Saadc; pub use crate::spim::Spim; pub use crate::timer::Timer; pub use crate::twim::Twim; -pub use crate::uarte::{DMAPool, DMAPoolNode, RXError, Uarte, UarteRX, UarteTX}; +pub use crate::uarte::{RXError, UARTEDMAPool, UARTEDMAPoolNode, Uarte, UarteRX, UarteTX}; diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 17e073cb..f72d354f 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -352,19 +352,19 @@ where /// interrupt in the end. Kept as a split for now, but might be merged in the future. pub fn split( self, - txc: Consumer<'static, Box, S>, + txc: Consumer<'static, Box, S>, timer: Timer, dma_pool_memory: &'static mut [u8], ) -> (UarteRX, UarteTX) where - S: ArrayLength>, + S: ArrayLength>, I: timer::Instance, { debug_assert!( - dma_pool_memory.len() >= core::mem::size_of::() * 2, - "The memory pool needs at least space for 2 `DMAPoolNode`s" + dma_pool_memory.len() >= core::mem::size_of::() * 2, + "The memory pool needs at least space for 2 `UARTEDMAPoolNode`s" ); - DMAPool::grow(dma_pool_memory); + UARTEDMAPool::grow(dma_pool_memory); let mut rx = UarteRX::::new(timer); rx.enable_interrupts(); @@ -378,45 +378,45 @@ where } /// DMA block size -/// Defaults to DMA_SIZE = 16 if not explicitly set +/// Defaults to UARTE_DMA_SIZE = 16 if not explicitly set #[cfg(not(any( - feature = "DMA_SIZE_4", - feature = "DMA_SIZE_8", - feature = "DMA_SIZE_16", - feature = "DMA_SIZE_32", - feature = "DMA_SIZE_64", - feature = "DMA_SIZE_128", - feature = "DMA_SIZE_256" + feature = "UARTE_DMA_SIZE_4", + feature = "UARTE_DMA_SIZE_8", + feature = "UARTE_DMA_SIZE_16", + feature = "UARTE_DMA_SIZE_32", + feature = "UARTE_DMA_SIZE_64", + feature = "UARTE_DMA_SIZE_128", + feature = "UARTE_DMA_SIZE_256" )))] -pub const DMA_SIZE: usize = 16; +pub const UARTE_DMA_SIZE: usize = 16; -#[cfg(feature = "DMA_SIZE_4")] -pub const DMA_SIZE: usize = 4; +#[cfg(feature = "UARTE_DMA_SIZE_4")] +pub const UARTE_DMA_SIZE: usize = 4; -#[cfg(feature = "DMA_SIZE_8")] -pub const DMA_SIZE: usize = 8; +#[cfg(feature = "UARTE_DMA_SIZE_8")] +pub const UARTE_DMA_SIZE: usize = 8; -#[cfg(feature = "DMA_SIZE_16")] -pub const DMA_SIZE: usize = 16; +#[cfg(feature = "UARTE_DMA_SIZE_16")] +pub const UARTE_DMA_SIZE: usize = 16; -#[cfg(feature = "DMA_SIZE_32")] -pub const DMA_SIZE: usize = 32; +#[cfg(feature = "UARTE_DMA_SIZE_32")] +pub const UARTE_DMA_SIZE: usize = 32; -#[cfg(feature = "DMA_SIZE_64")] -pub const DMA_SIZE: usize = 64; +#[cfg(feature = "UARTE_DMA_SIZE_64")] +pub const UARTE_DMA_SIZE: usize = 64; -#[cfg(feature = "DMA_SIZE_128")] -pub const DMA_SIZE: usize = 128; +#[cfg(feature = "UARTE_DMA_SIZE_128")] +pub const UARTE_DMA_SIZE: usize = 128; // Currently causes internal OOM, needs fixing // Maximum DMA size is 255 of the UARTE peripheral, see `MAXCNT` for details -#[cfg(feature = "DMA_SIZE_255")] -pub const DMA_SIZE: usize = 255; +#[cfg(feature = "UARTE_DMA_SIZE_255")] +pub const UARTE_DMA_SIZE: usize = 255; -// An alternative solution to the above is to define the DMA_SIZE +// An alternative solution to the above is to define the UARTE_DMA_SIZE // in a separate (default) crate, which can be overridden // by a patch in the user Cargo.toml, pointing to -// a local crate with the user defined DMA_SIZE constant. +// a local crate with the user defined UARTE_DMA_SIZE constant. // What would you prefer? // The DMA implementation shuld be hidden behind a feature POOL @@ -427,22 +427,22 @@ pub const DMA_SIZE: usize = 255; // The reason to have a POOL gate is that we don't want the POOL // to cause memory OH if not used by the application #[derive(Debug)] -pub struct DMAPoolNode { +pub struct UARTEDMAPoolNode { len: u8, - buf: [u8; DMA_SIZE], + buf: [u8; UARTE_DMA_SIZE], } -impl DMAPoolNode { +impl UARTEDMAPoolNode { pub fn new() -> Self { Self { len: 0, - buf: [0; DMA_SIZE], + buf: [0; UARTE_DMA_SIZE], } } pub fn write(&mut self, buf: &[u8]) -> usize { - if buf.len() > DMA_SIZE { - self.len = DMA_SIZE as u8; + if buf.len() > UARTE_DMA_SIZE { + self.len = UARTE_DMA_SIZE as u8; } else { self.len = buf.len() as u8; } @@ -466,7 +466,7 @@ impl DMAPoolNode { } fn max_len(&self) -> usize { - DMA_SIZE + UARTE_DMA_SIZE } fn buffer_address(&self) -> u32 { @@ -476,13 +476,13 @@ impl DMAPoolNode { pool!( #[allow(non_upper_case_globals)] - DMAPool: DMAPoolNode + UARTEDMAPool: UARTEDMAPoolNode ); /// UARTE RX part, used in interrupt driven contexts pub struct UarteRX { - rxq: Queue, U2>, // double buffering of DMA chunks - timer: Timer, // Timer for handling timeouts + rxq: Queue, U2>, // double buffering of DMA chunks + timer: Timer, // Timer for handling timeouts _marker: core::marker::PhantomData, } @@ -492,8 +492,8 @@ pub enum RXError { /// Out of memory error, global pool is depleted /// /// Potential causes: - /// 1. User code is saving the `Box` (and not dropping them) - /// 2. User code running `mem::forget` on the `Box` + /// 1. User code is saving the `Box` (and not dropping them) + /// 2. User code running `mem::forget` on the `Box` /// 3. The pool is too small for the use case OOM, } @@ -550,10 +550,10 @@ where // unique within the driver let uarte = unsafe { &*T::ptr() }; - let b = DMAPool::alloc() + let b = UARTEDMAPool::alloc() .ok_or(RXError::OOM)? - .init(DMAPoolNode::new()); // TODO: Find a way to not need new, the zeroing of the - // internal buffer is unnecessary + .init(UARTEDMAPoolNode::new()); // TODO: Find a way to not need new, the zeroing of the + // internal buffer is unnecessary compiler_fence(SeqCst); @@ -595,10 +595,10 @@ where /// handler/task. /// /// Will return: - /// 1. `Ok(Some(Box))` if data was received + /// 1. `Ok(Some(Box))` if data was received /// 2. `Ok(None)` if there was no data, i.e. UARTE interrupt was due to other events /// 3. `Err(RXError::OOM)` if the memory pool was depleted, see `RXError` for mitigations - pub fn process_interrupt(&mut self) -> Result>, RXError> { + pub fn process_interrupt(&mut self) -> Result>, RXError> { // This operation is safe due to type-state programming guaranteeing that the RX and TX are // unique within the driver let uarte = unsafe { &*T::ptr() }; @@ -660,20 +660,20 @@ where /// S is the queue length, can be U3, U4 etc. pub struct UarteTX where - S: ArrayLength>, + S: ArrayLength>, { - txc: Consumer<'static, Box, S>, // chunks to transmit - current: Option>, + txc: Consumer<'static, Box, S>, // chunks to transmit + current: Option>, _marker: core::marker::PhantomData, } impl UarteTX where T: Instance, - S: ArrayLength>, + S: ArrayLength>, { /// Construct new UARTE TX, hidden from users - used internally - fn new(txc: Consumer<'static, Box, S>) -> Self { + fn new(txc: Consumer<'static, Box, S>) -> Self { Self { txc, current: None, @@ -691,7 +691,7 @@ where } /// Sets up the UARTE to send DMA chunk - fn start_write(&mut self, b: Box) { + fn start_write(&mut self, b: Box) { // This operation is safe due to type-state programming guaranteeing that the RX and TX are // unique within the driver let uarte = unsafe { &*T::ptr() }; diff --git a/nrf52810-hal/Cargo.toml b/nrf52810-hal/Cargo.toml index 405acf45..4dad9a0f 100644 --- a/nrf52810-hal/Cargo.toml +++ b/nrf52810-hal/Cargo.toml @@ -43,13 +43,13 @@ doc = [] rt = ["nrf52810-pac/rt"] default = ["rt", "POOL"] POOL = ["nrf52-hal-common/POOL"] -DMA_SIZE_4 = ["nrf52-hal-common/DMA_SIZE_4"] -DMA_SIZE_8 = ["nrf52-hal-common/DMA_SIZE_8"] -DMA_SIZE_16 = ["nrf52-hal-common/DMA_SIZE_16"] -DMA_SIZE_32 = ["nrf52-hal-common/DMA_SIZE_32"] -DMA_SIZE_64 = ["nrf52-hal-common/DMA_SIZE_64"] -DMA_SIZE_128 = ["nrf52-hal-common/DMA_SIZE_128"] -DMA_SIZE_256 = ["nrf52-hal-common/DMA_SIZE_256"] +UARTE_DMA_SIZE_4 = ["nrf52-hal-common/UARTE_DMA_SIZE_4"] +UARTE_DMA_SIZE_8 = ["nrf52-hal-common/UARTE_DMA_SIZE_8"] +UARTE_DMA_SIZE_16 = ["nrf52-hal-common/UARTE_DMA_SIZE_16"] +UARTE_DMA_SIZE_32 = ["nrf52-hal-common/UARTE_DMA_SIZE_32"] +UARTE_DMA_SIZE_64 = ["nrf52-hal-common/UARTE_DMA_SIZE_64"] +UARTE_DMA_SIZE_128 = ["nrf52-hal-common/UARTE_DMA_SIZE_128"] +UARTE_DMA_SIZE_255 = ["nrf52-hal-common/UARTE_DMA_SIZE_255"] diff --git a/nrf52832-hal/Cargo.toml b/nrf52832-hal/Cargo.toml index 78d21f5f..02d9b19c 100644 --- a/nrf52832-hal/Cargo.toml +++ b/nrf52832-hal/Cargo.toml @@ -43,13 +43,13 @@ rt = ["nrf52832-pac/rt"] xxAA-package = [] xxAB-package = [] POOL = ["nrf52-hal-common/POOL"] -DMA_SIZE_4 = ["nrf52-hal-common/DMA_SIZE_4"] -DMA_SIZE_8 = ["nrf52-hal-common/DMA_SIZE_8"] -DMA_SIZE_16 = ["nrf52-hal-common/DMA_SIZE_16"] -DMA_SIZE_32 = ["nrf52-hal-common/DMA_SIZE_32"] -DMA_SIZE_64 = ["nrf52-hal-common/DMA_SIZE_64"] -DMA_SIZE_128 = ["nrf52-hal-common/DMA_SIZE_128"] -DMA_SIZE_256 = ["nrf52-hal-common/DMA_SIZE_256"] +UARTE_DMA_SIZE_4 = ["nrf52-hal-common/UARTE_DMA_SIZE_4"] +UARTE_DMA_SIZE_8 = ["nrf52-hal-common/UARTE_DMA_SIZE_8"] +UARTE_DMA_SIZE_16 = ["nrf52-hal-common/UARTE_DMA_SIZE_16"] +UARTE_DMA_SIZE_32 = ["nrf52-hal-common/UARTE_DMA_SIZE_32"] +UARTE_DMA_SIZE_64 = ["nrf52-hal-common/UARTE_DMA_SIZE_64"] +UARTE_DMA_SIZE_128 = ["nrf52-hal-common/UARTE_DMA_SIZE_128"] +UARTE_DMA_SIZE_255 = ["nrf52-hal-common/UARTE_DMA_SIZE_255"] # Note: We use the xxAB package because it has the least amount of available resources. diff --git a/nrf52840-hal/Cargo.toml b/nrf52840-hal/Cargo.toml index bb9486c7..4a57ff40 100644 --- a/nrf52840-hal/Cargo.toml +++ b/nrf52840-hal/Cargo.toml @@ -44,13 +44,13 @@ doc = [] rt = ["nrf52840-pac/rt"] default = ["rt", "POOL"] POOL = ["nrf52-hal-common/POOL"] -DMA_SIZE_4 = ["nrf52-hal-common/DMA_SIZE_4"] -DMA_SIZE_8 = ["nrf52-hal-common/DMA_SIZE_8"] -DMA_SIZE_16 = ["nrf52-hal-common/DMA_SIZE_16"] -DMA_SIZE_32 = ["nrf52-hal-common/DMA_SIZE_32"] -DMA_SIZE_64 = ["nrf52-hal-common/DMA_SIZE_64"] -DMA_SIZE_128 = ["nrf52-hal-common/DMA_SIZE_128"] -DMA_SIZE_256 = ["nrf52-hal-common/DMA_SIZE_256"] +UARTE_DMA_SIZE_4 = ["nrf52-hal-common/UARTE_DMA_SIZE_4"] +UARTE_DMA_SIZE_8 = ["nrf52-hal-common/UARTE_DMA_SIZE_8"] +UARTE_DMA_SIZE_16 = ["nrf52-hal-common/UARTE_DMA_SIZE_16"] +UARTE_DMA_SIZE_32 = ["nrf52-hal-common/UARTE_DMA_SIZE_32"] +UARTE_DMA_SIZE_64 = ["nrf52-hal-common/UARTE_DMA_SIZE_64"] +UARTE_DMA_SIZE_128 = ["nrf52-hal-common/UARTE_DMA_SIZE_128"] +UARTE_DMA_SIZE_255 = ["nrf52-hal-common/UARTE_DMA_SIZE_255"] From 902f322534173958f6b207fcaf96ed7ccc1049e7 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 8 Aug 2019 12:27:38 +0200 Subject: [PATCH 19/44] Updated UARTE interrupt example --- examples/rtfm-uarte-interrupts/src/main.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index 35c33adb..b3b8897d 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -12,7 +12,7 @@ use hal::gpio::{p0, Level}; use hal::target::{interrupt, TIMER0, UARTE0}; use hal::timer::*; use hal::{uarte, Uarte}; -use hal::{DMAPool, RXError, UarteRX, UarteTX, DMA_SIZE}; +use hal::{RXError, UARTEDMAPool, UARTEDMAPoolNode, UarteRX, UarteTX}; use heapless::{ consts::U3, @@ -24,26 +24,23 @@ use heapless::{ use rtfm::app; const NR_PACKAGES: usize = 10; -const DMA_MEM: usize = DMA_SIZE * NR_PACKAGES + 16; - +const DMA_MEM: usize = core::mem::size_of::() * NR_PACKAGES; type TXQSize = U3; #[app(device = crate::hal::target)] const APP: () = { static mut RX: UarteRX = (); static mut TX: UarteTX = (); - static mut PRODUCER: Producer<'static, Box, TXQSize> = (); + static mut PRODUCER: Producer<'static, Box, TXQSize> = (); #[init(spawn = [])] fn init() -> init::LateResources { // for the actual DMA buffers static mut MEMORY: [u8; DMA_MEM] = [0; DMA_MEM]; // for the producer/consumer of TX - static mut TX_RB: Queue, TXQSize> = Queue(heapless::i::Queue::new()); + static mut TX_RB: Queue, TXQSize> = Queue(heapless::i::Queue::new()); hprintln!("init").unwrap(); - // move MEMORY to P (the DMA buffer allocator) - DMAPool::grow(MEMORY); let port0 = p0::Parts::new(device.P0); @@ -62,7 +59,7 @@ const APP: () = { let timer = Timer::new(device.TIMER0); let (txp, txc) = TX_RB.split(); - let (rx, tx) = uarte0.split(Queue::new(), txc, timer); + let (rx, tx) = uarte0.split(txc, timer, MEMORY); init::LateResources { RX: rx, @@ -73,9 +70,9 @@ const APP: () = { // // we can get Box

us being now the owner #[task(capacity = 2, resources = [PRODUCER])] - fn printer(data: Box) { + fn printer(data: Box) { // enqueue a test message - // let mut b = DMAPool::alloc().unwrap().freeze(); + // let mut b = UARTEDMAPool::alloc().unwrap().freeze(); // b.copy_from_slice(&[0, 1, 2, 3]); // hprintln!("{:?}", &data).unwrap(); From 3d5112bb257a6b01bc6954d7f614472246f59c97 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 8 Aug 2019 12:29:40 +0200 Subject: [PATCH 20/44] Cleanup of UARTE interrupt example, added timeout handling --- examples/rtfm-uarte-interrupts/src/main.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index b3b8897d..3509cd41 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -9,7 +9,7 @@ use cortex_m_semihosting::hprintln; use nrf52832_hal as hal; use hal::gpio::{p0, Level}; -use hal::target::{interrupt, TIMER0, UARTE0}; +use hal::target::{interrupt, TIMER0 as TIM0, UARTE0}; use hal::timer::*; use hal::{uarte, Uarte}; use hal::{RXError, UARTEDMAPool, UARTEDMAPoolNode, UarteRX, UarteTX}; @@ -17,7 +17,6 @@ use hal::{RXError, UARTEDMAPool, UARTEDMAPoolNode, UarteRX, UarteTX}; use heapless::{ consts::U3, pool::singleton::Box, - pool::singleton::Pool, spsc::{Producer, Queue}, }; @@ -29,7 +28,7 @@ type TXQSize = U3; #[app(device = crate::hal::target)] const APP: () = { - static mut RX: UarteRX = (); + static mut RX: UarteRX = (); static mut TX: UarteTX = (); static mut PRODUCER: Producer<'static, Box, TXQSize> = (); @@ -86,6 +85,11 @@ const APP: () = { hprintln!("rx_error {:?}", err).unwrap(); } + #[interrupt(priority = 2, resources = [RX])] + fn TIMER0() { + resources.RX.process_timeout_interrupt(); + } + #[interrupt(priority = 2, resources = [RX, TX], spawn = [printer, rx_error])] fn UARTE0_UART0() { // probe RX From 399147790bc3031962be7a7c0ced2fa644eed2da Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 8 Aug 2019 12:30:42 +0200 Subject: [PATCH 21/44] Added commented pin definitions for DWM1001 dev board --- examples/rtfm-uarte-interrupts/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index 3509cd41..f03920b0 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -49,6 +49,9 @@ const APP: () = { uarte::Pins { txd: port0.p0_06.into_push_pull_output(Level::High).degrade(), rxd: port0.p0_08.into_floating_input().degrade(), + // Use the following for DWM-1001 dev board + // txd: port0.p0_05.into_push_pull_output(Level::High).degrade(), + // rxd: port0.p0_11.into_floating_input().degrade(), cts: None, rts: None, }, From 7c8285b1ae3e5a4cebe15de50499f29d09209ded Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 8 Aug 2019 13:07:45 +0200 Subject: [PATCH 22/44] Changed the Node struct to use MaybeUninit, added documentation --- examples/rtfm-uarte-interrupts/src/main.rs | 2 +- nrf52-hal-common/src/uarte.rs | 56 +++++++++++++++------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index f03920b0..1da002f1 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -79,7 +79,7 @@ const APP: () = { // hprintln!("{:?}", &data).unwrap(); // just do the buffer dance without copying - resources.PRODUCER.enqueue(data).unwrap(); + let _ = resources.PRODUCER.enqueue(data); rtfm::pend(interrupt::UARTE0_UART0); } diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index f72d354f..985ab0e2 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -5,6 +5,7 @@ //! - nrf52832: Section 35 //! - nrf52840: Section 6.34 use core::fmt; +use core::mem::MaybeUninit; use core::ops::Deref; use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; @@ -426,20 +427,23 @@ pub const UARTE_DMA_SIZE: usize = 255; // // The reason to have a POOL gate is that we don't want the POOL // to cause memory OH if not used by the application -#[derive(Debug)] + +/// Each node in the `UARTEDMAPool` consists of this struct. pub struct UARTEDMAPoolNode { len: u8, - buf: [u8; UARTE_DMA_SIZE], + buf: MaybeUninit<[u8; UARTE_DMA_SIZE]>, } impl UARTEDMAPoolNode { + /// Creates a new node for the UARTE DMA pub fn new() -> Self { Self { len: 0, - buf: [0; UARTE_DMA_SIZE], + buf: MaybeUninit::uninit(), } } + /// Used to write data into the node, and returns how many bytes were written from `buf`. pub fn write(&mut self, buf: &[u8]) -> usize { if buf.len() > UARTE_DMA_SIZE { self.len = UARTE_DMA_SIZE as u8; @@ -447,30 +451,41 @@ impl UARTEDMAPoolNode { self.len = buf.len() as u8; } - let internal_buffer = &mut self.buf[..self.len as usize]; - internal_buffer.copy_from_slice(&buf[..self.len as usize]); + // Used to write data into the `MaybeUninit`, safe based on the size check above + unsafe { + core::ptr::copy_nonoverlapping( + buf.as_ptr(), + self.buf.as_mut_ptr() as *mut _, + self.len as usize, + ); + } return self.len as usize; } + /// Returns a readable slice which maps to the buffers internal data pub fn read(&self) -> &[u8] { - &self.buf[..self.len as usize] + // Safe as it uses the internal length of valid data + unsafe { core::slice::from_raw_parts(self.buf.as_ptr() as *const _, self.len as usize) } } + /// Reads how many bytes are available pub fn len(&self) -> usize { self.len as usize } - fn set_len(&mut self, len: u8) { + /// This function is unsafe as it must be used in conjuction with `buffer_address` to write and + /// set the correct number of bytes from a DMA transaction + unsafe fn set_len_from_dma(&mut self, len: u8) { self.len = len; } - fn max_len(&self) -> usize { - UARTE_DMA_SIZE + unsafe fn buffer_address_for_dma(&self) -> u32 { + self.buf.as_ptr() as u32 } - fn buffer_address(&self) -> u32 { - self.buf.as_ptr() as u32 + const fn max_len(&self) -> usize { + UARTE_DMA_SIZE } } @@ -479,7 +494,8 @@ pool!( UARTEDMAPool: UARTEDMAPoolNode ); -/// UARTE RX part, used in interrupt driven contexts +/// UARTE RX driver, used in interrupt driven contexts +/// `I` is the timer instance pub struct UarteRX { rxq: Queue, U2>, // double buffering of DMA chunks timer: Timer, // Timer for handling timeouts @@ -550,10 +566,10 @@ where // unique within the driver let uarte = unsafe { &*T::ptr() }; + // This operation is fast as `UARTEDMAPoolNode::new()` does not zero the internal buffer let b = UARTEDMAPool::alloc() .ok_or(RXError::OOM)? - .init(UARTEDMAPoolNode::new()); // TODO: Find a way to not need new, the zeroing of the - // internal buffer is unnecessary + .init(UARTEDMAPoolNode::new()); compiler_fence(SeqCst); @@ -561,7 +577,7 @@ where uarte .rxd .ptr - .write(|w| unsafe { w.ptr().bits(b.buffer_address()) }); + .write(|w| unsafe { w.ptr().bits(b.buffer_address_for_dma()) }); // setup length uarte .rxd @@ -638,7 +654,11 @@ where // Read the true number of bytes and set the correct length of the packet before // returning it let bytes_read = uarte.rxd.amount.read().bits() as u8; - ret_b.set_len(bytes_read); + unsafe { + // This operation is safe as `buffer_address_for_dma` has written `bytes_read` + // number of bytes into the node + ret_b.set_len_from_dma(bytes_read); + } // Reset the event, otherwise it will always read `1` from now on. uarte.events_endrx.write(|w| w); @@ -656,7 +676,7 @@ where } } -/// UARTE TX part, used in interrupt driven contexts +/// UARTE TX driver, used in interrupt driven contexts /// S is the queue length, can be U3, U4 etc. pub struct UarteTX where @@ -704,7 +724,7 @@ where uarte .txd .ptr - .write(|w| unsafe { w.ptr().bits(b.buffer_address()) }); + .write(|w| unsafe { w.ptr().bits(b.buffer_address_for_dma()) }); // setup length uarte From dcc8a734582fe03b5bbf845d92f9f04e8f38aa03 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Fri, 9 Aug 2019 12:45:25 +0200 Subject: [PATCH 23/44] Cleared out panics, replaced with debug_assert, added Debug impl --- examples/rtfm-uarte-interrupts/src/main.rs | 12 +++++++---- nrf52-hal-common/src/uarte.rs | 25 ++++++++++++++-------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index 1da002f1..27e1f978 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -74,12 +74,16 @@ const APP: () = { #[task(capacity = 2, resources = [PRODUCER])] fn printer(data: Box) { // enqueue a test message - // let mut b = UARTEDMAPool::alloc().unwrap().freeze(); - // b.copy_from_slice(&[0, 1, 2, 3]); - + // let mut node = UARTEDMAPoolNode::new(); + // node.write(&[95, 95, 95, 95]); + // let b = UARTEDMAPool::alloc() + // .unwrap() + // .init(node); + // resources.PRODUCER.enqueue(b).unwrap(); // hprintln!("{:?}", &data).unwrap(); + // just do the buffer dance without copying - let _ = resources.PRODUCER.enqueue(data); + resources.PRODUCER.enqueue(data).unwrap(); rtfm::pend(interrupt::UARTE0_UART0); } diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 985ab0e2..d601b34a 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -434,6 +434,12 @@ pub struct UARTEDMAPoolNode { buf: MaybeUninit<[u8; UARTE_DMA_SIZE]>, } +impl core::fmt::Debug for UARTEDMAPoolNode { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self.read()) + } +} + impl UARTEDMAPoolNode { /// Creates a new node for the UARTE DMA pub fn new() -> Self { @@ -584,11 +590,10 @@ where .maxcnt .write(|w| unsafe { w.maxcnt().bits(b.max_len() as _) }); - if self.rxq.enqueue(b).is_err() { - panic!("Internal driver error, RX Queue Overflow"); - } else { - Ok(()) - } + let r = self.rxq.enqueue(b); + debug_assert!(r.is_ok(), "Internal driver error, RX Queue Overflow"); + + Ok(()) } /// Timeout handling for the RX driver - Must be called from the corresponding TIMERx Interrupt @@ -667,7 +672,7 @@ where return Ok(Some(ret_b)); // ok to return, rx started will be caught later } else { - panic!("Internal driver error, RX Queue Underflow"); + debug_assert!(false, "Internal driver error, RX Queue Underflow"); } } @@ -751,9 +756,11 @@ where match self.txc.dequeue() { None => { // a ENDTX without an started transaction is an error - if self.current.is_none() { - panic!("Internal error, ENDTX without current transaction.") - } + debug_assert!( + self.current.is_some(), + "Internal error, ENDTX without current transaction." + ); + // we don't have any more to send, so drop the current buffer self.current = None; } From 705eeeee97799db3c8f8127900b41cbc494aa06f Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Sun, 11 Aug 2019 17:32:26 +0200 Subject: [PATCH 24/44] Fixed miss in merge --- nrf52-hal-common/src/uarte.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index d601b34a..6d4fc1db 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -9,18 +9,11 @@ use core::mem::MaybeUninit; use core::ops::Deref; use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; -#[cfg(feature="9160")] -use crate::target::{ - uarte0_ns as uarte0, - UARTE0_NS as UARTE0, - UARTE1_NS as UARTE1, -}; +#[cfg(feature = "9160")] +use crate::target::{uarte0_ns as uarte0, UARTE0_NS as UARTE0, UARTE1_NS as UARTE1}; -#[cfg(not(feature="9160"))] -use crate::target::{ - uarte0, - UARTE0, -}; +#[cfg(not(feature = "9160"))] +use crate::target::{uarte0, UARTE0}; use crate::gpio::{Floating, Input, Output, Pin, PushPull}; use crate::prelude::*; @@ -830,7 +823,7 @@ impl Instance for UARTE0 { } } -#[cfg(feature="9160")] +#[cfg(feature = "9160")] impl Instance for UARTE1 { fn ptr() -> *const uarte0::RegisterBlock { UARTE1::ptr() From dea2e73c424b2aed4791b3c97b5431eefe10d80f Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Sun, 11 Aug 2019 17:35:05 +0200 Subject: [PATCH 25/44] Small renaming for easier readability --- examples/rtfm-uarte-interrupts/src/main.rs | 14 +++---- nrf52-hal-common/src/lib.rs | 10 ++--- nrf52-hal-common/src/uarte.rs | 48 +++++++++++----------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index 27e1f978..9e0d2b3b 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -12,7 +12,7 @@ use hal::gpio::{p0, Level}; use hal::target::{interrupt, TIMER0 as TIM0, UARTE0}; use hal::timer::*; use hal::{uarte, Uarte}; -use hal::{RXError, UARTEDMAPool, UARTEDMAPoolNode, UarteRX, UarteTX}; +use hal::{RXError, UarteDMAPool, UarteDMAPoolNode, UarteRX, UarteTX}; use heapless::{ consts::U3, @@ -23,21 +23,21 @@ use heapless::{ use rtfm::app; const NR_PACKAGES: usize = 10; -const DMA_MEM: usize = core::mem::size_of::() * NR_PACKAGES; +const DMA_MEM: usize = core::mem::size_of::() * NR_PACKAGES; type TXQSize = U3; #[app(device = crate::hal::target)] const APP: () = { static mut RX: UarteRX = (); static mut TX: UarteTX = (); - static mut PRODUCER: Producer<'static, Box, TXQSize> = (); + static mut PRODUCER: Producer<'static, Box, TXQSize> = (); #[init(spawn = [])] fn init() -> init::LateResources { // for the actual DMA buffers static mut MEMORY: [u8; DMA_MEM] = [0; DMA_MEM]; // for the producer/consumer of TX - static mut TX_RB: Queue, TXQSize> = Queue(heapless::i::Queue::new()); + static mut TX_RB: Queue, TXQSize> = Queue(heapless::i::Queue::new()); hprintln!("init").unwrap(); @@ -72,11 +72,11 @@ const APP: () = { // // we can get Box

us being now the owner #[task(capacity = 2, resources = [PRODUCER])] - fn printer(data: Box) { + fn printer(data: Box) { // enqueue a test message - // let mut node = UARTEDMAPoolNode::new(); + // let mut node = UarteDMAPoolNode::new(); // node.write(&[95, 95, 95, 95]); - // let b = UARTEDMAPool::alloc() + // let b = UarteDMAPool::alloc() // .unwrap() // .init(node); // resources.PRODUCER.enqueue(b).unwrap(); diff --git a/nrf52-hal-common/src/lib.rs b/nrf52-hal-common/src/lib.rs index 50b7856d..819cda71 100644 --- a/nrf52-hal-common/src/lib.rs +++ b/nrf52-hal-common/src/lib.rs @@ -17,12 +17,12 @@ pub use nrf9160_pac as target; pub mod clocks; pub mod delay; pub mod gpio; -#[cfg(not(feature="9160"))] +#[cfg(not(feature = "9160"))] pub mod rng; pub mod rtc; pub mod saadc; pub mod spim; -#[cfg(not(feature="9160"))] +#[cfg(not(feature = "9160"))] pub mod temp; pub mod time; pub mod timer; @@ -45,7 +45,7 @@ pub mod target_constants { pub const SRAM_UPPER: usize = 0x3000_0000; pub const FORCE_COPY_BUFFER_SIZE: usize = 255; } -#[cfg(any(feature = "52840", feature="9160"))] +#[cfg(any(feature = "52840", feature = "9160"))] pub mod target_constants { // NRF52840 and NRF9160 16 bits 1..0xFFFF pub const EASY_DMA_SIZE: usize = 65535; @@ -84,11 +84,11 @@ impl DmaSlice { pub use crate::clocks::Clocks; pub use crate::delay::Delay; -#[cfg(not(feature="9160"))] +#[cfg(not(feature = "9160"))] pub use crate::rng::Rng; pub use crate::rtc::Rtc; pub use crate::saadc::Saadc; pub use crate::spim::Spim; pub use crate::timer::Timer; pub use crate::twim::Twim; -pub use crate::uarte::{RXError, UARTEDMAPool, UARTEDMAPoolNode, Uarte, UarteRX, UarteTX}; +pub use crate::uarte::{RXError, Uarte, UarteDMAPool, UarteDMAPoolNode, UarteRX, UarteTX}; diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 6d4fc1db..cdaf716a 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -346,19 +346,19 @@ where /// interrupt in the end. Kept as a split for now, but might be merged in the future. pub fn split( self, - txc: Consumer<'static, Box, S>, + txc: Consumer<'static, Box, S>, timer: Timer, dma_pool_memory: &'static mut [u8], ) -> (UarteRX, UarteTX) where - S: ArrayLength>, + S: ArrayLength>, I: timer::Instance, { debug_assert!( - dma_pool_memory.len() >= core::mem::size_of::() * 2, - "The memory pool needs at least space for 2 `UARTEDMAPoolNode`s" + dma_pool_memory.len() >= core::mem::size_of::() * 2, + "The memory pool needs at least space for 2 `UarteDMAPoolNode`s" ); - UARTEDMAPool::grow(dma_pool_memory); + UarteDMAPool::grow(dma_pool_memory); let mut rx = UarteRX::::new(timer); rx.enable_interrupts(); @@ -421,19 +421,19 @@ pub const UARTE_DMA_SIZE: usize = 255; // The reason to have a POOL gate is that we don't want the POOL // to cause memory OH if not used by the application -/// Each node in the `UARTEDMAPool` consists of this struct. -pub struct UARTEDMAPoolNode { +/// Each node in the `UarteDMAPool` consists of this struct. +pub struct UarteDMAPoolNode { len: u8, buf: MaybeUninit<[u8; UARTE_DMA_SIZE]>, } -impl core::fmt::Debug for UARTEDMAPoolNode { +impl core::fmt::Debug for UarteDMAPoolNode { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{:?}", self.read()) } } -impl UARTEDMAPoolNode { +impl UarteDMAPoolNode { /// Creates a new node for the UARTE DMA pub fn new() -> Self { Self { @@ -490,13 +490,13 @@ impl UARTEDMAPoolNode { pool!( #[allow(non_upper_case_globals)] - UARTEDMAPool: UARTEDMAPoolNode + UarteDMAPool: UarteDMAPoolNode ); /// UARTE RX driver, used in interrupt driven contexts /// `I` is the timer instance pub struct UarteRX { - rxq: Queue, U2>, // double buffering of DMA chunks + rxq: Queue, U2>, // double buffering of DMA chunks timer: Timer, // Timer for handling timeouts _marker: core::marker::PhantomData, } @@ -507,8 +507,8 @@ pub enum RXError { /// Out of memory error, global pool is depleted /// /// Potential causes: - /// 1. User code is saving the `Box` (and not dropping them) - /// 2. User code running `mem::forget` on the `Box` + /// 1. User code is saving the `Box` (and not dropping them) + /// 2. User code running `mem::forget` on the `Box` /// 3. The pool is too small for the use case OOM, } @@ -565,10 +565,10 @@ where // unique within the driver let uarte = unsafe { &*T::ptr() }; - // This operation is fast as `UARTEDMAPoolNode::new()` does not zero the internal buffer - let b = UARTEDMAPool::alloc() + // This operation is fast as `UarteDMAPoolNode::new()` does not zero the internal buffer + let b = UarteDMAPool::alloc() .ok_or(RXError::OOM)? - .init(UARTEDMAPoolNode::new()); + .init(UarteDMAPoolNode::new()); compiler_fence(SeqCst); @@ -609,10 +609,10 @@ where /// handler/task. /// /// Will return: - /// 1. `Ok(Some(Box))` if data was received + /// 1. `Ok(Some(Box))` if data was received /// 2. `Ok(None)` if there was no data, i.e. UARTE interrupt was due to other events /// 3. `Err(RXError::OOM)` if the memory pool was depleted, see `RXError` for mitigations - pub fn process_interrupt(&mut self) -> Result>, RXError> { + pub fn process_interrupt(&mut self) -> Result>, RXError> { // This operation is safe due to type-state programming guaranteeing that the RX and TX are // unique within the driver let uarte = unsafe { &*T::ptr() }; @@ -678,20 +678,20 @@ where /// S is the queue length, can be U3, U4 etc. pub struct UarteTX where - S: ArrayLength>, + S: ArrayLength>, { - txc: Consumer<'static, Box, S>, // chunks to transmit - current: Option>, + txc: Consumer<'static, Box, S>, // chunks to transmit + current: Option>, _marker: core::marker::PhantomData, } impl UarteTX where T: Instance, - S: ArrayLength>, + S: ArrayLength>, { /// Construct new UARTE TX, hidden from users - used internally - fn new(txc: Consumer<'static, Box, S>) -> Self { + fn new(txc: Consumer<'static, Box, S>) -> Self { Self { txc, current: None, @@ -709,7 +709,7 @@ where } /// Sets up the UARTE to send DMA chunk - fn start_write(&mut self, b: Box) { + fn start_write(&mut self, b: Box) { // This operation is safe due to type-state programming guaranteeing that the RX and TX are // unique within the driver let uarte = unsafe { &*T::ptr() }; From 8c760727ee45b7c7c90b31d5c4e916d9aeedf542 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Sun, 11 Aug 2019 17:38:19 +0200 Subject: [PATCH 26/44] Removed POOL flag The LTO removes the pool when not used under release builds --- examples/rtfm-uarte-interrupts/Cargo.toml | 2 +- nrf52-hal-common/Cargo.toml | 1 - nrf52-hal-common/src/uarte.rs | 8 -------- nrf52810-hal/Cargo.toml | 3 +-- nrf52832-hal/Cargo.toml | 5 ++--- nrf52840-hal/Cargo.toml | 3 +-- 6 files changed, 5 insertions(+), 17 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/Cargo.toml b/examples/rtfm-uarte-interrupts/Cargo.toml index 00d6132d..0fb256dd 100644 --- a/examples/rtfm-uarte-interrupts/Cargo.toml +++ b/examples/rtfm-uarte-interrupts/Cargo.toml @@ -19,7 +19,7 @@ optional = true version = "0.8.0" path = "../../nrf52832-hal" optional = true -features = ["rt", "xxAB-package", "POOL"] +features = ["rt", "xxAB-package"] [dependencies.nrf52840-hal] version = "0.8.0" diff --git a/nrf52-hal-common/Cargo.toml b/nrf52-hal-common/Cargo.toml index e2e8a10a..4ecc47be 100644 --- a/nrf52-hal-common/Cargo.toml +++ b/nrf52-hal-common/Cargo.toml @@ -61,7 +61,6 @@ default = ["52832"] 52832 = ["nrf52832-pac"] 52840 = ["nrf52840-pac"] 9160 = ["nrf9160-pac"] -POOL = [] UARTE_DMA_SIZE_4 = [] UARTE_DMA_SIZE_8 = [] UARTE_DMA_SIZE_16 = [] diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index cdaf716a..713b9911 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -413,14 +413,6 @@ pub const UARTE_DMA_SIZE: usize = 255; // a local crate with the user defined UARTE_DMA_SIZE constant. // What would you prefer? -// The DMA implementation shuld be hidden behind a feature POOL -// This likely requires a mod {} around the related code -// or the non-ergonomic repetition of the gate. -// Is there a better solution? -// -// The reason to have a POOL gate is that we don't want the POOL -// to cause memory OH if not used by the application - /// Each node in the `UarteDMAPool` consists of this struct. pub struct UarteDMAPoolNode { len: u8, diff --git a/nrf52810-hal/Cargo.toml b/nrf52810-hal/Cargo.toml index 4dad9a0f..31f38693 100644 --- a/nrf52810-hal/Cargo.toml +++ b/nrf52810-hal/Cargo.toml @@ -41,8 +41,7 @@ version = "0.2.1" [features] doc = [] rt = ["nrf52810-pac/rt"] -default = ["rt", "POOL"] -POOL = ["nrf52-hal-common/POOL"] +default = ["rt"] UARTE_DMA_SIZE_4 = ["nrf52-hal-common/UARTE_DMA_SIZE_4"] UARTE_DMA_SIZE_8 = ["nrf52-hal-common/UARTE_DMA_SIZE_8"] UARTE_DMA_SIZE_16 = ["nrf52-hal-common/UARTE_DMA_SIZE_16"] diff --git a/nrf52832-hal/Cargo.toml b/nrf52832-hal/Cargo.toml index 02d9b19c..2ba5846b 100644 --- a/nrf52832-hal/Cargo.toml +++ b/nrf52832-hal/Cargo.toml @@ -42,7 +42,6 @@ doc = [] rt = ["nrf52832-pac/rt"] xxAA-package = [] xxAB-package = [] -POOL = ["nrf52-hal-common/POOL"] UARTE_DMA_SIZE_4 = ["nrf52-hal-common/UARTE_DMA_SIZE_4"] UARTE_DMA_SIZE_8 = ["nrf52-hal-common/UARTE_DMA_SIZE_8"] UARTE_DMA_SIZE_16 = ["nrf52-hal-common/UARTE_DMA_SIZE_16"] @@ -54,5 +53,5 @@ UARTE_DMA_SIZE_255 = ["nrf52-hal-common/UARTE_DMA_SIZE_255"] # Note: We use the xxAB package because it has the least amount of available resources. # However, most users will want to use the xxAA package. -# If disabling default features, "POOL" and "DMA_SIZE_XX" should be manually set. -default = ["rt", "xxAB-package", "POOL"] +# If disabling default features, "DMA_SIZE_XX" should be manually set. +default = ["rt", "xxAB-package"] diff --git a/nrf52840-hal/Cargo.toml b/nrf52840-hal/Cargo.toml index 4a57ff40..203b7efc 100644 --- a/nrf52840-hal/Cargo.toml +++ b/nrf52840-hal/Cargo.toml @@ -42,8 +42,7 @@ version = "0.2.1" [features] doc = [] rt = ["nrf52840-pac/rt"] -default = ["rt", "POOL"] -POOL = ["nrf52-hal-common/POOL"] +default = ["rt"] UARTE_DMA_SIZE_4 = ["nrf52-hal-common/UARTE_DMA_SIZE_4"] UARTE_DMA_SIZE_8 = ["nrf52-hal-common/UARTE_DMA_SIZE_8"] UARTE_DMA_SIZE_16 = ["nrf52-hal-common/UARTE_DMA_SIZE_16"] From 5dd0147e2ece758d38ea9f54c741dfc514f37a34 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Sun, 11 Aug 2019 18:10:01 +0200 Subject: [PATCH 27/44] All interrupt driven code in its own module, this should fix nRF9160 issue until heapless is updated --- examples/rtfm-uarte-interrupts/src/main.rs | 9 +- nrf52-hal-common/src/lib.rs | 2 +- nrf52-hal-common/src/uarte.rs | 711 +++++++++++---------- 3 files changed, 375 insertions(+), 347 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index 9e0d2b3b..362274db 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -11,8 +11,13 @@ use nrf52832_hal as hal; use hal::gpio::{p0, Level}; use hal::target::{interrupt, TIMER0 as TIM0, UARTE0}; use hal::timer::*; -use hal::{uarte, Uarte}; -use hal::{RXError, UarteDMAPool, UarteDMAPoolNode, UarteRX, UarteTX}; +use hal::{ + uarte::{ + self, + interrupt_driven::{RXError, UarteDMAPool, UarteDMAPoolNode, UarteRX, UarteTX}, + }, + Uarte, +}; use heapless::{ consts::U3, diff --git a/nrf52-hal-common/src/lib.rs b/nrf52-hal-common/src/lib.rs index 819cda71..1c032616 100644 --- a/nrf52-hal-common/src/lib.rs +++ b/nrf52-hal-common/src/lib.rs @@ -91,4 +91,4 @@ pub use crate::saadc::Saadc; pub use crate::spim::Spim; pub use crate::timer::Timer; pub use crate::twim::Twim; -pub use crate::uarte::{RXError, Uarte, UarteDMAPool, UarteDMAPoolNode, UarteRX, UarteTX}; +pub use crate::uarte::Uarte; diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 713b9911..d28e7530 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -5,7 +5,6 @@ //! - nrf52832: Section 35 //! - nrf52840: Section 6.34 use core::fmt; -use core::mem::MaybeUninit; use core::ops::Deref; use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; @@ -20,16 +19,15 @@ use crate::prelude::*; use crate::target_constants::EASY_DMA_SIZE; use crate::timer::{self, Timer}; -use embedded_hal::timer::Cancel; use heapless::{ - consts::*, - pool, pool::singleton::{Box, Pool}, - spsc::{Consumer, Queue}, + spsc::Consumer, ArrayLength, }; +use interrupt_driven::*; + // Re-export SVD variants to allow user to directly set values pub use crate::target::uarte0::{baudrate::BAUDRATEW as Baudrate, config::PARITYW as Parity}; @@ -344,6 +342,7 @@ where /// /// Note: The act of splitting might not be needed on the nRF52 chips, as they map to the same /// interrupt in the end. Kept as a split for now, but might be merged in the future. + #[cfg(not(feature = "9160"))] pub fn split( self, txc: Consumer<'static, Box, S>, @@ -360,411 +359,435 @@ where ); UarteDMAPool::grow(dma_pool_memory); - let mut rx = UarteRX::::new(timer); - rx.enable_interrupts(); - rx.prepare_read().unwrap(); - rx.start_read(); - + let rx = UarteRX::::new(timer); let tx = UarteTX::::new(txc); - tx.enable_interrupts(); (rx, tx) } } -/// DMA block size -/// Defaults to UARTE_DMA_SIZE = 16 if not explicitly set -#[cfg(not(any( - feature = "UARTE_DMA_SIZE_4", - feature = "UARTE_DMA_SIZE_8", - feature = "UARTE_DMA_SIZE_16", - feature = "UARTE_DMA_SIZE_32", - feature = "UARTE_DMA_SIZE_64", - feature = "UARTE_DMA_SIZE_128", - feature = "UARTE_DMA_SIZE_256" -)))] -pub const UARTE_DMA_SIZE: usize = 16; - -#[cfg(feature = "UARTE_DMA_SIZE_4")] -pub const UARTE_DMA_SIZE: usize = 4; - -#[cfg(feature = "UARTE_DMA_SIZE_8")] -pub const UARTE_DMA_SIZE: usize = 8; - -#[cfg(feature = "UARTE_DMA_SIZE_16")] -pub const UARTE_DMA_SIZE: usize = 16; - -#[cfg(feature = "UARTE_DMA_SIZE_32")] -pub const UARTE_DMA_SIZE: usize = 32; - -#[cfg(feature = "UARTE_DMA_SIZE_64")] -pub const UARTE_DMA_SIZE: usize = 64; - -#[cfg(feature = "UARTE_DMA_SIZE_128")] -pub const UARTE_DMA_SIZE: usize = 128; - -// Currently causes internal OOM, needs fixing -// Maximum DMA size is 255 of the UARTE peripheral, see `MAXCNT` for details -#[cfg(feature = "UARTE_DMA_SIZE_255")] -pub const UARTE_DMA_SIZE: usize = 255; - -// An alternative solution to the above is to define the UARTE_DMA_SIZE -// in a separate (default) crate, which can be overridden -// by a patch in the user Cargo.toml, pointing to -// a local crate with the user defined UARTE_DMA_SIZE constant. -// What would you prefer? - -/// Each node in the `UarteDMAPool` consists of this struct. -pub struct UarteDMAPoolNode { - len: u8, - buf: MaybeUninit<[u8; UARTE_DMA_SIZE]>, -} - -impl core::fmt::Debug for UarteDMAPoolNode { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{:?}", self.read()) +/// An interrupt driven implementation of the UARTE peripheral +#[cfg(not(feature = "9160"))] +pub mod interrupt_driven { + use core::mem::MaybeUninit; + use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; + + use crate::timer::{self, Timer}; + use embedded_hal::timer::{Cancel, CountDown}; + + use heapless::{ + consts::*, + pool, + pool::singleton::{Box, Pool}, + spsc::{Consumer, Queue}, + ArrayLength, + }; + + use crate::uarte; + + /// DMA block size + /// Defaults to UARTE_DMA_SIZE = 16 if not explicitly set + #[cfg(not(any( + feature = "UARTE_DMA_SIZE_4", + feature = "UARTE_DMA_SIZE_8", + feature = "UARTE_DMA_SIZE_16", + feature = "UARTE_DMA_SIZE_32", + feature = "UARTE_DMA_SIZE_64", + feature = "UARTE_DMA_SIZE_128", + feature = "UARTE_DMA_SIZE_256" + )))] + pub const UARTE_DMA_SIZE: usize = 16; + + #[cfg(feature = "UARTE_DMA_SIZE_4")] + pub const UARTE_DMA_SIZE: usize = 4; + + #[cfg(feature = "UARTE_DMA_SIZE_8")] + pub const UARTE_DMA_SIZE: usize = 8; + + #[cfg(feature = "UARTE_DMA_SIZE_16")] + pub const UARTE_DMA_SIZE: usize = 16; + + #[cfg(feature = "UARTE_DMA_SIZE_32")] + pub const UARTE_DMA_SIZE: usize = 32; + + #[cfg(feature = "UARTE_DMA_SIZE_64")] + pub const UARTE_DMA_SIZE: usize = 64; + + #[cfg(feature = "UARTE_DMA_SIZE_128")] + pub const UARTE_DMA_SIZE: usize = 128; + + // Currently causes internal OOM, needs fixing + // Maximum DMA size is 255 of the UARTE peripheral, see `MAXCNT` for details + #[cfg(feature = "UARTE_DMA_SIZE_255")] + pub const UARTE_DMA_SIZE: usize = 255; + + // An alternative solution to the above is to define the UARTE_DMA_SIZE + // in a separate (default) crate, which can be overridden + // by a patch in the user Cargo.toml, pointing to + // a local crate with the user defined UARTE_DMA_SIZE constant. + // What would you prefer? + + /// Each node in the `UarteDMAPool` consists of this struct. + pub struct UarteDMAPoolNode { + len: u8, + buf: MaybeUninit<[u8; UARTE_DMA_SIZE]>, } -} -impl UarteDMAPoolNode { - /// Creates a new node for the UARTE DMA - pub fn new() -> Self { - Self { - len: 0, - buf: MaybeUninit::uninit(), + impl core::fmt::Debug for UarteDMAPoolNode { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self.read()) } } - /// Used to write data into the node, and returns how many bytes were written from `buf`. - pub fn write(&mut self, buf: &[u8]) -> usize { - if buf.len() > UARTE_DMA_SIZE { - self.len = UARTE_DMA_SIZE as u8; - } else { - self.len = buf.len() as u8; + impl UarteDMAPoolNode { + /// Creates a new node for the UARTE DMA + pub fn new() -> Self { + Self { + len: 0, + buf: MaybeUninit::uninit(), + } } - // Used to write data into the `MaybeUninit`, safe based on the size check above - unsafe { - core::ptr::copy_nonoverlapping( - buf.as_ptr(), - self.buf.as_mut_ptr() as *mut _, - self.len as usize, - ); + /// Used to write data into the node, and returns how many bytes were written from `buf`. + pub fn write(&mut self, buf: &[u8]) -> usize { + if buf.len() > UARTE_DMA_SIZE { + self.len = UARTE_DMA_SIZE as u8; + } else { + self.len = buf.len() as u8; + } + + // Used to write data into the `MaybeUninit`, safe based on the size check above + unsafe { + core::ptr::copy_nonoverlapping( + buf.as_ptr(), + self.buf.as_mut_ptr() as *mut _, + self.len as usize, + ); + } + + return self.len as usize; } - return self.len as usize; - } + /// Returns a readable slice which maps to the buffers internal data + pub fn read(&self) -> &[u8] { + // Safe as it uses the internal length of valid data + unsafe { core::slice::from_raw_parts(self.buf.as_ptr() as *const _, self.len as usize) } + } - /// Returns a readable slice which maps to the buffers internal data - pub fn read(&self) -> &[u8] { - // Safe as it uses the internal length of valid data - unsafe { core::slice::from_raw_parts(self.buf.as_ptr() as *const _, self.len as usize) } - } + /// Reads how many bytes are available + pub fn len(&self) -> usize { + self.len as usize + } - /// Reads how many bytes are available - pub fn len(&self) -> usize { - self.len as usize - } + /// This function is unsafe as it must be used in conjuction with `buffer_address` to write and + /// set the correct number of bytes from a DMA transaction + unsafe fn set_len_from_dma(&mut self, len: u8) { + self.len = len; + } - /// This function is unsafe as it must be used in conjuction with `buffer_address` to write and - /// set the correct number of bytes from a DMA transaction - unsafe fn set_len_from_dma(&mut self, len: u8) { - self.len = len; - } + unsafe fn buffer_address_for_dma(&self) -> u32 { + self.buf.as_ptr() as u32 + } - unsafe fn buffer_address_for_dma(&self) -> u32 { - self.buf.as_ptr() as u32 + const fn max_len(&self) -> usize { + UARTE_DMA_SIZE + } } - const fn max_len(&self) -> usize { - UARTE_DMA_SIZE + pool!( + #[allow(non_upper_case_globals)] + UarteDMAPool: UarteDMAPoolNode + ); + + /// UARTE RX driver, used in interrupt driven contexts + /// `I` is the timer instance + pub struct UarteRX { + rxq: Queue, U2>, // double buffering of DMA chunks + timer: Timer, // Timer for handling timeouts + _marker: core::marker::PhantomData, } -} -pool!( - #[allow(non_upper_case_globals)] - UarteDMAPool: UarteDMAPoolNode -); - -/// UARTE RX driver, used in interrupt driven contexts -/// `I` is the timer instance -pub struct UarteRX { - rxq: Queue, U2>, // double buffering of DMA chunks - timer: Timer, // Timer for handling timeouts - _marker: core::marker::PhantomData, -} - -/// Receive error in interrupt driven context -#[derive(Debug)] -pub enum RXError { - /// Out of memory error, global pool is depleted - /// - /// Potential causes: - /// 1. User code is saving the `Box` (and not dropping them) - /// 2. User code running `mem::forget` on the `Box` - /// 3. The pool is too small for the use case - OOM, -} - -impl UarteRX -where - T: Instance, - I: timer::Instance, -{ - /// Construct new UARTE RX, hidden from users - used internally - fn new(timer: Timer) -> Self { - Self { - rxq: Queue::new(), - timer, - _marker: core::marker::PhantomData, - } + /// Receive error in interrupt driven context + #[derive(Debug)] + pub enum RXError { + /// Out of memory error, global pool is depleted + /// + /// Potential causes: + /// 1. User code is saving the `Box` (and not dropping them) + /// 2. User code running `mem::forget` on the `Box` + /// 3. The pool is too small for the use case + OOM, } - /// Used internally to set up the proper interrupts - fn enable_interrupts(&mut self) { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver - let uarte = unsafe { &*T::ptr() }; - - uarte.inten.modify(|_, w| { - w.endrx() - .set_bit() - .rxstarted() - .set_bit() - .rxto() - .set_bit() - .rxdrdy() - .set_bit() - }); + impl UarteRX + where + T: uarte::Instance, + I: timer::Instance, + { + /// Construct new UARTE RX, hidden from users - used internally + pub(crate) fn new(timer: Timer) -> Self { + let mut rx = Self { + rxq: Queue::new(), + timer, + _marker: core::marker::PhantomData, + }; + + rx.enable_interrupts(); + rx.prepare_read().unwrap(); + rx.start_read(); + + rx + } - self.timer.enable_interrupt_generation(); - } + /// Used internally to set up the proper interrupts + fn enable_interrupts(&mut self) { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; + + uarte.inten.modify(|_, w| { + w.endrx() + .set_bit() + .rxstarted() + .set_bit() + .rxto() + .set_bit() + .rxdrdy() + .set_bit() + }); + + self.timer.enable_interrupt_generation(); + } - /// Start a UARTE read transaction - fn start_read(&mut self) { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver - let uarte = unsafe { &*T::ptr() }; + /// Start a UARTE read transaction + fn start_read(&mut self) { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; - // Start UARTE Receive transaction - uarte.tasks_startrx.write(|w| + // Start UARTE Receive transaction + uarte.tasks_startrx.write(|w| // `1` is a valid value to write to task registers. unsafe { w.bits(1) }); - } + } - /// Prepare UARTE read transaction - fn prepare_read(&mut self) -> Result<(), RXError> { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver - let uarte = unsafe { &*T::ptr() }; + /// Prepare UARTE read transaction + fn prepare_read(&mut self) -> Result<(), RXError> { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; - // This operation is fast as `UarteDMAPoolNode::new()` does not zero the internal buffer - let b = UarteDMAPool::alloc() - .ok_or(RXError::OOM)? - .init(UarteDMAPoolNode::new()); + // This operation is fast as `UarteDMAPoolNode::new()` does not zero the internal buffer + let b = UarteDMAPool::alloc() + .ok_or(RXError::OOM)? + .init(UarteDMAPoolNode::new()); - compiler_fence(SeqCst); + compiler_fence(SeqCst); - // setup start address - uarte - .rxd - .ptr - .write(|w| unsafe { w.ptr().bits(b.buffer_address_for_dma()) }); - // setup length - uarte - .rxd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(b.max_len() as _) }); + // setup start address + uarte + .rxd + .ptr + .write(|w| unsafe { w.ptr().bits(b.buffer_address_for_dma()) }); + // setup length + uarte + .rxd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(b.max_len() as _) }); - let r = self.rxq.enqueue(b); - debug_assert!(r.is_ok(), "Internal driver error, RX Queue Overflow"); + let r = self.rxq.enqueue(b); + debug_assert!(r.is_ok(), "Internal driver error, RX Queue Overflow"); - Ok(()) - } + Ok(()) + } - /// Timeout handling for the RX driver - Must be called from the corresponding TIMERx Interrupt - /// handler/task. - pub fn process_timeout_interrupt(&mut self) { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver - let uarte = unsafe { &*T::ptr() }; + /// Timeout handling for the RX driver - Must be called from the corresponding TIMERx Interrupt + /// handler/task. + pub fn process_timeout_interrupt(&mut self) { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; - // Reset the event, otherwise it will always read `1` from now on. - self.timer.clear_interrupt(); + // Reset the event, otherwise it will always read `1` from now on. + self.timer.clear_interrupt(); - // Stop UARTE Receive transaction to generate the Timeout Event - uarte.tasks_stoprx.write(|w| + // Stop UARTE Receive transaction to generate the Timeout Event + uarte.tasks_stoprx.write(|w| // `1` is a valid value to write to task registers. unsafe { w.bits(1) }); - } - - /// Main entry point for the RX driver - Must be called from the corresponding UARTE Interrupt - /// handler/task. - /// - /// Will return: - /// 1. `Ok(Some(Box))` if data was received - /// 2. `Ok(None)` if there was no data, i.e. UARTE interrupt was due to other events - /// 3. `Err(RXError::OOM)` if the memory pool was depleted, see `RXError` for mitigations - pub fn process_interrupt(&mut self) -> Result>, RXError> { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver - let uarte = unsafe { &*T::ptr() }; - - // Handles the byte timeout timer - if uarte.events_rxdrdy.read().bits() == 1 { - self.timer.cancel().unwrap(); // Never fails - self.timer.start(10_000_u32); // 10 ms timeout for now - - // Reset the event, otherwise it will always read `1` from now on. - uarte.events_rxdrdy.write(|w| w); } - if uarte.events_rxto.read().bits() == 1 { - // Tell UARTE to flush FIFO to DMA buffer - uarte.tasks_flushrx.write(|w| unsafe { w.bits(1) }); + /// Main entry point for the RX driver - Must be called from the corresponding UARTE Interrupt + /// handler/task. + /// + /// Will return: + /// 1. `Ok(Some(Box))` if data was received + /// 2. `Ok(None)` if there was no data, i.e. UARTE interrupt was due to other events + /// 3. `Err(RXError::OOM)` if the memory pool was depleted, see `RXError` for mitigations + pub fn process_interrupt(&mut self) -> Result>, RXError> { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; + + // Handles the byte timeout timer + if uarte.events_rxdrdy.read().bits() == 1 { + self.timer.cancel().unwrap(); // Never fails + self.timer.start(10_000_u32); // 10 ms timeout for now - // Reset the event, otherwise it will always read `1` from now on. - uarte.events_rxto.write(|w| w); - } + // Reset the event, otherwise it will always read `1` from now on. + uarte.events_rxdrdy.write(|w| w); + } - // check if dma rx transaction has started - if uarte.events_rxstarted.read().bits() == 1 { - // DMA transaction has started - self.prepare_read()?; + if uarte.events_rxto.read().bits() == 1 { + // Tell UARTE to flush FIFO to DMA buffer + uarte.tasks_flushrx.write(|w| unsafe { w.bits(1) }); - // Reset the event, otherwise it will always read `1` from now on. - uarte.events_rxstarted.write(|w| w); - } + // Reset the event, otherwise it will always read `1` from now on. + uarte.events_rxto.write(|w| w); + } - // check if dma transaction finished - if uarte.events_endrx.read().bits() == 1 { - self.timer.cancel().unwrap(); // Never fails - - // our transaction has finished - if let Some(mut ret_b) = self.rxq.dequeue() { - // Read the true number of bytes and set the correct length of the packet before - // returning it - let bytes_read = uarte.rxd.amount.read().bits() as u8; - unsafe { - // This operation is safe as `buffer_address_for_dma` has written `bytes_read` - // number of bytes into the node - ret_b.set_len_from_dma(bytes_read); - } + // check if dma rx transaction has started + if uarte.events_rxstarted.read().bits() == 1 { + // DMA transaction has started + self.prepare_read()?; // Reset the event, otherwise it will always read `1` from now on. - uarte.events_endrx.write(|w| w); + uarte.events_rxstarted.write(|w| w); + } - self.start_read(); + // check if dma transaction finished + if uarte.events_endrx.read().bits() == 1 { + self.timer.cancel().unwrap(); // Never fails + + // our transaction has finished + if let Some(mut ret_b) = self.rxq.dequeue() { + // Read the true number of bytes and set the correct length of the packet before + // returning it + let bytes_read = uarte.rxd.amount.read().bits() as u8; + unsafe { + // This operation is safe as `buffer_address_for_dma` has written `bytes_read` + // number of bytes into the node + ret_b.set_len_from_dma(bytes_read); + } - return Ok(Some(ret_b)); // ok to return, rx started will be caught later - } else { - debug_assert!(false, "Internal driver error, RX Queue Underflow"); - } - } + // Reset the event, otherwise it will always read `1` from now on. + uarte.events_endrx.write(|w| w); - // the interrupt was not RXSTARTED or ENDRX, so no action - Ok(None) - } -} + self.start_read(); -/// UARTE TX driver, used in interrupt driven contexts -/// S is the queue length, can be U3, U4 etc. -pub struct UarteTX -where - S: ArrayLength>, -{ - txc: Consumer<'static, Box, S>, // chunks to transmit - current: Option>, - _marker: core::marker::PhantomData, -} + return Ok(Some(ret_b)); // ok to return, rx started will be caught later + } else { + debug_assert!(false, "Internal driver error, RX Queue Underflow"); + } + } -impl UarteTX -where - T: Instance, - S: ArrayLength>, -{ - /// Construct new UARTE TX, hidden from users - used internally - fn new(txc: Consumer<'static, Box, S>) -> Self { - Self { - txc, - current: None, - _marker: core::marker::PhantomData, + // the interrupt was not RXSTARTED or ENDRX, so no action + Ok(None) } } - /// Used internally to set up the proper interrupts - fn enable_interrupts(&self) { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver - let uarte = unsafe { &*T::ptr() }; - - uarte.inten.modify(|_, w| w.endtx().set_bit()); + /// UARTE TX driver, used in interrupt driven contexts + /// S is the queue length, can be U3, U4 etc. + pub struct UarteTX + where + S: ArrayLength>, + { + txc: Consumer<'static, Box, S>, // chunks to transmit + current: Option>, + _marker: core::marker::PhantomData, } - /// Sets up the UARTE to send DMA chunk - fn start_write(&mut self, b: Box) { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver - let uarte = unsafe { &*T::ptr() }; - - // Only send if the DMA chunk has data, else drop the `Box` - if b.len() > 0 { - compiler_fence(SeqCst); + impl UarteTX + where + T: uarte::Instance, + S: ArrayLength>, + { + /// Construct new UARTE TX, hidden from users - used internally + pub(crate) fn new(txc: Consumer<'static, Box, S>) -> Self { + let mut tx = Self { + txc, + current: None, + _marker: core::marker::PhantomData, + }; + + tx.enable_interrupts(); + tx + } - // setup start address - uarte - .txd - .ptr - .write(|w| unsafe { w.ptr().bits(b.buffer_address_for_dma()) }); + /// Used internally to set up the proper interrupts + fn enable_interrupts(&mut self) { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; - // setup length - uarte - .txd - .maxcnt - .write(|w| unsafe { w.maxcnt().bits(b.len() as _) }); - - // Start UARTE transmit transaction - uarte.tasks_starttx.write(|w| unsafe { w.bits(1) }); - self.current = Some(b); // drops the previous current package + uarte.inten.modify(|_, w| w.endtx().set_bit()); } - } - /// Main entry point for the TX driver - Must be called from the corresponding UARTE Interrupt - /// handler/task. - pub fn process_interrupt(&mut self) { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver - let uarte = unsafe { &*T::ptr() }; - - // ENDTX event? (DMA transaction finished) - if uarte.events_endtx.read().bits() == 1 { - // our transaction has finished - match self.txc.dequeue() { - None => { - // a ENDTX without an started transaction is an error - debug_assert!( - self.current.is_some(), - "Internal error, ENDTX without current transaction." - ); - - // we don't have any more to send, so drop the current buffer - self.current = None; - } - Some(b) => { - self.start_write(b); - } + /// Sets up the UARTE to send DMA chunk + fn start_write(&mut self, b: Box) { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; + + // Only send if the DMA chunk has data, else drop the `Box` + if b.len() > 0 { + compiler_fence(SeqCst); + + // setup start address + uarte + .txd + .ptr + .write(|w| unsafe { w.ptr().bits(b.buffer_address_for_dma()) }); + + // setup length + uarte + .txd + .maxcnt + .write(|w| unsafe { w.maxcnt().bits(b.len() as _) }); + + // Start UARTE transmit transaction + uarte.tasks_starttx.write(|w| unsafe { w.bits(1) }); + self.current = Some(b); // drops the previous current package } + } - // Reset the event, otherwise it will always read `1` from now on. - uarte.events_endtx.write(|w| w); - } else { - if self.current.is_none() { + /// Main entry point for the TX driver - Must be called from the corresponding UARTE Interrupt + /// handler/task. + pub fn process_interrupt(&mut self) { + // This operation is safe due to type-state programming guaranteeing that the RX and TX are + // unique within the driver + let uarte = unsafe { &*T::ptr() }; + + // ENDTX event? (DMA transaction finished) + if uarte.events_endtx.read().bits() == 1 { + // our transaction has finished match self.txc.dequeue() { - Some(b) => - // we were idle, so start a new transaction - { - self.start_write(b) + None => { + // a ENDTX without an started transaction is an error + debug_assert!( + self.current.is_some(), + "Internal error, ENDTX without current transaction." + ); + + // we don't have any more to send, so drop the current buffer + self.current = None; + } + Some(b) => { + self.start_write(b); + } + } + + // Reset the event, otherwise it will always read `1` from now on. + uarte.events_endtx.write(|w| w); + } else { + if self.current.is_none() { + match self.txc.dequeue() { + Some(b) => + // we were idle, so start a new transaction + { + self.start_write(b) + } + None => (), } - None => (), } } } From f84e5ec3d5a451b906642893cf4e8b193900d707 Mon Sep 17 00:00:00 2001 From: Jacob Rosenthal Date: Mon, 12 Aug 2019 15:18:38 -0700 Subject: [PATCH 28/44] few more fixes --- examples/rtfm-uarte-interrupts/Cargo.toml | 7 +++++-- examples/rtfm-uarte-interrupts/src/main.rs | 9 ++++++++- nrf52-hal-common/src/uarte.rs | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/Cargo.toml b/examples/rtfm-uarte-interrupts/Cargo.toml index 0fb256dd..c6a7ade6 100644 --- a/examples/rtfm-uarte-interrupts/Cargo.toml +++ b/examples/rtfm-uarte-interrupts/Cargo.toml @@ -1,7 +1,8 @@ [package] name = "rtfm-uarte-interrupts" version = "0.1.0" -authors = ["James Munns "] +authors = ["Per Lindgren ", + "Emil Fresk "] edition = "2018" [dependencies] @@ -14,17 +15,19 @@ heapless = ">= 0.5.0" version = "0.8.0" path = "../../nrf52810-hal" optional = true +features = ["UARTE_DMA_SIZE_16"] [dependencies.nrf52832-hal] version = "0.8.0" path = "../../nrf52832-hal" optional = true -features = ["rt", "xxAB-package"] +features = ["xxAB-package", "UARTE_DMA_SIZE_16"] [dependencies.nrf52840-hal] version = "0.8.0" path = "../../nrf52840-hal" optional = true +features = ["UARTE_DMA_SIZE_16"] [features] 52810 = ["nrf52810-hal"] diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index 362274db..8ba19485 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -6,8 +6,15 @@ extern crate panic_semihosting; use cortex_m_semihosting::hprintln; +#[cfg(feature = "52810")] +use nrf52810_hal as hal; + +#[cfg(feature = "52832")] use nrf52832_hal as hal; +#[cfg(feature = "52840")] +use nrf52840_hal as hal; + use hal::gpio::{p0, Level}; use hal::target::{interrupt, TIMER0 as TIM0, UARTE0}; use hal::timer::*; @@ -48,10 +55,10 @@ const APP: () = { let port0 = p0::Parts::new(device.P0); - //adafruit nrf52 le let uarte0 = Uarte::new( device.UARTE0, uarte::Pins { + // adafruit-nrf52-bluefruit-le, adafruit_nrf52pro, nRF52-DK, nRF52840-DK txd: port0.p0_06.into_push_pull_output(Level::High).degrade(), rxd: port0.p0_08.into_floating_input().degrade(), // Use the following for DWM-1001 dev board diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index d28e7530..a9ff526c 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -393,7 +393,7 @@ pub mod interrupt_driven { feature = "UARTE_DMA_SIZE_32", feature = "UARTE_DMA_SIZE_64", feature = "UARTE_DMA_SIZE_128", - feature = "UARTE_DMA_SIZE_256" + feature = "UARTE_DMA_SIZE_255" )))] pub const UARTE_DMA_SIZE: usize = 16; From 759f67693a81e8e8b5b04a9dd82b1572e0abfaf4 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Tue, 13 Aug 2019 13:19:13 +0200 Subject: [PATCH 29/44] Implemented fmt::write for UarteDMAPoolNode --- nrf52-hal-common/src/uarte.rs | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index a9ff526c..87260e5c 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -335,15 +335,11 @@ where self.0 } - /// Splits the UARTE into a transmitter and receiver for interrupt driven use + /// Splits the UARTE into an interrupt driven transmitter and receiver /// - /// In needs a `Queue` to place received DMA chunks, and a `Consumer` to place DMA chunks to - /// send - /// - /// Note: The act of splitting might not be needed on the nRF52 chips, as they map to the same - /// interrupt in the end. Kept as a split for now, but might be merged in the future. - #[cfg(not(feature = "9160"))] - pub fn split( + /// In needs a `Consumer` to place DMA chunks to send, a `Timer` for checking byte timeouts, + /// and a `&'static mut [u8]` memory block to use. + pub fn into_interrupt_driven( self, txc: Consumer<'static, Box, S>, timer: Timer, @@ -366,8 +362,8 @@ where } /// An interrupt driven implementation of the UARTE peripheral -#[cfg(not(feature = "9160"))] pub mod interrupt_driven { + use core::fmt; use core::mem::MaybeUninit; use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; @@ -432,13 +428,26 @@ pub mod interrupt_driven { buf: MaybeUninit<[u8; UARTE_DMA_SIZE]>, } - impl core::fmt::Debug for UarteDMAPoolNode { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + impl fmt::Debug for UarteDMAPoolNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self.read()) } } + impl fmt::Write for UarteDMAPoolNode { + fn write_str(&mut self, s: &str) -> fmt::Result { + if s.len() > Self::MAX_SIZE { + Err(fmt::Error) + } else { + self.write_checked(s.as_bytes()); + Ok(()) + } + } + } + impl UarteDMAPoolNode { + pub const MAX_SIZE: usize = UARTE_DMA_SIZE; + /// Creates a new node for the UARTE DMA pub fn new() -> Self { Self { @@ -448,7 +457,7 @@ pub mod interrupt_driven { } /// Used to write data into the node, and returns how many bytes were written from `buf`. - pub fn write(&mut self, buf: &[u8]) -> usize { + pub fn write_checked(&mut self, buf: &[u8]) -> usize { if buf.len() > UARTE_DMA_SIZE { self.len = UARTE_DMA_SIZE as u8; } else { From b243ac54dc759b31acf403c08fe2f992cc74c681 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Tue, 13 Aug 2019 13:20:56 +0200 Subject: [PATCH 30/44] split renamed to into_interrupt_driven to convey meaning --- examples/rtfm-uarte-interrupts/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index 8ba19485..67413a02 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -73,7 +73,7 @@ const APP: () = { let timer = Timer::new(device.TIMER0); let (txp, txc) = TX_RB.split(); - let (rx, tx) = uarte0.split(txc, timer, MEMORY); + let (rx, tx) = uarte0.into_interrupt_driven(txc, timer, MEMORY); init::LateResources { RX: rx, From 9c9fbb2e0ee0971c909dbbd319de1c607b69fc13 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Tue, 13 Aug 2019 15:01:18 +0200 Subject: [PATCH 31/44] Fixed UarteDMAPoolNode::max_len() --- nrf52-hal-common/src/uarte.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 87260e5c..3f8cff2d 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -368,6 +368,7 @@ pub mod interrupt_driven { use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; use crate::timer::{self, Timer}; + use crate::uarte; use embedded_hal::timer::{Cancel, CountDown}; use heapless::{ @@ -378,8 +379,6 @@ pub mod interrupt_driven { ArrayLength, }; - use crate::uarte; - /// DMA block size /// Defaults to UARTE_DMA_SIZE = 16 if not explicitly set #[cfg(not(any( @@ -497,7 +496,7 @@ pub mod interrupt_driven { self.buf.as_ptr() as u32 } - const fn max_len(&self) -> usize { + const fn max_len() -> usize { UARTE_DMA_SIZE } } @@ -601,7 +600,7 @@ pub mod interrupt_driven { uarte .rxd .maxcnt - .write(|w| unsafe { w.maxcnt().bits(b.max_len() as _) }); + .write(|w| unsafe { w.maxcnt().bits(UarteDMAPoolNode::max_len() as _) }); let r = self.rxq.enqueue(b); debug_assert!(r.is_ok(), "Internal driver error, RX Queue Overflow"); From 5dd16d659c0d5a76d47ef4a9ed50d06c80f6489b Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Tue, 13 Aug 2019 15:02:20 +0200 Subject: [PATCH 32/44] Fixed pub for max_len --- nrf52-hal-common/src/uarte.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 3f8cff2d..5f5ec1eb 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -496,7 +496,7 @@ pub mod interrupt_driven { self.buf.as_ptr() as u32 } - const fn max_len() -> usize { + pub const fn max_len() -> usize { UARTE_DMA_SIZE } } From 63a58068a4ed3481ee4e7223ed813c55906aa4e9 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Wed, 14 Aug 2019 14:35:33 +0200 Subject: [PATCH 33/44] Testing a direct write interface --- examples/rtfm-uarte-interrupts/src/main.rs | 2 +- nrf52-hal-common/src/uarte.rs | 78 ++++++++++++++++------ 2 files changed, 57 insertions(+), 23 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index 67413a02..6e2080a2 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -87,7 +87,7 @@ const APP: () = { fn printer(data: Box) { // enqueue a test message // let mut node = UarteDMAPoolNode::new(); - // node.write(&[95, 95, 95, 95]); + // node.write_slice(&[95, 95, 95, 95]); // let b = UarteDMAPool::alloc() // .unwrap() // .init(node); diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 5f5ec1eb..2bed0674 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -361,11 +361,16 @@ where } } -/// An interrupt driven implementation of the UARTE peripheral +/// An interrupt driven implementation of the UARTE peripheral. +/// +/// ## Example +/// +/// ``` +/// +/// ``` pub mod interrupt_driven { - use core::fmt; - use core::mem::MaybeUninit; use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; + use core::{fmt, mem, ptr, slice}; use crate::timer::{self, Timer}; use crate::uarte; @@ -421,10 +426,17 @@ pub mod interrupt_driven { // a local crate with the user defined UARTE_DMA_SIZE constant. // What would you prefer? + pool!( + /// Pool allocator for the DMA engine running the transfers, where each node in the + /// allocator is an `UarteDMAPoolNode` + #[allow(non_upper_case_globals)] + UarteDMAPool: UarteDMAPoolNode + ); + /// Each node in the `UarteDMAPool` consists of this struct. pub struct UarteDMAPoolNode { len: u8, - buf: MaybeUninit<[u8; UARTE_DMA_SIZE]>, + buf: mem::MaybeUninit<[u8; UARTE_DMA_SIZE]>, } impl fmt::Debug for UarteDMAPoolNode { @@ -438,34 +450,62 @@ pub mod interrupt_driven { if s.len() > Self::MAX_SIZE { Err(fmt::Error) } else { - self.write_checked(s.as_bytes()); + self.write_slice(s.as_bytes()); Ok(()) } } } impl UarteDMAPoolNode { + /// The maximum buffer size the node can hold pub const MAX_SIZE: usize = UARTE_DMA_SIZE; /// Creates a new node for the UARTE DMA - pub fn new() -> Self { + pub const fn new() -> Self { Self { len: 0, - buf: MaybeUninit::uninit(), + buf: mem::MaybeUninit::uninit(), + } + } + + /// Gives a `&mut [u8]` slice to write into with the maximum size, the `commit` method + /// must then be used to set the actual number of bytes written. + /// + /// Note that this function internally first zeros the node's buffer. + /// + /// ## Example + /// + /// ``` + /// + /// ``` + pub fn write(&mut self) -> &mut [u8] { + // Initialize memory with a safe value + self.buf = unsafe { mem::zeroed() }; + self.len = Self::MAX_SIZE as _; // Set to max so `commit` may shrink it if needed + + unsafe { slice::from_raw_parts_mut(self.buf.as_mut_ptr() as *mut _, Self::MAX_SIZE) } + } + + /// Used to shrink the current size of the slice in the node, mostly used in conjunction + /// with `write`. + pub fn commit(&mut self, shrink_to: usize) { + // Only shrinking is allowed to remain safe with the `MaybeUninit` + if shrink_to < self.len as _ { + self.len = shrink_to as _; } } /// Used to write data into the node, and returns how many bytes were written from `buf`. - pub fn write_checked(&mut self, buf: &[u8]) -> usize { - if buf.len() > UARTE_DMA_SIZE { - self.len = UARTE_DMA_SIZE as u8; + pub fn write_slice(&mut self, buf: &[u8]) -> usize { + if buf.len() > Self::MAX_SIZE { + self.len = Self::MAX_SIZE as u8; } else { self.len = buf.len() as u8; } // Used to write data into the `MaybeUninit`, safe based on the size check above unsafe { - core::ptr::copy_nonoverlapping( + ptr::copy_nonoverlapping( buf.as_ptr(), self.buf.as_mut_ptr() as *mut _, self.len as usize, @@ -478,7 +518,7 @@ pub mod interrupt_driven { /// Returns a readable slice which maps to the buffers internal data pub fn read(&self) -> &[u8] { // Safe as it uses the internal length of valid data - unsafe { core::slice::from_raw_parts(self.buf.as_ptr() as *const _, self.len as usize) } + unsafe { slice::from_raw_parts(self.buf.as_ptr() as *const _, self.len as usize) } } /// Reads how many bytes are available @@ -497,17 +537,11 @@ pub mod interrupt_driven { } pub const fn max_len() -> usize { - UARTE_DMA_SIZE + Self::MAX_SIZE } } - pool!( - #[allow(non_upper_case_globals)] - UarteDMAPool: UarteDMAPoolNode - ); - - /// UARTE RX driver, used in interrupt driven contexts - /// `I` is the timer instance + /// UARTE RX driver, used in interrupt driven contexts, where `I` is the timer instance. pub struct UarteRX { rxq: Queue, U2>, // double buffering of DMA chunks timer: Timer, // Timer for handling timeouts @@ -693,8 +727,8 @@ pub mod interrupt_driven { } } - /// UARTE TX driver, used in interrupt driven contexts - /// S is the queue length, can be U3, U4 etc. + /// UARTE TX driver, used in interrupt driven contexts, where `S` is the queue length, + /// can be `U3`, `U4` etc. pub struct UarteTX where S: ArrayLength>, From c7daa976fc3ad57104b23ae3fce7710c80e100ff Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Fri, 16 Aug 2019 15:58:12 +0200 Subject: [PATCH 34/44] Added transmission status to help in event based systems to load the tx queue --- nrf52-hal-common/src/uarte.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 2bed0674..70a62a29 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -738,6 +738,13 @@ pub mod interrupt_driven { _marker: core::marker::PhantomData, } + /// Transmission status in interrupt driven context + #[derive(Debug)] + pub enum TXStatus { + /// Status when a TX packet has been sent and another spot is available in the TX queue + TransmisionFinished, + } + impl UarteTX where T: uarte::Instance, @@ -794,7 +801,7 @@ pub mod interrupt_driven { /// Main entry point for the TX driver - Must be called from the corresponding UARTE Interrupt /// handler/task. - pub fn process_interrupt(&mut self) { + pub fn process_interrupt(&mut self) -> Option { // This operation is safe due to type-state programming guaranteeing that the RX and TX are // unique within the driver let uarte = unsafe { &*T::ptr() }; @@ -820,6 +827,8 @@ pub mod interrupt_driven { // Reset the event, otherwise it will always read `1` from now on. uarte.events_endtx.write(|w| w); + + Some(TXStatus::TransmisionFinished) } else { if self.current.is_none() { match self.txc.dequeue() { @@ -831,6 +840,8 @@ pub mod interrupt_driven { None => (), } } + + None } } } From 949bd385e92ae43f2f44855c31b8e6dcde49534e Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Fri, 16 Aug 2019 16:01:47 +0200 Subject: [PATCH 35/44] Fix spelling error --- nrf52-hal-common/src/uarte.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 70a62a29..6d178619 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -742,7 +742,7 @@ pub mod interrupt_driven { #[derive(Debug)] pub enum TXStatus { /// Status when a TX packet has been sent and another spot is available in the TX queue - TransmisionFinished, + TransmissionFinished, } impl UarteTX @@ -828,7 +828,7 @@ pub mod interrupt_driven { // Reset the event, otherwise it will always read `1` from now on. uarte.events_endtx.write(|w| w); - Some(TXStatus::TransmisionFinished) + Some(TXStatus::TransmissionFinished) } else { if self.current.is_none() { match self.txc.dequeue() { From 9b5130461b6ea0cd52e5850f4fc9690b205ee620 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Sun, 18 Aug 2019 12:06:12 +0200 Subject: [PATCH 36/44] Updated uarte example with write! --- examples/rtfm-uarte-interrupts/src/main.rs | 22 +++++++++++++--------- nrf52-hal-common/src/uarte.rs | 7 +++---- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index 6e2080a2..8b8da7ab 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -27,16 +27,22 @@ use hal::{ }; use heapless::{ - consts::U3, + consts, pool::singleton::Box, spsc::{Producer, Queue}, }; +// Needed for the write! example code +// use core::{fmt::Write, ops::DerefMut}; +// use heapless::pool::singleton::Pool; + use rtfm::app; const NR_PACKAGES: usize = 10; const DMA_MEM: usize = core::mem::size_of::() * NR_PACKAGES; -type TXQSize = U3; + +// Using power-of-2 constants is faster (see the crate heapless for details) +type TXQSize = consts::U4; #[app(device = crate::hal::target)] const APP: () = { @@ -86,15 +92,13 @@ const APP: () = { #[task(capacity = 2, resources = [PRODUCER])] fn printer(data: Box) { // enqueue a test message - // let mut node = UarteDMAPoolNode::new(); - // node.write_slice(&[95, 95, 95, 95]); - // let b = UarteDMAPool::alloc() - // .unwrap() - // .init(node); - // resources.PRODUCER.enqueue(b).unwrap(); + // let mut node = UarteDMAPool::alloc().unwrap().init(UarteDMAPoolNode::new()); + // write!(&mut node, "test").unwrap(); // Using the write! trait + // node.write_slice(&[95, 95, 95, 95]); // Using raw slice writing + // resources.PRODUCER.enqueue(node).unwrap(); // hprintln!("{:?}", &data).unwrap(); - // just do the buffer dance without copying + // Echo the buffer back without any changes or copying resources.PRODUCER.enqueue(data).unwrap(); rtfm::pend(interrupt::UARTE0_UART0); } diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 6d178619..ffd5ae9a 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -377,8 +377,7 @@ pub mod interrupt_driven { use embedded_hal::timer::{Cancel, CountDown}; use heapless::{ - consts::*, - pool, + consts, pool, pool::singleton::{Box, Pool}, spsc::{Consumer, Queue}, ArrayLength, @@ -543,8 +542,8 @@ pub mod interrupt_driven { /// UARTE RX driver, used in interrupt driven contexts, where `I` is the timer instance. pub struct UarteRX { - rxq: Queue, U2>, // double buffering of DMA chunks - timer: Timer, // Timer for handling timeouts + rxq: Queue, consts::U2>, // double buffering of DMA chunks + timer: Timer, // Timer for handling timeouts _marker: core::marker::PhantomData, } From 48827552c686545164a712712031152ed74dffb2 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Sun, 18 Aug 2019 12:13:17 +0200 Subject: [PATCH 37/44] More clear example --- examples/rtfm-uarte-interrupts/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rtfm-uarte-interrupts/src/main.rs b/examples/rtfm-uarte-interrupts/src/main.rs index 8b8da7ab..d360d0e9 100644 --- a/examples/rtfm-uarte-interrupts/src/main.rs +++ b/examples/rtfm-uarte-interrupts/src/main.rs @@ -33,7 +33,7 @@ use heapless::{ }; // Needed for the write! example code -// use core::{fmt::Write, ops::DerefMut}; +// use core::fmt::Write; // use heapless::pool::singleton::Pool; use rtfm::app; @@ -94,7 +94,7 @@ const APP: () = { // enqueue a test message // let mut node = UarteDMAPool::alloc().unwrap().init(UarteDMAPoolNode::new()); // write!(&mut node, "test").unwrap(); // Using the write! trait - // node.write_slice(&[95, 95, 95, 95]); // Using raw slice writing + // node.write_slice(&b"test"[..]); // Using raw slice writing // resources.PRODUCER.enqueue(node).unwrap(); // hprintln!("{:?}", &data).unwrap(); From 07ee0b17cf45fc40525a2eee2c9dc4c093b478ee Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Tue, 3 Sep 2019 11:22:04 +0200 Subject: [PATCH 38/44] Updated heapless for armv8 support --- nrf52-hal-common/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nrf52-hal-common/Cargo.toml b/nrf52-hal-common/Cargo.toml index 4ecc47be..c562995e 100644 --- a/nrf52-hal-common/Cargo.toml +++ b/nrf52-hal-common/Cargo.toml @@ -23,7 +23,7 @@ fpa = "0.1.0" rand_core = "0.4.0" [dependencies.heapless] -version = "0.5.0" +version = "0.5.1" [dependencies.void] default-features = false From 73f729261caa0d1b85213f5c7f990d6d0243b784 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Tue, 3 Sep 2019 11:29:02 +0200 Subject: [PATCH 39/44] Now using the optional NVIC API for enabling interrupts --- nrf52-hal-common/src/timer.rs | 9 --------- nrf52-hal-common/src/uarte.rs | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/nrf52-hal-common/src/timer.rs b/nrf52-hal-common/src/timer.rs index cfe0105f..4a9b71a3 100644 --- a/nrf52-hal-common/src/timer.rs +++ b/nrf52-hal-common/src/timer.rs @@ -55,15 +55,6 @@ where self.0.cc[1].read().bits() } - /// Enables an interrupt that is fired when the timer reaches the value that - /// is given as an argument to `start`. - pub(crate) fn enable_interrupt_generation(&mut self) { - // As of this writing, the timer code only uses - // `cc[0]`/`events_compare[0]`. If the code is extended to use other - // compare registers, the following needs to be adapted. - self.0.intenset.modify(|_, w| w.compare0().set()); - } - /// Clears the interrupt for this timer, external NVIC modification /// /// Enables an interrupt that is fired when the timer reaches the value that diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index ffd5ae9a..1671d8f4 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -596,7 +596,7 @@ pub mod interrupt_driven { .set_bit() }); - self.timer.enable_interrupt_generation(); + self.timer.enable_interrupt(None); } /// Start a UARTE read transaction From 9dee2249a8ef8e17463b443bd9908a57df541d69 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Tue, 3 Sep 2019 11:36:26 +0200 Subject: [PATCH 40/44] Fixed use of write_slice --- nrf52-hal-common/src/uarte.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 1671d8f4..44755462 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -435,7 +435,7 @@ pub mod interrupt_driven { /// Each node in the `UarteDMAPool` consists of this struct. pub struct UarteDMAPoolNode { len: u8, - buf: mem::MaybeUninit<[u8; UARTE_DMA_SIZE]>, + buf: [mem::MaybeUninit; UARTE_DMA_SIZE], } impl fmt::Debug for UarteDMAPoolNode { @@ -463,7 +463,7 @@ pub mod interrupt_driven { pub const fn new() -> Self { Self { len: 0, - buf: mem::MaybeUninit::uninit(), + buf: [mem::MaybeUninit::uninit(); UARTE_DMA_SIZE], } } @@ -495,23 +495,29 @@ pub mod interrupt_driven { } /// Used to write data into the node, and returns how many bytes were written from `buf`. + /// + /// If the node is already partially filled, this will continue filling the node. pub fn write_slice(&mut self, buf: &[u8]) -> usize { - if buf.len() > Self::MAX_SIZE { - self.len = Self::MAX_SIZE as u8; - } else { - self.len = buf.len() as u8; - } + let free = Self::MAX_SIZE - self.len as usize; + let new_size = buf.len(); + let count = if new_size > free { free } else { new_size }; // Used to write data into the `MaybeUninit`, safe based on the size check above unsafe { ptr::copy_nonoverlapping( buf.as_ptr(), - self.buf.as_mut_ptr() as *mut _, - self.len as usize, + self.buf.as_mut_ptr().offset(self.len as isize) as *mut u8, + count, ); } - return self.len as usize; + self.len = self.len + count as u8; + return count; + } + + /// Clear the node of all data making it empty + pub fn clear(&mut self) { + self.len = 0; } /// Returns a readable slice which maps to the buffers internal data From cac02d3c83935f826930201a0edb16234b0d81e9 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Tue, 3 Sep 2019 11:41:55 +0200 Subject: [PATCH 41/44] Fix for nrf9160 --- nrf52-hal-common/src/uarte.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 44755462..374392b2 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -29,7 +29,7 @@ use heapless::{ use interrupt_driven::*; // Re-export SVD variants to allow user to directly set values -pub use crate::target::uarte0::{baudrate::BAUDRATEW as Baudrate, config::PARITYW as Parity}; +pub use uarte0::{baudrate::BAUDRATEW as Baudrate, config::PARITYW as Parity}; /// Interface to a UARTE instance /// From 09a98a09b7366a964a9aaa8cd2057d66bb773ac5 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Tue, 3 Sep 2019 12:39:15 +0200 Subject: [PATCH 42/44] Minor update if uninit initialization --- nrf52-hal-common/src/uarte.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 374392b2..68023c4e 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -435,7 +435,7 @@ pub mod interrupt_driven { /// Each node in the `UarteDMAPool` consists of this struct. pub struct UarteDMAPoolNode { len: u8, - buf: [mem::MaybeUninit; UARTE_DMA_SIZE], + buf: [mem::MaybeUninit; Self::MAX_SIZE], } impl fmt::Debug for UarteDMAPoolNode { @@ -463,7 +463,7 @@ pub mod interrupt_driven { pub const fn new() -> Self { Self { len: 0, - buf: [mem::MaybeUninit::uninit(); UARTE_DMA_SIZE], + buf: [mem::MaybeUninit::uninit(); Self::MAX_SIZE], } } @@ -479,7 +479,7 @@ pub mod interrupt_driven { /// ``` pub fn write(&mut self) -> &mut [u8] { // Initialize memory with a safe value - self.buf = unsafe { mem::zeroed() }; + self.buf = unsafe { [mem::zeroed(); Self::MAX_SIZE] }; self.len = Self::MAX_SIZE as _; // Set to max so `commit` may shrink it if needed unsafe { slice::from_raw_parts_mut(self.buf.as_mut_ptr() as *mut _, Self::MAX_SIZE) } From bf1733c18ef6fe5402edf738cc137f01f6154fae Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Tue, 3 Sep 2019 13:30:19 +0200 Subject: [PATCH 43/44] Added size check in write_str --- nrf52-hal-common/src/uarte.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 68023c4e..5950f719 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -446,7 +446,9 @@ pub mod interrupt_driven { impl fmt::Write for UarteDMAPoolNode { fn write_str(&mut self, s: &str) -> fmt::Result { - if s.len() > Self::MAX_SIZE { + let free = Self::MAX_SIZE - self.len as usize; + + if s.len() > free { Err(fmt::Error) } else { self.write_slice(s.as_bytes()); From 3bf3ecd3c536f67da9dd76bc82773d18dc2181fe Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Tue, 3 Sep 2019 13:47:40 +0200 Subject: [PATCH 44/44] Documentation update --- nrf52-hal-common/src/uarte.rs | 56 +++++++++++++++++------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/nrf52-hal-common/src/uarte.rs b/nrf52-hal-common/src/uarte.rs index 5950f719..3d3c6198 100644 --- a/nrf52-hal-common/src/uarte.rs +++ b/nrf52-hal-common/src/uarte.rs @@ -533,8 +533,8 @@ pub mod interrupt_driven { self.len as usize } - /// This function is unsafe as it must be used in conjuction with `buffer_address` to write and - /// set the correct number of bytes from a DMA transaction + /// This function is unsafe as it must be used in conjunction with `buffer_address` to + /// write and set the correct number of bytes from a DMA transaction unsafe fn set_len_from_dma(&mut self, len: u8) { self.len = len; } @@ -589,8 +589,8 @@ pub mod interrupt_driven { /// Used internally to set up the proper interrupts fn enable_interrupts(&mut self) { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver + // This operation is safe due to type-state programming guaranteeing that the RX and + // TX are unique within the driver let uarte = unsafe { &*T::ptr() }; uarte.inten.modify(|_, w| { @@ -609,8 +609,8 @@ pub mod interrupt_driven { /// Start a UARTE read transaction fn start_read(&mut self) { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver + // This operation is safe due to type-state programming guaranteeing that the RX and + // TX are unique within the driver let uarte = unsafe { &*T::ptr() }; // Start UARTE Receive transaction @@ -621,8 +621,8 @@ pub mod interrupt_driven { /// Prepare UARTE read transaction fn prepare_read(&mut self) -> Result<(), RXError> { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver + // This operation is safe due to type-state programming guaranteeing that the RX and + // TX are within the driver let uarte = unsafe { &*T::ptr() }; // This operation is fast as `UarteDMAPoolNode::new()` does not zero the internal buffer @@ -649,11 +649,11 @@ pub mod interrupt_driven { Ok(()) } - /// Timeout handling for the RX driver - Must be called from the corresponding TIMERx Interrupt - /// handler/task. + /// Timeout handling for the RX driver - Must be called from the corresponding TIMERx + /// Interrupt handler/task. pub fn process_timeout_interrupt(&mut self) { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver + // This operation is safe due to type-state programming guaranteeing that the RX and + // TX are unique within the driver let uarte = unsafe { &*T::ptr() }; // Reset the event, otherwise it will always read `1` from now on. @@ -665,16 +665,16 @@ pub mod interrupt_driven { unsafe { w.bits(1) }); } - /// Main entry point for the RX driver - Must be called from the corresponding UARTE Interrupt - /// handler/task. + /// Main entry point for the RX driver - Must be called from the corresponding UARTE + /// Interrupt handler/task. /// /// Will return: /// 1. `Ok(Some(Box))` if data was received /// 2. `Ok(None)` if there was no data, i.e. UARTE interrupt was due to other events /// 3. `Err(RXError::OOM)` if the memory pool was depleted, see `RXError` for mitigations pub fn process_interrupt(&mut self) -> Result>, RXError> { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver + // This operation is safe due to type-state programming guaranteeing that the RX and + // TX are unique within the driver let uarte = unsafe { &*T::ptr() }; // Handles the byte timeout timer @@ -709,12 +709,12 @@ pub mod interrupt_driven { // our transaction has finished if let Some(mut ret_b) = self.rxq.dequeue() { - // Read the true number of bytes and set the correct length of the packet before - // returning it + // Read the true number of bytes and set the correct length of the packet + // before returning it let bytes_read = uarte.rxd.amount.read().bits() as u8; unsafe { - // This operation is safe as `buffer_address_for_dma` has written `bytes_read` - // number of bytes into the node + // This operation is safe as `buffer_address_for_dma` has written + // `bytes_read` number of bytes into the node ret_b.set_len_from_dma(bytes_read); } @@ -771,8 +771,8 @@ pub mod interrupt_driven { /// Used internally to set up the proper interrupts fn enable_interrupts(&mut self) { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver + // This operation is safe due to type-state programming guaranteeing that the RX and + // TX are unique within the driver let uarte = unsafe { &*T::ptr() }; uarte.inten.modify(|_, w| w.endtx().set_bit()); @@ -780,8 +780,8 @@ pub mod interrupt_driven { /// Sets up the UARTE to send DMA chunk fn start_write(&mut self, b: Box) { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver + // This operation is safe due to type-state programming guaranteeing that the RX and + // TX are unique within the driver let uarte = unsafe { &*T::ptr() }; // Only send if the DMA chunk has data, else drop the `Box` @@ -806,11 +806,11 @@ pub mod interrupt_driven { } } - /// Main entry point for the TX driver - Must be called from the corresponding UARTE Interrupt - /// handler/task. + /// Main entry point for the TX driver - Must be called from the corresponding UARTE + /// Interrupt handler/task. pub fn process_interrupt(&mut self) -> Option { - // This operation is safe due to type-state programming guaranteeing that the RX and TX are - // unique within the driver + // This operation is safe due to type-state programming guaranteeing that the RX and + // TX are unique within the driver let uarte = unsafe { &*T::ptr() }; // ENDTX event? (DMA transaction finished)