aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/export.rs8
-rw-r--r--src/lib.rs117
-rw-r--r--src/tq.rs145
3 files changed, 84 insertions, 186 deletions
diff --git a/src/export.rs b/src/export.rs
index 72d954ab..ab5984e8 100644
--- a/src/export.rs
+++ b/src/export.rs
@@ -16,6 +16,7 @@ pub use cortex_m::{
use heapless::spsc::SingleCore;
pub use heapless::{consts, i::Queue as iQueue, spsc::Queue};
pub use heapless::{i::BinaryHeap as iBinaryHeap, BinaryHeap};
+pub use rtic_core::monotonic::Monotonic;
pub type SCFQ<N> = Queue<u8, N, u8, SingleCore>;
pub type SCRQ<T, N> = Queue<(T, u8), N, u8, SingleCore>;
@@ -112,6 +113,13 @@ where
{
}
+#[inline(always)]
+pub fn assert_monotonic<T>()
+where
+ T: Monotonic,
+{
+}
+
/// Lock the resource proxy by setting the BASEPRI
/// and running the closure with interrupt::free
///
diff --git a/src/lib.rs b/src/lib.rs
index 360ea91d..1d4df651 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -32,126 +32,21 @@
#![deny(missing_docs)]
#![deny(rust_2018_compatibility)]
#![deny(rust_2018_idioms)]
-#![deny(warnings)]
+// #![deny(warnings)]
#![no_std]
-use core::ops::Sub;
-
-use cortex_m::{
- interrupt::InterruptNumber,
- peripheral::{CBP, CPUID, DCB, DWT, FPB, FPU, ITM, MPU, NVIC, SCB, TPIU},
-};
+use cortex_m::{interrupt::InterruptNumber, peripheral::NVIC};
pub use cortex_m_rtic_macros::app;
-pub use rtic_core::{prelude as mutex_prelude, Exclusive, Mutex};
+pub use rtic_core::{
+ monotonic::{self, embedded_time as time, Monotonic},
+ prelude as mutex_prelude, Exclusive, Mutex,
+};
-#[cfg(armv7m)]
-pub mod cyccnt;
#[doc(hidden)]
pub mod export;
#[doc(hidden)]
mod tq;
-/// `cortex_m::Peripherals` minus `SYST`
-#[allow(non_snake_case)]
-pub struct Peripherals {
- /// Cache and branch predictor maintenance operations (not present on Cortex-M0 variants)
- pub CBP: CBP,
-
- /// CPUID
- pub CPUID: CPUID,
-
- /// Debug Control Block
- pub DCB: DCB,
-
- /// Data Watchpoint and Trace unit
- pub DWT: DWT,
-
- /// Flash Patch and Breakpoint unit (not present on Cortex-M0 variants)
- pub FPB: FPB,
-
- /// Floating Point Unit (only present on `thumbv7em-none-eabihf`)
- pub FPU: FPU,
-
- /// Instrumentation Trace Macrocell (not present on Cortex-M0 variants)
- pub ITM: ITM,
-
- /// Memory Protection Unit
- pub MPU: MPU,
-
- /// Nested Vector Interrupt Controller
- pub NVIC: NVIC,
-
- /// System Control Block
- pub SCB: SCB,
-
- // SysTick: System Timer
- // pub SYST: SYST,
- /// Trace Port Interface Unit (not present on Cortex-M0 variants)
- pub TPIU: TPIU,
-}
-
-impl From<cortex_m::Peripherals> for Peripherals {
- fn from(p: cortex_m::Peripherals) -> Self {
- Self {
- CBP: p.CBP,
- CPUID: p.CPUID,
- DCB: p.DCB,
- DWT: p.DWT,
- FPB: p.FPB,
- FPU: p.FPU,
- ITM: p.ITM,
- MPU: p.MPU,
- NVIC: p.NVIC,
- SCB: p.SCB,
- TPIU: p.TPIU,
- }
- }
-}
-
-/// A fraction
-pub struct Fraction {
- /// The numerator
- pub numerator: u32,
-
- /// The denominator
- pub denominator: u32,
-}
-
-/// A monotonic clock / counter
-pub trait Monotonic {
- /// A measurement of this clock, use `CYCCNT` as a reference implementation for `Instant`.
- /// Note that the Instant must be a signed value such as `i32`.
- type Instant: Copy + Ord + Sub;
-
- /// The ratio between the system timer (SysTick) frequency and this clock frequency, i.e.
- /// `Monotonic clock * Fraction = System clock`
- ///
- /// The ratio must be expressed in *reduced* `Fraction` form to prevent overflows. That is
- /// `2 / 3` instead of `4 / 6`
- fn ratio() -> Fraction;
-
- /// Returns the current time
- ///
- /// # Correctness
- ///
- /// This function is *allowed* to return nonsensical values if called before `reset` is invoked
- /// by the runtime. Therefore application authors should *not* call this function during the
- /// `#[init]` phase.
- fn now() -> Self::Instant;
-
- /// Resets the counter to *zero*
- ///
- /// # Safety
- ///
- /// This function will be called *exactly once* by the RTIC runtime after `#[init]` returns and
- /// before tasks can start; this is also the case in multi-core applications. User code must
- /// *never* call this function.
- unsafe fn reset();
-
- /// A `Self::Instant` that represents a count of *zero*
- fn zero() -> Self::Instant;
-}
-
/// Sets the given `interrupt` as pending
///
/// This is a convenience function around
diff --git a/src/tq.rs b/src/tq.rs
index b2a84c85..4c89a66c 100644
--- a/src/tq.rs
+++ b/src/tq.rs
@@ -1,28 +1,18 @@
-use core::{
- cmp::{self, Ordering},
- convert::TryInto,
- mem,
- ops::Sub,
-};
-
-use cortex_m::peripheral::{SCB, SYST};
+use crate::{time::Instant, Monotonic};
+use core::cmp::Ordering;
use heapless::{binary_heap::Min, ArrayLength, BinaryHeap};
-use crate::Monotonic;
-
-pub struct TimerQueue<M, T, N>(pub BinaryHeap<NotReady<M, T>, N, Min>)
+pub struct TimerQueue<Mono, Task, N>(pub BinaryHeap<NotReady<Mono, Task>, N, Min>)
where
- M: Monotonic,
- <M::Instant as Sub>::Output: TryInto<u32>,
- N: ArrayLength<NotReady<M, T>>,
- T: Copy;
+ Mono: Monotonic,
+ N: ArrayLength<NotReady<Mono, Task>>,
+ Task: Copy;
-impl<M, T, N> TimerQueue<M, T, N>
+impl<Mono, Task, N> TimerQueue<Mono, Task, N>
where
- M: Monotonic,
- <M::Instant as Sub>::Output: TryInto<u32>,
- N: ArrayLength<NotReady<M, T>>,
- T: Copy,
+ Mono: Monotonic,
+ N: ArrayLength<NotReady<Mono, Task>>,
+ Task: Copy,
{
/// # Safety
///
@@ -31,7 +21,15 @@ where
///
/// Enqueue a task without checking if it is full
#[inline]
- pub unsafe fn enqueue_unchecked(&mut self, nr: NotReady<M, T>) {
+ pub unsafe fn enqueue_unchecked<F1, F2>(
+ &mut self,
+ nr: NotReady<Mono, Task>,
+ enable_interrupt: F1,
+ pend_handler: F2,
+ ) where
+ F1: FnOnce(),
+ F2: FnOnce(),
+ {
let mut is_empty = true;
// Check if the top contains a non-empty element and if that element is
// greater than nr
@@ -45,57 +43,59 @@ where
.unwrap_or(true);
if if_heap_max_greater_than_nr {
if is_empty {
- mem::transmute::<_, SYST>(()).enable_interrupt();
+ // mem::transmute::<_, SYST>(()).enable_interrupt();
+ enable_interrupt();
}
// Set SysTick pending
- SCB::set_pendst();
+ // SCB::set_pendst();
+ pend_handler();
}
self.0.push_unchecked(nr);
}
+ /// Check if the timer queue is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.0.is_empty()
+ }
+
/// Dequeue a task from the TimerQueue
#[inline]
- pub fn dequeue(&mut self) -> Option<(T, u8)> {
+ pub fn dequeue<F>(&mut self, disable_interrupt: F) -> Option<(Task, u8)>
+ where
+ F: FnOnce(),
+ {
unsafe {
- if let Some(instant) = self.0.peek().map(|p| p.instant) {
- let now = M::now();
+ Mono::clear_compare();
- if instant < now {
+ if let Some(instant) = self.0.peek().map(|p| p.instant) {
+ if instant < Mono::now() {
// task became ready
let nr = self.0.pop_unchecked();
Some((nr.task, nr.index))
} else {
- // set a new timeout
- const MAX: u32 = 0x00ffffff;
-
- let ratio = M::ratio();
- let dur = match (instant - now).try_into().ok().and_then(|x| {
- x.checked_mul(ratio.numerator)
- .map(|x| x / ratio.denominator)
- }) {
- None => MAX,
-
- // ARM Architecture Reference Manual says:
- // "Setting SYST_RVR to zero has the effect of
- // disabling the SysTick counter independently
- // of the counter enable bit."
- Some(0) => 1,
-
- Some(x) => cmp::min(MAX, x),
- };
- mem::transmute::<_, SYST>(()).set_reload(dur);
-
- // Start counting down from the new reload
- mem::transmute::<_, SYST>(()).clear_current();
-
- None
+ // TODO: Fix this hack...
+ // Extract the compare time.
+ Mono::set_compare(*instant.duration_since_epoch().integer());
+
+ // Double check that the instant we set is really in the future, else
+ // dequeue. If the monotonic is fast enough it can happen that from the
+ // read of now to the set of the compare, the time can overflow. This is to
+ // guard against this.
+ if instant < Mono::now() {
+ let nr = self.0.pop_unchecked();
+
+ Some((nr.task, nr.index))
+ } else {
+ None
+ }
}
} else {
- // The queue is empty
- mem::transmute::<_, SYST>(()).disable_interrupt();
+ // The queue is empty, disable the interrupt.
+ disable_interrupt();
None
}
@@ -103,52 +103,47 @@ where
}
}
-pub struct NotReady<M, T>
+pub struct NotReady<Mono, Task>
where
- T: Copy,
- M: Monotonic,
- <M::Instant as Sub>::Output: TryInto<u32>,
+ Task: Copy,
+ Mono: Monotonic,
{
pub index: u8,
- pub instant: M::Instant,
- pub task: T,
+ pub instant: Instant<Mono>,
+ pub task: Task,
}
-impl<M, T> Eq for NotReady<M, T>
+impl<Mono, Task> Eq for NotReady<Mono, Task>
where
- T: Copy,
- M: Monotonic,
- <M::Instant as Sub>::Output: TryInto<u32>,
+ Task: Copy,
+ Mono: Monotonic,
{
}
-impl<M, T> Ord for NotReady<M, T>
+impl<Mono, Task> Ord for NotReady<Mono, Task>
where
- T: Copy,
- M: Monotonic,
- <M::Instant as Sub>::Output: TryInto<u32>,
+ Task: Copy,
+ Mono: Monotonic,
{
fn cmp(&self, other: &Self) -> Ordering {
self.instant.cmp(&other.instant)
}
}
-impl<M, T> PartialEq for NotReady<M, T>
+impl<Mono, Task> PartialEq for NotReady<Mono, Task>
where
- T: Copy,
- M: Monotonic,
- <M::Instant as Sub>::Output: TryInto<u32>,
+ Task: Copy,
+ Mono: Monotonic,
{
fn eq(&self, other: &Self) -> bool {
self.instant == other.instant
}
}
-impl<M, T> PartialOrd for NotReady<M, T>
+impl<Mono, Task> PartialOrd for NotReady<Mono, Task>
where
- T: Copy,
- M: Monotonic,
- <M::Instant as Sub>::Output: TryInto<u32>,
+ Task: Copy,
+ Mono: Monotonic,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(&other))