Requirements For Time And Power-Sensitive Embedded Designs
A key consideration in embedded designs is whether the application requires a real-time operating system (RTOS). Many embedded designers are reluctant to use an RTOS kernel because of concerns that kernels disable interrupts when handling critical sections that can prevent deadlines from being met in time-sensitive applications. It turns out that RTOSs are especially well suited to meet hard deadlines while keeping power consumption to a minimum.
What Is an RTOS?
An RTOS manages the time of a central processing unit (CPU), micro processing unit (MPU) or even a digital signal processor (DSP) as efficiently as possible. Most RTOS kernels are written in C and require a small portion of code written in assembly language to adapt the kernel to different processor architectures.
A kernel provides many useful services to a programmer such as multitasking, interrupt management, inter-task communication and signaling, resource management, time management, memory partition management and more. The application is basically split into multiple tasks, each one responsible for a portion of the application. A task is a simple program that thinks it has the CPU all to itself. Each task is assigned a priority based on the importance of the task.
Multitasking is the process of scheduling and switching the CPU between several sequential tasks. Multitasking provides the illusion of having multiple CPUs and maximizes the use of the CPU. as shown in Figure 1. Multitasking also helps in the creation of modular applications. With an RTOS kernel, application programs are easier to design and maintain.
Most kernels used for embedded systems are “preemptive,” meaning that the Preemptive Kernel always executes the most important task that is ready to run and they are event-driven. , which means that tasks are designed to wait for events to occur in order to execute. When the event occurs, the task executes and performs its function. If the event that the task is waiting for doesn’t occur, the kernel runs other tasks. Waiting for a task consumes zero CPU time. Kernels allow you to avoid using polling loops, which is a bad use of the CPU’s time.
Bluetooth Low Energy (LE)
IoT devices are increasingly equipped with Bluetooth LE software because, when combined with smartphones or similar handheld devices, Bluetooth LE makes commissioning and configuration of these IoT devices simple and convenient.
Bluetooth LE can have multiple different operating modes, multiple connections, multiple advertisers etc and some of them can even overlap. Scanning and connection modes require a response from the device within 150 microseconds whereas advertising is significantly less demanding. and can happen between 20 milliseconds and about three hours.
150 microseconds might seem like a long time for a 32-bit CPU, but there is much to do when processing an incoming request: packets have flow control information indicating what sequence number to request from the other end; there may be address whitelist filtering, which needs to be processed; decryption and encryption, and more. In practice, 120 to 130 µs of CPU time are consumed to perform these operations. Nothing bad typically happens if a packet can’t be processed within 150 µs; data throughput may drop slightly or opening a connection might be delayed. From a customer’s point of view, the behavior is the same as radio interference. However, continuously missing this deadline is not an option as it would make the end product unusable.
Using an RTOS in Bluetooth LE Applications
If an RTOS can potentially disable interrupts for tens of microseconds, then why would you consider using one in a Bluetooth LE-based application? Well, the answer is that these time-critical events can be easily handled outside the RTOS. Specifically, it’s possible to allocate specific time-sensitive interrupt service routines (ISRs) outside the reach of the RTOS. These are called non-kernel aware (nKA) ISRs, and as the name implies, they simply bypass the RTOS kernel. nKA ISRs are ISRs that have a higher priority than kernel aware (KA) ISRs.
Figure 2 shows the priority levels of ISRs and tasks for a typical Cortex-M3 CPU. If the RTOS needs to protect critical section, it will set the Cortex-M3 CPU’s BASEPRI register to 0x40 and thus disable KA ISRs (priorities 0x40 and below). Since priorities 0x00 and 0x20 have higher priorities, they will be allowed to interrupt the CPU, even if the RTOS is in the middle of a critical section.
So, our time-sensitive Bluetooth LE ISR(s) can simply be assigned either priority 0x00 or 0x20, and when they occur, they will be processed immediately, irrespective of the state of lower priority ISRs or tasks.
It’s possible that a task will provide setup information (operating modes, configuration, etc.) for the nKA ISR. An nKA ISR may also require further non-time-critical processing to be performed at the task level. So, if an nKA ISR is not allowed to make any RTOS API calls, how does an nKA ISR communicate with a task? It’s fairly easy to set up shared memory as shown in Figure 3.
The nKA ISR deposits information into memory that it shares with a task.
Since the nKA ISR cannot make any RTOS API calls, it needs to trigger a KA interrupt, which in turn will be allowed to make kernel calls. The ARM Cortex-M CPU’s nested vectored interrupt controller (NVIC) allows system designers to do just that, but the designer would need to identify a peripheral device that is not used by the application and steal its interrupt vector to use for this purpose. In this case, you would simply manually trigger the interrupt by writing to the NVIC->ISPR[n] associated the unused peripheral. Of course, the ISR would not do anything with the peripheral since we are only trying to use its interrupt vector.
The KA ISR can thus signal the task to let it know that data is available in the shared RAM.
When all ISRs have completed and the RTOS has decided that the signaled task is now the highest priority, the task can read the data sent to it by the nKA ISR.
The task can deposit information (as needed) for the nKA ISR in a shared region that is only read by the nKA ISR. Data is written in the shared RAM but can only be read when the ‘Data Available’ flag is set. The ARM Cortex-M3 CPU (and above) has special instructions that ensure that setting or clearing the Data Available flag can be done automatically to prevent race conditions and, without having to disable global interrupts.
The nKA ISR would poll the data provided by the task. That’s typically not a problem since this would happen when the nKA ISR occurs anyway.
Reducing power consumption in an RTOS
When an RTOS has nothing to do, it typically switches to the Idle Task; a task that loops continuously. In order to avoid consuming energy while idling, designers typically invoke a callback function to place the CPU in low-power mode. When an event occurs, the CPU resumes normal execution and services the ISR.
Most kernels are also provided with a periodic time based called the clock tick. Clock tick interrupts are useful to keep track of coarse time delays and timeouts but, they typically wake up the CPU at a regular interval, often at a rate of about 1000 times per second. Of course, Bluetooth Low Energy LE and other power sensitive applications would rather not waste the energy expended by the clock tick so, many RTOSs can completely disable the clock tick interrupt (this is called Tickless systems) or, use a method to optimize the way the clock tick operates. Specifically, instead of waking up the CPU every millisecond, the hardware timer used for the tick interrupt would be reprogrammed to only generate an interrupt when the next delay or the timeout expires. This is called Dynamic Tick and provides the lowest possible energy consumption while still allowing the application to benefit from having a tick source.
RTOS and time-sensitive applications like Bluetooth LE can easily coexist by making time-sensitive ISRs non-kernel aware nKA. Using a scheme similar to this ensures that time-critical code is not affected by the presence of an RTOS. The RTOS can make the most efficient use of the CPU for code that is not time sensitive.
Also, selecting an RTOS that offers a dynamic tick greatly reduces power consumption while providing the benefits of a tick source.