Attribute Macro cortex_m_rt::exception

source ·
#[exception]
Expand description

Attribute to declare an exception handler

§Syntax

#[exception]
fn SysTick() {
    // ..
}

where the name of the function must be one of:

  • DefaultHandler
  • NonMaskableInt
  • HardFault
  • MemoryManagement (a)
  • BusFault (a)
  • UsageFault (a)
  • SecureFault (b)
  • SVCall
  • DebugMonitor (a)
  • PendSV
  • SysTick

(a) Not available on Cortex-M0 variants (thumbv6m-none-eabi)

(b) Only available on ARMv8-M

§Usage

§HardFault handler

#[exception(trampoline = true)] unsafe fn HardFault(.. sets the hard fault handler. If the trampoline parameter is set to true, the handler must have signature unsafe fn(&ExceptionFrame) -> !. If set to false, the handler must have signature unsafe fn() -> !.

This handler is not allowed to return as that can cause undefined behavior.

To maintain backwards compatibility the attribute can be used without trampoline parameter (#[exception]), which sets the trampoline to true.

§Default handler

#[exception] unsafe fn DefaultHandler(.. sets the default handler. All exceptions which have not been assigned a handler will be serviced by this handler. This handler must have signature unsafe fn(irqn: i16) [-> !]. irqn is the IRQ number (See CMSIS); irqn will be a negative number when the handler is servicing a core exception; irqn will be a positive number when the handler is servicing a device specific exception (interrupt).

§Other handlers

#[exception] fn Name(.. overrides the default handler for the exception with the given Name. These handlers must have signature [unsafe] fn() [-> !]. When overriding these other exception it’s possible to add state to them by declaring static mut variables at the beginning of the body of the function. These variables will be safe to access from the function body.

§Properties

Exception handlers can only be called by the hardware. Other parts of the program can’t refer to the exception handlers, much less invoke them as if they were functions.

static mut variables declared within an exception handler are safe to access and can be used to preserve state across invocations of the handler. The compiler can’t prove this is safe so the attribute will help by making a transformation to the source code: for this reason a variable like static mut FOO: u32 will become let FOO: &mut u32;.

§Safety

It is not generally safe to register handlers for non-maskable interrupts. On Cortex-M, HardFault is non-maskable (at least in general), and there is an explicitly non-maskable interrupt NonMaskableInt.

The reason for that is that non-maskable interrupts will preempt any currently running function, even if that function executes within a critical section. Thus, if it was safe to define NMI handlers, critical sections wouldn’t work safely anymore.

This also means that defining a DefaultHandler must be unsafe, as that will catch NonMaskableInt and HardFault if no handlers for those are defined.

The safety requirements on those handlers is as follows: The handler must not access any data that is protected via a critical section and shared with other interrupts that may be preempted by the NMI while holding the critical section. As long as this requirement is fulfilled, it is safe to handle NMIs.

§Examples

  • Setting the default handler
use cortex_m_rt::exception;

#[exception]
unsafe fn DefaultHandler(irqn: i16) {
    println!("IRQn = {}", irqn);
}
  • Overriding the SysTick handler
use cortex_m_rt::exception;

#[exception]
fn SysTick() {
    static mut COUNT: i32 = 0;

    // `COUNT` is safe to access and has type `&mut i32`
    *COUNT += 1;

    println!("{}", COUNT);
}