NuttX – a user review on Arm Cortex-M7
Author: Frank Benkert, FRB Computersysteme GmbH
Contribution – Embedded Software Engineering Congress 2017
Development projects for new embedded products are usually confronted at the beginning with the same fundamental question: With or without an operating system. If without, then how? If so, which one? There's no single, universally applicable answer to this question. However, if you examine the requirements for the new product more closely, the answer often becomes clear. But what facts truly help with the decision? How do you gather this information? What questions need to be asked? Who can answer them? The following section will use a real-world project to illustrate how this selection process and subsequent integration can be successfully achieved.
The project
The following descriptions are based on a real-world project that aimed to develop a new family of devices for controlling large motors. After almost two years of development, the project was successfully completed a few months ago (within the planned budget). Some versions of the devices are already in production, while others are still undergoing certification or approval processes.
The platform used was an ATMEL Arm Cortex-M7 (automotive variant). This document is intended as a general basis, therefore the wording (wherever possible) does not refer directly to the project. Direct references to the described development project are in italics.
What is an operating system?
In order to even ask the question of "with or without", it must be clear what the individual participants understand by the term operating system.
The deeper a developer works within the system, the more nuanced their view becomes of the "thing" between hardware and application. Regardless of the definition ultimately agreed upon, it is crucial to share a common understanding of this term.
The project team agreed on the following definition: "An operating system consists of a task scheduler with an associated driver architecture." The size or completeness of the "driver architecture" was not a decisive factor.
With or without an operating system
Answering this question is much simpler than many people think. Only a few key points serve as the basis for the decision:
- Does the product require multiple concurrent execution streams (tasks)?
- Are these tasks active (or do they only react to external events)?
- Are there time-critical requirements for the mutual processing?
If at least one of these questions is answered with "yes", then it is advisable to at least start using a scheduler.
The question of active versus reactive systems points in the direction of interrupts. A purely reactive system can, for example, have more than one execution path using multiple interrupt routines. These are then (usually) sequential. Systems with "interrupt priorities" and "nested interrupts" are an exception. Such a technique can already be described as a pseudo-scheduler.
Should you decide against a scheduler despite a "yes" vote, the project will almost certainly deliver a scheduler as an output in addition to the actual product.
However, to answer the question of the necessity of a driver architecture, there is actually only one single point:
- Is there any hardware that should be abstracted away from the application?
A "yes" answer means that at least one driver is required. Together with the answer to the question about the scheduler, the most fundamental question of "with or without" can now be easily answered.
The project opted for "Mit".
Operating system requirements
To later make a selection from the hundreds of operating systems available on the market, it is important to compile the requirements in a matrix. The following list is intended as a starting point for addressing this question. Depending on the product, this list will of course need to be expanded, modified, or shortened.
Is the processor core supported?
Processors now support operating systems with a multitude of integrated functions. What previously had to be implemented manually in the scheduler is now handled directly by the processor with just a few assembly instructions. From automated task switching and stack management to permission checks, many functions are now integrated into processors. However, this requires that the scheduler kernel recognizes and controls these features. Only then is it possible to extract optimal performance from the processor.
Does the scheduler support the necessary scheduler strategies?
A real-time scheduler has become virtually indispensable in the development of embedded products. Its purpose is to ensure that deadlines are met and predictability is maintained. Initially, a strictly priority-driven implementation is sufficient. But what happens when multiple tasks need to operate at the same priority? Which one then takes precedence?
Additional strategies such as "Round Robin" or "First In, First Out" exist for this purpose. Schedulers are also available that guarantee fairness in one way or another. However, these are rarely required in embedded systems.
What level of granularity must the scheduler offer?
An embedded system sometimes needs to make decisions or trigger actions on a microsecond scale. Depending on the desired system architecture, it's crucial to consider whether, for example, an external message can be processed every 2 milliseconds or an actuator value can be rewritten within a 300-microsecond timeframe. While a scheduler with a fixed 20ms interval might be fast, it's ultimately unsuitable.
Are synchronization and signaling supported?
When multiple tasks are running within a system, it is inevitable that they will have to share resources. Atomic mechanisms are required to synchronize access to these resources. These are typically implemented as "counting semaphores," upon which various other synchronization mechanisms can be built.
Does the project require interprocess communication (IPC)?
When information is processed across multiple tasks, it may be necessary to exchange messages between system components. This can be done, for example, via pipes or queues. If the product exhibits this issue, an operating system candidate should also be tested against this requirement.
Does the system include support for MMUs?
An increasing number of embedded systems are equipped with Memory Management Units (MMUs). Depending on the system size, these MMUs offer a range of functions – from simple cache management (which memory area is mapped by the CPU cache?) and access control to complex mapping tasks within a virtual address space. Depending on the product requirements and hardware specifications, this represents a helpful operating system function.
Does the system include support for storage management?
The standard interfaces for dynamic memory allocation are well known to every programmer: "malloc" and "free". Behind this seemingly simple interface, however, lie complex strategies for reducing memory fragmentation, for example. If the product requires such functionality, it is crucial that the operating system already provides tried and tested mechanisms for this purpose.
Support for peripherals and interfaces
Even though peripheral connectivity is often provided by manufacturers as a reference implementation, it still saves a lot of work if a similar component or the required interface already exists as a ready-made driver for that specific operating system. Ideally, it would already be fully configured and tested, or at least include a set of test functions that can be executed on the user's own hardware.
IDE and debugging support
Whether an operating system comes with its own "full-featured IDE" with an integrated compiler, or whether you have to assemble the components yourself, is irrelevant. What's important when evaluating this point is that a closed loop is possible, from programming in a user-friendly editor, through compilation and deployment of the compiled code to the target, all the way to line-level debugging. Of course, with some products, the latter is only achievable through emulators. These options should be tested before deciding on a solution.
Is the source code of the operating system available?
On embedded systems, the integration between application, drivers, and scheduler is inherently very tight. This often necessitates traversing external functions during debugging for better understanding. Many commercial vendors therefore grant limited access to their source code under certain contractual conditions to support this approach. This issue naturally does not arise with open-source systems.
What license does the operating system have?
This is a question that concerns not only engineers but also product managers. Just as there are many licensing models in the open-source world, there are just as many in the world of commercial products. What each license actually means must be examined in detail for each specific product. For example, a commercial license per development site is just as detrimental for distributed teams as a license that requires the author to be credited in the manual for a product without customer documentation.
Support and Community
Often overlooked, but nonetheless important, is the question of community. Even the manufacturer's commercial support can hardly replace a lively online discussion group. A place where questions are answered without bureaucracy, code snippets are posted, or bugs are reported is often more valuable than a support contract. For some time now, commercial providers have also been hosting mailing lists where both users and support staff can exchange information.
In addition to this general list, many other aspects played a role in the actual project, such as support for the I2C, SPI, QSPI, and USB interfaces, as well as file systems and fieldbuses. Furthermore, soft factors such as future-proofing, licensing risks, testability, and training effort were also included in the evaluation.
Selection process
The selection process should be limited to a few promising candidates. In addition to (unfortunately often outdated) lists from the internet and information from the providers, the experiences of participating developers can also be helpful in the pre-selection process. The selection process itself is not as straightforward as one might think, which is why it's good to consider as few alternatives as possible. It is recommended to include a maximum of five applicants.
Contrary to what one might expect, the process doesn't simply involve ticking boxes for features, but primarily involves researching existing documentation online and contacting support. Whether feature XY listed in the hit list actually represents the required combination of X and Y, or whether the manufacturer only considers a subset of it, is often difficult to ascertain and requires extensive research.
A reasonable deadline should be set for the selection process. It's easy to get bogged down in the analysis of features. To save time, it's also advisable to allow answers such as "very likely" or "XX percent" in addition to "yes" and "no".
Once the evaluation matrix is nearly complete, further factors are added depending on the answers to the feature questions:
- What costs arise from insufficient or non-existent support for a feature?
- What risk is posed by the uncertainty of whether a feature will be (only partially) supported?
- What risks are associated with a lack of support or a missing or very small community?
After a selection process lasting several weeks, in which many aspects had to be evaluated not only through documentation and support requests, but also through tests, the project decided on the open source operating system NuttX [1].
What is NuttX [1] – and why this decision?
In short, NuttX is a real-time operating system with a POSIX-compliant driver and interface architecture under the BSD license. It was first released in 2007 by Gregory Nutt and has been actively developed under his leadership ever since. Because NuttX is under the BSD license, no user (except in their manual) needs to disclose that they are using NuttX. As a result, the system remained relatively quiet for a long time. Few publications referenced the system, such as the open-hardware project PX4 [2] – a (quadcopter) autopilot hardware project developed in collaboration with ETH Zurich.
The number of supported processor types, however, shows that there was far more interest than public perception suggested. Currently, this list includes over 150 processor families, from ARM to ZiLOG Z80, plus a Linux/Cygwin simulation platform.
The decision to use NuttX was extremely close for the project, as not all of the required functions and features were yet integrated at that time. They are now – thanks to upstreaming the source code.
The download figures [3] of the NuttX homepage show that Europe ranks only third, behind China and the USA. This may also be one reason why we in Europe have heard so little about NuttX so far. In recent years, however, interest in NuttX has grown steadily, as can be seen, for example, in the increasing number of posts on the mailing list. Furthermore, the LinkedIn group, which was only launched this year, now has over 1000 users. Companies are also now publicly acknowledging NuttX. For example, at the beginning of the year, Sony launched a family of digital voice recorders (e.g., the ICD-SX2000) and published its further developments of NuttX in connection with these products for reintegration into the mainline under its company name.
We can look forward to seeing how the growth continues.
Goodies
Besides many "normal" features, NuttX also offers highlights that make it stand out from the crowd of embedded systems.
C++11 Support
While rudimentary C++ support had been provided for several years via µClibC++, the C++11 compatible „libc++“ from the LLVM project was integrated in 2016.
„"It's like Linux"“
The programming of NuttX hardly differs from that of Linux – from „pthreads“ to „everything is a file“ within a virtual file system to a shell that is accessible via the serial interface.
Diagnostic commands such as "free" or "ps" can be activated in the same way as "dd" or "hexdump".
This means that the learning curve for programmers of (usually larger) embedded Linux systems is very short. Existing source code from custom function libraries can also be migrated to NuttX almost seamlessly.
Tickless Scheduler
Standard schedulers use the cyclical clock of a timer chip to manage their scheduler execution. With each tick, a function is triggered that handles task management. This results in a very high interrupt load above a certain frequency (tick rate), which significantly impacts embedded systems. NuttX offers the "Tickless Scheduler" feature, where the scheduler calculates when the next action needs to be executed and programs the timer chip (essentially as a dynamic alarm clock) for that specific time. This enables higher accuracy at lower frequencies and thus lower interrupt loads.
Dynamic Composite USB Device
NuttX offers not only host USB drivers but also device USB drivers. A relatively new feature is the runtime-configurable composite USB device. This allows, for example, the activation of additional serial interfaces within a composite device for maintenance mode or debugging, which are not active in the default settings.
Visual Studio with VisualGDB [4] as IDE
Since NuttX is open source, the task management is completely transparent. Configurable debugger plugins can read the task structures and stack frames, thus enabling convenient debugging.
The project used an Atmel Cortex-M7 processor. The connection to the hardware debugger was established via the SWD interface. Information processing was implemented using a debugger plugin, so that the display in Visual Studio was indistinguishable from debugging a local (Windows) process.
Conclusion
Selecting an operating system for a microcontroller is a complex process and should not be underestimated. For projects lasting months or years, it is essential to invest a significant amount of time in evaluating different systems.
In retrospect, the decision to develop the NuttX project was the right one, even though (as already explained) the facts were not entirely clear.
References
[3] unfortunately only available until 2015
Download the article as a PDF file
Real-time – MicroConsult Training & Coaching
Do you want to bring yourself up to date with the latest technology?
Then find out more here MircoConsult offers training courses/seminars/workshops and individual coaching on the topic of embedded and real-time software development.
Training & coaching on the other topics in our portfolio can be found here. here.
Real-time expertise
Valuable expertise in the field of embedded and real-time software development is available. here Available for you to download free of charge.
You can find expertise on other topics in our portfolio here. here.
