Download presentation
Presentation is loading. Please wait.
1
Chapter 25 Embedded systems programming
Bjarne Stroustrup
2
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 Nov'13
3
Overview Embedded systems What’s special/different Resource management
predictability Resource management memory Access to hardware Absolute addresses Bits – unsigned Coding standards Stroustrup/Programming Nov'13
4
Embedded systems Hard real time Soft real time
Response must occur before the deadline Soft real time Response should occur before the deadline most of the time Often there are plenty of resources to handle the common cases 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 Nov'13
5
Embedded systems Computers used as part of a larger system
That usually doesn’t look like a computer That usually controls physical devices Often reliability is critical “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 Nov'13
6
Embedded systems What are we talking about? Fuel injector controls
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 Fuel injector controls Medical equipment monitors PDAs Printer controllers Sound systems Rice cookers Telephone switches Water pump controllers Welding machines Windmills Wrist watches … Stroustrup/Programming Nov'13
7
Do You Need to Know This Stuff ?
Computer Engineers – You will build and oversee the building of these systems All “close to the 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 Electrical Engineers – You will build and oversee the building of these systems. 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 how to do this or only work on web applications (and the like) Stroustrup/Programming Nov'13
8
Predictability C++ operations execute in constant, measurable time
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) With the exception of: 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 Nov'13
9
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 Nov'13
10
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 Nov'13
11
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 Nov'13
12
How to live without new What’s the problem?
old object Free space old object What’s the problem? C++ code refers directly to memory Once allocated, an object cannot be moved (or can it?) Allocation delays 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 New object An object cannot be moved because it doesn’t know which pointers containing its address need to be updated. Stroustrup/Programming Nov'13
13
How to live without new Solution: pre-allocate Global objects Stacks
Allocated at startup time Sets aside a fixed amount of memory Stacks Grow and shrink only at the top No fragmentation Constant time operations Pools of fixed sized objects We can allocate and deallocate in any order Stack: Top of stack Pool: Stroustrup/Programming Nov'13
14
How to live without new No new (of course)
And no malloc() (memory allocation during runtime) either (for those of you who speak C) No standard library containers (they use free store indirectly) Unless you have a special hard-real time implementation Instead Define (or borrow) fixed-sized Pools Define (or borrow) fixed-sized Stacks Do not regress to using arrays and lots of pointers Stroustrup/Programming Nov'13
15
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* p); // 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 Nov'13
16
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(256 * sizeof(int)); // allocate array of ints 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); void * must be static_cast before storing in int *, etc. Stroustrup/Programming Nov'13
17
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 Nov'13
18
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 But sometimes a memory bit just decides to change (cosmic ray, silicon fatigue, …) Why? Power surges/failure The connector vibrated out of its socket Falling debris Falling computer X-rays … Transient errors are the worst 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 Nov'13
19
How to live with failing hardware
Replicate In emergency, use a spare Self-check 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 Replicated navigation computers in space shuttle “Limp home” mode for automobile control computers Stroustrup/Programming Nov'13
20
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 (e.g., memory-mapped I/O) 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 Nov'13
21
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 true/false auto-converts to/from 1/0 Use only if you really need more than 32 bits std::bitset bs(314); // 314 bits Use if you really need more than 32 bits Typically efficient for multiples of sizeof(int) In C, 2 sizeof(short) sizeof(int) sizeof(long), I think, and so the sizes vary from compiler to compiler. Thus the program should check how many bytes a type contains to avoid portability problems. Stroustrup/Programming Nov'13
22
Bit manipulation & and | inclusive or ^ exclusive or
1 1 1 1 0xaa b: & and | inclusive or ^ exclusive or << left shift >> right shift ~ one’s complement 1 1 1 1 0x0f a&b: 0x0a 1 1 a|b: 0xaf 1 1 1 1 1 1 a^b: 0xa5 1 1 1 1 a<<1: 0x54 1 1 1 b>>2: 0x03 1 1 ~b: 0xf0 1 1 1 1 Stroustrup/Programming Nov'13
23
Bit manipulation Bitwise operations For example
Sign bit Bitwise operations & (and) | (or) ^ (exclusive or – xor) << (left shift) >> (right shift) ~ (one's complement) Basically, what the hardware provides right: For example void f(unsigned short val) // assume 16-bit, 2-byte unsigned 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) // … } 8 bits == 1 byte val 1 1 1 1 1 1 1 1 0xff: 1 1 1 1 1 1 1 1 1 1 1 1 true false Stroustrup/Programming Nov'13
24
Bit manipulation Or | And & For example:
Set a bit (whether or not already set) And & 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 0xff: 1 1 1 1 1 1 1 1 val 1 1 1 1 Stroustrup/Programming Nov'13
25
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 1 1 1 0xaa b: 1 1 1 1 0x0f a^b: 0xa5 1 1 1 1 Stroustrup/Programming Nov'13
26
Unsigned integers You can do ordinary arithmetic on unsigned integers
Avoid that when you can 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 int x = -2;// a negative number unsigned int y = x;// a very large positive number if (x < 1) cout << "no surprise: x<1\n"; if (y < 1) cout << "y<1\n"; else cout << "surprise? not y<1\n"; if (-3 < x) cout << "no surprise: -3<x\n"; if (-3 < y) cout << "surprise? -3<y\n"; if (3 < y) cout << "surprise? 3<y\n"; Stroustrup/Programming Nov'13
27
Unsigned integers You can do ordinary arithmetic on unsigned integers
You can’t completely avoid unsigned arithmetic Indexing into standard library containers uses unsigned (in my opinion, that’s a design error; arrays use signed ints) vector<int> v; // … for (int i = 0; i<v.size(); ++i) … for (unsigned 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) … for (auto p = v.begin(); p!=v.end(); ++p) … for (auto i = 0; i<v.size(); ++i) … for (int x : v) … unsigned signed correct, but pedantic A C++11 way signed Yet another C++11 way Stroustrup/Programming Nov'13
28
Complexity One source of errors is complicated problems
Inherent complexity Another source of errors is poorly-written code Incidental complexity Reasons for unnecessarily complicated code Overly clever programmers Who use features they don’t understand Undereducated programmers Who don’t use the most appropriate features Large variations in programming style Stroustrup/Programming Nov'13
29
Coding standards A coding standard is a set of rules for what code should look like Typically specifying naming and indentation rules E.g., use “Stroustrup” layout Typically specifying a subset of a language E.g., don’t use new or throw (to avoid predictability problems) Typically specifying rules for commenting Every function must have a comment explaining what it does Often requiring the use of certain libraries 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 Nov'13
30
Coding standards A good coding standard is better than no standard
I wouldn’t start a major (multi-person, multi-year) industrial project without one A poor coding standard can be worse than no standard 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 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 “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 Nov'13
31
Coding standards Common aims Reliability Portability Maintainability
Testability Reusability Extensibility Readability Stroustrup/Programming Nov'13
32
Some sample rules No function shall have more than 200 lines (30 would be even better) that is, 200 non-comment source lines 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 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 Nov'13
33
Some more sample rules Identifiers in an inner scope should not be identical to identifiers in an outer scope E.g., int var = 9; { int var = 7; ++var; } // violation: var hides var Declarations shall be declared in the smallest possible scope Variables shall be initialized 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; // ok if( a<b || c<=d) // 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 Nov'13
34
An example of bit manipulation
The Tiny Encryption Algorithm (TEA) Originally by David Wheeler 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) 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 Nov'13
35
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 Nov'13
36
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 Nov'13
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.