aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--macros/src/codegen.rs24
-rw-r--r--macros/src/codegen/init.rs2
-rw-r--r--macros/src/codegen/module.rs16
-rw-r--r--macros/src/codegen/post_init.rs18
-rw-r--r--macros/src/codegen/pre_init.rs20
-rw-r--r--macros/src/codegen/software_tasks.rs2
-rw-r--r--macros/src/codegen/timer_queue.rs21
-rw-r--r--macros/src/codegen/util.rs10
-rw-r--r--src/export.rs4
-rw-r--r--src/lib.rs6
-rw-r--r--src/tq.rs68
12 files changed, 134 insertions, 58 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 20631350..37290387 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -58,6 +58,7 @@ required-features = ["__v7"]
cortex-m = "0.7.0"
cortex-m-rtic-macros = { path = "macros", version = "0.6.0-alpha.0" }
rtic-core = { git = "https://github.com/rtic-rs/rtic-core", branch = "new_monotonic" }
+rtic-monotonic = { git = "https://github.com/rtic-rs/rtic-monotonic", branch = "master" }
#rtic-core = "0.3.1"
heapless = "0.5.0"
bare-metal = "1.0.0"
diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs
index bb8aa4e7..bdfcd36d 100644
--- a/macros/src/codegen.rs
+++ b/macros/src/codegen.rs
@@ -104,13 +104,35 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
));
}
+ let app_name = &app.name;
+ let app_path = quote! {crate::#app_name};
+
let monotonic_imports: Vec<_> = app
.monotonics
.iter()
.map(|(_, monotonic)| {
let name = &monotonic.ident;
let ty = &monotonic.ty;
- quote!(pub type #name = #ty;)
+ let mangled_name = util::mangle_monotonic_type(&name.to_string());
+ let ident = util::monotonic_ident(&name.to_string());
+ quote! {
+ #[doc(hidden)]
+ pub type #mangled_name = #ty;
+
+ pub mod #name {
+ pub fn now() -> rtic::time::Instant<#app_path::#mangled_name> {
+ rtic::export::interrupt::free(|_| {
+ use rtic::Monotonic as _;
+ use rtic::time::Clock as _;
+ if let Ok(v) = unsafe{ (&*#app_path::#ident.as_ptr()).try_now() } {
+ v
+ } else {
+ unreachable!("Your monotonic is not infallible!")
+ }
+ })
+ }
+ }
+ }
})
.collect();
diff --git a/macros/src/codegen/init.rs b/macros/src/codegen/init.rs
index 66c3bc4e..aa9adcb0 100644
--- a/macros/src/codegen/init.rs
+++ b/macros/src/codegen/init.rs
@@ -69,7 +69,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
let app_path = quote! {crate::#app_name};
let locals_new = locals_new.iter();
let call_init = Some(
- quote!(let (late, monotonics) = #app_path::#name(#(#locals_new,)* #name::Context::new(core.into()));),
+ quote!(let (late, mut monotonics) = #app_path::#name(#(#locals_new,)* #name::Context::new(core.into()));),
);
root_init.push(module::codegen(
diff --git a/macros/src/codegen/module.rs b/macros/src/codegen/module.rs
index 93fbeaef..f0f403b2 100644
--- a/macros/src/codegen/module.rs
+++ b/macros/src/codegen/module.rs
@@ -126,7 +126,7 @@ pub fn codegen(
.monotonics
.iter()
.map(|(_, monotonic)| {
- let mono = &monotonic.ident;
+ let mono = util::mangle_monotonic_type(&monotonic.ident.to_string());
quote! {#app_path::#mono}
})
.collect();
@@ -234,6 +234,7 @@ pub fn codegen(
let tq = util::tq_ident(&monotonic.ident.to_string());
let t = util::schedule_t_ident();
let m = &monotonic.ident;
+ let m_mangled = util::mangle_monotonic_type(&monotonic.ident.to_string());
let m_isr = &monotonic.args.binds;
let enum_ = util::interrupt_ident();
@@ -242,9 +243,10 @@ pub fn codegen(
items.push(quote!(pub use #m::spawn_at;));
}
- let (unmask, pend) = if &*m_isr.to_string() == "SysTick" {
+ let (enable_interrupt, pend) = if &*m_isr.to_string() == "SysTick" {
(
- quote!(core::mem::transmute::<_, cortex_m::peripheral::SYST>(()).disable_interrupt()),
+ quote!(core::mem::transmute::<_, cortex_m::peripheral::SYST>(())
+ .enable_interrupt()),
quote!(cortex_m::peripheral::SCB::set_pendst()),
)
} else {
@@ -263,16 +265,16 @@ pub fn codegen(
#(,#args)*
) -> Result<(), #ty>
where D: rtic::time::duration::Duration + rtic::time::fixed_point::FixedPoint,
- D::T: Into<<#app_path::#m as rtic::time::Clock>::T>,
+ D::T: Into<<#app_path::#m_mangled as rtic::time::Clock>::T>,
{
- let instant = <#app_path::#m as rtic::Monotonic>::now();
+ let instant = #app_path::#m::now();
spawn_at(instant + duration, #(,#untupled)*)
}
#(#cfgs)*
pub fn spawn_at(
- instant: rtic::time::Instant<#app_path::#m>
+ instant: rtic::time::Instant<#app_path::#m_mangled>
#(,#args)*
) -> Result<(), #ty> {
unsafe {
@@ -296,7 +298,7 @@ pub fn codegen(
rtic::export::interrupt::free(|_| #app_path::#tq.enqueue_unchecked(
nr,
- || #unmask,
+ || #enable_interrupt,
|| #pend,
));
diff --git a/macros/src/codegen/post_init.rs b/macros/src/codegen/post_init.rs
index 9268e040..b6cf47c3 100644
--- a/macros/src/codegen/post_init.rs
+++ b/macros/src/codegen/post_init.rs
@@ -1,6 +1,7 @@
-use proc_macro2::TokenStream as TokenStream2;
+use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::quote;
use rtic_syntax::ast::App;
+use syn::Index;
use crate::{analyze::Analysis, codegen::util};
@@ -25,12 +26,17 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
}
}
- for (monotonic, _) in app.monotonics.iter() {
- stmts.push(quote!(#monotonic::reset();));
- }
+ for (i, (monotonic, _)) in app.monotonics.iter().enumerate() {
+ let idx = Index {
+ index: i as u32,
+ span: Span::call_site(),
+ };
+ stmts.push(quote!(monotonics.#idx.reset();));
- // Forget the monotonics so they won't be dropped.
- stmts.push(quote!(core::mem::forget(monotonics);));
+ // Store the monotonic
+ let name = util::monotonic_ident(&monotonic.to_string());
+ stmts.push(quote!(#name.as_mut_ptr().write(monotonics.#idx);));
+ }
// Enable the interrupts -- this completes the `init`-ialization phase
stmts.push(quote!(rtic::export::interrupt::enable();));
diff --git a/macros/src/codegen/pre_init.rs b/macros/src/codegen/pre_init.rs
index e7b1b03b..fbfff3b5 100644
--- a/macros/src/codegen/pre_init.rs
+++ b/macros/src/codegen/pre_init.rs
@@ -77,14 +77,17 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
}
// Initialize monotonic's interrupts
- for (priority, name) in app
+ for (ident, priority, name) in app
.monotonics
.iter()
- .map(|(_, monotonic)| (&monotonic.args.priority, &monotonic.args.binds))
+ .map(|(ident, monotonic)| (ident, &monotonic.args.priority, &monotonic.args.binds))
{
// Compile time assert that this priority is supported by the device
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
+ let app_name = &app.name;
+ let app_path = quote! {crate::#app_name};
+ let mono_type = util::mangle_monotonic_type(&ident.to_string());
if &*name.to_string() == "SysTick" {
stmts.push(quote!(
@@ -92,6 +95,12 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
rtic::export::SystemHandler::SysTick,
rtic::export::logical2hw(#priority, #nvic_prio_bits),
);
+
+ // Always enable monotonic interrupts if they should never be off
+ if !#app_path::#mono_type::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
+ core::mem::transmute::<_, cortex_m::peripheral::SYST>(())
+ .enable_interrupt();
+ }
));
} else {
// NOTE this also checks that the interrupt exists in the `Interrupt` enumeration
@@ -101,10 +110,13 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
#rt_err::#interrupt::#name,
rtic::export::logical2hw(#priority, #nvic_prio_bits),
);
+
+ // Always enable monotonic interrupts if they should never be off
+ if !#app_path::#mono_type::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
+ rtic::export::NVIC::unmask(#app_path::#rt_err::#interrupt::#name);
+ }
));
}
-
- // NOTE we do not unmask the interrupt as this is part of the monotonic to keep track of
}
// If there's no user `#[idle]` then optimize returning from interrupt handlers
diff --git a/macros/src/codegen/software_tasks.rs b/macros/src/codegen/software_tasks.rs
index 53de50b9..a760b067 100644
--- a/macros/src/codegen/software_tasks.rs
+++ b/macros/src/codegen/software_tasks.rs
@@ -62,7 +62,7 @@ pub fn codegen(
for (_, monotonic) in &app.monotonics {
let instants = util::monotonic_instants_ident(name, &monotonic.ident);
- let m = &monotonic.ident;
+ let m = util::mangle_monotonic_type(&monotonic.ident.to_string());
let uninit = mk_uninit();
mod_app.push(quote!(
diff --git a/macros/src/codegen/timer_queue.rs b/macros/src/codegen/timer_queue.rs
index 9a430a07..54b2c1f0 100644
--- a/macros/src/codegen/timer_queue.rs
+++ b/macros/src/codegen/timer_queue.rs
@@ -42,7 +42,10 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
let monotonic_name = monotonic.ident.to_string();
let tq = util::tq_ident(&monotonic_name);
let t = util::schedule_t_ident();
- let m = &monotonic.ident;
+ let m = util::mangle_monotonic_type(&monotonic_name);
+ let m_ident = util::monotonic_ident(&monotonic_name);
+ let app_name = &app.name;
+ let app_path = quote! {crate::#app_name};
// Static variables and resource proxy
{
@@ -63,6 +66,15 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
)
);
));
+
+ let mono = util::monotonic_ident(&monotonic_name);
+ let doc = &format!("Storage for {}", monotonic_name);
+ let mono_ty = quote!(core::mem::MaybeUninit<#m>);
+
+ items.push(quote!(
+ #[doc = #doc]
+ static mut #mono: #mono_ty = core::mem::MaybeUninit::uninit();
+ ));
}
// Timer queue handler
@@ -100,8 +112,8 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
.collect::<Vec<_>>();
let bound_interrupt = &monotonic.args.binds;
- let enable_isr = if &*bound_interrupt.to_string() == "SysTick" {
- quote!(core::mem::transmute::<_, cortex_m::peripheral::SYST>(()).enable_interrupt())
+ let disable_isr = if &*bound_interrupt.to_string() == "SysTick" {
+ quote!(core::mem::transmute::<_, cortex_m::peripheral::SYST>(()).disable_interrupt())
} else {
quote!(rtic::export::NVIC::mask(#rt_err::#enum_::#bound_interrupt))
};
@@ -111,7 +123,8 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
#[allow(non_snake_case)]
unsafe fn #bound_interrupt() {
while let Some((task, index)) = rtic::export::interrupt::free(|_| #tq.dequeue(
- || #enable_isr,
+ || #disable_isr,
+ &mut *#app_path::#m_ident.as_mut_ptr(),
))
{
match task {
diff --git a/macros/src/codegen/util.rs b/macros/src/codegen/util.rs
index 287ba408..7a12f23e 100644
--- a/macros/src/codegen/util.rs
+++ b/macros/src/codegen/util.rs
@@ -239,6 +239,16 @@ pub fn tq_ident(name: &str) -> Ident {
Ident::new(&format!("TQ_{}", name), Span::call_site())
}
+/// Generates an identifier for monotonic timer storage
+pub fn monotonic_ident(name: &str) -> Ident {
+ Ident::new(&format!("MONOTONIC_STORAGE_{}", name), Span::call_site())
+}
+
+/// Generates an identifier for monotonic timer storage
+pub fn mangle_monotonic_type(name: &str) -> Ident {
+ Ident::new(&format!("MonotonicMangled{}", name), Span::call_site())
+}
+
/// The name to get better RT flag errors
pub fn rt_err_ident() -> Ident {
Ident::new(
diff --git a/src/export.rs b/src/export.rs
index ab5984e8..91a4a5ef 100644
--- a/src/export.rs
+++ b/src/export.rs
@@ -16,7 +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 use rtic_monotonic as monotonic;
pub type SCFQ<N> = Queue<u8, N, u8, SingleCore>;
pub type SCRQ<T, N> = Queue<(T, u8), N, u8, SingleCore>;
@@ -116,7 +116,7 @@ where
#[inline(always)]
pub fn assert_monotonic<T>()
where
- T: Monotonic,
+ T: monotonic::Monotonic,
{
}
diff --git a/src/lib.rs b/src/lib.rs
index 1d4df651..16f2e9fa 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,10 +37,8 @@
use cortex_m::{interrupt::InterruptNumber, peripheral::NVIC};
pub use cortex_m_rtic_macros::app;
-pub use rtic_core::{
- monotonic::{self, embedded_time as time, Monotonic},
- prelude as mutex_prelude, Exclusive, Mutex,
-};
+pub use rtic_core::{prelude as mutex_prelude, Exclusive, Mutex};
+pub use rtic_monotonic::{self, embedded_time as time, Monotonic};
#[doc(hidden)]
pub mod export;
diff --git a/src/tq.rs b/src/tq.rs
index 4c89a66c..6697f100 100644
--- a/src/tq.rs
+++ b/src/tq.rs
@@ -1,4 +1,7 @@
-use crate::{time::Instant, Monotonic};
+use crate::{
+ time::{Clock, Instant},
+ Monotonic,
+};
use core::cmp::Ordering;
use heapless::{binary_heap::Min, ArrayLength, BinaryHeap};
@@ -42,7 +45,7 @@ where
})
.unwrap_or(true);
if if_heap_max_greater_than_nr {
- if is_empty {
+ if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE && is_empty {
// mem::transmute::<_, SYST>(()).enable_interrupt();
enable_interrupt();
}
@@ -61,44 +64,53 @@ where
self.0.is_empty()
}
+ #[inline]
+ fn unwrapper<T, E>(val: Result<T, E>) -> T {
+ if let Ok(v) = val {
+ v
+ } else {
+ unreachable!("Your monotonic is not infallible")
+ }
+ }
+
/// Dequeue a task from the TimerQueue
#[inline]
- pub fn dequeue<F>(&mut self, disable_interrupt: F) -> Option<(Task, u8)>
+ pub fn dequeue<F>(&mut self, disable_interrupt: F, mono: &mut Mono) -> Option<(Task, u8)>
where
F: FnOnce(),
{
- unsafe {
- Mono::clear_compare();
+ mono.clear_compare_flag();
+
+ if let Some(instant) = self.0.peek().map(|p| p.instant) {
+ if instant < Self::unwrapper(Clock::try_now(mono)) {
+ // task became ready
+ let nr = unsafe { self.0.pop_unchecked() };
- 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 {
+ // 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 < Self::unwrapper(Clock::try_now(mono)) {
+ let nr = unsafe { self.0.pop_unchecked() };
Some((nr.task, nr.index))
} else {
- // 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
- }
+ None
}
- } else {
- // The queue is empty, disable the interrupt.
+ }
+ } else {
+ // The queue is empty, disable the interrupt.
+ if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
disable_interrupt();
-
- None
}
+
+ None
}
}
}