Interrupt handling is an important part of embedded systems development: it allows separating application logic from peripheral interfacing, while removing the need for polling and allowing real-time operations of peripherals.
With interrupt handling in mind, the library may add functionality that requires different implementation while inside an interrupt context. Alternatively, a library function may require checks and calls when running outside an interrupt.
The rule of thumb for interrupt handling is the faster, the better. This usually rules out automatic context detection at runtime. So, library writers generate two versions of the same function, optimizing for the context where they’re executed.
One example of an API that extensively uses of this technique is FreeRTOS’s API. We can take its Timer API as an example, which provides many pairs of these functions:
xTimerStart
/xTimerStartFromISR
xTimerStop
/xTimerStopFromISR
xTimerChangePeriod
/xTimerChangePeriodFromISR
xTimerReset
/xTimerResetFromISR
xTimerPendFunctionCall
/xTimerPendFunctionCallFromISR
But this approach has some issues:
- A user depends on an IDE or documentation to know if a
FromISR
function even exists - If a free function does not have the
FromISR
suffix, does it mean it’s interrupt-safe or not?- Do we really expect a programmer to access documentation to verify if a call is valid in a specific context?
It’s 2021, we can do better than that. In this article, we’ll explore 4 ways of improving an interface like that with C++.
But wait, there’s more: for those who won’t/can’t use C++, we’ll also see 2 ways of doing this with C!