Transcript Document

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
2
Overview


Embedded systems
What’s special/different


Resource management


memory
Access to hardware



predictability
Absolute addresses
Bits – unsigned
Coding standards
Stroustrup/Programming
3
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 doesn’t
Stroustrup/Programming
4
Embedded systems

Computers used as part of a larger system



Often reliability is critical



That usually doesn’t 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
5
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
…
6
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 – you’ll know to do this or only work on
web applications (and the like)
Stroustrup/Programming
7
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 that’ll 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 wouldn’t fly in a plane that used those

In 5 years, we’ll 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
8
Ideals/aims

Given the constraints

Keep the highest level of abstraction




Don’t write glorified assembler code
Represent your ideas directly in code
As always, try to write the clearest, cleanest, most
maintainable code
Don’t optimize until you have to


People far too often optimize prematurely
John Bentley's rules for optimization


First law: Don’t do it
Second law (for experts only): Don’t do it yet
Stroustrup/Programming
9
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” (that’s 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 won’t go into details here

That’s what specific courses and manuals are for
Stroustrup/Programming
11
How to live without new
old object
Free space

old object
What’s 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 can’t/don’t 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;
unsigned short us;
unsigned int ui;

unsigned long int ul;

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)



// 8 bits
// typically 16 bits
// typically 16 bits or 32 bits
// (check before using)
// many embedded systems have 16-bit ints
// typically 32 bits or 64 bits
Stroustrup/Programming
21
Bit manipulation






&
|
^
<<
>>
~
and
inclusive or
exclusive or
left shift
right shift
one’s 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

For example
Sign bit
8 bits == 1 byte
& (and)
val
| (or)
0 1 1 0 0 0 1 1 0 1 0 0 1 1 0 1
^ (exclusive or – xor)
<< (left shift)
>> (right shift)
0xff: 1 1 1 1 1 1 1 1
~ (one's complement)
0 1 0 0 1 1 0 1
Basically, what the hardware provides
right:
true
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 2’s 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
// doesn’t 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 can’t completely avoid unsigned arithmetic

signed
Try never to use unsigned just to get another bit of precision
If you need one extra bit, soon, you’ll need another
Don’t mix signed and unsigned in an expression
Indexing into standard library containers uses unsigned
(in my opinion, that’s 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 don’t understand
Who don’t 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., don’t 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 wouldn’t 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)




Don’t look too hard at the code (unless you happen to need a
good simple encryption algorithm for an application); it’s
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