Introduction
I guess most of us as beginners in embedded systems programming in C++, probably start writing firmware with a super loop like architecture where
- all our statements/function calls reside in the main loop
- we start including arduino like libraries
- we create global objects & start using the objects in the main loop.
- being a bit more mature & in order to manage evolving large code base we bring hierarchical models to subgroup our code across different classes
The problem with the super loop is that it is not a very good approach to attain hard real-time performance and is not suited for the embedded applications where you need hard/soft real-time response. So what could be the solution?
The concept of RTOS
The concept of RTOS
The firmware industry has a long history of being written in C with the RTOS approach, for example, VxWorks , freeRtos are very popular and robust. Obviously, RTOS is better than Super Loop considering real-time operation
RTOS types
RTOS is of two types: cooperative and preemptive
In Co-operative RTOS each task must finish before the time allotted for the completion of the task gets over. Meaning there should not be any blocking part in the code. There is an excellent book named “Patterns for Time-triggered Embedded Systems” by Michael J point where many design patterns have been shown to design embedded software using Co-operative RTOS. The author also suggests why a cooperative scheduler can be more effective and reliable than a preemptive scheduler if properly implemented.
On the other hand In preemptive RTOS Tasks can have blocking parts and in this part, context switching i.e. task switching can occur. Task switching can also occur in the middle of a task execution if a higher priority task is needed to be executed. This is called preemption. When a preemption occurs the RTOS saves the current tasks states and then switches to another task. So usage of RAM is an issue here and also other complexity arises. Free RTOS is a well popular preemptive RTOS.
Remember CO-operative RTOS has also priority-based operation capability.
The concept of Active Object
The concept of Active Object
As a firmware engineer, I always wanted to have a combination of all the best options out there. For instance i want to use some of the C++ & OOP features , use arduino ready made libraries & also use RTOS like scheduler to achieve soft/hard real time operation.
Looking around i found Event-driven programming & active object concepts from Miro Samek, he is renowned in the embedded software industry. He created the Active object framework.
Active object has the following properties:
- Encapsulated
- Non-blocking
- HSM (hierarchical state machine)
- Event queues
- Event Publish and subscribe capability
Miro samek’s quantum leaps offers Active object framework solution for different microprocessor architectures. They also offer modelling tools to generate code from UML diagrams. Currently these are the frameworks provided by quantum leaps:
- QP-nano
- QP-C
- QP-C++
These frameworks can work with 2 types of kernels underneath these are:
- Cooperative kernel (QV) (much like co-operative RTOS)
- Preemptive Non-Blocking Kernel (QK) (much like preemptive RTOS but with non-blocking code)
There is an excellent document by miro samek named “beyond the RTOS” to explain the concepts
A minimum Event driven framework looks like this - void loop()
- {
- if( event1() ) { Event_1_handler(); }
- else if( event1() ) { Event_1_handler(); }
- else if( event1() ) { Event_1_handler(); }
- else
- {
- goTo_idleState();
- }
- }
Here the framework/ Supervisory event driven infrastructure waits for events
and dispatches them to application
Some important notes and dispatches them to application
- Calls to functions that poll internally (like delay()) are not allowed, because they would slow down the main loop and defeat the main purpose of event-driven programming
- The Event handler code MUST consist of Linear code that quickly returns control to the framework after handling each event
- The event handler code must be designed in a way so that the event handler can pick up where it left for the last event. But to do this you need if-else branches and code is likely to become “spaghetti code “. The solution is concept of state machine
- Qp –nano framework allows to combine event driven programming with state machines
- In qp-nano framework there is multiple event queues with priority property
- There is a state machine corresponding to each event
- These Event queues are constantly monitored by a scheduler
- Scheduler picks up the highest priority not-empty queue , after finding it > the scheduler extracts the event from the queue and sends it to the state machine associated with it . This is called dispatching of an event to the state machine
- The design guarantees that the dispatch() operation for each state machine always runs to completion and returns to the main Arduino loop before any other event can be processed
- When all event queues are empty the situation is idle condition . in this case QV_onIdle() is called , here processor can go to a low power sleep mode
I think event driven programming is good for battery powered applications
I wish to work with this Active object framework at near future and write a blog post describing my hands on experience
0 comments:
Post a Comment