Crates.io | cortex-m-interrupt |
lib.rs | cortex-m-interrupt |
version | 0.2.0 |
source | src |
created_at | 2022-10-27 09:22:46.098102 |
updated_at | 2022-10-27 11:56:31.421139 |
description | Function-like, trait-based interrupt handler registration. |
homepage | https://github.com/datdenkikniet/cortex-m-interrupt |
repository | https://github.com/datdenkikniet/cortex-m-interrupt |
max_upload_size | |
id | 699012 |
size | 28,533 |
This crate provides a method of delegating creation of occupations, and attempts to improve pains associated with creating registrations.
As an end-user of this crate, you will want to use the [take_nvic_interrupt
] and [take_exception
] macros. These generate implementors of the [NvicInterruptRegistration
] and [ExceptionRegistration
] traits respectively, which can be passed to functions that make use of interrupts.
To see information on how you can use [InterruptRegistration
], [NvicInterruptRegistration
] and [ExceptionRegistration
] refer to the docs on those traits.
To demonstrate the problem that this crate tries to solve, we will use an example use case.
To help explain the use case of this crate, we use the following definitions:
Our goal with the use case is:
SysTick
interrupt so that it triggers once every 1337
cycles.SysTick
interrupt occurs.When using the cortex_m_rt
crate, we would do something like this:
# fn systick_reload(_: u32) {}
# fn setup_systick_exception(_: u32) {}
use cortex_m_rt::{exception, entry};
#[exception]
fn SysTick() { // This is the "registration" (can only
// be provided once in entirety of the
// program, incl. libraries)
static mut COUNTER: u32 = 0; // This is part of the "occupation"
*COUNTER += 1; // This is the "occupation", the
systick_reload(1337); // actual code to be executed
// when handling the SysTick
// interrupt.
}
#[entry]
fn main() {
setup_systick_exception(1337);
loop {}
}
And within the crate providing setup_systick_exception
and systick_reload
:
pub fn setup_systick_exception(reload_value: u32) {
/* Setup systick so that it triggers the SysTick interrupt
after `reload_value` cycles
*/
}
pub fn systick_reload(reload_value: u32) {
// Reload the systick value
}
In this example:
setup_systick_exception
and the registration/occupation besides naming and possibly documentation.setup_systick_exception
and systick_reload
has no control over the occupation or registration.To represent registrations, the [InterruptRegistration
], [NvicInterruptRegistration
], and [ExceptionRegistration
] traits are provided. They can be used to insert occupations in a more dynamic way.
These traits allow for the following:
To alleviate difficulties with creating registrations, the [take_nvic_interrupt
] and [take_exception
] proc-macros are provided. They perform the less self explanatory parts of the setting up a registration, and provide an implementor of [NvicInterruptRegistration
] and [ExceptionRegistration
], respectively.
With these new tools, we can rewrite our code to look as follows:
# fn setup_systick_exception<T: cortex_m_interrupt::InterruptRegistration>(_: u32, _: T, _: fn()) {}
use cortex_m_rt::entry;
use cortex_m::peripheral::scb::Exception::SysTick;
static mut COUNTER: u32 = 0;
fn increase_counter() {
unsafe { COUNTER += 1 };
}
#[entry]
fn main() -> ! {
// We create the registration
let systick_registration = cortex_m_interrupt::take_exception!(SysTick);
// And pass it to some function that will do some configuration and
// provide a occupation for that registration. It also allows us to
// inject our own expansion to the occupation.
setup_systick_exception(1337, systick_registration, increase_counter);
loop {}
}
In the crate providing setup_systick_exception
:
# use cortex_m_interrupt::ExceptionRegistration;
pub fn setup_systick_exception<Registration: ExceptionRegistration>(
reload_value: u32,
registration: Registration,
f: fn(),
) {
// Assert that we've been given a registration of the correct
// exception/interrupt.
assert_eq!(
cortex_m::peripheral::scb::Exception::SysTick,
registration.exception()
);
/* Setup systick so that it triggers the SysTick interrupt
after `reload_value` cycles
*/
use core::mem::MaybeUninit;
static mut USER_HANDLE: MaybeUninit<fn()> = MaybeUninit::uninit();
static mut RELOAD_VALUE: MaybeUninit<u32> = MaybeUninit::uninit();
unsafe { USER_HANDLE.write(f) };
unsafe { RELOAD_VALUE.write(reload_value) };
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Release);
registration.occupy(|| {
systick_reload(unsafe { RELOAD_VALUE.assume_init() });
// Call extra user code
unsafe { (USER_HANDLE.assume_init())(); }
});
}
fn systick_reload(reload_value: u32) {
// Reload the systick value
}
In the revised example:
setup_systick_exception
has full control over the occupation, and can optionally allow user code to perform some extra actions.setup_systick_exception
can verify that the correct registration is passed to it.The main differences between the cortex-m-rt
approach and what cortex-m-interrupt
provides are the following:
cortex-m-interrupt
offers a way of creating clearer separation of responsibilities when it comes to registering interrupt handlers.cortex-m-interrupt
support a tighter semantic connection between creating a registration and creating an occupation.cortex-m-rt
has slightly less overhead as it does not require a trampoline.