aboutsummaryrefslogtreecommitdiff
path: root/rtic-macros/src/codegen/pre_init.rs
diff options
context:
space:
mode:
authorGravatar Henrik Tjäder <henrik@tjaders.com> 2023-02-04 16:47:17 +0100
committerGravatar Henrik Tjäder <henrik@tjaders.com> 2023-03-01 00:35:13 +0100
commit9e445b3583c15c7701f3167eaa8dfe4afd541691 (patch)
tree167565d51598f42c0454d60b34e1170589ae1056 /rtic-macros/src/codegen/pre_init.rs
parent4124fbdd61ff823c6217a2a16ebb4d813146116c (diff)
downloadrtic-9e445b3583c15c7701f3167eaa8dfe4afd541691.tar.gz
rtic-9e445b3583c15c7701f3167eaa8dfe4afd541691.tar.zst
rtic-9e445b3583c15c7701f3167eaa8dfe4afd541691.zip
Move rtic macros to repo root, tune xtask
Diffstat (limited to 'rtic-macros/src/codegen/pre_init.rs')
-rw-r--r--rtic-macros/src/codegen/pre_init.rs85
1 files changed, 85 insertions, 0 deletions
diff --git a/rtic-macros/src/codegen/pre_init.rs b/rtic-macros/src/codegen/pre_init.rs
new file mode 100644
index 00000000..28ba29c0
--- /dev/null
+++ b/rtic-macros/src/codegen/pre_init.rs
@@ -0,0 +1,85 @@
+use crate::syntax::ast::App;
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+
+use crate::{analyze::Analysis, codegen::util};
+
+/// Generates code that runs before `#[init]`
+pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
+ let mut stmts = vec![];
+
+ let rt_err = util::rt_err_ident();
+
+ // Disable interrupts -- `init` must run with interrupts disabled
+ stmts.push(quote!(rtic::export::interrupt::disable();));
+
+ stmts.push(quote!(
+ // To set the variable in cortex_m so the peripherals cannot be taken multiple times
+ let mut core: rtic::export::Peripherals = rtic::export::Peripherals::steal().into();
+ ));
+
+ let device = &app.args.device;
+ let nvic_prio_bits = quote!(#device::NVIC_PRIO_BITS);
+
+ // check that all dispatchers exists in the `Interrupt` enumeration regardless of whether
+ // they are used or not
+ let interrupt = util::interrupt_ident();
+ for name in app.args.dispatchers.keys() {
+ stmts.push(quote!(let _ = #rt_err::#interrupt::#name;));
+ }
+
+ let interrupt_ids = analysis.interrupts.iter().map(|(p, (id, _))| (p, id));
+
+ // Unmask interrupts and set their priorities
+ for (&priority, name) in interrupt_ids.chain(app.hardware_tasks.values().filter_map(|task| {
+ if util::is_exception(&task.args.binds) {
+ // We do exceptions in another pass
+ None
+ } else {
+ Some((&task.args.priority, &task.args.binds))
+ }
+ })) {
+ let es = format!(
+ "Maximum priority used by interrupt vector '{name}' is more than supported by hardware"
+ );
+ // Compile time assert that this priority is supported by the device
+ stmts.push(quote!(
+ const _: () = if (1 << #nvic_prio_bits) < #priority as usize { ::core::panic!(#es); };
+ ));
+
+ stmts.push(quote!(
+ core.NVIC.set_priority(
+ #rt_err::#interrupt::#name,
+ rtic::export::logical2hw(#priority, #nvic_prio_bits),
+ );
+ ));
+
+ // NOTE unmask the interrupt *after* setting its priority: changing the priority of a pended
+ // interrupt is implementation defined
+ stmts.push(quote!(rtic::export::NVIC::unmask(#rt_err::#interrupt::#name);));
+ }
+
+ // Set exception priorities
+ for (name, priority) in app.hardware_tasks.values().filter_map(|task| {
+ if util::is_exception(&task.args.binds) {
+ Some((&task.args.binds, task.args.priority))
+ } else {
+ None
+ }
+ }) {
+ let es = format!(
+ "Maximum priority used by interrupt vector '{name}' is more than supported by hardware"
+ );
+ // Compile time assert that this priority is supported by the device
+ stmts.push(quote!(
+ const _: () = if (1 << #nvic_prio_bits) < #priority as usize { ::core::panic!(#es); };
+ ));
+
+ stmts.push(quote!(core.SCB.set_priority(
+ rtic::export::SystemHandler::#name,
+ rtic::export::logical2hw(#priority, #nvic_prio_bits),
+ );));
+ }
+
+ stmts
+}