In many products that surround us every day, software works on microcontrollers with very limited resources (memory, processing power, energy). This software must be highly optimized in order to reliably perform its work on the limited hardware platform.
The reasons why only limited resources are available for many applications are manifold: Very often there are devices that are produced in large quantities (e.g. household appliances), so considerable costs can be saved by using only a few cents cheaper hardware components (e.g. less powerful processor, smaller memory). In other cases, it is a matter of achieving a long operational time with little energy (e.g. battery-operated metering devices, handheld measuring instruments).
Frequently 32-bit microcontrollers based on ARM Cortex-M cores or very low-power 16-bit microcontrollers (e.g. TI MSP430) are used today in such applications. Occasionally there are still platforms with 8-bit microcontrollers (for example Atmel ATmega).
redlogix is intimately familiar with the specific challenges of embedded software development for this type of applications and has developed software for a variety of such products.
- operating interfaces with graphical touch displays for (gastronomic) dishwashers
- RFID readers for product tracking and inventory in industrial production
- HMI devices for industrial control tasks
- compact laser distance meters
- mobile measuring devices for the measurement of discharge currents in switchgear and cables
- metering devices (e.g., water, heat, electrical energy)
- vending machines (e.g. for parking tickets)
- tracker wristband to support the arm rehabilitation therapy of stroke patients
- control modules for floor cleaning devices
- combined display instruments in commercial vehicles and construction machinery (e.g., hours of operation, temperature, state of charge)
- C and C++
- Bluetooth LE
- NFC / RFID
- Segger emWin
- Keil µVision
- IAR Workbench
- Atollic TrueSTUDIO
- redBlocks Toolkit and SiL-Tests with the redBlocks Simulator
A key feature of such deeply embedded software is the fact that the software operates on the bare hardware, i.e. it must directly access the peripherals that are externally connected or built into the microcontroller. Accordingly, much of the software consists of drivers for these hardware components and is executed in part in the context of interrupt service routines.
In this class of platforms, unlike for example, systems based on embedded Linux, there is no operating system that provides a standardized execution environment for the software application. Instead, the program code is typically executed directly from the microcontroller’s flash memory and data memory operations are performed by directly accessing the physical address space of the CPU, i.e. without access protection through the virtual memory management of an operating system. Because there is only a small amount of data memory available, the software also must not request and release dynamic memory in a non-deterministic way (risk of memory fragmentation).
Just because the platform itself does not specify a clean separation between hardware-dependent and hardware-independent software components, it is necessary for this type of software applications to define this separation by means of a suitable platform-specific and application-specific software architecture. Only then it is possible to work with unit tests during software verification and to port the application functionality to other hardware platforms at reasonable cost.
And even with deeply embedded software, you do not want to redevelop all needed functionality over and over again, but preferably rely on generic and reusable software components. However, because the available hardware resources are very limited, this must not introduce any significant overhead (larger code, additional runtime decisions, etc.).
These two contradictory requirements, i.e. a clean software structure with reusable components but without significant overhead can be achieved by the concept of so-called static polymorphism. It stipulates that the software components are already configured during compile time according to their purpose and integrated with each other so that the configuration options do not result in any needless runtime decisions or indirections (e.g. via function pointers). The resulting executable program is as small and fast as "highly optimized" software without a clean structure. However, it can be much better maintained and can usually be developed much faster through the use of existing software components.
Especially for such deeply embedded software applications, redlogix has developed the product redBlocks (red = rapid embedded development). The generic and flexibly reusable software components from the redBlocks component library are consistently based on the concept of static polymorphism and let the developer implement highly efficient embedded software applications faster and thus more cost-effectively. The product redBlocks is used in several software applications realized by redlogix on our customers’ behalf, but is also available as a licensable product for our customers' own development projects.
RTOS or Mainloop Approach?
We are often asked whether the use of a preemptive embedded RTOS is worthwhile for these types of applications over a simple run-to-completion mainloop scheduling. Of course there is no simple answer to that. Rather, the advantages and disadvantages of both approaches need to be considered based on the respective application’s requirements. According to our experience, an embedded RTOS is often used, because it is supposed to be "state-of-the-art" and without also considering the associated disadvantages (overall higher resource requirements, error-prone configuration of the required stack size per task, more complex dealing with concurrency issues, costs / effort for certification of the RTOS code in safety-critical applications, ...). Yet, the same application functionality can often be realized much more straightforward with a simple mainloop scheduler.
Also, the hope that using an RTOS results in better structured code is often not met. We therefore recommend analyzing the requirements of the embedded software first in order to be able to make a deliberate decision on this basis. We are happy to advise our customers in this development phase with our long-standing know-how in this area.
C or C++?
Another question we are often asked is the choice of implementation language. Sometimes there are reservations about using C++ when implementing software applications for platforms with extremely limited resources, even though the use of a C++ compiler does not "cost" any resources at all (in the form of larger or slower binary code). However, there are a considerable number of extremely helpful C++ language features, such as data encapsulation and class access protection, inheritance, the use of namespaces, operator overloading and so on that come for free, i.e. do not add any overhead whatsoever compared to the C programming language. Only when language features such as virtual methods, exceptions or dynamic memory management come into play (also "unintentionally", e.g. through the use of container classes from the STL), significant differences in size may occur between C and C++ programs.
Therefore, it is necessary to understand the C++ programming language very well before taking advantage of its many benefits for the development of efficient embedded software applications. redlogix has many years of experience using C++ as an implementation language on embedded platforms and conveys this knowledge in the form of coaching and training.
If there is freedom of choice, there is no reason that speaks against the use of C++. However, there may be other, typically non-technical aspects that speak for the use of C (e.g. existing C code base, regulatory requirements, ...). We are also happy to advise our customers with this decision. Thus, do not hesitate to contact us if you have any questions or need a neutral opinion.