Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added interrupt driven UARTE (open for feedback, do not merge yet) #102

Open
wants to merge 47 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
7233780
Added interrupt driven UARTE
korken89 May 2, 2019
dce32c3
Updated heapless dep, added missing exports
korken89 May 2, 2019
4fcd3bf
transmit queue generic over size S
May 3, 2019
42e2039
DMA_SIZE now parametrised
perlindgren May 4, 2019
c64c41d
uarte interrupt example from https://github.com/korken89/rtfm_worksho…
jacobrosenthal Jul 15, 2019
afda33b
add missing .cargo for rtfm-uarte-interrupts example
jacobrosenthal Jul 16, 2019
ccc77d6
default build target
jacobrosenthal Jul 31, 2019
3eb1cae
fix to original example
jacobrosenthal Aug 4, 2019
65f56b2
Use release RTFM version
korken89 Aug 7, 2019
9e21101
Added plumbing for timeout Timer in UARTE
korken89 Aug 7, 2019
552035a
Fixed so there is an extra way to enable the timers interrupts
korken89 Aug 7, 2019
ad0d255
Timeout almost done, need to handle non full packets being read
korken89 Aug 7, 2019
7ea8d88
Now working with sizes of packets added
korken89 Aug 8, 2019
d36946e
Added check for 0 sized chunks being sent
korken89 Aug 8, 2019
8593b58
Cleanup of chunk check
korken89 Aug 8, 2019
4229a18
Handle DMA pool inside the driver
korken89 Aug 8, 2019
cdea379
Updated timeout to 10 ms
korken89 Aug 8, 2019
a7d470a
Renaming to better describing names
korken89 Aug 8, 2019
902f322
Updated UARTE interrupt example
korken89 Aug 8, 2019
3d5112b
Cleanup of UARTE interrupt example, added timeout handling
korken89 Aug 8, 2019
3991477
Added commented pin definitions for DWM1001 dev board
korken89 Aug 8, 2019
7c8285b
Changed the Node struct to use MaybeUninit, added documentation
korken89 Aug 8, 2019
dcc8a73
Cleared out panics, replaced with debug_assert, added Debug impl
korken89 Aug 9, 2019
705eeee
Fixed miss in merge
korken89 Aug 11, 2019
dea2e73
Small renaming for easier readability
korken89 Aug 11, 2019
8c76072
Removed POOL flag
korken89 Aug 11, 2019
5dd0147
All interrupt driven code in its own module, this should fix nRF9160 …
korken89 Aug 11, 2019
f84e5ec
few more fixes
jacobrosenthal Aug 12, 2019
759f676
Implemented fmt::write for UarteDMAPoolNode
korken89 Aug 13, 2019
b243ac5
split renamed to into_interrupt_driven to convey meaning
korken89 Aug 13, 2019
9c9fbb2
Fixed UarteDMAPoolNode::max_len()
korken89 Aug 13, 2019
5dd16d6
Fixed pub for max_len
korken89 Aug 13, 2019
63a5806
Testing a direct write interface
korken89 Aug 14, 2019
c7daa97
Added transmission status to help in event based systems to load the …
korken89 Aug 16, 2019
949bd38
Fix spelling error
korken89 Aug 16, 2019
9b51304
Updated uarte example with write!
korken89 Aug 18, 2019
4882755
More clear example
korken89 Aug 18, 2019
07ee0b1
Updated heapless for armv8 support
korken89 Sep 3, 2019
73f7292
Now using the optional NVIC API for enabling interrupts
korken89 Sep 3, 2019
9dee224
Fixed use of write_slice
korken89 Sep 3, 2019
cac02d3
Fix for nrf9160
korken89 Sep 3, 2019
09a98a0
Minor update if uninit initialization
korken89 Sep 3, 2019
bf1733c
Added size check in write_str
korken89 Sep 3, 2019
3bf3ecd
Documentation update
korken89 Sep 3, 2019
90c0861
Merge branch 'master' into master
korken89 Sep 4, 2019
bd650ba
Merge remote-tracking branch 'upstream/master'
korken89 Sep 20, 2019
f46e00c
Merge branch 'master' into master
korken89 Oct 23, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ members = [
"nrf52840-hal",
"nrf9160-hal",
"examples/rtfm-demo",
"examples/rtfm-uarte-interrupts",
"examples/spi-demo",
"examples/twi-ssd1306",
]
Expand Down
2 changes: 1 addition & 1 deletion examples/rtfm-demo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ authors = ["James Munns <[email protected]>"]
edition = "2018"

[dependencies]
cortex-m-rtfm = "0.4.3"
cortex-m-rtfm = "0.4"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why make the version requirement less specific? I think it can be useful to see what the latest version was, when a dependency was added or last updated.

I also think being less specific can make breakage more likely in some scenarios, although this is unlikely to be the case here.

panic-semihosting = "0.5.1"
cortex-m-semihosting = "0.3.3"

Expand Down
5 changes: 5 additions & 0 deletions examples/rtfm-uarte-interrupts/.cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[target.thumbv7em-none-eabihf]
runner = "arm-none-eabi-gdb -tui"

[build]
target = "thumbv7em-none-eabihf"
10 changes: 10 additions & 0 deletions examples/rtfm-uarte-interrupts/.gdbinit
Original file line number Diff line number Diff line change
@@ -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
36 changes: 36 additions & 0 deletions examples/rtfm-uarte-interrupts/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[package]
name = "rtfm-uarte-interrupts"
version = "0.1.0"
authors = ["Per Lindgren <[email protected]>",
"Emil Fresk <[email protected]>"]
edition = "2018"

[dependencies]
cortex-m-rtfm = "0.4"
panic-semihosting = "0.5.1"
cortex-m-semihosting = "0.3.3"
heapless = ">= 0.5.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the >= requirement? Won't this include 0.6 and later versions, which may break this code?


[dependencies.nrf52810-hal]
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 = ["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"]
52832 = ["nrf52832-hal"]
52840 = ["nrf52840-hal"]
default = ["52832"]
138 changes: 138 additions & 0 deletions examples/rtfm-uarte-interrupts/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#![no_main]
#![no_std]

// panic handler
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::*;
use hal::{
uarte::{
self,
interrupt_driven::{RXError, UarteDMAPool, UarteDMAPoolNode, UarteRX, UarteTX},
},
Uarte,
};

use heapless::{
consts,
pool::singleton::Box,
spsc::{Producer, Queue},
};

// Needed for the write! example code
// use core::fmt::Write;
// use heapless::pool::singleton::Pool;

use rtfm::app;

const NR_PACKAGES: usize = 10;
const DMA_MEM: usize = core::mem::size_of::<UarteDMAPoolNode>() * NR_PACKAGES;

// Using power-of-2 constants is faster (see the crate heapless for details)
type TXQSize = consts::U4;

#[app(device = crate::hal::target)]
const APP: () = {
static mut RX: UarteRX<UARTE0, TIM0> = ();
static mut TX: UarteTX<UARTE0, TXQSize> = ();
static mut PRODUCER: Producer<'static, Box<UarteDMAPool>, 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<Box<UarteDMAPool>, TXQSize> = Queue(heapless::i::Queue::new());

hprintln!("init").unwrap();

let port0 = p0::Parts::new(device.P0);

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
// txd: port0.p0_05.into_push_pull_output(Level::High).degrade(),
// rxd: port0.p0_11.into_floating_input().degrade(),
cts: None,
rts: None,
},
uarte::Parity::EXCLUDED,
uarte::Baudrate::BAUD115200,
);

let timer = Timer::new(device.TIMER0);
let (txp, txc) = TX_RB.split();
let (rx, tx) = uarte0.into_interrupt_driven(txc, timer, MEMORY);

init::LateResources {
RX: rx,
TX: tx,
PRODUCER: txp,
}
}

// // we can get Box<P> us being now the owner
#[task(capacity = 2, resources = [PRODUCER])]
fn printer(data: Box<UarteDMAPool>) {
// 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(&b"test"[..]); // Using raw slice writing
// resources.PRODUCER.enqueue(node).unwrap();
// hprintln!("{:?}", &data).unwrap();

// Echo the buffer back without any changes or copying
resources.PRODUCER.enqueue(data).unwrap();
rtfm::pend(interrupt::UARTE0_UART0);
}

#[task]
fn rx_error(err: RXError) {
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
match resources.RX.process_interrupt() {
Ok(Some(b)) => {
// delegate data to printer
match spawn.printer(b) {
Err(_) => spawn.rx_error(RXError::OOM).unwrap(),
_ => (),
};
}
Ok(None) => (), // no
Err(err) => spawn.rx_error(err).unwrap(),
}

resources.TX.process_interrupt();
}

extern "C" {
fn SWI1_EGU1();
fn SWI2_EGU2();
}
};
10 changes: 10 additions & 0 deletions nrf52-hal-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ nb = "0.1.1"
fpa = "0.1.0"
rand_core = "0.4.0"

[dependencies.heapless]
version = "0.5.1"

[dependencies.void]
default-features = false
version = "1.0.2"
Expand Down Expand Up @@ -58,3 +61,10 @@ default = ["52832"]
52832 = ["nrf52832-pac"]
52840 = ["nrf52840-pac"]
9160 = ["nrf9160-pac"]
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 = []
16 changes: 6 additions & 10 deletions nrf52-hal-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -46,7 +46,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;
Expand All @@ -59,8 +59,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
Expand All @@ -73,10 +72,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 {
Expand All @@ -89,7 +85,7 @@ 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;
Expand Down
14 changes: 13 additions & 1 deletion nrf52-hal-common/src/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ use core::marker::PhantomData;
pub struct OneShot;
pub struct Periodic;


/// Interface to a TIMER instance
///
/// Right now, this is a very basic interface. The timer will always be
Expand Down Expand Up @@ -105,6 +104,19 @@ where
self.0.cc[1].read().bits()
}

/// 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
Expand Down
Loading