You are on page 1of 35

Chapter 25

Embedded systems programming


Bjarne Stroustrup
www.stroustrup.com/Programming

Abstract

This lecture provides a brief overview of what


distinguishes embedded systems programming
from ordinary programming. It then touches
upon facilities that become prominent or
problems when working close to the
hardware such as free store use, bit
manipulation, and coding standards.
Remember: not all computers are little grey
boxes hiding under desks in offices.
Stroustrup/Programming

Overview

Embedded systems
Whats special/different

Resource management

memory

Access to hardware

predictability

Absolute addresses
Bits unsigned

Coding standards
Stroustrup/Programming

Embedded systems

Hard real time

Soft real time

Response should occur before the deadline most of the time

Often there are plenty of resources to handle the common cases

Response must occur before the deadline

But crises happen and must be handled

Predictability is key
Correctness is even more important than usual

correctness is not an abstract concept


but I assumed that the hardware worked correctly is no excuse

Over a long time and over a large range of conditions, it simply doesnt

Stroustrup/Programming

Embedded systems

Computers used as part of a larger system

Often reliability is critical

That usually doesnt look like a computer


That usually controls physical devices

Critical as in if the system fails someone might die

Often resources (memory, processor capacity) are limited


Often real-time response is essential
Stroustrup/Programming

Embedded systems

What are we talking about?

Assembly line quality monitors


Bar code readers
Bread machines
Cameras
Car assembly robots
Cell phones
Centrifuge controllers
CD players
Disk drive controllers
Smart card processors

Stroustrup/Programming

Fuel injector controls


Medical equipment monitors
PDAs
Printer controllers
Sound systems
Rice cookers
Telephone switches
Water pump controllers
Welding machines
Windmills
Wrist watches

Do You Need to Know This Stuff ?

Computer Engineers You will build and oversee the building of


these systems

Electrical Engineers You will build and oversee the building of


these systems.

All close to he hardware code resembles this


The concern for correctness and predictability of embedded systems code is
simply a more critical form of what we want for all code

You have to work with the computer guys


You have to be able to talk to them
You may have to teach them
You may have to take over for them

Computer scientists youll know to do this or only work on web


applications (and the like)
Stroustrup/Programming

Predictability

C++ operations execute in constant, measurable time

With the exception of:

E.g., you can simply measure the time for an add operation or a virtual
function call and thatll be the cost of every such add operation and every
virtual function call (pipelining, caching, implicit concurrency makes this
somewhat trickier on some modern processors)
Free store allocation (new)
Exception throw

So throw and new are typically banned in hard real-time


applications

Today, I wouldnt fly in a plane that used those

In 5 years, well have solved the problem for throw

Each individual throw is predictable

Not just in C++ programs

Similar operations in other languages are similarly avoided


Stroustrup/Programming

Ideals/aims

Given the constraints

Keep the highest level of abstraction

Dont write glorified assembler code


Represent your ideas directly in code

As always, try to write the clearest, cleanest, most


maintainable code
Dont optimize until you have to

People far too often optimize prematurely


John Bentley's rules for optimization

First law: Dont do it


Second law (for experts only): Dont do it yet

Stroustrup/Programming

Embedded systems programming

You (usually) have to be much more aware of the resources


consumed in embedded systems programming than you have
to in ordinary programs

Time
Space
Communication channels
Files
ROM (Read-Only Memory)
Flash memory

You must take the time to learn about the way your language
features are implemented for a particular platform

Hardware
Operating system
Libraries
Stroustrup/Programming

10

Embedded systems programming

A lot of this kind of programming is

Looking at specialized features of an RTOS (Real Time


Operating System)
Using a Non-hosted environment (thats one way of
saying a language right on top of hardware without an
operating system)
Involving (sometimes complex) device driver architectures
Dealing directly with hardware device interfaces

We wont go into details here

Thats what specific courses and manuals are for

Stroustrup/Programming

11

How to live without new


old object
Free space

old object

Whats the problem

C++ code refers directly to memory

New object

Allocation delays

Once allocated, an object cannot be moved (or can it?)

The effort needed to find a new free chunk of memory of a


given size depends on what has already been allocated

Fragmentation

If you have a hole (free space) of size N and you allocate an


object of size M where M<N in it, you now have a fragment of
size N-M to deal with
After a while, such fragments constitute much of the memory
Stroustrup/Programming

12

How to live without new

Solution: pre-allocate

Global objects

Allocated at startup time

Sets aside a fixed amount of memory

Stacks

Grow and shrink only at the top

Stack:

No fragmentation
Constant time operations

Pools of fixed sized objects

We can allocate and deallocate

No fragmentation
Constant time operations
Top of stack

Pool:
Stroustrup/Programming

13

How to live without new

No new (of course)

No standard library containers (they use free store indirectly)


Instead

And no malloc() (memory allocation during runtime) either (for those


of you who speak C)

Define (or borrow) fixed-sized Pools


Define (or borrow) fixed-sized Stacks

Do not regress to using arrays and lots of pointers

Stroustrup/Programming

14

Pool example
// Note: element type known at compile time
// allocation times are completely predictable (and short)
// the user has to pre-calculate the maximum number of elements needed
template<class T, int N>class Pool {
public:
Pool();
// make pool of N Ts construct pools only during startup
T* get();
// get a T from the pool; return 0 if no free Ts
void free(T*);
// return a T given out by get() to the pool
private:
// keep track of T[N] array (e.g., a list of free objects)
};
Pool<Small_buffer,10> sb_pool;
Pool<Status_indicator,200> indicator_pool;
Stroustrup/Programming

15

Stack example
// Note: allocation times completely predictable (and short)
// the user has to pre-calculate the maximum number of elements needed
template<int N>class Stack {
public:
Stack();
// make an N byte stack construct stacks only during startup
void* get(int N); // allocate n bytes from the stack; return 0 if no free space
void free(void* p);
// return the last block returned by get() to the stack
private:
// keep track of an array of N bytes (e.g. a top of stack pointer)
};
Stack<50*1024> my_free_store; // 50K worth of storage to be used as a stack
void* pv1 = my_free_store.get(1024);
int* pi = static_cast<int*>(pv1); // you have to convert memory to objects
void* pv2 = my_free_store.get(50);
Pump_driver* pdriver = static_cast<Pump_driver*>(pv2);

Stroustrup/Programming

16

Templates

Excellent for embedded systems work

No runtime overhead for inline operations

Sometimes performance matters

No memory used for unused operations

In embedded systems memory is often critical (limited)

Stroustrup/Programming

17

How to live with failing hardware

Failing how?

In general, we cannot know


In practice, we can assume that some kinds of errors are more common than
others

Why?

Power surges/failure
The connector vibrated out of its socket
Falling debris
Falling computer
X-rays

Transient errors are the worst

But sometimes a memory bit just decides to change

E.g., only when the temperature exceeds 100 F. and the cabinet door is closed

Errors that occur away from the lab are the worst

E.g., on Mars

Stroustrup/Programming

18

How to live with failing hardware

Replicate

Self-check

In emergency, use a spare


Know when the program (or hardware) is misbehaving

Have a quick way out of misbehaving code

Make systems modular


Have some other module, computer, part of the system
responsible for serious errors

In the end, maybe a person i.e., manual override


Remember HAL ?

Monitor (sub)systems

In case they cant/dont notice problems themselves


Stroustrup/Programming

19

Absolute addresses

Physical resources (e.g., control registers for external devices)


and their most basic software controls typically exist at
specific addresses in a low-level system
We have to enter such addresses into our programs and give a
type to such data
For example
Device_driver* p = reinterpret_cast<Device_driver*>(0xffb8);
Serial_port_base *COM1 =
reinterpret_cast<Serial_port_base*>(0x3f8);

Stroustrup/Programming

20

Bit manipulation: Unsigned integers

How do you represent a set of bits in C++?

unsigned char uc; // 8 bits


unsigned short us;// typically 16 bits
unsigned int ui; // typically 16 bits or 32 bits
// (check before using)
// many embedded systems have 16-bit ints
unsigned long int ul;
// typically 32 bits or 64 bits
std::vector<bool> vb(93); // 93 bits
Use only if you really need more than 32 bits
std::bitset bs(314);
// 314 bits
Use only if you really need more than 32 bits
Typically efficient for multiples of sizeof(int)
Stroustrup/Programming

21

Bit manipulation

&
|
^
<<
>>
~

and
inclusive or
exclusive or
left shift
right shift
ones complement

a:

1 0 1 0 1 0 1 0 0xaa

b:

0 0 0 0 1 1 1 1 0x0f

a&b: 0 0 0 0 1 0 1 0 0x0a
a|b:

1 0 1 0 1 1 1 1 0xaf

a^b:

1 0 1 0 0 1 0 1 0xa5

a<<1:

0 1 0 1 0 1 0 0 0x54

b>>2:

0 0 0 0 0 0 1 1 0x03

~b:

1 1 1 1 0 0 0 0 0xf0

Stroustrup/Programming

22

Bit manipulation

Bitwise operations

Sign bit
8 bits == 1 byte

& (and)
val
| (or)
^ (exclusive or xor)
0 1 1 0 0 0 1 1 0 1 0 0 1 1 0 1
<< (left shift)
>> (right shift)
0xff: 1 1 1 1 1 1 1 1
~ (one's complement)
Basically, what the hardware provides
right:
0 1 0 0 1 1 0 1

true

For example

false

void f(unsigned short val)


// assume 16-bit, 2-byte short integer
{
unsigned char right = val & 0xff ;
// rightmost (least significant) byte
unsigned char left = (val>>8) & 0xff ; // leftmost (most significant) byte
bool negative = val & 0x8000 ;
// sign bit (if 2s complement)
//
}

Stroustrup/Programming

23

Bit manipulation

Or |

1 1 1 1 1 1 1 1

val

1 0 1 0 1 0 1 0

And &

Set a bit

0xff:

Is a bit set? Select (mask) some bits

For example:
enum Flags { bit4=1<<4, bit3=1<<3, bit2=1<<2, bit1=1<<1, bit0=1 };
unsigned char x = bit3 | bit1; // x becomes 8+2
x |= bit2;
// x becomes 8+4+2
if (x&bit3) {
// is bit3 set? (yes, it is)
//
}
unsigned char y = x &(bit4|bit2);
// y becomes 4
Flags z = Flags(bit2|bit0); // the cast is necessary because the compiler
// doesnt know that 5 is in the Flags range
Stroustrup/Programming

24

Bit manipulation

Exclusive or (xor) ^

a^b means (a|b) & !(a&b) either a or b but not both


unsigned char a = 0xaa;
unsigned char b = 0x0f;
unsigned char c = a^b;

Immensely important in graphics and cryptography


a:

1 0 1 0 1 0 1 0 0xaa

b:

0 0 0 0 1 1 1 1 0x0f

a^b:

1 0 1 0 0 1 0 1 0xa5

Stroustrup/Programming

25

Unsigned integers

You can do ordinary arithmetic on unsigned integers

Avoid that when you can

You cant completely avoid unsigned arithmetic

signed

Try never to use unsigned just to get another bit of precision


If you need one extra bit, soon, youll need another
Dont mix signed and unsigned in an expression
Indexing into standard library containers uses unsigned
(in my opinion, thats a design error)
vector<int> v;
unsigned
correct, but pedantic
//
for (int i = 0; i<v.size(); ++i)
for (vector<int>::size_type i = 0; i<v.size(); ++i)
for (vector<int>::iterator p = v.begin(); p!=v.end(); ++p)

Yet another way


Stroustrup/Programming

26

Complexity

One source of errors is complicated problems

Another source of errors is poorly-written code

Inherent complexity
Incidental complexity

Reasons for unnecessarily complicated code

Overly clever programmers

Undereducated programmers

Who use features they dont understand


Who dont use the most appropriate features

Large variations in programming style

Stroustrup/Programming

27

Coding standards

A coding standard is a set of rules for what code should


look like

Typically specifying naming and indentation rules

Typically specifying a subset of a language

Every function must have a comment explaining what it does

Often requiring the use of certain libraries

E.g., dont use new or throw to avoid predictability problems

Typically specifying rules for commenting

E.g., use Stroustrup layout

E.g., use <iostream> rather than <stdio.h> to avoid safety problems

Organizations often try to manage complexity through


coding standards

Often they fail and create more complexity than they manage
Stroustrup/Programming

28

Coding standards

A good coding standard is better than no standard

A poor coding standard can be worse than no standard

Even the good ones


All programmers want to write their code exactly their own way

A good coding standard is prescriptive as well as restrictive

C++ coding standards that restrict programming to something like the C subset do
harm
They are not uncommon

All coding standards are disliked by programmers

I wouldnt start a major (multi-person, multi-year) industrial project without one

Here is a good way of doing things as well as


Never do this

A good coding standard gives rationales for its rules

And examples

Stroustrup/Programming

29

Coding standards

Common aims

Reliability
Portability
Maintainability
Testability
Reusability
Extensibility
Readability

Stroustrup/Programming

30

Some sample rules

No function shall have more than 200 lines (30 would be even better)

Each new statement starts on a new line

E.g., int a = 7; x = a+7; f(x,9);

// violation!

No macros shall be used except for source control

that is, 200 non-comment source lines

using #ifdef and #ifndef

Identifiers should be given descriptive names

May contain common abbreviations and acronyms


When used conventionally, x, y, i, j, etc., are descriptive
Use the number_of_elements style rather than the numberOfElements style
Type names and constants start with a capital letter

E.g., Device_driver and Buffer_pool

Identifiers shall not differ only by case

E.g., Head and head

// violation!

Stroustrup/Programming

31

Some more sample rules

Identifiers in an inner scope should not be identical to identifiers


in an outer scope

E.g., int var;

// violation: var is not initialized

Casts should be used only when essential


Code should not depend on precedence rules below the level of
arithmetic expressions
E.g., x = a*b+c;
if( a<b || c<=d)

// violation: var hides var

Declarations shall be declared in the smallest possible scope


Variables shall be initialized

E.g., int var = 9; { int var = 7; ++var; }

// ok
// violation: parenthesize (a<b) and (c<=d)

Increment and decrement operations shall not be used as


subexpressions

E.g., int x = v[++i]; // violation (that increment might be overlooked)


Stroustrup/Programming

32

An example of bit manipulation

The Tiny Encryption Algorithm (TEA)

Dont look too hard at the code (unless you happen to need a
good simple encryption algorithm for an application); its
simply to give you the flavor of some bit manipulation code
It takes one word (4 bytes at a time)

Originally by David Wheeler


http://143.53.36.235:8080/tea.htm

E.g., 4 characters from a string or an image file

It assumes 4-byte long integers


Explanation is at the link (and in the book)

Without the explanation this is just an example of how bit manipulation


code can look. This code is not meant to be self-explanatory.
Stroustrup/Programming

33

TEA
void encipher(
const unsigned long *const v,
unsigned long *const w,
const unsigned long * const k)
{
unsigned long y = v[0];
unsigned long z = v[1];
unsigned long sum = 0;
unsigned long delta = 0x9E3779B9;
unsigned long n = 32;
while(n-->0) {
y += (z << 4 ^ z >> 5) + z ^ sum + k[sum&3];
sum += delta;
z += (y << 4 ^ y >> 5) + y ^ sum + k[sum>>11 & 3];
}
w[0]=y;
w[1]=z;
}
Stroustrup/Programming

34

TEA

void decipher(
const unsigned long *const v,
unsigned long *const w,
const unsigned long * const k)
{
unsigned long y = v[0];
unsigned long z = v[1];
unsigned long sum = 0xC6EF3720;
unsigned long delta = 0x9E3779B9;
unsigned long n = 32;
// sum = delta<<5; in general, sum = delta * n
while(n-->0) {
z -= (y << 4 ^ y >> 5) + y ^ sum + k[sum>>11 & 3];
sum -= delta;
y -= (z << 4 ^ z >> 5) + z ^ sum + k[sum&3];
}
w[0]=y;
w[1]=z;
}
Stroustrup/Programming

35

You might also like