Ask any member of the sales or support staff at a major RTOS provider what question they hear most frequently from prospective users of their software, and they’re likely to offer some variation of “Does your software run on my board?” There’s little wonder this question is raised so often; embedded systems developers today seem to have an endless variety of MCUs, evaluation boards, and IDEs available for use in new designs, and it is not always easy to determine which RTOSes support a particular combination of hardware and tools.
While both RTOS providers and prospective users would prefer a simple “yes” as the answer to the ubiquitous hardware-support question, the actual response to this question tends to be somewhat more nuanced. RTOS providers are typically small organizations (in relation to their counterparts in the hardware world, at least), and their expertise lies in the core software that they develop, not necessarily the boards on which this software runs. Accordingly, the resources simply don’t exist for a single provider to truly offer full support for all of the evaluation and development boards in use today.
One way for an RTOS provider to deal with the inevitable issue of limited resources is to write portable software that can easily be integrated with low-level code from a variety of sources. For Micriµm, the provider of the popular “µC” family of RTOS components, this strategy is key. Micriµm supports a large number of hardware platforms with simple, kernel-based example projects that allow developers to get code running, and that are written so they can be expanded, with relative ease, to support a range of different peripheral devices and hardware components.
Micriμm’s lineup of RTOS components is anchored by the μC/OS-II and μC/OS-III kernels. These modules serve as the foundation for nearly every example project that Micriμm’s engineers develop. Thus, when Micriμm makes the decision to officially support a particular hardware platform, the engineering team’s initial focus is on the kernels.
Although kernels are not trivial pieces of code, the job of adapting a kernel to a particular piece of hardware is a rather straightforward one, especially for an engineer already familiar with both the kernel and the hardware. The hardware-specific routines within a kernel are collectively referred to as a “port,” and a typical port for μC/OS-II or μC/OS-III comprises around 1000 lines of code. Micriμm’s engineers, then, can complete a new port within a relatively short amount of time.
In addition to being relatively easy to write, ports lend themselves well to reuse. All of the ports that Micriμm’s engineers prepare for μC/OS-II and μC/OS-III target a CPU architecture, rather than a particular implementation of an architecture. The μC/OS-II and μC/OS-III ports for Renesas’s RX MCU family, for example, allow developers to run the kernels on essentially any RX device, as Figure 1 illustrates.
Figure 1: Micriμm’s RX kernel port is compatible with numerous devices.
The absence of any excessively complex development work from the process of adapting a kernel to new hardware has allowed Micriμm to amass a collection of ports for over 40 different architectures, while the wide applicability of these ports provides developers a means of running μC/OS-II and μC/OS-III on an incredibly large collection of MCUs. If a port is available for a particular CPU architecture, there’s usually very little to be done to make either of the kernels run on an implementation of that architecture. A few low-level routines constituting a very simple BSP (board support package) may be needed to initialize clocks and, in general, lay the ground for C code to execute, but these sorts of routines are, of course, required in all projects, and can typically be taken directly from examples provided by hardware and tool vendors.
The support situation for Micriμm’s other components, such as the μC/TCP-IP and μC/USB protocol stacks, is highly similar to that of the kernel. Each of these components requires a low-level driver that, like a kernel port, is often applicable to more than one hardware platform. The other components do not yet support quite the same range of platforms as the kernels, but the currently available collection of drivers represents a number of popular MCU families and is expanding at a steady pace.
Ultimately, then, if the conversation is limited to Micriμm’s components, the question of hardware support is an easy one to answer; it depends almost entirely on the availability of drivers. However, developers sometimes need drivers for peripheral devices that are not managed by any of Micriμm’s components. For instance, a developer would be able to use μC/TCP-IP for sending and receiving data via an Ethernet controller but could not, in a similar fashion, turn to any Micriμm components for outputting signals via a PWM timer.
It is in situations of the latter variety that the ease of combining Micriμm’s projects with low-level code from tool and hardware vendors can prove to be substantially beneficial. While Micriμm might not have any software components dedicated to the use of PWM timers, there are numerous pieces of example PWM code available from Micriμm’s partners. In many instances, such third-party code can be added to Micriμm-based projects with minimal work.
The process of combining Micriμm’s code with low-level code from other sources can easily be illustrated with an example. The hardware platform for this example will be the YRDKRX63N board from Renesas, and the low-level code in question will correspond, as in the above examples, to a PWM. The source of the low-level code will be Micriμm’s longtime IDE partner, IAR Systems.
The well-known IAR Embedded Workbench IDE has grown over the past several years to support practically every CPU architecture popular amongst embedded systems developers, and an important part of this support is the gigantic collection of example projects to which IAR Embedded Workbench users have access. A number of examples are available for the YRDKRX63N, including the PWM example shown in Figure 2. A developer seeking to adapt this example’s PWM driver to a Micriμm-based project could do so in three simple steps.
Figure 2: An RX63N-based PWM example is provided with the RX version of IAR Embedded Workbench (\rx\examples\RDKRX63N\Basic_samples\MTU_PWM)
The first step to take in converting the PWM driver for use with Micriμm’s software would be to modify its interrupt-related code. In a project based on a preemptive kernel, such as either μC/OS-II or μC/OS-III, interrupt handlers must adhere to a particular format. Of course, for drivers that are polled, as opposed to interrupt driven, there are no handlers to modify. For other drivers, the changes that are required are often minimal. In the case of the RX PWM driver, the necessary changes would follow from the guidelines provided in the documentation for Micriμm’s latest RX kernel ports, and would amount to little more than removing the __interrupt keyword from the prototypes of the driver’s two interrupt handlers and updating application code with calls to register the handlers.
With the interrupt code modified as required by Micriμm’s kernels, the PWM driver from the example project would already, to a limited extent, be compatible with Micriμm-based projects. However, in this state the driver could not be safely invoked from multiple tasks in such a project. The second step in converting the driver, then, would be to modify any passages of code that could cause problems in a multi-task environment.
The primary sources of potential problems for drivers that are moved from a single-task environment to a multi-task, or kernel-based, project involve the drivers’ use of shared resources, such as global variables and peripheral devices. In multi-task projects, shared resources must be protected, and most kernels provide one or more mechanisms for implementing this protection. A developer intending to protect the PWM driver’s shared resources (consisting chiefly of memory-mapped registers for the PWM and other peripherals) would have four options under μC/OS-II or μC/OS-III: critical sections, scheduler locking, semaphores, and mutexes.
Figure 3 shows how shared resources in the PWM driver’s initialization routine could be protected through the use of a critical section. Other resource-protection approaches could be taken in this function, but they would involve more overhead than a critical section and could not protect the function’s resources from accesses by interrupt handlers. (Additional information on the pros and cons of the different resource-protection mechanisms offered through μC/OS-II and μC/OS-III is available in the well-known books that have been written around these kernels. A Renesas RX version of the μC/OS-III book is available as a free PDF from the Micriμm Web site.)
Figure 3: Shared resources, such as memory-mapped registers, can be protected through the use of critical sections in a multi-task application.
The third and final step to take in modifying the PWM driver for use in a Micriμm-based project would be optional, and it would involve enhancing the driver to take advantage of the services available in a multi-task environment. There are many ways to optimize a device driver for use with a kernel, but the most common may be to rewrite or replace delay functions. The empty loops that are commonly used for time delays in single-task driver code are wasteful in a multi-task environment and should be replaced with calls to equivalent kernel functions, as indicated by Figure 4. Although this specific modification could not be made to the PWM driver (since it does not contain any loops), the use of kernel delay functions could certainly be advantageous in other drivers.
Figure 4: In kernel-based applications, delay functions can be used in place of empty loops.
Ideally, embedded systems developers would not have to undertake the work of importing third-party driver code into their projects, regardless of the extent to which the drivers would require modification. In a growing number of cases, developers can indeed avoid these low-level details, thanks to robust example projects from Micriμm and other RTOS vendors. It is still true, though, that supporting every popular hardware platform with comprehensive example projects is too much for a single vendor to handle. To effectively support customers across a wide range of platforms, RTOS providers must turn to partners in the hardware and tool fields.
Embedded systems developers are, in the end, the primary beneficiaries of collaborating RTOS, hardware, and tool providers. In addition to gaining access to a wider base of low-level code, developers can benefit from unique product features that straddle the boundaries between different areas of specialization, such as IAR Systems helpful kernel-awareness packages for μC/OS-II and μC/OS-III. The results of collaboration amongst RTOS vendors and their partners can afford developers a flexible, yet dependable, foundation for putting together successful embedded systems.
This articlei is written by Matt Gordon, Sr. Applications Engineer, Micriµm.