After spending the entire day Thursday implementing the scuba computer, we found out Friday morning that the use of a real-time operating system (RTOS) to implement it was overkill.
I shouldn’t really be surprised; at my work I have worked on projects of much greater complexity without needing an RTOS. The reality is, is that there is a continuum between hard real-time and soft real-time, along which most embedded systems fall, and using an RTOS may bring more disadvantages than advantages.
Specifically when you have a priority scheme allowing a high priority task to snatch the processor away from a lower priority task it leads to a number of complicated problems regarding sharing the processor’s resources. If a low priority task is using the serial port for example, and a high priority task takes over and wants to use the serial port, it could lead to corruption of the serial port data. Tasks need to play nice and share the processors peripherals in a manor that won’t lead to corruption, while at the same time ensuring that the high priority tasks meet their time constraints.
Now these problems have all been addressed in the design of modern RTOS’s but these solutions are not free, they require processor time, resulting in a lot of overhead that simply isn’t required if an RTOS is not used.
So Friday’s lecture was about RTOS alternatives, and it turns out that there are quite a few. Specifically we talked about the following:
- Big loop + interrupt systems
- Cyclic executive systems
- Co-routine systems
- Proto-thread systems
- Function Queue systems
- State-machine systems
I don’t have time to touch on them here but from my perspective I have used 1, 5 and 6 to some extent.
State-machine programming is the topic that I want to discuss today, because more than all of the others it really is an entirely different programming paradigm.
What I mean by a paradigm is both the style of programming used, and subsequently the thought processes used to break down a problem.
There are many different programming paradigms, the most common being: procedural, functional, parallel, and object-oriented.
Traditional embedded programming is entirely procedural with some parallel programming concept thrown in when using an RTOS.
State-machine programming is something a little different. In has a correlation with the desktop world where it goes by the name of event-driven programming. For example in Windows if you are writing an application you might draw a nice little button using the graphical tools Windows supplies and then you program the code to handle all the possible events that might happen to that button. Specifically you would tell the computer what to do if a user clicked on the button.
In the embedded world you can design a system in a somewhat similar way. Using our scuba computer as an example we could define some states that our system might be in. They might be:
- At the surface with no oxygen
- At the surface with oxygen
- Decending with sufficient oxygen to reach the surface
- Ascending with sufficient oxygen to reach the surface
- Decending without sufficient oxygen to reach the surface
- Ascending without sufficient oxygen to reach the surface
- Below the surface at a depth of greater than 40m
- Ascending faster than 15m per minute
These are the system states. We then also would define the possible events that could occur. Some may be:
- Oxygen is added.
- Oxygen is depleted
- Ascending
- Descending
We then program the system to change state depending on each event that might occur. For example if we are in the “at the surface with no oxygen” state and then oxygen is added, our new state would be at the surface with oxygen. If instead the “descending” event occurred without adding oxygen, our state would be “descending without sufficing oxygen to reach the surface”. Also not all events would be handled by each state. If we are at the surface we would simply ignore the ascending event. Also some events might just keep us in the current state. If we are descending, a descending event wouldn’t change our state unless at the same time we ran low on oxygen or we exceeded the maximum depth.
It might not be immediately obvious to the non-programmer, but this way of thinking about a system is very different from the usual procedural way of thinking, when we instruct the computer to first do one then then do another. Now the program literally does nothing until an event triggers it to do something. Then with each event we might do something as we leave a state, do something as we transition between states and then maybe do something upon entering a new state. Once this was done we then sit and spin in the new state doing nothing but waiting for the next event. To my mind this is a fascinating way to look at a whole set of problems that I face day in and day out as an embedded programmer.
I wasn’t unfamiliar with these techniques before the course, but certainly now having had them refreshed I feed much more capable as an embedded programmer and ready to tackle the next problem that my employer sends my way.