As already mentioned in Overview , this book explains and shows examples of how to implement soft real time systems. This chapter will explain basic concepts of asynchronous event handling as well as how to implement required functionality without complex state machines, and/or task scheduing.
Event Loop
Most bare-metal embedded products require only two modes of operation:
Interrupt (or service) mode
Non-interrupt (or user) mode.
The job of the code, that is executed in interrupt mode, is to respond to hardware events (interrupts) by performing minimal job of updating various status registers and schedule proper handling of event (if applicable) to be executed in non-interrupt mode. In most projects the interrupt handlers are not prioritised, and the next hardware event (interrupt) won’t be handled until the previously called interrupt handler returns, i.e. CPU is ready to return to non-interrupt mode. Therefore, it is important for the interrupt handler to do its job as quickly as possible.
There are multiple ways to schedule the execution of event handling code in non-interrupt mode from code being executed in interrupt mode. One of the easiest and straightforward ones is to have some kind of global flag that indicates that event has occurred and the processing is required:
bool g_buttonPressed = false ; void gpioInterruptHandler () { ... if ( /*button_gpio_recognised*/ ) { g_buttonPressed = true ; } } int main ( int argc , const char * argv []) { ... while ( true ) { // infinite event processing loop enableInterrupts (); ... if ( g_buttonPressed ) { disableInterrupt (); // avoid races g_buttonPressed = false ; enableInterrupts (); ... // Handle button press } ... disableInterrupts (); if ( /* no_more_events */ ) { WFI (); // “Wait for interrupt” assembler instruction, // instruction will exit when there is pending // interrupt. } } }
It is quite clear that this approach is not scalable, i.e. will quickly become a mess when number of hardware events the code needs to handle grows. The events may also be handled not in the same order they occurred, which may create undesired races and side effects on some systems.
Another widely used approach is to create a queue-like container (linked list or circular buffer) of event IDs which are handled in the similar event loop:
... continue reading