Design Article

A six step process for migrating embedded C into a C++ object-oriented framework

Dirk Braun

5/14/2008 12:15 AM EDT

Object oriented programming in embedded systems is still not widely employed. Many programmers in this area either come from a hardware electronics background or are pure computer scientists.

This article discusses one role that object oriented programming can play in embedded systems while maintaining requirements concerning safety and reliability that are often imposed by standards like MISRA.

I will show how good object-oriented design of embedded software can result in many benefits - smaller code and improved ease of source-code maintenance - but with only a slight trade off in terms of performance.

Using an example as the starting point (a standard timer module written in C that services timer units that are provided by nearly every MCU) I will describe a six step process by which to convert C code into object oriented C++ code classes.

Several steps in this process will illustrate a safe path for migrating this source code into an object oriented class. An instance of this class then is a HW- Timer-Peripheral with a much nicer SW-Interface than registers and interrupts. Then it is a matter of simply instantiating the timer class once per HW-Timer available on the particular MCU.

This process can be applied to any situation where more than a single instance of one type of HW-peripheral is to be used in an embedded project. Measurements of performance and code size are provided and topics like OO-in embedded systems and the improved SW-Architecture will be discussed more generally.

The examples we will work through use two timers on an ARM7. They can be completely worked through without any real hardware, using Keil's ARM7 simulator and the Keil Realview Compiler only. Because many other MCUs have at least 2 on-chip-timers these examples can be ported to other platforms, too.

Starting point: the standard Timer-Module in C
A hardware-timer is a counter/comparator with reset- and interrupt-logic. This timer "wakes up" an interrupt service routine at regular programmed intervals. But many embedded applications need more timers than HW-timers that are available on a given MCU.

We can duplicate the timer, by e.g. letting the HW-timer interrupt at 1 ms intervals. The ISR can then call function A every 3 ms and call another function B every 5 ms. This way we have used one HW-timer to realize several SW-timers, each with it's own time base. This method is fairly common practice.

For reasons out of the scope of this article the project's various timer-functions are registered with the timer-module and will then be called back when their time has come. The timer module (Figure 1 below) is based on a single HW-timer and each registered timer-callback-function has its own time interval. This is very similar to how a cyclic-task-scheduler works.

Figure 1. Module and process-flow overview. Registration of timer callbacks (1 & 2) and their cyclic execution (x, a and b)

The time base of the timer module depends on the cycle-times requested by the various application modules. If app. A wants 30 ms and B wants 50 ms, then the HW-timer can realize this using an overall time base of 10 ms. If A wants 9 and B wants 3 ms, then the main time base needs to interrupt every 3 ms.

Raising the interrupt no more often than absolutely necessary saves processor performance. This main-time-base is automatically adjusted (by reprogramming the counter register) when timer-callbacks are registered by means of a "greatest common divider" function.

Listing 1

Listing 1 above and Listing 2 below show excerpts of the interface and implementation which realize this concept of a timer module.

The result is a module that represents a single HW-timer and provides many SW-timers.

Let us now return to the main topic and start converting it into a class. Afterwards we will be able the instantiate a class for each HW-timer, where each provides many SW-timers.

Listing 2. Implementation of timer module


Next:




xyin

5/15/2008 3:40 PM EDT

Mostly agree with Jean, there are already mature methods to implement OO concepts with C, the really benefits of C++ over C are C++ take care of method overloading and class inheritance etc. for you, but for sure C can do the same thing with optimal code size and speed, but with more programmer's time to take care of method overloading and class inheritance etc.

Sign in to Reply



rJohnr

5/16/2008 9:08 AM EDT

My two Pennies....

I come from an embedded C++ backround where OOD was heavily used.

Every aspect of the system was written in C++ including the interrupt handlers and OS, even down to the point of the context switches ( thought these were inline assembly routines).

No matter where I go there is always shock and horror on peoples faces when I explain that even drivers can be written in C++ in an object orientated way.

Of course writng a driver c which controls hardware, can sometimes be more optimised, but from my experience the same is true for using C++ concepts, there are things you can do in C++ which can result in code equivalent to that in C.

And of course you can just about do every C++ concept in C, but the onus is on the programmer to create these constructs, there is no help from the compiler and there is increased likelyhood that the programmer will make a mistake, which is really hard to find when you use really generic object orientated constructs in C. Plus you also find that the code is very difficult to understand, and not very portable, sure you can write a library which is easily portable, but set two programmers on a task to create two new libraries which follow the C constructs of the original library and I garauntee that they will both come back with different results and tweaks to make things work. C++ removes this from the programmer, the constructs are already part of the language, it provides more stringent type checking, how many bugs have you come across in C where the types were mixed? of course if you were running the code through lint you would hope to get an error, but if not it could go un noticed( worse still any casts may hide the error..nasty ), especially if builds take a long time with thousands of files, it is quite easy to miss in a build log unless you have warnings as errors turned on, which I would recommend.

I have been working on a C code base for the last three years, and I can't help but notice that there are many constructs I see which just scream for the use of C++, C++ in my view greatly reduces the number of programmer type bugs. C++ makes code a little cleaner in general, modules can become more focused to a particular item of functionality( this in turn makes it easier to test ). I would also say that C++ code is far more easy to refactor and designs if done correctly can have far less coupling.

I would say that to effectively use C++ in emmbedded, you should be careful on the level of abstraction, go as granular as you need only to make the solution simpler, don't model down to the bits in a register..unless you really want to provide a simple API or where overhead is not so much of a concern, i.e don't use in interrupt handlers or any code where execution time is a concern.

Sign in to Reply



RMiller

3/4/2009 7:56 AM EST

Over the past 30+ years, I've written drivers in C, C++, and several flavors of assembly (and a few oddball languages as well). There are pluses and minuses to all of them and I've found that no language is inherently better than any other language FOR ALL USES.

I'm a very disciplined software engineer, always putting in error checking, creating functions to access data, etc. Everyone that I've ever worked with has commented numerous times that my C code is well-documented, easy to follow, and of the highest quality. I strongly disagree with rJohnr that similar code written in C and C++ is more difficult to understand in C.

My experience has taught me that C++ is NOT inherently better for writing drivers - I can code a driver faster, more efficiently, and with less effort in C. I do, however, like C++ for GUI's and application level programming, and Java seems to be even better for some of those things.

One point that seems to always be overlooked in these types of articles is that C++ code with overloading and inheritance is more difficult to debug in drivers and kernel-level code using a debugger. When I debug C code, I can see which line of code should be executing by looking at the source file; this isn't always the case with C++.

There was an IEEE article back in the 80's that put forth the idea that projects should be multilingual, that we should choose the best language individually for each part of a project. I agree with this idea, though I have yet to see any company actually do this. I respectfully disagree with articles like this one that I'm commenting on that the language-du-jour is the best fit for every use.

Sign in to Reply



Please sign in to post comment

Navigate to related information

Datasheets.com Parts Search

185 million searchable parts
(please enter a part number or hit search to begin)

Feedback Form