diff options
| author | Jorge Aparicio <jorge@japaric.io> | 2019-04-21 20:45:24 +0200 |
|---|---|---|
| committer | Jorge Aparicio <jorge@japaric.io> | 2019-05-01 22:36:54 +0200 |
| commit | 09ec5a7a41d951ad7a1ef61391896df4a1f5fc18 (patch) | |
| tree | 0ab3172a9f2fd42d7236b4e989726ce312e363ce /book/en/src/internals/interrupt-configuration.md | |
| parent | bc024f197929be1ce7dac9e6cbf6672c3980437e (diff) | |
document internals
note that this assumes that RFC #155 has been implemented
Diffstat (limited to 'book/en/src/internals/interrupt-configuration.md')
| -rw-r--r-- | book/en/src/internals/interrupt-configuration.md | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/book/en/src/internals/interrupt-configuration.md b/book/en/src/internals/interrupt-configuration.md new file mode 100644 index 0000000..b34b308 --- /dev/null +++ b/book/en/src/internals/interrupt-configuration.md @@ -0,0 +1,74 @@ +# Interrupt configuration + +Interrupts are core to the operation of RTFM applications. Correctly setting +interrupt priorities and ensuring they remain fixed at runtime is a requisite +for the memory safety of the application. + +The RTFM framework exposes interrupt priorities as something that is declared at +compile time. However, this static configuration must be programmed into the +relevant registers during the initialization of the application. The interrupt +configuration is done before the `init` function runs. + +This example gives you an idea of the code that the RTFM framework runs: + +``` rust +#[rtfm::app(device = ..)] +const APP: () = { + #[init] + fn init(c: init::Context) { + // .. user code .. + } + + #[idle] + fn idle(c: idle::Context) -> ! { + // .. user code .. + } + + #[interrupt(binds = UART0, priority = 2)] + fn foo(c: foo::Context) { + // .. user code .. + } +}; +``` + +The framework generates an entry point that looks like this: + +``` rust +// the real entry point of the program +#[no_mangle] +unsafe fn main() -> ! { + // transforms a logical priority into a hardware / NVIC priority + fn logical2hw(priority: u8) -> u8 { + // this value comes from the device crate + const NVIC_PRIO_BITS: u8 = ..; + + // the NVIC encodes priority in the higher bits of a bit + // also a bigger numbers means lower priority + ((1 << NVIC_PRIORITY_BITS) - priority) << (8 - NVIC_PRIO_BITS) + } + + cortex_m::interrupt::disable(); + + let mut core = cortex_m::Peripheral::steal(); + + core.NVIC.enable(Interrupt::UART0); + + // value specified by the user + let uart0_prio = 2; + + // check at compile time that the specified priority is within the supported range + let _ = [(); (1 << NVIC_PRIORITY_BITS) - (uart0_prio as usize)]; + + core.NVIC.set_priority(Interrupt::UART0, logical2hw(uart0_prio)); + + // call into user code + init(/* .. */); + + // .. + + cortex_m::interrupt::enable(); + + // call into user code + idle(/* .. */) +} +``` |
