SlideShare a Scribd company logo
1 / 115
CoreHard 2018 Minsk
(small) embeded system?
use C++ !
Wouter van Ooijen MSc (ir)
Hogeschool Utrecht, Netherlands,
senior lecturer Computer Engineering
SG14 member
wouter.vanooijen@hu.nl
2 / 115
A detour …..
Some 20 years ago I worked for a small Dutch space company
3 / 115
… on the the European Robotic Arm project
4 / 115
Which was delayed, delayed and delayed,
and finally mothballed for lack of a purpose.
5 / 115
Ariane 4 ➔ Ariane 5
6 / 115
Big day
Ariane 5 maiden flight
Payment!
7 / 115
8 / 115
9 / 115
10 / 115
the Flight Control system
11 / 115
the Inertial Reference System
12 / 115
• Requirement: CPU load at launch must be < 80%
• IRS CPU load is too high
• Analysis: physically HVB can’t be out of range
• Agreed solution: remove the checks for HVB
Design process…
13 / 115
14 / 115
• Floating-point HRS value is out of 16-bits bounds
• Conversion exception occurs
• Is caugth at main level, application shutdown
• Switch to backup IRS fails
• Diagnostic information is put on the databus
• Is interpreted as flight data by the main computer
• Causes extreme steering
• Boosters break loose
• Self-destruct engages
• (Flight control commands self-destruct)
Chain of events
15 / 115
Spot the important difference
16 / 115
So who/what is to blame?
- Task running when no longer needed
- < 80 % CPU utilization requirement
- Using underpowered hardware
- Redundancy in HW but not in SW
- Stopping all tasks when an unexpected exception occurs
- Fail-totally instead of fail-gradually
- Re-using Ariane 4 software in Ariane 5 (untested)
- Having only ‘positive’ requirements
- Using Ada
- ……………… add your own?
17 / 115
The cluster
18 / 115
Welcome to the embedded world – where things can go kaboom!
19 / 115
Not always that serious
20 / 115
Dental brace retainer
21 / 115
Airbag
Late might even be worse than not at all…
22 / 115
Wide span of seriousness
23 / 115
Wide span of response time
µs ms s
24 / 115
Real-time
25 / 115
Wide span of replication
1
Disclaimer: all figures are just wild guesses
100’000
10’000
100
1’000’000
26 / 115
1MiB 1GiB1KiB
4-bit
8-bit : 8051, PIC, AVR, …
16-bit : MSP430, PIC, …
64-bit
No full standard C/C++
32-bit : ARM, MIPS, Tensilca,
Intel, …
Wide span of hardware
27 / 115
Wide span of support software
Bare metal:
• libraries
• no separate
OS
1MiB 1GiB1KiB
Desktop OS:
• Linux
• Windows
• Interpreter
• RTOS
28 / 115
Embedded languages
AspenCore: my current embedded project is programmed mostly in…
29 / 115
Embedded languages
2010 VDC survey
30 / 115
=
Not a usable term to define
a (single) programming style
Embedded
31 / 115
Let’s quantify
10F200 Arduino Uno Arduino Due Raspberry Pi Desktop
Code 375 B 32 KiB 512 KiB 8 GiB 1 TiB
Data 16 B 2 KiB 96 KiB 1 GiB 4 GiB
CPU 8 bit 8 bit 32 bit 32 bit 64 bit
Clock 4 MHz 16 MHz 84 MHz 900 MHz 3 GHz
32 / 115
Real numbers
1MiB 1GiB1KiB
10F200 Arduino Uno Arduino Due Raspberry Pi Desktop
Code 375 32768 524288 8589934592 1099511627776
Data 16 2048 98304 1073741824 4294967296
CPU 1000000 16000000 168000000 3600000000 30000000000
33 / 115
Relative
10F200 Arduino Uno Arduino Due Raspberry Pi Desktop
Code 1 87 1398 22906492 2932031007
Data 1 128 6144 67108864 268435456
CPU 1 16 128 3600 30000
34 / 115
10 * Log
10F200 Arduino Uno Arduino Due Raspberry Pi Desktop
Code 0.000000 44.70282 72.42870 169.46931 217.98961
Data 0.000000 48.52030 87.23231 180.21827 194.08121
CPU 0.000000 27.72588 51.239639 81.886891 103.089526
35 / 115
Rounded 10 * log
10F200 Arduino Uno Arduino Due Raspberry Pi Desktop
Code 0 45 72 169 218
Data 0 49 87 180 194
CPU 0 28 51 82 103
36 / 115
Unit of (log) size?
37 / 115
Unit of (log) speed?
38 / 115
Relative, in dMore and dHopper
10F200 Arduino Uno Arduino Due Raspberry Pi Desktop
code
dMoore
0 +45 +27 +97 +49
data
Moore
0 +49 +38 +93 +14
dHopper
0 +28 +31 +31 +21
relative to previous column
39 / 115
10F200 Arduino Uno Arduino Due Raspberry Pi Desktop
code
dMoore
0 +45 +27 +97 +49
data
Moore
0 +49 +38 +93 +14
dHopper
0 +28 +31 +31 +21
Assembler
No alternative
I am actually doing electronics diguised as software.
Maybe I’ll consider C
40 / 115
10F200 Arduino Uno Arduino Due Raspberry Pi Desktop
code
dMoore
0 +45 +27 +97 +49
data
Moore
0 +49 +38 +93 +14
RTOS GP OS
Interpreter – I run desktop code in a small chip
You can afford
41 / 115
10F200 Arduino Uno Arduino Due Raspberry Pi Desktop
code
dMoore
0 +45 +27 +97 +49
data
Moore
0 +49 +38 +93 +14
dHopper
0 +28 +31 +31 +21
RTOS GP OSInterpreter
Where does C++ fit in?
Assembler
If you need performance …
42 / 115
Otherwise
43 / 115
44 / 115
C++ versus Python
Actually compiled versus interpreted
Penalty
Size 3 .. 13 dMoore
Speed 3 .. 23 dHopper
45 / 115
C++ versus Python
Actually compiled versus interpreted
Penalty
Size 3 .. 13 dMoore (factor 2 .. 20)
Speed 3 .. 23 dHopper (factor 2 .. 200)
46 / 115
10F200 Arduino Uno Arduino Due Raspberry Pi Desktop
code
dMoore
0 +45 +27 +97 +49
data
Moore
0 +49 +38 +93 +14
dHopper
0 +28 +31 +31 +21
RTOS GP OSInterpreter
Where does C++ fit in?
Assembler
small-embedded C++ alley
47 / 115
dMoore 0 +10 +20
dHopper
0 +10 +20
Size & speed margin
Very low margin:
Use Assembler
Comfortable margin:
Consider using an interpreter
small-embedded C++ alley
48 / 115
large-embedded
small-embedded
MiB, GiB
GHz, multi-core
Memory latency, caches
Worry about latency
bytes, KiB, worry about size
MHz, Interrupts
Hardware peripherals
Battery life-time
49 / 115
large-embedded
small-embedded
fast trading
gaming
simulation
SG14:
low-latency
50 / 115
What does C++ do for embedded?
- ADTs: abstraction, data hiding, type-checking, enum class
- Overloading, operators
- Namespaces
- Argument defaults, references, std::array<>
- Const, constexpr, constexpr if
- }, RAII
- Templates
- DSLs (using templates, operators, overloading)
51 / 115
Note that most:
• Are zero cost
• Were NOT included for embedded
• Help to reduce MACRO’S
- ADTs: abstraction, data hiding, type-checking, enum
class
- Overloading, operators
- Namespaces
- Argument defaults, references, std::array<>
- Const, constexpr, constexpr if
- }, RAII
- Templates
- DSLs (using templates, operators, overloading)
52 / 115
Less usefull?
- Heap : (small-) embedded is often ‘mission-critical’
- Exceptions : idem
- Classic OO : not free
- Bit-fields : not enough control, and can be done adequately
(and encapsulated!) with other means
- The libraries (large - but unspecified! - parts can’t be used)
53 / 115
Annoying
All (library) assumptions that are hard-coded
- Extra space is allocated on the heap
- Integer calculations are done using int
- Floating-point calculations are done using double
- Special situations are reported by exceptions
- This function must be fast / small
- Caching determines speed, so avoid linked lists
- All that matters is amortized complexity
54 / 115
Heap
The heap is flexibility with respect to the amount of data, at the cost of (some)
unpredictability in run-time and maximum available memory (fragmentation).
A typical small embedded system
❑ has a rigidly prescribed task, including the size of the data involved
❑ Must meet real-time constraints
❑ Should be certain to meet work OK all the time (not just for a certain sequence of
actions).
➔A heap and a small embedded system don’t match very well. Better:
❑ Global allocation (!)
❑ Fixed size pools or fixed size containers
55 / 115
Exceptions
Exceptions are great to handle a local problem that requires a (more) global response.
❑ A small system often has a rather simple, rigidly defined task
➔there are no exceptions, only different situations.
❑ No heap ➔ one reason less to use exceptions.
❑ Exception implementation often uses the heap….
Straw man: exceptions are slow and have unpredictable timing.
56 / 115
Floating point
FP is useful when a wide dynamic range is needed. For an embedded
application the ranges are often very well known. (but… Ariane 5?)
Small micro-controllers often don’t have a hardware FPU. A software FP
library
❑ Is considerably slower
❑ Takes up ROM
Make your software ‘open’:
template< typename value_type = double >
class your_amazing_library {
. . .
57 / 115
”Just” print
struct location { int x, y; };
void print_location( FILE * f, location v ){
fprintf( f, "(%d,%d)", v.x, v.y );
}
std::ostream & operator<<( std::ostream & out, const location & v ){
return out << '(' << v.x << ',' << v.y << ')';
}
template< typename OUT >
auto operator<<( OUT & out, const location & v )
-> decltype( out << 'x' ) &
{
return out << '(' << v.x << ',' << v.y << ')';
}
58 / 115
General
embedded / low-latency / standalone
‘profile’
- No heap use (in the critical code)
- No exceptions thrown or caught (in the critical code)
- No RTTI
59 / 115
Small-embedded profile
- No heap included
- Compiled without exceptions
- No RTTI
- No floating point
- No OS support, no file system, no std::cout
60 / 115
Embedded ’paranoia’ profiles
- No heap included
- Compiled without exceptions
- No RTTI
- No floating point
- No OS support, no file system, no std::cout
- Analyzable stack size: no recursion, no indirection
- Analyzable run-time: no unbounded loops
61 / 115
What does C++ NOT (yet) do
for small-embedded
- Comprehensible, single-way-of-doing-things language
- Usable set of libraries
- Examples (books, websites, blogs, etc.) that show the
(or even an) appropriate modern programming style
62 / 115
Why don’t they all use C++?
- No compiler available (PIC, 8051)
- No programmers available
- Not allowed
- Existing code base (often in C)
- The style is inappropriate
- It is too complex (doesn’t show what happens)
- Code bloat
- No advantages
63 / 115
Why don’t they all use C++?
- No compiler available (PIC, 8051)
- No programmers available
- Not allowed
- Existing code base (often in C)
- The style is inappropriate
- It is too complex (doesn’t show what happens)
- Code bloat
- No advantages
64 / 115
Remark from The Embedded Muse (salary) survey:
http://www.ganssle.com/tem/tem347.html
At my job we are developing embedded software using C++11 and there
are exceedingly few resources on how to develop embedded systems
using modern C++. We try to stick to industry best practices, but a lot of
the time there is a lack of standards (or even discussion) regarding parts
of C++ that are now 7+ years old. I would love to see more discussion
and use of modern C++ in the embedded community.
65 / 115
What’s in the pipeline
- Concepts
- Class types in non-type template parameters
- Freestanding
- Ranges
66 / 115
Samll example: take a C-style ‘C++’ library
Arduino library for
- Reading RFID tags
- Using MRFC522 chip
- SPI interface
- Can read/write registers on the chip
- Special command register
67 / 115
Use enum classes
#define CommandReg 0x01
#define CommIEnReg 0x02
#define DivlEnReg 0x03
#define CommIrqReg 0x04
#define DivIrqReg 0x05
void writeMFRC522( uint8_t addr, uint8_t val );
writeMFRC522( DivlEnReg, 0x80 );
writeMFRC522( 0x80, DivlEnReg );
enum class reg : uint8_t {
Command = 0x01,
ComIEn = 0x02,
DivIEn = 0x03,
ComIrq = 0x04,
DivIrq = 0x05,
. . .
void write( reg r, uint8_t d );
write( reg::DivlEnReg, 0x80 );
write( 0x80, reg::DivlEnReg );
• Unscoped #define -> scoped enum class
• Enum class name is part of the name
• No name clashes
• Strong typing
C-style ‘C++’ Modern C++
68 / 115
Strong typing + overloading
#define CommandReg 0x01
#define CommIEnReg 0x02
#define DivlEnReg 0x03
#define CommIrqReg 0x04
#define DivIrqReg 0x05
void writeMFRC522( uint8_t addr, uint8_t val );
writeMFRC522( DivlEnReg, 0x80 );
#define PCD_IDLE 0x00
#define PCD_AUTHENT 0x0E
#define PCD_CALCCRC 0x03
writeMFRC522( CommandReg, PCD_CALCCRC );
enum class reg : uint8_t {
Command = 0x01,
ComIEn = 0x02,
DivIEn = 0x03,
ComIrq = 0x04,
DivIrq = 0x05,
. . .
void write( reg r, uint8_t d );
write( reg::DivlEnReg, 0x80 );
enum class cmd : uint8_t {
Idle = 0x00,
MFAuthent = 0x0E,
CalcCRC = 0x03,
. . .
void write( cmd d );
write( cmd::CalcCRC );
Modern C++C-style ‘C++’
Define the function in the header -> compiler can inline when appropriate
69 / 115
Template parameter, const, implicit size, overloading
void writeMFRC522( uint8_t addr, uint8_t val );
void RFID::calculateCRC(
uint8_t *pIndata, uint8_t len
{
uint8_t i, n;
for( i=0; i<len; i++ )
writeMFRC522( FIFODataReg, *(pIndata+i) );
. . .
void write( reg r, uint8_t d );
template< size_t n >
void write(
reg r,
const std::array< uint8_t, n > & data );
Modern C++C-style ‘C++’
Watch out for template bloat -> maybe (!) use flyweight pattern
70 / 115
(The) hard-embedded programming
example:
Let’s blink a LED!
for(;;){
led.set( true );
wait();
led.set( false );
wait();
};
71 / 115
In this case, take the blue pill
72 / 115
STM32Duino ”Blue pill”
• STM32F103C8T6, Cortex-M3 32 bit CPU, 72 MHz
• 64 Kbyte FLASH (code & contants memory)
• 20 Kbyte RAM
• 32 I/O pins (chip has max 37)
• < E 2.00 (aliexpress)
73 / 115
Memory map
GPIO registers
74 / 115
How to make a pin high or low
75 / 115
In C - directly
// blink the on-board LED at PORTC, pin 13
#include "stm32f103x6.h"
void wait();
int main( void ){
// enable the PORTC peripheral clock
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
// make the pin an output
GPIOC->CRH &= ~( 0x0F << 20 ); // CRH if pin > 7;
GPIOC->CRH |= ( 0x03 << 20 ); // 20 = 4 * ( 13 % 8 )
for(;;){
GPIOC->BSRR |= ( 0x01 << 13 ); // 1 << 13 for reset
wait();
GPIOC->BSRR |= ( 0x01 << 29 ); // 1 << ( 13 + 16 ) for set
wait();
};
}
76 / 115
In C - directly
for(;;){
GPIOC->BSRR = ( 0x01 << 13 );
wait();
GPIOC->BSRR = ( 0x01 << 29 );
wait();
};
mov r6, #8192
mov r5, #536870912
ldr r4, .L3+4
. . .
.L2:
str r6, [r4, #16]
bl _Z4waitv
str r5, [r4, #16]
bl _Z4waitv
b .L2
. . .
.L3:
.word 1073876992
.word 1073811456
gcc 6.2.0, -mcpu=cortex-m3 -Os -std=c11
http://www.github.com/wovo/2017-berlin
Instructions Direct
Call 1*
Library -
77 / 115
In C – use a macro
Abstraction of an I/O pin
+ Efficient
- It is a macro! (scope, textual parameters, … )
- Can’t easily be replaced or augmented by the user
- not easy to separate what from how
// set the pin port.pin to value
#define PIN_SET( port, pin, value ) . . .
78 / 115
In C - functions
// blink the on-board LED at PORTC, pin 13
#include "stm32f103x6.h"
void wait();
void pin_set( int, bool );
int main( void ){
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
GPIOC->CRH &= ~( 0x0F << 20 ); // CRH if pin > 7
GPIOC->CRH |= ( 0x03 << 20 ); // 20 = 4 * ( 13 % 8 )
for(;;){
pin_set( 77, true );
wait();
pin_set( 77, false );
wait();
};
}
#include "stm32f103x6.h"
GPIO_TypeDef * port_registers[] = {
GPIOA, GPIOB, GPIOC, GPIOD };
// pin == 32 * port + pin
void pin_set( int pin, bool value ){
port_registers[ pin / 32 ]->BSRR =
0x01 << ( ( pin % 16 ) + ( value ? 0 : 16 ) );
}
79 / 115
In C - functions
#include "stm32f103x6.h"
GPIO_TypeDef * port_registers[] = {
GPIOA, GPIOB, GPIOC, GPIOD };
// pin == 32 * port + pin
void pin_set( int pin, bool value ){
port_registers[ pin / 32 ]->BSRR =
0x01 << ( ( pin % 16 ) + ( value ? 0 : 16 ) );
}
80 / 115
In C - functions
for(;;){
pin_set( 77, true );
wait();
pin_set( 77, false );
wait();
};
.L2:
movs r1, #1
movs r0, #77
bl _Z7pin_setib
bl _Z4waitv
movs r1, #0
movs r0, #77
bl _Z7pin_setib
bl _Z4waitv
b .L2
_Z7pin_setib:
movs r3, #32
sdiv r3, r0, r3
ldr r2, .L4
ldr r2, [r2, r3, lsl #2]
rsbs r3, r0, #0
and r3, r3, #15
and r0, r0, #15
it pl
rsbpl r0, r3, #0
cmp r1, #0
ite ne
movne r3, #0
moveq r3, #16
add r3, r3, r0
movs r0, #1
lsls r0, r0, r3
str r0, [r2, #16]
bx lr
void pin_set( int pin, bool value ){
port_registers[ pin / 32 ]->BSRR =
0x01 << ( ( pin % 16 ) + ( value ? 0 : 16 ) );
}
Instructions Direct Function
Call 1* 3
Library - 18
81 / 115
In C++ - objects
. . .
#include "pin.hpp"
int main( void ){
. . .
auto led = pin( 2, 13 );
for(;;){
led.set( true );
wait();
led.set( false );
wait();
};
}
// pin.cpp
#include "stm32f103x6.h"
#include "pin.hpp"
GPIO_TypeDef * port_registers[] = {
GPIOA, GPIOB, GPIOC, GPIOD };
pin::pin( int port, int num ):
port( port ), num( num ){}
void pin::set( bool value ){
port_registers[ port ]->BSRR =
0x01 << ( ( num % 16 ) + ( value ? 0 : 16 ) );
}
// pin.hpp
class pin {
private:
int port, num;
public:
pin( int port, int num );
void set( bool value );
};
82 / 115
In C++ - objects
. . .
#include "pin.hpp"
int main( void ){
. . .
auto led = pin( 2, 13 );
for(;;){
led.set( true );
wait();
led.set( false );
wait();
};
}
movs r2, #13
movs r1, #2
mov r0, sp
bl _ZN3pinC1Eii
.L2:
mov r0, sp
movs r1, #1
bl _ZN3pin3setEb
bl _Z4waitv
movs r1, #0
mov r0, sp
bl _ZN3pin3setEb
bl _Z4waitv
b .L2
83 / 115
In C++ - objects
void pin::set( bool value ){
port_registers[ port ]->BSRR =
0x01 << ( ( num % 16 ) + ( value ? 0 : 16 ) );
}
_ZN3pin3setEb:
ldr r2, [r0]
ldr r3, .L5
push {r4, lr}
ldr r4, [r3, r2, lsl #2]
ldr r3, [r0, #4]
rsbs r2, r3, #0
and r2, r2, #15
and r3, r3, #15
it pl
rsbpl r3, r2, #0
cmp r1, #0
ite ne
movne r2, #0
moveq r2, #16
add r2, r2, r3
movs r3, #1
lsls r3, r3, r2
str r3, [r4, #16]
pop {r4, pc}
Instructions Direct Function OO
Call 1* 3 3*
Library - 18 19
84 / 115
…… Well, in some situations.
85 / 115
In C++ - class templates
. . .
#include "pin.hpp"
int main( void ){
. . .
using led = gpio< 2, 13 >;
for(;;){
led::set( true );
wait();
led::set( false );
wait();
};
}
// pin.hpp
#include "stm32f103x6.h"
GPIO_TypeDef * port_registers[] = {
GPIOA, GPIOB, GPIOC, GPIOD };
template< int port, int pin >
class gpio {
public:
static void set( bool value ){
port_registers[ port ]->BSRR =
0x01 << ( ( pin % 16 ) + ( value ? 0 : 16 ) );
}
};
86 / 115
In C++ - class templates
. . .
#include "pin.hpp"
int main( void ){
. . .
using led = gpio< 2, 13 >;
for(;;){
led::set( true );
wait();
led::set( false );
wait();
};
}
mov r6, #8192
mov r5, #536870912
ldr r4, .L3+4
. . .
.L2:
ldr r3, [r4, #8]
str r6, [r3, #16]
bl _Z4waitv
ldr r3, [r4, #8]
str r5, [r3, #16]
bl _Z4waitv
b .L2
. . .
.L3:
.word 1073876992
.word .LANCHOR0
.word 1073811456
Instructions Direct Function OO Template
Call 1* 3 3* 2*
Library - 18 19 -
87 / 115
compile-time polymorphism
❑ Static classes (or structs) can be used as compile-time
encapsulation of data and operations.
❑ Template parameters can be used to pass such an
encapsulation to another one.
❑ These are compile-time-only actions, hence fully visible to
the optimizer.
88 / 115
Run-time
polymorphism
struct pin_out {
virtual void set( bool ) = 0;
};
struct lpc1114_gpio : public pin_out {
lpc1114_gpio( . . . ) . . .
void set( bool x ) override { . . . }
};
struct blink {
pin_out & pin;
blink( pin_out & pin ): pin( pin ){}
void run(){
. . .
pin.set( 1 );
}
}
int main(){
blink( lpc1114_gpio( 1, 2 )).run();
}
template< int port, int pin >
struct lpc1114_gpio {
static void set( bool value ){ . . . }
};
template< typename pin >
struct blink {
void run(){
. . .
pin::set( 1 );
}
}
int main(){
blink< lpc1114_gpio< 1, 2 >>::run();
}
As before, lots of ugly details (initialization, timing, …) are omitted.
Compile-time
polymorphism
struct pin_out_archetype {
typedef void has_pin_out;
static void set( bool value ){}
}
template< int port, int pin >
struct lpc1114_gpio : public pin_out_archetype {
static void set( bool value ){ . . . }
};
template< typename pin >
struct blink {
void run(){
. . .
pin::set( 1 );
}
}
int main(){
blink< lpc1114_gpio< 1, 2 >>::run();
}
89 / 115
struct pin_oc_archetype {
typedef void has_pin_oc;
static void init();
static bool get();
static void set( bool value );
};
struct pin_out_archetype {
typedef void has_pin_out;
static void init();
static void set( bool value );
};
struct pin_in_out_archetype {
typedef void has_pin_in_out;
static void init();
static void direction_set_input();
static void direction_set_output();
static bool get();
static void set( bool value );
};
Four pin archetypes
struct pin_in_archetype {
typedef void has_pin_in;
static void init();
static bool get();
};
90 / 115
#include "targets/lpc1114fn28.hpp"
typedef hwcpp::lpc1114fn28<> target;
int main(){
hwcpp::blink< target::gpio_0_0, target::waiting >::run();
}
template<
typename arg_pin,
typename arg_timing
> struct blinking {
typedef pin_out_from< arg_pin > pin;
typedef waiting_from< arg_timing > timing;
typedef typename timing::duration duration;
static void run( const duration t = duration::ms( 500 ) ){
timing::init();
pin::init();
for(;;){
pin::set( 1 );
timing::wait( t / 2 );
pin::set( 0 );
timing::wait( t / 2 );
}
}
};
Blink: some (ugly?) details
#include "targets/lpc1114fn28.hpp"
typedef hwcpp::lpc1114fn28<> target;
int main(){
hwcpp::blink< target::gpio_1_2, target::waiting >::run();
}
Type narrowing
Explicit initialization
91 / 115
template< class unsupported, class dummy = void > struct pin_out_from {
static_assert( sizeof( unsupported ) == 0, . . . ); };
pin_out_from< . . . > template
template< class unsupported, class dummy = void > struct pin_out_from {
static_assert( sizeof( unsupported ) == 0, . . . ); };
template< class pin > struct pin_out_from < pin, typename pin::has_pin_out > :
public pin_out_archetype
{
static void init(){ pin::init(); }
static void set( bool value ){ pin::set( value ); }
};
template< class pin > struct pin_out_from < pin, typename pin::has_pin_oc > :
public pin_out_archetype
{
static void init(){ pin::init(); }
static void set( bool value ){ pin::set( value ); }
};
template< class unsupported, class dummy = void > struct pin_out_from {
static_assert( sizeof( unsupported ) == 0, . . . ); };
template< class pin > struct pin_out_from < pin, typename pin::has_pin_out > :
public pin_out_archetype
{
static void init(){ pin::init(); }
static void set( bool value ){ pin::set( value ); }
};
template< class pin > struct pin_out_from < pin, typename pin::has_pin_oc > :
public pin_out_archetype
{
static void init(){ pin::init(); }
static void set( bool value ){ pin::set( value ); }
};
template< class pin > struct pin_out_from < pin, typename pin::has_pin_in_out > :
public pin_out_archetype
{
static void init(){ pin::init(); pin::direction_set_output(); }
static void set( bool value ){ pin::set( value ); }
};
92 / 115
Type narrowing
class target {
typedef . . . pin_a0;
}
typedef target::pin_a0 alarm;
int main(){
alarm::init();
alarm::direction_set_output();
alarm::set( false );
if( . . . ){
alarm::set( true );
}
}
class target {
typedef . . . pin_a0;
}
typedef pin_out_from< target::pin_a0 > alarm;
int main(){
alarm::init();
alarm::direction_set_output();
alarm::set( false );
if( . . . ){
alarm::set( true );
}
}
❑ The template parameter is type-checked
❑ The template adapts to the parameter type
❑ Initialization is ‘complete’
❑ The code can’t accidentally use an inappropriate method
93 / 115
Don’t say it in a comment
namespace target {
typedef . . . pin_a0;
}
typedef target::pin_a0 alarm_led;
int main(){
alarm_led::set( false );
if( . . . ){
alarm_led::set( true );
}
}
namespace target {
typedef . . . pin_a0;
}
typedef invert< target::pin_a0 > alarm_led;
int main(){
alarm_led::set( false );
if( . . . ){
alarm_led::set( true );
}
}
Say it in the code
invert< . . . >
decorator
namespace target {
typedef . . . pin_a0;
}
typedef target::pin_a0 alarm_led;
// the alarm LED pin is active low
const bool alarm_led_active = false;
int main(){
alarm_led::set( ! alarm_led_active );
if( . . . ){
alarm_led::set( alarm_led_active );
}
}
94 / 115
Pin invert< . . . >
template< class unsupported, class dummy = void > struct invert {
static_assert( sizeof( unsupported ) == 0, ". . ." ); };
template< class pin > struct invert< pin, typename pin::has_pin_in > :
public pin_in_archetype {
static void init(){ pin::init(); }
static bool get(){ return ! pin::get(); } };
template< class pin > struct invert< pin, typename pin::has_pin_out > :
public pin_out_archetype {
static void init(){ pin::init(); }
static void set( bool x ){ pin::set( ! x ); } };
template< class pin > struct invert< pin, typename pin::has_pin_in_out > :
public pin_in_out_archetype {
static void init(){ pin::init(); }
static void direction_set_input(){ pin::direction_set_input(); }
static void direction_set_output(){ pin::direction_set_output(); }
static void set( bool x ){ pin::set( ! x ); }
static bool get(){ return ! pin::get(); } };
template< class pin > struct invert< pin, typename pin::has_pin_oc > :
public pin_oc_archetype {
static void init(){ pin::init(); }
static void set( bool x ){ pin::set( ! x ); }
static bool get(){ return ! pin::get(); } };
Often:
ZERO cost!
95 / 115
Some more pin & port decorators
// create the stated pin or port type from p
pin_in_from< p >
pin_out_from< p >
pin_in_out_from< p >
pin_oc_from< p >
port_in_from< p >
port_out_from< p >
port_in_out_from< p >
port_oc_from< p >
// create a port of the stated type from pins
port_in_from_pins< p, ... >
port_out_from_pins< p, ... >
port_in_out_from_pins< p, ... >
// invert the value read from or written to p
invert< p >
// pin or port that writes to all pins or ports
all< p, ... >
96 / 115
Using static class templates:
consequences
❑ Abstraction tool is the class template with only
static contents (classes, methods, attributes)
❑ Composition is by template instantiation
❑ Method call syntax is class::method(…) instead
of object.method(…)
❑ Header-only
97 / 115
Using static class templates:
more consequences
❑ No objects (of such classes) are created
❑ No memory management, no dangling references
❑ Collections don’t contain unused elements
❑ Sharing of identical constructs is automatic
❑ No automatic construction: explicit init() calls
❑ Abstraction overhead can be zero
98 / 115
What does a
programming language
want?
99 / 115
“Give me just one generation of youth,
and I'll transform the whole world.”
100 / 115
What motivates the next generation of
programmers?
• Websites : (that isn’t real programming)
• Mobile : mostly Android, Java, Java-frameworks
• Easy power : RaspberryPi, Python
• (Micro Bit, Lego) : graphic programming
• Cheap, low-energy, hardware interfacing : Arduino
101 / 115
The Arduino ecosystem
• Hardware designs & webshop
• Bootloaders
• IDE with toolchain, libraries, download tools
• Third-party libraries
• ‘Counterfeit’ hardware
• Web coverage
102 / 115
Official hardware designs - AVR
Uno, Leonardo, 101, esplora, micro,
nano, mini, mega, ethrente, lilypad
103 / 115
Official hardware designs - Cortex
Zero, Due, M0, MKR Zero
104 / 115
Some other boards
Blue Pill, ATTiny85, ESP8266, ESP32
105 / 115
Arduino software
- Crappy IDE, but it works quite reliably
- Some behind-the-scenes magic
- Uses C++ compiler, but almost no C++ features
- Lots of overlapping third-party libraries
- Configuration is often by editing the library source
(each LCD driver has its own graphics library)
- And yet: tremendously popular!
106 / 115
Opportunities!
- Lots of black magic & cargo-cult beliefs
- Lots of duplicate efforts (overlapping libraries)
- Lack of leverage (no component-based culture)
A well-structured set of C++ libraries, books, websites,
clubs, etc. could make these folks love C++ for their
life!
107 / 115
Target audience?
- Kids
- Professional C++ programmers in their spare time
- non-EE/CE professionals (artists!)
108 / 115
and don’t let them escape!
Grab the next generation
109 / 115
Takaways
- Embedded? Please be more specific!
- The C++ is the language for (small-) embedded
- but ’they’ don’t know that yet ☹
- and we don’t yet agree on how to use it
- C++ libraries could be more embedded-friendly

More Related Content

PDF
Let's write a Debugger!
PPTX
Linux rt in financial markets
PDF
TIP1 - Overview of C/C++ Debugging/Tracing/Profiling Tools
PDF
Translation Cache Policies for Dynamic Binary Translation
PPTX
Onnc intro
PPT
emips_overview_apr08
PDF
Optimizing Python
PPTX
Klessydra t - designing vector coprocessors for multi-threaded edge-computing...
Let's write a Debugger!
Linux rt in financial markets
TIP1 - Overview of C/C++ Debugging/Tracing/Profiling Tools
Translation Cache Policies for Dynamic Binary Translation
Onnc intro
emips_overview_apr08
Optimizing Python
Klessydra t - designing vector coprocessors for multi-threaded edge-computing...

What's hot (20)

PDF
Kernel Recipes 2016 - entry_*.S: A carefree stroll through kernel entry code
PPT
Contiki introduction I.
DOCX
Arduino 101
PPTX
An Open Discussion of RISC-V BitManip, trends, and comparisons _ Claire
PDF
Things you should know for network programming
PDF
Memory management
PPT
09 accelerators
PPT
Troubleshooting Linux Kernel Modules And Device Drivers
PDF
Analyzing OS X Systems Performance with the USE Method
PDF
Netflix: From Clouds to Roots
PDF
Netflix SRE perf meetup_slides
PPTX
Track c-High speed transaction-based hw-sw coverification -eve
PDF
Real-time in the real world: DIRT in production
PDF
LAS16-101: Efficient kernel backporting
PDF
Linux Performance Analysis: New Tools and Old Secrets
PPTX
Testing CAN network with help of CANToolz
PDF
[DCG 25] Александр Большев - Never Trust Your Inputs or How To Fool an ADC
PDF
DTrace Topics: Introduction
PDF
OSMC 2014: Server Hardware Monitoring done right | Werner Fischer
PDF
FreeBSD 2014 Flame Graphs
Kernel Recipes 2016 - entry_*.S: A carefree stroll through kernel entry code
Contiki introduction I.
Arduino 101
An Open Discussion of RISC-V BitManip, trends, and comparisons _ Claire
Things you should know for network programming
Memory management
09 accelerators
Troubleshooting Linux Kernel Modules And Device Drivers
Analyzing OS X Systems Performance with the USE Method
Netflix: From Clouds to Roots
Netflix SRE perf meetup_slides
Track c-High speed transaction-based hw-sw coverification -eve
Real-time in the real world: DIRT in production
LAS16-101: Efficient kernel backporting
Linux Performance Analysis: New Tools and Old Secrets
Testing CAN network with help of CANToolz
[DCG 25] Александр Большев - Never Trust Your Inputs or How To Fool an ADC
DTrace Topics: Introduction
OSMC 2014: Server Hardware Monitoring done right | Werner Fischer
FreeBSD 2014 Flame Graphs
Ad

Similar to Objects? No thanks! (20)

PPTX
Fedor Polyakov - Optimizing computer vision problems on mobile platforms
PDF
Include os @ flossuk 2018
PDF
Bits of Advice for the VM Writer, by Cliff Click @ Curry On 2015
PDF
XPDDS18: Real Time in XEN on ARM - Andrii Anisov, EPAM Systems Inc.
PDF
Computação Paralela: Benefícios e Desafios - Intel Software Conference 2013
PDF
May2010 hex-core-opt
PPT
Servers and Processes: Behavior and Analysis
PDF
Linux Systems Performance 2016
KEY
SMP implementation for OpenBSD/sgi
PPTX
Linux Network Stack
PDF
How to deploy & optimize eZ Publish
PDF
Programar para GPUs
PPT
20081114 Friday Food iLabt Bart Joris
PDF
Secure Coding Practices for Middleware
PDF
Where Did All These Cycles Go?
PPTX
Getting started with Intel IoT Developer Kit
PPTX
UNIT 3 - General Purpose Processors
PDF
Arduino delphi 2014_7_bonn
PDF
Performance Analysis: new tools and concepts from the cloud
PDF
Kernel Recipes 2016 - Speeding up development by setting up a kernel build farm
Fedor Polyakov - Optimizing computer vision problems on mobile platforms
Include os @ flossuk 2018
Bits of Advice for the VM Writer, by Cliff Click @ Curry On 2015
XPDDS18: Real Time in XEN on ARM - Andrii Anisov, EPAM Systems Inc.
Computação Paralela: Benefícios e Desafios - Intel Software Conference 2013
May2010 hex-core-opt
Servers and Processes: Behavior and Analysis
Linux Systems Performance 2016
SMP implementation for OpenBSD/sgi
Linux Network Stack
How to deploy & optimize eZ Publish
Programar para GPUs
20081114 Friday Food iLabt Bart Joris
Secure Coding Practices for Middleware
Where Did All These Cycles Go?
Getting started with Intel IoT Developer Kit
UNIT 3 - General Purpose Processors
Arduino delphi 2014_7_bonn
Performance Analysis: new tools and concepts from the cloud
Kernel Recipes 2016 - Speeding up development by setting up a kernel build farm
Ad

More from corehard_by (20)

PPTX
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
PPTX
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
PDF
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
PPTX
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
PPTX
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
PPTX
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
PPTX
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
PPTX
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
PPTX
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
PPTX
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
PDF
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
PPTX
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
PPTX
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
PDF
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
PDF
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
PDF
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
PDF
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
PPTX
Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019
PDF
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
PDF
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019
C++ CoreHard Autumn 2018. Создание пакетов для открытых библиотек через conan...
C++ CoreHard Autumn 2018. Что должен знать каждый C++ программист или Как про...
C++ CoreHard Autumn 2018. Actors vs CSP vs Tasks vs ... - Евгений Охотников
C++ CoreHard Autumn 2018. Знай свое "железо": иерархия памяти - Александр Титов
C++ CoreHard Autumn 2018. Информационная безопасность и разработка ПО - Евген...
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
C++ CoreHard Autumn 2018. Ускорение сборки C++ проектов, способы и последстви...
C++ CoreHard Autumn 2018. Метаклассы: воплощаем мечты в реальность - Сергей С...
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...
C++ CoreHard Autumn 2018. Concurrency and Parallelism in C++17 and C++20/23 -...
C++ CoreHard Autumn 2018. Обработка списков на C++ в функциональном стиле - В...
C++ Corehard Autumn 2018. Обучаем на Python, применяем на C++ - Павел Филонов
C++ CoreHard Autumn 2018. Asynchronous programming with ranges - Ivan Čukić
C++ CoreHard Autumn 2018. Debug C++ Without Running - Anastasia Kazakova
C++ CoreHard Autumn 2018. Полезный constexpr - Антон Полухин
C++ CoreHard Autumn 2018. Text Formatting For a Future Range-Based Standard L...
Исключительная модель памяти. Алексей Ткаченко ➠ CoreHard Autumn 2019
Как помочь и как помешать компилятору. Андрей Олейников ➠ CoreHard Autumn 2019
Автоматизируй это. Кирилл Тихонов ➠ CoreHard Autumn 2019

Recently uploaded (20)

PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Machine learning based COVID-19 study performance prediction
PDF
cuic standard and advanced reporting.pdf
PDF
Empathic Computing: Creating Shared Understanding
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Accuracy of neural networks in brain wave diagnosis of schizophrenia
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Getting Started with Data Integration: FME Form 101
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PPT
Teaching material agriculture food technology
PPTX
Machine Learning_overview_presentation.pptx
Building Integrated photovoltaic BIPV_UPV.pdf
Diabetes mellitus diagnosis method based random forest with bat algorithm
Machine learning based COVID-19 study performance prediction
cuic standard and advanced reporting.pdf
Empathic Computing: Creating Shared Understanding
Mobile App Security Testing_ A Comprehensive Guide.pdf
Programs and apps: productivity, graphics, security and other tools
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Network Security Unit 5.pdf for BCA BBA.
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Accuracy of neural networks in brain wave diagnosis of schizophrenia
MIND Revenue Release Quarter 2 2025 Press Release
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Assigned Numbers - 2025 - Bluetooth® Document
Per capita expenditure prediction using model stacking based on satellite ima...
Getting Started with Data Integration: FME Form 101
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Reach Out and Touch Someone: Haptics and Empathic Computing
Teaching material agriculture food technology
Machine Learning_overview_presentation.pptx

Objects? No thanks!

  • 1. 1 / 115 CoreHard 2018 Minsk (small) embeded system? use C++ ! Wouter van Ooijen MSc (ir) Hogeschool Utrecht, Netherlands, senior lecturer Computer Engineering SG14 member wouter.vanooijen@hu.nl
  • 2. 2 / 115 A detour ….. Some 20 years ago I worked for a small Dutch space company
  • 3. 3 / 115 … on the the European Robotic Arm project
  • 4. 4 / 115 Which was delayed, delayed and delayed, and finally mothballed for lack of a purpose.
  • 5. 5 / 115 Ariane 4 ➔ Ariane 5
  • 6. 6 / 115 Big day Ariane 5 maiden flight Payment!
  • 10. 10 / 115 the Flight Control system
  • 11. 11 / 115 the Inertial Reference System
  • 12. 12 / 115 • Requirement: CPU load at launch must be < 80% • IRS CPU load is too high • Analysis: physically HVB can’t be out of range • Agreed solution: remove the checks for HVB Design process…
  • 14. 14 / 115 • Floating-point HRS value is out of 16-bits bounds • Conversion exception occurs • Is caugth at main level, application shutdown • Switch to backup IRS fails • Diagnostic information is put on the databus • Is interpreted as flight data by the main computer • Causes extreme steering • Boosters break loose • Self-destruct engages • (Flight control commands self-destruct) Chain of events
  • 15. 15 / 115 Spot the important difference
  • 16. 16 / 115 So who/what is to blame? - Task running when no longer needed - < 80 % CPU utilization requirement - Using underpowered hardware - Redundancy in HW but not in SW - Stopping all tasks when an unexpected exception occurs - Fail-totally instead of fail-gradually - Re-using Ariane 4 software in Ariane 5 (untested) - Having only ‘positive’ requirements - Using Ada - ……………… add your own?
  • 17. 17 / 115 The cluster
  • 18. 18 / 115 Welcome to the embedded world – where things can go kaboom!
  • 19. 19 / 115 Not always that serious
  • 20. 20 / 115 Dental brace retainer
  • 21. 21 / 115 Airbag Late might even be worse than not at all…
  • 22. 22 / 115 Wide span of seriousness
  • 23. 23 / 115 Wide span of response time µs ms s
  • 25. 25 / 115 Wide span of replication 1 Disclaimer: all figures are just wild guesses 100’000 10’000 100 1’000’000
  • 26. 26 / 115 1MiB 1GiB1KiB 4-bit 8-bit : 8051, PIC, AVR, … 16-bit : MSP430, PIC, … 64-bit No full standard C/C++ 32-bit : ARM, MIPS, Tensilca, Intel, … Wide span of hardware
  • 27. 27 / 115 Wide span of support software Bare metal: • libraries • no separate OS 1MiB 1GiB1KiB Desktop OS: • Linux • Windows • Interpreter • RTOS
  • 28. 28 / 115 Embedded languages AspenCore: my current embedded project is programmed mostly in…
  • 29. 29 / 115 Embedded languages 2010 VDC survey
  • 30. 30 / 115 = Not a usable term to define a (single) programming style Embedded
  • 31. 31 / 115 Let’s quantify 10F200 Arduino Uno Arduino Due Raspberry Pi Desktop Code 375 B 32 KiB 512 KiB 8 GiB 1 TiB Data 16 B 2 KiB 96 KiB 1 GiB 4 GiB CPU 8 bit 8 bit 32 bit 32 bit 64 bit Clock 4 MHz 16 MHz 84 MHz 900 MHz 3 GHz
  • 32. 32 / 115 Real numbers 1MiB 1GiB1KiB 10F200 Arduino Uno Arduino Due Raspberry Pi Desktop Code 375 32768 524288 8589934592 1099511627776 Data 16 2048 98304 1073741824 4294967296 CPU 1000000 16000000 168000000 3600000000 30000000000
  • 33. 33 / 115 Relative 10F200 Arduino Uno Arduino Due Raspberry Pi Desktop Code 1 87 1398 22906492 2932031007 Data 1 128 6144 67108864 268435456 CPU 1 16 128 3600 30000
  • 34. 34 / 115 10 * Log 10F200 Arduino Uno Arduino Due Raspberry Pi Desktop Code 0.000000 44.70282 72.42870 169.46931 217.98961 Data 0.000000 48.52030 87.23231 180.21827 194.08121 CPU 0.000000 27.72588 51.239639 81.886891 103.089526
  • 35. 35 / 115 Rounded 10 * log 10F200 Arduino Uno Arduino Due Raspberry Pi Desktop Code 0 45 72 169 218 Data 0 49 87 180 194 CPU 0 28 51 82 103
  • 36. 36 / 115 Unit of (log) size?
  • 37. 37 / 115 Unit of (log) speed?
  • 38. 38 / 115 Relative, in dMore and dHopper 10F200 Arduino Uno Arduino Due Raspberry Pi Desktop code dMoore 0 +45 +27 +97 +49 data Moore 0 +49 +38 +93 +14 dHopper 0 +28 +31 +31 +21 relative to previous column
  • 39. 39 / 115 10F200 Arduino Uno Arduino Due Raspberry Pi Desktop code dMoore 0 +45 +27 +97 +49 data Moore 0 +49 +38 +93 +14 dHopper 0 +28 +31 +31 +21 Assembler No alternative I am actually doing electronics diguised as software. Maybe I’ll consider C
  • 40. 40 / 115 10F200 Arduino Uno Arduino Due Raspberry Pi Desktop code dMoore 0 +45 +27 +97 +49 data Moore 0 +49 +38 +93 +14 RTOS GP OS Interpreter – I run desktop code in a small chip You can afford
  • 41. 41 / 115 10F200 Arduino Uno Arduino Due Raspberry Pi Desktop code dMoore 0 +45 +27 +97 +49 data Moore 0 +49 +38 +93 +14 dHopper 0 +28 +31 +31 +21 RTOS GP OSInterpreter Where does C++ fit in? Assembler If you need performance …
  • 44. 44 / 115 C++ versus Python Actually compiled versus interpreted Penalty Size 3 .. 13 dMoore Speed 3 .. 23 dHopper
  • 45. 45 / 115 C++ versus Python Actually compiled versus interpreted Penalty Size 3 .. 13 dMoore (factor 2 .. 20) Speed 3 .. 23 dHopper (factor 2 .. 200)
  • 46. 46 / 115 10F200 Arduino Uno Arduino Due Raspberry Pi Desktop code dMoore 0 +45 +27 +97 +49 data Moore 0 +49 +38 +93 +14 dHopper 0 +28 +31 +31 +21 RTOS GP OSInterpreter Where does C++ fit in? Assembler small-embedded C++ alley
  • 47. 47 / 115 dMoore 0 +10 +20 dHopper 0 +10 +20 Size & speed margin Very low margin: Use Assembler Comfortable margin: Consider using an interpreter small-embedded C++ alley
  • 48. 48 / 115 large-embedded small-embedded MiB, GiB GHz, multi-core Memory latency, caches Worry about latency bytes, KiB, worry about size MHz, Interrupts Hardware peripherals Battery life-time
  • 49. 49 / 115 large-embedded small-embedded fast trading gaming simulation SG14: low-latency
  • 50. 50 / 115 What does C++ do for embedded? - ADTs: abstraction, data hiding, type-checking, enum class - Overloading, operators - Namespaces - Argument defaults, references, std::array<> - Const, constexpr, constexpr if - }, RAII - Templates - DSLs (using templates, operators, overloading)
  • 51. 51 / 115 Note that most: • Are zero cost • Were NOT included for embedded • Help to reduce MACRO’S - ADTs: abstraction, data hiding, type-checking, enum class - Overloading, operators - Namespaces - Argument defaults, references, std::array<> - Const, constexpr, constexpr if - }, RAII - Templates - DSLs (using templates, operators, overloading)
  • 52. 52 / 115 Less usefull? - Heap : (small-) embedded is often ‘mission-critical’ - Exceptions : idem - Classic OO : not free - Bit-fields : not enough control, and can be done adequately (and encapsulated!) with other means - The libraries (large - but unspecified! - parts can’t be used)
  • 53. 53 / 115 Annoying All (library) assumptions that are hard-coded - Extra space is allocated on the heap - Integer calculations are done using int - Floating-point calculations are done using double - Special situations are reported by exceptions - This function must be fast / small - Caching determines speed, so avoid linked lists - All that matters is amortized complexity
  • 54. 54 / 115 Heap The heap is flexibility with respect to the amount of data, at the cost of (some) unpredictability in run-time and maximum available memory (fragmentation). A typical small embedded system ❑ has a rigidly prescribed task, including the size of the data involved ❑ Must meet real-time constraints ❑ Should be certain to meet work OK all the time (not just for a certain sequence of actions). ➔A heap and a small embedded system don’t match very well. Better: ❑ Global allocation (!) ❑ Fixed size pools or fixed size containers
  • 55. 55 / 115 Exceptions Exceptions are great to handle a local problem that requires a (more) global response. ❑ A small system often has a rather simple, rigidly defined task ➔there are no exceptions, only different situations. ❑ No heap ➔ one reason less to use exceptions. ❑ Exception implementation often uses the heap…. Straw man: exceptions are slow and have unpredictable timing.
  • 56. 56 / 115 Floating point FP is useful when a wide dynamic range is needed. For an embedded application the ranges are often very well known. (but… Ariane 5?) Small micro-controllers often don’t have a hardware FPU. A software FP library ❑ Is considerably slower ❑ Takes up ROM Make your software ‘open’: template< typename value_type = double > class your_amazing_library { . . .
  • 57. 57 / 115 ”Just” print struct location { int x, y; }; void print_location( FILE * f, location v ){ fprintf( f, "(%d,%d)", v.x, v.y ); } std::ostream & operator<<( std::ostream & out, const location & v ){ return out << '(' << v.x << ',' << v.y << ')'; } template< typename OUT > auto operator<<( OUT & out, const location & v ) -> decltype( out << 'x' ) & { return out << '(' << v.x << ',' << v.y << ')'; }
  • 58. 58 / 115 General embedded / low-latency / standalone ‘profile’ - No heap use (in the critical code) - No exceptions thrown or caught (in the critical code) - No RTTI
  • 59. 59 / 115 Small-embedded profile - No heap included - Compiled without exceptions - No RTTI - No floating point - No OS support, no file system, no std::cout
  • 60. 60 / 115 Embedded ’paranoia’ profiles - No heap included - Compiled without exceptions - No RTTI - No floating point - No OS support, no file system, no std::cout - Analyzable stack size: no recursion, no indirection - Analyzable run-time: no unbounded loops
  • 61. 61 / 115 What does C++ NOT (yet) do for small-embedded - Comprehensible, single-way-of-doing-things language - Usable set of libraries - Examples (books, websites, blogs, etc.) that show the (or even an) appropriate modern programming style
  • 62. 62 / 115 Why don’t they all use C++? - No compiler available (PIC, 8051) - No programmers available - Not allowed - Existing code base (often in C) - The style is inappropriate - It is too complex (doesn’t show what happens) - Code bloat - No advantages
  • 63. 63 / 115 Why don’t they all use C++? - No compiler available (PIC, 8051) - No programmers available - Not allowed - Existing code base (often in C) - The style is inappropriate - It is too complex (doesn’t show what happens) - Code bloat - No advantages
  • 64. 64 / 115 Remark from The Embedded Muse (salary) survey: http://www.ganssle.com/tem/tem347.html At my job we are developing embedded software using C++11 and there are exceedingly few resources on how to develop embedded systems using modern C++. We try to stick to industry best practices, but a lot of the time there is a lack of standards (or even discussion) regarding parts of C++ that are now 7+ years old. I would love to see more discussion and use of modern C++ in the embedded community.
  • 65. 65 / 115 What’s in the pipeline - Concepts - Class types in non-type template parameters - Freestanding - Ranges
  • 66. 66 / 115 Samll example: take a C-style ‘C++’ library Arduino library for - Reading RFID tags - Using MRFC522 chip - SPI interface - Can read/write registers on the chip - Special command register
  • 67. 67 / 115 Use enum classes #define CommandReg 0x01 #define CommIEnReg 0x02 #define DivlEnReg 0x03 #define CommIrqReg 0x04 #define DivIrqReg 0x05 void writeMFRC522( uint8_t addr, uint8_t val ); writeMFRC522( DivlEnReg, 0x80 ); writeMFRC522( 0x80, DivlEnReg ); enum class reg : uint8_t { Command = 0x01, ComIEn = 0x02, DivIEn = 0x03, ComIrq = 0x04, DivIrq = 0x05, . . . void write( reg r, uint8_t d ); write( reg::DivlEnReg, 0x80 ); write( 0x80, reg::DivlEnReg ); • Unscoped #define -> scoped enum class • Enum class name is part of the name • No name clashes • Strong typing C-style ‘C++’ Modern C++
  • 68. 68 / 115 Strong typing + overloading #define CommandReg 0x01 #define CommIEnReg 0x02 #define DivlEnReg 0x03 #define CommIrqReg 0x04 #define DivIrqReg 0x05 void writeMFRC522( uint8_t addr, uint8_t val ); writeMFRC522( DivlEnReg, 0x80 ); #define PCD_IDLE 0x00 #define PCD_AUTHENT 0x0E #define PCD_CALCCRC 0x03 writeMFRC522( CommandReg, PCD_CALCCRC ); enum class reg : uint8_t { Command = 0x01, ComIEn = 0x02, DivIEn = 0x03, ComIrq = 0x04, DivIrq = 0x05, . . . void write( reg r, uint8_t d ); write( reg::DivlEnReg, 0x80 ); enum class cmd : uint8_t { Idle = 0x00, MFAuthent = 0x0E, CalcCRC = 0x03, . . . void write( cmd d ); write( cmd::CalcCRC ); Modern C++C-style ‘C++’ Define the function in the header -> compiler can inline when appropriate
  • 69. 69 / 115 Template parameter, const, implicit size, overloading void writeMFRC522( uint8_t addr, uint8_t val ); void RFID::calculateCRC( uint8_t *pIndata, uint8_t len { uint8_t i, n; for( i=0; i<len; i++ ) writeMFRC522( FIFODataReg, *(pIndata+i) ); . . . void write( reg r, uint8_t d ); template< size_t n > void write( reg r, const std::array< uint8_t, n > & data ); Modern C++C-style ‘C++’ Watch out for template bloat -> maybe (!) use flyweight pattern
  • 70. 70 / 115 (The) hard-embedded programming example: Let’s blink a LED! for(;;){ led.set( true ); wait(); led.set( false ); wait(); };
  • 71. 71 / 115 In this case, take the blue pill
  • 72. 72 / 115 STM32Duino ”Blue pill” • STM32F103C8T6, Cortex-M3 32 bit CPU, 72 MHz • 64 Kbyte FLASH (code & contants memory) • 20 Kbyte RAM • 32 I/O pins (chip has max 37) • < E 2.00 (aliexpress)
  • 73. 73 / 115 Memory map GPIO registers
  • 74. 74 / 115 How to make a pin high or low
  • 75. 75 / 115 In C - directly // blink the on-board LED at PORTC, pin 13 #include "stm32f103x6.h" void wait(); int main( void ){ // enable the PORTC peripheral clock RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // make the pin an output GPIOC->CRH &= ~( 0x0F << 20 ); // CRH if pin > 7; GPIOC->CRH |= ( 0x03 << 20 ); // 20 = 4 * ( 13 % 8 ) for(;;){ GPIOC->BSRR |= ( 0x01 << 13 ); // 1 << 13 for reset wait(); GPIOC->BSRR |= ( 0x01 << 29 ); // 1 << ( 13 + 16 ) for set wait(); }; }
  • 76. 76 / 115 In C - directly for(;;){ GPIOC->BSRR = ( 0x01 << 13 ); wait(); GPIOC->BSRR = ( 0x01 << 29 ); wait(); }; mov r6, #8192 mov r5, #536870912 ldr r4, .L3+4 . . . .L2: str r6, [r4, #16] bl _Z4waitv str r5, [r4, #16] bl _Z4waitv b .L2 . . . .L3: .word 1073876992 .word 1073811456 gcc 6.2.0, -mcpu=cortex-m3 -Os -std=c11 http://www.github.com/wovo/2017-berlin Instructions Direct Call 1* Library -
  • 77. 77 / 115 In C – use a macro Abstraction of an I/O pin + Efficient - It is a macro! (scope, textual parameters, … ) - Can’t easily be replaced or augmented by the user - not easy to separate what from how // set the pin port.pin to value #define PIN_SET( port, pin, value ) . . .
  • 78. 78 / 115 In C - functions // blink the on-board LED at PORTC, pin 13 #include "stm32f103x6.h" void wait(); void pin_set( int, bool ); int main( void ){ RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; GPIOC->CRH &= ~( 0x0F << 20 ); // CRH if pin > 7 GPIOC->CRH |= ( 0x03 << 20 ); // 20 = 4 * ( 13 % 8 ) for(;;){ pin_set( 77, true ); wait(); pin_set( 77, false ); wait(); }; } #include "stm32f103x6.h" GPIO_TypeDef * port_registers[] = { GPIOA, GPIOB, GPIOC, GPIOD }; // pin == 32 * port + pin void pin_set( int pin, bool value ){ port_registers[ pin / 32 ]->BSRR = 0x01 << ( ( pin % 16 ) + ( value ? 0 : 16 ) ); }
  • 79. 79 / 115 In C - functions #include "stm32f103x6.h" GPIO_TypeDef * port_registers[] = { GPIOA, GPIOB, GPIOC, GPIOD }; // pin == 32 * port + pin void pin_set( int pin, bool value ){ port_registers[ pin / 32 ]->BSRR = 0x01 << ( ( pin % 16 ) + ( value ? 0 : 16 ) ); }
  • 80. 80 / 115 In C - functions for(;;){ pin_set( 77, true ); wait(); pin_set( 77, false ); wait(); }; .L2: movs r1, #1 movs r0, #77 bl _Z7pin_setib bl _Z4waitv movs r1, #0 movs r0, #77 bl _Z7pin_setib bl _Z4waitv b .L2 _Z7pin_setib: movs r3, #32 sdiv r3, r0, r3 ldr r2, .L4 ldr r2, [r2, r3, lsl #2] rsbs r3, r0, #0 and r3, r3, #15 and r0, r0, #15 it pl rsbpl r0, r3, #0 cmp r1, #0 ite ne movne r3, #0 moveq r3, #16 add r3, r3, r0 movs r0, #1 lsls r0, r0, r3 str r0, [r2, #16] bx lr void pin_set( int pin, bool value ){ port_registers[ pin / 32 ]->BSRR = 0x01 << ( ( pin % 16 ) + ( value ? 0 : 16 ) ); } Instructions Direct Function Call 1* 3 Library - 18
  • 81. 81 / 115 In C++ - objects . . . #include "pin.hpp" int main( void ){ . . . auto led = pin( 2, 13 ); for(;;){ led.set( true ); wait(); led.set( false ); wait(); }; } // pin.cpp #include "stm32f103x6.h" #include "pin.hpp" GPIO_TypeDef * port_registers[] = { GPIOA, GPIOB, GPIOC, GPIOD }; pin::pin( int port, int num ): port( port ), num( num ){} void pin::set( bool value ){ port_registers[ port ]->BSRR = 0x01 << ( ( num % 16 ) + ( value ? 0 : 16 ) ); } // pin.hpp class pin { private: int port, num; public: pin( int port, int num ); void set( bool value ); };
  • 82. 82 / 115 In C++ - objects . . . #include "pin.hpp" int main( void ){ . . . auto led = pin( 2, 13 ); for(;;){ led.set( true ); wait(); led.set( false ); wait(); }; } movs r2, #13 movs r1, #2 mov r0, sp bl _ZN3pinC1Eii .L2: mov r0, sp movs r1, #1 bl _ZN3pin3setEb bl _Z4waitv movs r1, #0 mov r0, sp bl _ZN3pin3setEb bl _Z4waitv b .L2
  • 83. 83 / 115 In C++ - objects void pin::set( bool value ){ port_registers[ port ]->BSRR = 0x01 << ( ( num % 16 ) + ( value ? 0 : 16 ) ); } _ZN3pin3setEb: ldr r2, [r0] ldr r3, .L5 push {r4, lr} ldr r4, [r3, r2, lsl #2] ldr r3, [r0, #4] rsbs r2, r3, #0 and r2, r2, #15 and r3, r3, #15 it pl rsbpl r3, r2, #0 cmp r1, #0 ite ne movne r2, #0 moveq r2, #16 add r2, r2, r3 movs r3, #1 lsls r3, r3, r2 str r3, [r4, #16] pop {r4, pc} Instructions Direct Function OO Call 1* 3 3* Library - 18 19
  • 84. 84 / 115 …… Well, in some situations.
  • 85. 85 / 115 In C++ - class templates . . . #include "pin.hpp" int main( void ){ . . . using led = gpio< 2, 13 >; for(;;){ led::set( true ); wait(); led::set( false ); wait(); }; } // pin.hpp #include "stm32f103x6.h" GPIO_TypeDef * port_registers[] = { GPIOA, GPIOB, GPIOC, GPIOD }; template< int port, int pin > class gpio { public: static void set( bool value ){ port_registers[ port ]->BSRR = 0x01 << ( ( pin % 16 ) + ( value ? 0 : 16 ) ); } };
  • 86. 86 / 115 In C++ - class templates . . . #include "pin.hpp" int main( void ){ . . . using led = gpio< 2, 13 >; for(;;){ led::set( true ); wait(); led::set( false ); wait(); }; } mov r6, #8192 mov r5, #536870912 ldr r4, .L3+4 . . . .L2: ldr r3, [r4, #8] str r6, [r3, #16] bl _Z4waitv ldr r3, [r4, #8] str r5, [r3, #16] bl _Z4waitv b .L2 . . . .L3: .word 1073876992 .word .LANCHOR0 .word 1073811456 Instructions Direct Function OO Template Call 1* 3 3* 2* Library - 18 19 -
  • 87. 87 / 115 compile-time polymorphism ❑ Static classes (or structs) can be used as compile-time encapsulation of data and operations. ❑ Template parameters can be used to pass such an encapsulation to another one. ❑ These are compile-time-only actions, hence fully visible to the optimizer.
  • 88. 88 / 115 Run-time polymorphism struct pin_out { virtual void set( bool ) = 0; }; struct lpc1114_gpio : public pin_out { lpc1114_gpio( . . . ) . . . void set( bool x ) override { . . . } }; struct blink { pin_out & pin; blink( pin_out & pin ): pin( pin ){} void run(){ . . . pin.set( 1 ); } } int main(){ blink( lpc1114_gpio( 1, 2 )).run(); } template< int port, int pin > struct lpc1114_gpio { static void set( bool value ){ . . . } }; template< typename pin > struct blink { void run(){ . . . pin::set( 1 ); } } int main(){ blink< lpc1114_gpio< 1, 2 >>::run(); } As before, lots of ugly details (initialization, timing, …) are omitted. Compile-time polymorphism struct pin_out_archetype { typedef void has_pin_out; static void set( bool value ){} } template< int port, int pin > struct lpc1114_gpio : public pin_out_archetype { static void set( bool value ){ . . . } }; template< typename pin > struct blink { void run(){ . . . pin::set( 1 ); } } int main(){ blink< lpc1114_gpio< 1, 2 >>::run(); }
  • 89. 89 / 115 struct pin_oc_archetype { typedef void has_pin_oc; static void init(); static bool get(); static void set( bool value ); }; struct pin_out_archetype { typedef void has_pin_out; static void init(); static void set( bool value ); }; struct pin_in_out_archetype { typedef void has_pin_in_out; static void init(); static void direction_set_input(); static void direction_set_output(); static bool get(); static void set( bool value ); }; Four pin archetypes struct pin_in_archetype { typedef void has_pin_in; static void init(); static bool get(); };
  • 90. 90 / 115 #include "targets/lpc1114fn28.hpp" typedef hwcpp::lpc1114fn28<> target; int main(){ hwcpp::blink< target::gpio_0_0, target::waiting >::run(); } template< typename arg_pin, typename arg_timing > struct blinking { typedef pin_out_from< arg_pin > pin; typedef waiting_from< arg_timing > timing; typedef typename timing::duration duration; static void run( const duration t = duration::ms( 500 ) ){ timing::init(); pin::init(); for(;;){ pin::set( 1 ); timing::wait( t / 2 ); pin::set( 0 ); timing::wait( t / 2 ); } } }; Blink: some (ugly?) details #include "targets/lpc1114fn28.hpp" typedef hwcpp::lpc1114fn28<> target; int main(){ hwcpp::blink< target::gpio_1_2, target::waiting >::run(); } Type narrowing Explicit initialization
  • 91. 91 / 115 template< class unsupported, class dummy = void > struct pin_out_from { static_assert( sizeof( unsupported ) == 0, . . . ); }; pin_out_from< . . . > template template< class unsupported, class dummy = void > struct pin_out_from { static_assert( sizeof( unsupported ) == 0, . . . ); }; template< class pin > struct pin_out_from < pin, typename pin::has_pin_out > : public pin_out_archetype { static void init(){ pin::init(); } static void set( bool value ){ pin::set( value ); } }; template< class pin > struct pin_out_from < pin, typename pin::has_pin_oc > : public pin_out_archetype { static void init(){ pin::init(); } static void set( bool value ){ pin::set( value ); } }; template< class unsupported, class dummy = void > struct pin_out_from { static_assert( sizeof( unsupported ) == 0, . . . ); }; template< class pin > struct pin_out_from < pin, typename pin::has_pin_out > : public pin_out_archetype { static void init(){ pin::init(); } static void set( bool value ){ pin::set( value ); } }; template< class pin > struct pin_out_from < pin, typename pin::has_pin_oc > : public pin_out_archetype { static void init(){ pin::init(); } static void set( bool value ){ pin::set( value ); } }; template< class pin > struct pin_out_from < pin, typename pin::has_pin_in_out > : public pin_out_archetype { static void init(){ pin::init(); pin::direction_set_output(); } static void set( bool value ){ pin::set( value ); } };
  • 92. 92 / 115 Type narrowing class target { typedef . . . pin_a0; } typedef target::pin_a0 alarm; int main(){ alarm::init(); alarm::direction_set_output(); alarm::set( false ); if( . . . ){ alarm::set( true ); } } class target { typedef . . . pin_a0; } typedef pin_out_from< target::pin_a0 > alarm; int main(){ alarm::init(); alarm::direction_set_output(); alarm::set( false ); if( . . . ){ alarm::set( true ); } } ❑ The template parameter is type-checked ❑ The template adapts to the parameter type ❑ Initialization is ‘complete’ ❑ The code can’t accidentally use an inappropriate method
  • 93. 93 / 115 Don’t say it in a comment namespace target { typedef . . . pin_a0; } typedef target::pin_a0 alarm_led; int main(){ alarm_led::set( false ); if( . . . ){ alarm_led::set( true ); } } namespace target { typedef . . . pin_a0; } typedef invert< target::pin_a0 > alarm_led; int main(){ alarm_led::set( false ); if( . . . ){ alarm_led::set( true ); } } Say it in the code invert< . . . > decorator namespace target { typedef . . . pin_a0; } typedef target::pin_a0 alarm_led; // the alarm LED pin is active low const bool alarm_led_active = false; int main(){ alarm_led::set( ! alarm_led_active ); if( . . . ){ alarm_led::set( alarm_led_active ); } }
  • 94. 94 / 115 Pin invert< . . . > template< class unsupported, class dummy = void > struct invert { static_assert( sizeof( unsupported ) == 0, ". . ." ); }; template< class pin > struct invert< pin, typename pin::has_pin_in > : public pin_in_archetype { static void init(){ pin::init(); } static bool get(){ return ! pin::get(); } }; template< class pin > struct invert< pin, typename pin::has_pin_out > : public pin_out_archetype { static void init(){ pin::init(); } static void set( bool x ){ pin::set( ! x ); } }; template< class pin > struct invert< pin, typename pin::has_pin_in_out > : public pin_in_out_archetype { static void init(){ pin::init(); } static void direction_set_input(){ pin::direction_set_input(); } static void direction_set_output(){ pin::direction_set_output(); } static void set( bool x ){ pin::set( ! x ); } static bool get(){ return ! pin::get(); } }; template< class pin > struct invert< pin, typename pin::has_pin_oc > : public pin_oc_archetype { static void init(){ pin::init(); } static void set( bool x ){ pin::set( ! x ); } static bool get(){ return ! pin::get(); } }; Often: ZERO cost!
  • 95. 95 / 115 Some more pin & port decorators // create the stated pin or port type from p pin_in_from< p > pin_out_from< p > pin_in_out_from< p > pin_oc_from< p > port_in_from< p > port_out_from< p > port_in_out_from< p > port_oc_from< p > // create a port of the stated type from pins port_in_from_pins< p, ... > port_out_from_pins< p, ... > port_in_out_from_pins< p, ... > // invert the value read from or written to p invert< p > // pin or port that writes to all pins or ports all< p, ... >
  • 96. 96 / 115 Using static class templates: consequences ❑ Abstraction tool is the class template with only static contents (classes, methods, attributes) ❑ Composition is by template instantiation ❑ Method call syntax is class::method(…) instead of object.method(…) ❑ Header-only
  • 97. 97 / 115 Using static class templates: more consequences ❑ No objects (of such classes) are created ❑ No memory management, no dangling references ❑ Collections don’t contain unused elements ❑ Sharing of identical constructs is automatic ❑ No automatic construction: explicit init() calls ❑ Abstraction overhead can be zero
  • 98. 98 / 115 What does a programming language want?
  • 99. 99 / 115 “Give me just one generation of youth, and I'll transform the whole world.”
  • 100. 100 / 115 What motivates the next generation of programmers? • Websites : (that isn’t real programming) • Mobile : mostly Android, Java, Java-frameworks • Easy power : RaspberryPi, Python • (Micro Bit, Lego) : graphic programming • Cheap, low-energy, hardware interfacing : Arduino
  • 101. 101 / 115 The Arduino ecosystem • Hardware designs & webshop • Bootloaders • IDE with toolchain, libraries, download tools • Third-party libraries • ‘Counterfeit’ hardware • Web coverage
  • 102. 102 / 115 Official hardware designs - AVR Uno, Leonardo, 101, esplora, micro, nano, mini, mega, ethrente, lilypad
  • 103. 103 / 115 Official hardware designs - Cortex Zero, Due, M0, MKR Zero
  • 104. 104 / 115 Some other boards Blue Pill, ATTiny85, ESP8266, ESP32
  • 105. 105 / 115 Arduino software - Crappy IDE, but it works quite reliably - Some behind-the-scenes magic - Uses C++ compiler, but almost no C++ features - Lots of overlapping third-party libraries - Configuration is often by editing the library source (each LCD driver has its own graphics library) - And yet: tremendously popular!
  • 106. 106 / 115 Opportunities! - Lots of black magic & cargo-cult beliefs - Lots of duplicate efforts (overlapping libraries) - Lack of leverage (no component-based culture) A well-structured set of C++ libraries, books, websites, clubs, etc. could make these folks love C++ for their life!
  • 107. 107 / 115 Target audience? - Kids - Professional C++ programmers in their spare time - non-EE/CE professionals (artists!)
  • 108. 108 / 115 and don’t let them escape! Grab the next generation
  • 109. 109 / 115 Takaways - Embedded? Please be more specific! - The C++ is the language for (small-) embedded - but ’they’ don’t know that yet ☹ - and we don’t yet agree on how to use it - C++ libraries could be more embedded-friendly