Real-time operating systems (RTOSes) have become a critical component in many embedded systems. Transitioning from bare-metal scheduling to an RTOS can be tricky business. Here are seven tips to help make the transition easier.
Tip #1 – Plan out your architecture first
If you have never used UML or been big into software architectures, now is the time to learn about it. When using an RTOS, it is critical that developers think through each task, synchronization and communication mechanisms. These details can’t just be stored in the mind of an engineer but need to be put down in diagram form so that they can be reviewed and updated as needed. Developing an RTOS based application can get complicated fast and it’s important to think through how the application will behave.
Tip #2 – Carefully track memory usage
Unlike when developing a baremetal application, RTOS tasks and synchronization constructs can very quickly suck the memory dry in a resource constrained device. Developers need to monitor memory very carefully and keep track where it is all going. It is not uncommon to create a half dozen tasks, a few semaphores and mutexes only to find that malloc is failing because all the heap space has been used.
Tip #3 – Create all the tasks up-front
An RTOS provides developers with a wide range of capabilities such as the ability to create tasks and destroy tasks. A developer concerned with memory usage may be tempted to only create tasks when they are needed and then destroy them once they have completed. While this is great in concept, in a resource constrained system there usually is not a complex heap manager that can handle heap fragmentation. The result can be a fragmented heap that at some point during program execution suddenly has no memory that can be allocated. The recommendation is to create all objects that use the heap during system initialization. The result appears to be statically allocated objects and if there is a memory issue, the issue will be apparent during system start-up.
Tip #4 – Never turn the stack guard off!
Baremetal developers are often obsessed with writing the most efficient code possible. The realization that there is a stack monitor using up clock cycles become a tempting target for optimization and removal. DON’T DO IT! The stack monitor is there to detect stack overflows and other issues related to the stack. While yes it does use a few clock cycles, the benefit far outweighs the performance cost.
Tip #5 – Optimize every tasks stack
Don’t rely on the default stack size. In many RTOSes the default stack size for a task is around 0x200. That is often the stack depth not the number of bytes used! That single task that is only blinking an LED could be using an entire kilobyte of heap space! Make sure you perform a worst case stack analysis and size each tasks stack appropriately. This will help save memory in the long run!
Tip #6 – Enable RTOS aware debugging
Modern microcontrollers have some really cool debugging features such as real-time tracing and RTOS aware debugging. Enable these features on the microcontroller and within the RTOS. They will allow a developer to trace which tasks are running for how long, in what order and can help identify many common problems associated with RTOSes.
Tip #7 – Select task priorities carefully
One reason that developing a software up front can be so helpful is that it provides the big picture for everything that is happening in the system. With that big picture, it becomes easier to decide on the priorities for each task within the system. Careful selection for the priorities must be made in order to make sure that a task is not starved for CPU time and to ensure that issues like priority inversion cannot occur in the system.
Using an RTOS can be extremely rewarding for developers and can help speed up the development cycle. Many middleware, libraries and frameworks rely on an RTOS and in today’s big push for IoT devices, baremetal is out and mastering the RTOS is mandatory.