0% found this document useful (0 votes)
75 views14 pages

Microcontrollers Cpp2

C++ and microcontrollers: using and testing The author discusses their experience using C++ for microcontroller projects instead of the more commonly used C language. While C++ enables object-oriented programming features like encapsulation and polymorphism, it can be riskier than C due to its more dynamic memory usage. The author provides examples of how C code is often already written in an object-oriented style, and how C++ can provide more flexible solutions through features like polymorphism. However, C++ also poses dangers for memory-constrained microcontrollers from its increased use of dynamic memory allocation and deallocation.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
75 views14 pages

Microcontrollers Cpp2

C++ and microcontrollers: using and testing The author discusses their experience using C++ for microcontroller projects instead of the more commonly used C language. While C++ enables object-oriented programming features like encapsulation and polymorphism, it can be riskier than C due to its more dynamic memory usage. The author provides examples of how C code is often already written in an object-oriented style, and how C++ can provide more flexible solutions through features like polymorphism. However, C++ also poses dangers for memory-constrained microcontrollers from its increased use of dynamic memory allocation and deallocation.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

(Ref: C++ and microcontrollers: using and testing - CodeProject)

C++ and microcontrollers: using and testing

Alexandr Surkov
29 Feb 2016CPOL10 min read
My expiriance of using C++ with microcontrollers

Introduction
Historically, the primary language for work with the microcontrollers is C. Many large projects are
written on it. But life does not stand still. Modern development tools for embedded systems are
allready supporting C++. However, this approach is still quite rare. Not so long ago I tried to use
C++ for my next project. This experience I'll discuss in this article.

Most part of my work with microcontrollers is written on C. First it was the customer's
requirements, and then it became a habit. At the same time, when I wrote applications for
Windows, I used C++ as well as C#.

Questions about selection between C and C++ is not encountered me for a long time. Even
release of new version of the Keil MDK with C++ support do not confused me. If you look at Keil
demo projects, you will see that everything is written in C. C++ example is placed in a separate
folder like a Blinky-project. CMSIS, LPCOpen also written in C. And if "all" are using C, then there
is some reason for that.

This situation was changed by .Net Micro Framework. If someone does not know, it is the
realization of .Net allows to write applications for microcontrollers with C# in Visual Studio. More
information about it can be found in these articles.

.Net Micro Framework is written with using of C++. Impressed by this, I decided to try create
another project in C++. I must say that I could not find unambiguous arguments in favor of C ++,
but there are some interesting and useful points in this approach.

What is the difference between projects on C


and C++?
One of the main differences between C and C++ is that the second is object-oriented language.
Well-known encapsulation, polymorphism and inheritance are commonplace here. C is a
procedural language. There is only the functions and procedures, and the modules (a pair .h + .c)
are used for logical grouping of code. But if you look at how C is used in microcontrollers, we can
see the usual object-oriented approach.

Let's look at the code for LEDs from Keil’s example for MCB1000 (Keil_v5\ARM\
Boards\Keil\MCB1000\MCB11C14\CAN_Demo):

LED.h:

C++
Copy Code

#ifndef __LED_H
#define __LED_H

/* LED Definitions */
#define LED_NUM 8 /* Number of user LEDs */

extern void LED_init(void);


extern void LED_on (uint8_t led);
extern void LED_off (uint8_t led);
extern void LED_out (uint8_t led);

#endif

LED.c:

C++
Shrink ▲ Copy Code
#include "LPC11xx.h" /* LPC11xx definitions */
#include "LED.h"

const unsigned long led_mask[] = {1UL << 0, 1UL << 1, 1UL << 2, 1UL << 3,
1UL << 4, 1UL << 5, 1UL << 6, 1UL << 7 };

/*----------------------------------------------------------------------------

initialize LED Pins

*----------------------------------------------------------------------------*/

void LED_init (void) {

LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 6); /* enable clock for GPIO */

/* configure GPIO as output */

LPC_GPIO2->DIR |= (led_mask[0] | led_mask[1] | led_mask[2] | led_mask[3] |


led_mask[4] | led_mask[5] | led_mask[6] | led_mask[7] );
LPC_GPIO2->DATA &= ~(led_mask[0] | led_mask[1] | led_mask[2] | led_mask[3] |
led_mask[4] | led_mask[5] | led_mask[6] | led_mask[7] );

}
/*----------------------------------------------------------------------------

Function that turns on requested LED

*----------------------------------------------------------------------------*/

void LED_on (uint8_t num) {

LPC_GPIO2->DATA |= led_mask[num];

/*----------------------------------------------------------------------------
Function that turns off requested LED
*----------------------------------------------------------------------------*/
void LED_off (uint8_t num) {

LPC_GPIO2->DATA &= ~led_mask[num];


}

/*----------------------------------------------------------------------------
Output value to LEDs
*----------------------------------------------------------------------------*/
void LED_out(uint8_t value) {
int i;

for (i = 0; i < LED_NUM; i++) {


if (value & (1<<i)) {
LED_on (i);
} else {
LED_off(i);
}
}
}

If you look closely, you can draw an analogy with the object oriented programming. LED is an
object that has a public constant, constructor, three public method and one private field:

C++

class LED
{
private:
const unsigned long led_mask[] = {1UL << 0, 1UL << 1, 1UL << 2, 1UL << 3,
1UL << 4, 1UL << 5, 1UL << 6, 1UL << 7 };
public:

unsigned char LED_NUM=8;

public:

LED(); //LED_init
void on (uint8_t led);
void off (uint8_t led);
void out (uint8_t led);
}

Even if the code is written in C, it uses object-oriented programming paradigm. .c File is an object
that allows encapsulation mechanisms in the implementation of public methods described in the
.h file. But there is no inheritance and polymorphism.

Most of the code in the projects that I have seen, written in the same style. And if you are using
OOP approach, why not use the language, fully supports it? And if you want to change languege
from C to C++ you will need to change only syntax, but not the design principles.

Consider another example. Suppose we have a device that uses a temperature sensor connected
via I2C. But there was a new revision of the device and the same sensor is now connected to SPI.
What to do? You should support first and second revision of the device, it means that the code
should be flexible to take into account these changes. In C you can use the #define
predefinitions, in order to not to write two nearly identical file. For example

C++
Copy Code

#ifdef REV1
#include "i2c.h"
#endif
#ifdef REV2
#include "spi.h"
#endif

void TEMPERATURE_init()
{
#ifdef REV1
I2C_int()
#endif
#ifdef REV2
SPI_int()
#endif
}

and so on. In C++, you can solve this problem much more elegantly. Make interface:

C++

Copy Code

class ITemperature

public:
virtual unsigned char GetValue() = 0;

and two implementations:

C++
Copy Code
class Temperature_I2C: public ITemperature
{
public:
virtual unsigned char GetValue();
}

class Temperature_SPI: public ITemperature


{
public:
virtual unsigned char GetValue();
}

Then you can use a particular implementation depending on the revision:

Shrink ▲ Copy Code


class TemperatureGetter
{
private:
ITemperature* _temperature;

public:
Init(ITemperature* temperature)
{
_temperature = temperature;
}

private:
void GetTemperature()
{
_temperature->GetValue();
}

#ifdef REV1

Temperature_I2C temperature;

#endif

#ifdef REV2

Temperature_SPI temperature;

#endif
TemperatureGetter tGetter;

void main()

tGetter.Init(&temperature);
}

It seems that the difference is not very large between the code in C and C++. Object-oriented
version looks even more cumbersome. But it allows you to make a more flexible solution.

When you using C you have two main solutions:

1. Use #define as shown above. This option is not very good because it "blur" the module
responsibility. It turns out that it is responsible for several project versions. When count of these
files grow support them becomes quite difficult.
2. Make 2 module as well as in C++. In this solution the "blur" does not occur, but use of these
modules will be more complicated. Since they do not have a single interface, the use of each
method of the pair should be enclosed in #ifdef. This degrades the readability and code
maintainability. And when separation of the place will rice higher absraction level, then the code
will be more unwieldy. Thus it is necessary to think of another name for the function of each
module, so that they do not overlap, it is also fraught with the deterioration of the readability of
the code.

Using of polymorphism gives a beautiful result. On the one hand, each class decides clear atomic
problem, on the other hand, the code is not littered.

It is still need to branch code for board revision in both cases, but use of polymorphism makes it
easier to move the place of the branch between the layers of the program with minimum using
of #ifdef.

Using of polymorphism makes it easy to make even more interesting solution.

Suppose there was a new revision, which contains both temperature sensors.

The same code with minimal changes allows you to select SPI or I2C implementation in real time,
simply by using Init(&temperature) method.

This example of a very simple, but in a real project, I used the same approach in order to realize
the same protocol on top of two different physical data interfaces. This made it easy to make the
choice of interface in the device settings.

However, with all the above facts, the difference between using of C and C ++ is not very big. The
benefits of C ++, associated with the OOP are not so obvious and are from the category of
personal preferences. But the use of C ++ in microcontrollers have some serious problems.
What is the danger of using C++?
The second important difference between C and C++ is manner of using memory. C is static in
most part. All functions and procedures have fixed addresses and heap is using only when it is
necessary. C++ is more dynamic language. Typically, it involves active using of memoty allocation
and deallocation. This is big danger of C++. The microcontrollers have very few resources, so
controling of them is very important. The uncontrolled use of RAM is fraught with corruption of
data stored there. Many developers are faced with such problems.

If you look carefully at the examples above, it may be noted that the classes do not have
constructors and destructors. This is because they have never created dynamically.

Using dynamic memory (even using "new" keyword) always leads to calling malloc function,
which allocates the required number of bytes from the heap. Even if you have thought of
everything and will carefully monitor using of memory, you may encounter a problem of its
fragmentation.

The heap can be represented as an array. For example, there are 20 bytes in the heap:

Every memory allocation leads to review all the memory (from left to right or right to left - is not
so important) for the presence of a predetermined amount of idle bytes. Moreover, these bytes
must all be located together:

When the memory is no longer needed, it is returned to its original state:


Easily can happen situation when there are a sufficient number of available bytes, but they are
not arranged in a row. Let there be allocated 10 zones with 2 bytes in each zone:

Then will be released 2,4,6,8,10 zones:

Formally half of the heap (10 bytes) remains free. However, you can't allocate memory with size
of 3 bytes , since there is no array of 3 located together free cells. This is called memory
fragmentation.

This situation can be easily faked. I did this on LPC11C24 with Keil mVision.

Let's set the heap size to 256 bytes:

Suppose we have 2 classes:

C++
Shrink ▲ Copy Code
#include <stdint.h>

class foo
{
private:
int32_t _pr1;
int32_t _pr2;
int32_t _pr3;
int32_t _pr4;

int32_t _pb1;
int32_t _pb2;
int32_t _pb3;
int32_t _pb4;

int32_t _pc1;
int32_t _pc2;
int32_t _pc3;
int32_t _pc4;

public:
foo()
{
_pr1 = 100;
_pr2 = 200;
_pr3 = 300;
_pr4 = 400;

_pb1 = 100;
_pb2 = 200;
_pb3 = 300;
_pb4 = 400;

_pc1 = 100;
_pc2 = 200;
_pc3 = 300;
_pc4 = 400;
}

~foo(){};

int32_t F1(int32_t a)
{
return _pr1*a;
};

int32_t F2(int32_t a)
{
return _pr1/a;
};

int32_t F3(int32_t a)
{
return _pr1+a;
};

int32_t F4(int32_t a)
{
return _pr1-a;
};

class bar
{
private:
int32_t _pr1;
int8_t _pr2;

public:
bar()
{
_pr1 = 100;
_pr2 = 10;
}

~bar() {};

int32_t F1(int32_t a)
{
return _pr2/a;
}

int16_t F2(int32_t a)
{
return _pr2*a;
}
};

As you can see, bar class will take up more memory than foo.

Let’s fill heap by 14 copyes of bar class. Then memory for foo class can’t be allocated:

C++
Copy Code

int main(void)
{
foo *f;
bar *b[14];

b[0] = new bar();


b[1] = new bar();
b[2] = new bar();
b[3] = new bar();
b[4] = new bar();
b[5] = new bar();
b[6] = new bar();
b[7] = new bar();
b[8] = new bar();
b[9] = new bar();
b[10] = new bar();
b[11] = new bar();
b[12] = new bar();
b[13] = new bar();

f = new foo();
}

But if we create only 7 copyes of bar class foo class can be created too:

C++
Copy Code
int main(void)
{
foo *f;
bar *b[14];

//b[0] = new bar();


b[1] = new bar();
//b[2] = new bar();
b[3] = new bar();
//b[4] = new bar();
b[5] = new bar();
//b[6] = new bar();
b[7] = new bar();
//b[8] = new bar();
b[9] = new bar();
//b[10] = new bar();
b[11] = new bar();
//b[12] = new bar();
b[13] = new bar();

f = new foo();
}

However, if you first create 14 copies of the bar and remove 0,2,4,6,8,10 and 12 copies, then
allocate memory for foo class can’t be compleated because of the fragmentation of the heap:

C++
Shrink ▲ Copy Code

int main(void)
{
foo *f;
bar *b[14];

b[0] = new bar();


b[1] = new bar();
b[2] = new bar();
b[3] = new bar();
b[4] = new bar();
b[5] = new bar();
b[6] = new bar();
b[7] = new bar();
b[8] = new bar();
b[9] = new bar();
b[10] = new bar();
b[11] = new bar();
b[12] = new bar();
b[13] = new bar();

delete b[0];
delete b[2];
delete b[4];
delete b[6];
delete b[8];
delete b[10];
delete b[12];

f = new foo();
}

It turns out that the full C++ can not be fully used, and this is a significant drawback. From an
architectural point of view, C++ superior to C, but only slightly. As a result, switching to C++
does not bring anysignificant benefits. But it does not bring any large negative moments too.
Thus, because of the small difference, language choice will remain just a personal preference of
the developer.

But for myself, I found a significant positive point in the use of C++. The fact is that with the right
approach C++ code for the microcontroller can be easily cover by unit tests in Visual Studio.

A big plus of C ++ is the ability to use Visual


Studio.
Testing code for microcontrollers has always been difficult task for me. Code is tested in various
ways, but creation of a full automatic test systems always require huge costs, since it is necessary
to create special hardware and write special firmware for it. Especially if we are talking about IoT
distributed system consisting of hundreds of devices.

When I started writing C++ project, I wanted to try to insert code in Visual Studio and use Keil
mVision only for debugging. Firstly, Visual Studio have a very powerful and easy to use code
editor. Secondly, Keil mVision have not friendly integration with version control systems but
Visual Studio is all worked out to automaticity. Third, I had hoped that there will be chance to
cover part of the code by unit tests, which are also well supported in Visual Studio. And fourthly,
it is the new version of Resharper C++ - Visual Studio extension for C++ code which can help
you to follow styling of code and to avoid many potential bugs and.

Create a project in Visual Studio, and connect it to the version control system does not cause any
problems. But with the unit tests it was not so easy.

Classes, abstracted from the hardware (eg, protocol parsers), can be easily tested. But I wanted
more. In my projects I use the header files from Keil to work with peripherals. For
example,LPC11xx.h for LPC11C24. These files describe all the registers in accordance with CMSIS
standard. Definitions of a particular register is done through #define:

C++
Copy Code
#define LPC_I2C_BASE (LPC_APB0_BASE + 0x00000)
#define LPC_I2C ((LPC_I2C_TypeDef *) LPC_I2C_BASE )

It turned out that if override registers definitions and do a couple of stubs, the code that uses the
periphery may well be compiled in VisualStudio. Moreover, if you make a static class and specify
its field as the register addresses, you get a complete microcontroller emulator that allows you to
test peripherial code:

C++
Copy Code

#include <LPC11xx.h>

class LPC11C24Emulator
{
public:
static class Registers
{
public:
static LPC_ADC_TypeDef ADC;

public:
static void Init()
{
memset(&ADC, 0x00, sizeof(LPC_ADC_TypeDef));
}
};
}

#undef LPC_ADC
#define LPC_ADC ((LPC_ADC_TypeDef *) &LPC11C24Emulator::Registers::ADC)

And then do loke this:

C++
Copy Code
#if defined ( _M_IX86 )
#include "..\Emulator\LPC11C24Emulator.h"
#else
#include <LPC11xx.h>
#endif

Thus it is possible to compile and test the entire code of the project for microcontrollers in
VisualStudio with minimal changes.
I have written more than 300 tests covering a purely hardware aspects and code that abstracted
from the hardware . In advance I found about 20 serious errors , which, due to the size of the
project, would not be easy to detect without automatic testing.

Summary
To use or not to use C++ when working with microcontrollers is a complicated question. Above I
have shown that, on the one hand, the architectural advantages of a full supported OOP is not so
great, and ,on the other hand, limits of using of heap is quite a big problem. Considering these
aspects, there is not so big difference between C and C++ for work with microcontrollers. So
choice between them can be justified only by the personal preferences of the developer.

However, I found a great positive point of using C++ - using Visual Studio. This can significantly
improve the reliability of the development due to work with version control systems, use of unit
tests (including tests of peripherals) and other advantages of Visual Studio.

You might also like