check task priority at compile time

before we were checking the priority at runtime. The compile time error message
when the priority is too high is kind of awful though.
This commit is contained in:
Jorge Aparicio 2019-04-16 23:04:24 +02:00
parent 8da925647e
commit aa7eec0299
5 changed files with 55 additions and 6 deletions

View file

@ -69,6 +69,13 @@ the critical section created by the lowest priority handler.
$ cargo run --example lock $ cargo run --example lock
{{#include ../../../../ci/expected/lock.run}}``` {{#include ../../../../ci/expected/lock.run}}```
One more note about priorities: choosing a priority higher than what the device
supports (that is `1 << NVIC_PRIO_BITS`) will result in a compile error. Due to
limitations in the language the error is currently far from helpful: it will say
something along the lines of "evaluation of constant value failed" and the span
of the error will *not* point out to the problematic interrupt value -- we are
sorry about this!
## Late resources ## Late resources
Unlike normal `static` variables, which need to be assigned an initial value Unlike normal `static` variables, which need to be assigned an initial value

View file

@ -1989,15 +1989,13 @@ fn pre_init(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::Toke
)) ))
} }
// TODO turn the assertions that check that the priority is not larger than what's supported by
// the device into compile errors
let device = &app.args.device; let device = &app.args.device;
let nvic_prio_bits = quote!(#device::NVIC_PRIO_BITS); let nvic_prio_bits = quote!(#device::NVIC_PRIO_BITS);
for (handler, interrupt) in &app.interrupts { for (handler, interrupt) in &app.interrupts {
let name = interrupt.args.binds(handler); let name = interrupt.args.binds(handler);
let priority = interrupt.args.priority; let priority = interrupt.args.priority;
exprs.push(quote!(p.NVIC.enable(#device::Interrupt::#name);)); exprs.push(quote!(p.NVIC.enable(#device::Interrupt::#name);));
exprs.push(quote!(assert!(#priority <= (1 << #nvic_prio_bits));)); exprs.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
exprs.push(quote!(p.NVIC.set_priority( exprs.push(quote!(p.NVIC.set_priority(
#device::Interrupt::#name, #device::Interrupt::#name,
((1 << #nvic_prio_bits) - #priority) << (8 - #nvic_prio_bits), ((1 << #nvic_prio_bits) - #priority) << (8 - #nvic_prio_bits),
@ -2007,7 +2005,7 @@ fn pre_init(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::Toke
for (priority, dispatcher) in &analysis.dispatchers { for (priority, dispatcher) in &analysis.dispatchers {
let name = &dispatcher.interrupt; let name = &dispatcher.interrupt;
exprs.push(quote!(p.NVIC.enable(#device::Interrupt::#name);)); exprs.push(quote!(p.NVIC.enable(#device::Interrupt::#name);));
exprs.push(quote!(assert!(#priority <= (1 << #nvic_prio_bits));)); exprs.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
exprs.push(quote!(p.NVIC.set_priority( exprs.push(quote!(p.NVIC.set_priority(
#device::Interrupt::#name, #device::Interrupt::#name,
((1 << #nvic_prio_bits) - #priority) << (8 - #nvic_prio_bits), ((1 << #nvic_prio_bits) - #priority) << (8 - #nvic_prio_bits),

View file

@ -1039,10 +1039,10 @@ fn parse_args(
} }
let value = lit.value(); let value = lit.value();
if value > u64::from(u8::MAX) { if value > u64::from(u8::MAX) || value == 0 {
return Err(parse::Error::new( return Err(parse::Error::new(
lit.span(), lit.span(),
"this literal must be in the range 0...255", "this literal must be in the range 1...255",
)); ));
} }

View file

@ -0,0 +1,22 @@
#![no_main]
#![no_std]
extern crate lm3s6965;
extern crate panic_halt;
extern crate rtfm;
use rtfm::app;
#[app(device = lm3s6965)] //~ error evaluation of constant value failed
const APP: () = {
#[init]
fn init() {}
// OK, this is the maximum priority supported by the device
#[interrupt(priority = 8)]
fn UART0() {}
// this value is too high!
#[interrupt(priority = 9)]
fn UART1() {}
};

View file

@ -0,0 +1,22 @@
#![no_main]
#![no_std]
extern crate lm3s6965;
extern crate panic_halt;
extern crate rtfm;
use rtfm::app;
#[app(device = lm3s6965)]
const APP: () = {
#[init]
fn init() {}
// OK, this is the minimum priority that tasks can have
#[interrupt(priority = 1)]
fn UART0() {}
// this value is too low!
#[interrupt(priority = 0)] //~ error this literal must be in the range 1...255
fn UART1() {}
};