You are on page 1of 398

Infotronik

Lecture
Script & Material
Author:
Erich Styger
erich.styger@hslu.ch
February 17, 2014
a
b
Revision History
Revision Date Author(s) Description
0.10 02-Jan-2011 ES Initial version with L
A
T
E
X.
0.20 10-Jan-2011 ES Added LSCs.
0.30 04-Feb-2011 ES Using problem solving sheets.
1.00 14-Feb-2011 ES Published rst parts on ILIAS for
SS11.
1.10 22-Aug-2011 ES Updates for new course, including
C++. Released for HS2011.
1.11 14-Sept-2011 ES Updated course schedule and sim-
plied LSC.
1.20 01-Feb-2012 ES Updated for INTRO in FS2012.
1.21 15-Feb-2012 ES Released for INTRO in FS2012.
1.30 21-Jun-2012 ES New recap questions from FS2012.
1.40 12-Sep-2012 ES Updated Events and Trigger chap-
ters for HS2012.
1.41 17-Sep-2012 ES Updated LSCs.
1.42 02-Oct-2012 ES Added LSC Nokia LCD.
1.50 11-Feb-2013 ES Version for FS2013.
1.60 15-Sep-2013 ES Version for HS2013.
1.61 21-Oct-2013 ES Replaced .eps images with tikz.
1.62 19-Dec-2013 ES Extended for next semester con-
tent.
1.70 09-Feb-2014 ES Version for INTRO FS2014.
Erich Styger (ES)
c
d
Contents
I Overview 1
1 Course Preconditions 3
1.1 Preconditions . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2 Course Information 7
2.1 Instructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3 Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.4 Required Entry Competencies . . . . . . . . . . . . . . . . . . 9
2.5 Exam Admission Conditions . . . . . . . . . . . . . . . . . . . 10
2.6 Exam and Grading Policy . . . . . . . . . . . . . . . . . . . . 11
2.7 Competencies . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.8 Course Philosophy . . . . . . . . . . . . . . . . . . . . . . . . 12
2.9 How To Reach A Good Grade . . . . . . . . . . . . . . . . . . 13
2.10 Course Material . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.11 Laboratory Organization . . . . . . . . . . . . . . . . . . . . . 14
3 Learning Goals 15
3.1 Systems and Realtime . . . . . . . . . . . . . . . . . . . . . . 15
3.2 LED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.3 Doxygen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.4 Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.5 Sequential State Machines . . . . . . . . . . . . . . . . . . . . 17
3.6 Embedded Systems and Drivers . . . . . . . . . . . . . . . . . 17
3.7 Clock and Timer . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.8 Synchronization and Interrupts . . . . . . . . . . . . . . . . . 18
3.9 C Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.10 Simple Events and Triggers . . . . . . . . . . . . . . . . . . . 20
3.11 Push Buttons . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.12 Low Power . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
i
INTRO V1.70
3.13 Sensor and Actuator, Quadrature, Motor and PID . . . . . . . 22
3.14 C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.15 IEEE802.15.4 and ZigBee . . . . . . . . . . . . . . . . . . . . 23
3.16 RTOS, FreeRTOS and Semaphores . . . . . . . . . . . . . . . 24
3.17 Processor Expert . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.18 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.19 LSC I/O Software Synchronization . . . . . . . . . . . . . . . 26
3.20 LSC Exploring Embedded C . . . . . . . . . . . . . . . . . . . 26
3.21 LSC Interrupts using C . . . . . . . . . . . . . . . . . . . . . . 27
3.22 LSC Multiple Interrupts . . . . . . . . . . . . . . . . . . . . . 28
3.23 LSC Bouncing Switch in C . . . . . . . . . . . . . . . . . . . . 28
3.24 LSC Computer Operating Properly . . . . . . . . . . . . . . . 28
3.25 LSC RS-232-C . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.26 LSC Analog Input Sampling . . . . . . . . . . . . . . . . . . . 29
3.27 Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
II Embedded Systems 37
4 Introduction 39
5 Project Structure 41
5.1 Header and Source Files . . . . . . . . . . . . . . . . . . . . . 41
5.2 Common Files . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.2.1 Copy Project . . . . . . . . . . . . . . . . . . . . . . . 42
5.2.2 Master-Slave Project . . . . . . . . . . . . . . . . . . . 44
5.2.3 Library Project . . . . . . . . . . . . . . . . . . . . . . 45
5.3 Referencing Files and Folders . . . . . . . . . . . . . . . . . . 46
6 Your First Day at INTRO 49
7 Requirements 51
7.1 System Requirements . . . . . . . . . . . . . . . . . . . . . . . 52
7.2 Non-Functional Requirements . . . . . . . . . . . . . . . . . . 53
7.3 System Decomposition . . . . . . . . . . . . . . . . . . . . . . 53
8 Systems 57
8.1 Transforming Systems . . . . . . . . . . . . . . . . . . . . . . 58
8.2 Reactive Systems . . . . . . . . . . . . . . . . . . . . . . . . . 59
8.3 Interactive Systems . . . . . . . . . . . . . . . . . . . . . . . . 59
8.4 Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
c Erich Styger ii
INTRO V1.70
9 Realtime 63
9.1 Reality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
9.2 Timeliness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
9.3 Correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
9.4 Realtime for Computer Systems . . . . . . . . . . . . . . . . . 65
9.5 Hard and Soft Realtime . . . . . . . . . . . . . . . . . . . . . 66
9.6 Periodic Realtime . . . . . . . . . . . . . . . . . . . . . . . . . 67
9.7 Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
10 Synchronization 71
10.1 I/O Devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
10.2 Realtime Synchronization . . . . . . . . . . . . . . . . . . . . 74
10.3 Gady Synchronization . . . . . . . . . . . . . . . . . . . . . . 76
10.4 Handshaking . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
10.5 Interrupt Synchronization . . . . . . . . . . . . . . . . . . . . 79
10.6 Sharing Code . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
10.7 Sharing Data . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
10.8 Disable and Enable Interrupts . . . . . . . . . . . . . . . . . . 84
10.9 Enter and Exit Critical Section . . . . . . . . . . . . . . . . . 86
10.10Priorities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
10.11Example Interrupt System . . . . . . . . . . . . . . . . . . . . 88
10.12Architectures . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
10.13Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
III Building Blocks 95
11 Introduction 97
12 ANSI-C 99
12.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
12.2 Static and Extern . . . . . . . . . . . . . . . . . . . . . . . . . 100
12.3 Storage Class . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
12.4 Declaration and Denition . . . . . . . . . . . . . . . . . . . . 101
12.5 Static and Extern for Functions . . . . . . . . . . . . . . . . . 101
12.6 Source and Header Files . . . . . . . . . . . . . . . . . . . . . 102
12.6.1 Textual Inclusion . . . . . . . . . . . . . . . . . . . . . 103
12.6.2 Recursive Includes . . . . . . . . . . . . . . . . . . . . 103
12.6.3 Guarding . . . . . . . . . . . . . . . . . . . . . . . . . 104
12.6.4 Self Containment . . . . . . . . . . . . . . . . . . . . . 105
12.6.5 Example . . . . . . . . . . . . . . . . . . . . . . . . . . 106
c Erich Styger iii
INTRO V1.70
12.7 Conguration with Macros . . . . . . . . . . . . . . . . . . . . 107
12.8 Macro Comments . . . . . . . . . . . . . . . . . . . . . . . . . 109
12.9 Macro Traps & Pitfalls . . . . . . . . . . . . . . . . . . . . . . 111
12.10String and Concatenation Directives . . . . . . . . . . . . . . 114
12.11Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
13 Position Encoder 117
13.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
13.2 Absolute Digital Angle Encoder . . . . . . . . . . . . . . . . . 117
13.3 Binary-Reected Gray Code . . . . . . . . . . . . . . . . . . . 118
13.4 Constructing n-Bit Gray Code . . . . . . . . . . . . . . . . . . 119
13.5 Converting Binary Code into Gray Code . . . . . . . . . . . . 121
13.6 Converting Gray Code into Binary Code . . . . . . . . . . . . 121
13.7 Gray Absolute Angle Encoder . . . . . . . . . . . . . . . . . . 121
13.8 Simple Regular Encoder . . . . . . . . . . . . . . . . . . . . . 122
13.9 Quadrature Encoder . . . . . . . . . . . . . . . . . . . . . . . 123
13.9.1 Quadrature Encoder Implementation . . . . . . . . . . 124
13.10Realtime Aspects . . . . . . . . . . . . . . . . . . . . . . . . . 125
13.11Quadrature Decoding . . . . . . . . . . . . . . . . . . . . . . . 126
13.11.1Error Correction . . . . . . . . . . . . . . . . . . . . . 128
13.12Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
13.13Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
14 ANSI-C++ 133
14.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
14.2 What is NOT Covered . . . . . . . . . . . . . . . . . . . . . . 133
14.3 From C to C++ . . . . . . . . . . . . . . . . . . . . . . . . . . 134
14.3.1 Enabling C++ Compilation . . . . . . . . . . . . . . . 134
14.3.2 Additional Keywords . . . . . . . . . . . . . . . . . . . 134
14.3.3 Comments . . . . . . . . . . . . . . . . . . . . . . . . . 135
14.3.4 Predened Macro cplusplus . . . . . . . . . . . . . . 136
14.3.5 Void Or No Parameters . . . . . . . . . . . . . . . . . 136
14.3.6 Return Values . . . . . . . . . . . . . . . . . . . . . . . 136
14.3.7 Implicit Parameter declaration . . . . . . . . . . . . . . 136
14.3.8 Enumerations . . . . . . . . . . . . . . . . . . . . . . . 137
14.3.9 Variable Declaration . . . . . . . . . . . . . . . . . . . 138
14.3.10Constants . . . . . . . . . . . . . . . . . . . . . . . . . 138
14.3.11Constant Object Linkage . . . . . . . . . . . . . . . . . 139
14.3.12New and Delete . . . . . . . . . . . . . . . . . . . . . . 139
14.3.13Namespace . . . . . . . . . . . . . . . . . . . . . . . . 140
14.3.14Mixing C and C++: C Linkage and Name Encoding . 141
c Erich Styger iv
INTRO V1.70
14.4 C++ Features . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
14.4.1 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Class and Struct . . . . . . . . . . . . . . . . . . . . . 144
Member Functions and this . . . . . . . . . . . . . . . 144
Inlining . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Base Class . . . . . . . . . . . . . . . . . . . . . . . . . 145
Static Members . . . . . . . . . . . . . . . . . . . . . . 146
14.4.2 Member Access Control . . . . . . . . . . . . . . . . . 147
Base Class Access Control . . . . . . . . . . . . . . . . 148
Friends . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
14.4.3 Special Member Functions . . . . . . . . . . . . . . . . 150
Constructors . . . . . . . . . . . . . . . . . . . . . . . 150
Destructors . . . . . . . . . . . . . . . . . . . . . . . . 151
Conversion by Constructor . . . . . . . . . . . . . . . . 151
Conversion Functions . . . . . . . . . . . . . . . . . . . 152
Compiler Generated Functions . . . . . . . . . . . . . . 152
14.4.4 Overloading . . . . . . . . . . . . . . . . . . . . . . . . 152
Function Overloading . . . . . . . . . . . . . . . . . . . 152
Operator Overloading . . . . . . . . . . . . . . . . . . 153
Default Arguments . . . . . . . . . . . . . . . . . . . . 153
Operator new and delete . . . . . . . . . . . . . . . . . 153
Compiler Generated Functions . . . . . . . . . . . . . . 156
14.5 The C++ Slider Widget . . . . . . . . . . . . . . . . . . . . . 156
14.5.1 The Problem . . . . . . . . . . . . . . . . . . . . . . . 156
14.5.2 Requirements . . . . . . . . . . . . . . . . . . . . . . . 157
14.5.3 Touchscreen Library . . . . . . . . . . . . . . . . . . . 158
14.5.4 External Interface . . . . . . . . . . . . . . . . . . . . . 158
14.5.5 Design . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
14.5.6 RangeValue: Data Member . . . . . . . . . . . . . . . 161
14.5.7 RangeValue: Methods . . . . . . . . . . . . . . . . . . 161
14.5.8 Default Constructor . . . . . . . . . . . . . . . . . . . 162
14.5.9 Initialization and Assignment . . . . . . . . . . . . . . 163
14.5.10Constructor Initialization List . . . . . . . . . . . . . . 164
14.5.11Inlining . . . . . . . . . . . . . . . . . . . . . . . . . . 164
14.5.12Widget Class . . . . . . . . . . . . . . . . . . . . . . . 165
14.5.13SliderWidget Class . . . . . . . . . . . . . . . . . . . . 166
14.5.14Operator Overloading . . . . . . . . . . . . . . . . . . 167
14.5.15Operator ++ and - - . . . . . . . . . . . . . . . . . . . 167
14.5.16Prex ++ . . . . . . . . . . . . . . . . . . . . . . . . . 168
14.5.17Postx ++ . . . . . . . . . . . . . . . . . . . . . . . . 168
14.5.18Global Object Initialization . . . . . . . . . . . . . . . 168
c Erich Styger v
INTRO V1.70
14.6 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
14.7 Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
15 LED 173
15.1 Limiting Current . . . . . . . . . . . . . . . . . . . . . . . . . 173
15.2 Digital I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
15.3 LED Driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
15.4 One or Multiple . . . . . . . . . . . . . . . . . . . . . . . . . . 179
15.5 Eciency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
15.6 Driver Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . 181
15.7 Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
16 State Machines 183
16.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
16.2 Conventional Implementation . . . . . . . . . . . . . . . . . . 184
16.3 Switch Implementation . . . . . . . . . . . . . . . . . . . . . . 185
16.4 Table Implementation . . . . . . . . . . . . . . . . . . . . . . 186
17 Events 189
17.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
17.2 Room Temperature Unit . . . . . . . . . . . . . . . . . . . . . 189
17.3 Event System . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
17.4 Event Handle . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
17.5 Event Methods . . . . . . . . . . . . . . . . . . . . . . . . . . 194
17.6 Event Data Structure . . . . . . . . . . . . . . . . . . . . . . . 195
17.7 Reentrancy . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
17.7.1 Disable and Enable Interrupts . . . . . . . . . . . . . . 197
17.7.2 EnterCritical and ExitCritical . . . . . . . . . . . . . . 198
17.7.3 Semaphores . . . . . . . . . . . . . . . . . . . . . . . . 198
17.7.4 Implementation with Enter/ExitCritical . . . . . . . . 198
17.8 Event Processing . . . . . . . . . . . . . . . . . . . . . . . . . 199
17.9 Integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
18 Triggers 203
18.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
18.2 Blinking LED . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
18.3 Design Idea . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
18.4 Tick Timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
18.5 Trigger Interface . . . . . . . . . . . . . . . . . . . . . . . . . 206
18.6 Trigger Descriptor . . . . . . . . . . . . . . . . . . . . . . . . . 207
18.7 Data Allocation . . . . . . . . . . . . . . . . . . . . . . . . . . 208
c Erich Styger vi
INTRO V1.70
18.8 SetTrigger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
18.9 IncTicks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
18.10Making it reentrant . . . . . . . . . . . . . . . . . . . . . . . . 213
18.11Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
18.12Blink! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
18.13Beep! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
18.14Realtime Aspects . . . . . . . . . . . . . . . . . . . . . . . . . 217
19 Doxygen 219
19.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
19.2 Learning Goals . . . . . . . . . . . . . . . . . . . . . . . . . . 219
19.3 Doxygen, Graphvic and Eclox . . . . . . . . . . . . . . . . . . 219
19.4 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
19.5 Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
IV Laboratory Short Courses 225
20 Introduction 227
20.1 Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
20.2 Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
21 Exploring Embedded C 229
21.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
21.2 Learning Objectives . . . . . . . . . . . . . . . . . . . . . . . . 229
21.3 Success Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . 229
21.4 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
21.5 Comparison of Embedded and Desktop C Programs . . . . . . 230
21.6 The Outline of an Embedded C Program . . . . . . . . . . . . 231
21.7 Initializing Variables . . . . . . . . . . . . . . . . . . . . . . . 232
21.8 Minimal Startup . . . . . . . . . . . . . . . . . . . . . . . . . 233
21.9 Plain Char . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
21.10Volatile Variables . . . . . . . . . . . . . . . . . . . . . . . . . 234
21.11Using Individual Bits in a Memory Location . . . . . . . . . . 235
21.12ANSI-C Extensions . . . . . . . . . . . . . . . . . . . . . . . . 236
21.13Accessing I/O Registers . . . . . . . . . . . . . . . . . . . . . 237
21.14CodeWarrior I/O Port and Bit Addressing . . . . . . . . . . . 237
21.15Using Interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . 238
21.16Connecting a C Program to an Assembly Language Program . 239
21.17Problem: const variables . . . . . . . . . . . . . . . . . . . . . 239
21.18Reection on Learning . . . . . . . . . . . . . . . . . . . . . . 240
c Erich Styger vii
INTRO V1.70
21.19Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
21.20Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
22 Bouncing Switch 245
22.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
22.2 Learning Objectives . . . . . . . . . . . . . . . . . . . . . . . . 245
22.3 Success Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . 245
22.4 More Resources and Further Information . . . . . . . . . . . . 245
22.5 A Guide to Debouncing . . . . . . . . . . . . . . . . . . . . . 246
22.6 Explore 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
22.7 Problem: Software Switch Debouncing Using a Delay . . . . . 247
22.8 Stimulate 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
22.9 Switch Debouncing Using an Counting Debouncer . . . . . . . 248
22.10Explore 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
22.11Problem 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
22.12Communication - Inter-Group . . . . . . . . . . . . . . . . . . 249
22.13Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
22.14Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
23 I/O Software Synchronization 251
23.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
23.2 Learning Objectives . . . . . . . . . . . . . . . . . . . . . . . . 251
23.3 Success Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . 251
23.4 More Resources and Further Information . . . . . . . . . . . . 252
23.5 I/O Software Synchronization . . . . . . . . . . . . . . . . . . 252
23.6 Polling I/O Devices . . . . . . . . . . . . . . . . . . . . . . . . 252
23.7 Stimulate 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
23.8 Handshaking I/O Devices . . . . . . . . . . . . . . . . . . . . 253
23.9 Input Handshaking . . . . . . . . . . . . . . . . . . . . . . . . 254
23.10Output Handshaking . . . . . . . . . . . . . . . . . . . . . . . 254
23.11Explore 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
23.12Stimulate 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
23.13Problem 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
23.14Handshaking Implementation . . . . . . . . . . . . . . . . . . 256
23.15Reection on Learning . . . . . . . . . . . . . . . . . . . . . . 256
23.16Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
23.17Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
24 Serial I/O Interfaces - RS-232-C 259
24.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
24.2 Learning Objectives . . . . . . . . . . . . . . . . . . . . . . . . 259
c Erich Styger viii
INTRO V1.70
24.3 Success Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . 259
24.4 The Electrical Interface . . . . . . . . . . . . . . . . . . . . . . 259
24.5 Explore 1: Noise Margin . . . . . . . . . . . . . . . . . . . . . 261
24.6 RS-232-C Logic Levels . . . . . . . . . . . . . . . . . . . . . . 261
24.7 Voltage Translation . . . . . . . . . . . . . . . . . . . . . . . . 261
24.8 Explore 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
24.9 RS-232-C Device Types . . . . . . . . . . . . . . . . . . . . . 262
24.10Stimulate 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
24.11RS-232-C Cables and Connectors . . . . . . . . . . . . . . . . 262
24.12Handshaking for Flow Control . . . . . . . . . . . . . . . . . . 264
24.13Stimulate 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
24.14What Kind of Device do You have? . . . . . . . . . . . . . . . 267
24.15Stimulate 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
24.16Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
24.17Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
25 Interrupts using C 273
25.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
25.2 Learning Objectives . . . . . . . . . . . . . . . . . . . . . . . . 273
25.3 Success Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . 273
25.4 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
25.5 More Resources and Further Information . . . . . . . . . . . . 274
25.6 Stimulate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
25.7 Interrupt Jargon . . . . . . . . . . . . . . . . . . . . . . . . . 274
25.8 Explore 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
25.9 Interrupt System . . . . . . . . . . . . . . . . . . . . . . . . . 276
25.10Interrupt Sources . . . . . . . . . . . . . . . . . . . . . . . . . 277
25.11Explore 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
25.12The Interrupt Sequence . . . . . . . . . . . . . . . . . . . . . . 278
25.13Stimulate 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
25.14Interrupt Software . . . . . . . . . . . . . . . . . . . . . . . . 279
25.15Explore 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
25.16The C Compiler Interrupt Interface . . . . . . . . . . . . . . . 280
25.17Explore 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
25.18Problem 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
25.19Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
25.20Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
c Erich Styger ix
INTRO V1.70
26 Multiple Interrupts 285
26.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
26.2 Learning Objectives . . . . . . . . . . . . . . . . . . . . . . . . 285
26.3 Success Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . 285
26.4 More Resources and Further Information . . . . . . . . . . . . 286
26.5 Stimulate 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
26.6 Interrupt System Jargon Review . . . . . . . . . . . . . . . . . 286
26.7 Explore 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
26.8 Interrupt System . . . . . . . . . . . . . . . . . . . . . . . . . 289
26.9 Interrupt Software for Multiple Interrupts . . . . . . . . . . . 290
26.10Stimulate 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
26.11Interrupt Device Priorities - Hardware . . . . . . . . . . . . . 292
26.12Interrupt Device Priorities - Software . . . . . . . . . . . . . . 292
26.13Explore 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
26.14Stimulate 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
26.15Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
26.16Communication - Inter-Group . . . . . . . . . . . . . . . . . . 294
26.17Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
26.18Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
27 Analog Input Sampling 299
27.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
27.2 Learning Objectives . . . . . . . . . . . . . . . . . . . . . . . . 299
27.3 Success Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . 299
27.4 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
27.5 AD Information . . . . . . . . . . . . . . . . . . . . . . . . . . 300
27.6 Analog-to-Digital Denitions . . . . . . . . . . . . . . . . . . . 301
27.7 Explore 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
27.8 Stimulate 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
27.9 Explore 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
27.10Stimulate 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
27.11Sampling Criteria and Nyquist . . . . . . . . . . . . . . . . . . 304
27.12Stimulate 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
27.13Dynamic Range . . . . . . . . . . . . . . . . . . . . . . . . . . 304
27.14Stimulate 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
27.15Aperture Time . . . . . . . . . . . . . . . . . . . . . . . . . . 305
27.16Stimulate 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
27.17Explore 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
27.18A/D Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
27.19Quantization Noise . . . . . . . . . . . . . . . . . . . . . . . . 308
27.20Putting it All Together - the A/D System . . . . . . . . . . . 308
c Erich Styger x
INTRO V1.70
27.21Choosing the A/D . . . . . . . . . . . . . . . . . . . . . . . . 309
27.22Stimulate 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
27.23Sample-and-Hold Aperture Time . . . . . . . . . . . . . . . . 311
27.24Stimulate 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
27.25Designing the Signal Conditional Conditioning Electronics . . 312
27.26Stimulate 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
27.27Skill Exercise . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
27.28Communication - Inter-Group . . . . . . . . . . . . . . . . . . 314
27.29Reection on Learning . . . . . . . . . . . . . . . . . . . . . . 314
27.30Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
28 Computer Operating Properly 315
28.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
28.2 Learning Objectives . . . . . . . . . . . . . . . . . . . . . . . . 315
28.3 Success Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . 315
28.4 More Resources and Further Information . . . . . . . . . . . . 316
28.5 Ganssle: Great Watchdogs . . . . . . . . . . . . . . . . . . . . 316
28.6 Explore 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
28.7 Basics of the COP in Microcontrollers . . . . . . . . . . . . . . 316
28.8 Explore 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
28.9 The COP Reset Vector . . . . . . . . . . . . . . . . . . . . . . 319
28.10Problem 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
28.11Problem 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
28.12Communication - Inter-Group . . . . . . . . . . . . . . . . . . 320
28.13Reection on Learning . . . . . . . . . . . . . . . . . . . . . . 320
28.14Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
29 Nokia LCD 321
29.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
29.2 Learning Objectives . . . . . . . . . . . . . . . . . . . . . . . . 322
29.3 Success Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . 322
29.4 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
29.5 More Resources and Further Information . . . . . . . . . . . . 323
29.6 Explore: First Steps . . . . . . . . . . . . . . . . . . . . . . . 323
29.7 Stimulate: Research . . . . . . . . . . . . . . . . . . . . . . . . 324
29.8 Explore PDC8544 Component . . . . . . . . . . . . . . . . . . 326
29.9 Stimulate: Implementation Details . . . . . . . . . . . . . . . 328
29.10Display Memory . . . . . . . . . . . . . . . . . . . . . . . . . . 328
29.11Explore: GDisplay . . . . . . . . . . . . . . . . . . . . . . . . 332
29.12Explore: Software Architecture . . . . . . . . . . . . . . . . . 332
29.13Stimulate: Drawing Primitives . . . . . . . . . . . . . . . . . . 334
c Erich Styger xi
INTRO V1.70
29.14Explore: Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . 335
29.15Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
29.16Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
29.17Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
V Appendix 339
Glossary 341
Acronyms 343
Symbols 345
Index 347
Bibliography 351
Afterword 355
VI Problems 357
Problems 359
c Erich Styger xii
Course Starting Poll
Name:
1. List your personal motivation for this course:
2. List your personal goals for this course:
3. List the things you will do to make this course a success for you:
xiii
INTRO V1.70
c Erich Styger xiv
Preface
For the things we have to learn
before we can do, we learn by
doing.(Aristotle, 384-322 BC)[1]
Welcome to the world of Infotronik
1
! Infotronik is is about advanced
microcontroller programming. It is about building and programming em-
bedded systems. It is about learning something you can use in your own
projects, either your own projects or the projects you are working on in your
profession.
The target audience for this book are both electrical engineers as well
software engineers.
This document is the script to the Infotronik lecture at the Lucerne Uni-
versity of Applied Sciences and Arts
2
, Switzerland. The script does not re-
place the the lecture, it only augments it. It shall help the students on their
learning journey. Crucial to the learning content in Infotronik (INTRO) does
not replace any of the material or lab work within the Infotronik lecture, and
cannot be considered as complete. This document shall help the students to
understand the material using a dierent form (written book) plus can be
used as an additional reference.
1
Infotronik is a word combination of Informatik (Computer Science) and Electron-
ics. The word is reecting the topic of this book and lecture script: the combination of
Embedded Software and Electronics.
2
http://www.hslu.ch
xv
INTRO V1.70
c Erich Styger xvi
Part I
Overview
1
Chapter 1
Course Preconditions
1.1 Preconditions
It is assumed that the reader has knowledge in electrical and software engi-
neering. As such it is expected that you have completed the MC
1
course.
You should be familiar with following topics:
You have used an Eclipse based Integrated Development Environment
(IDE) like CodeWarrior for Microcontrollers
2
You should be familiar with the basics of the ANSI-C
3
language. You
are able to write small examples in C and to understand C sources.
You master the basic data types (char, int, long, oat, double, ...)
with if-else, do-while and switch constructs. You can use pointers,
structs, enumerations, denes and bit masking operations.
You should know and be able to apply basic concepts of Object Ori-
ented Programming (OOP): class, method, inheritance.
You should be able to read and understand assembly code produced by
the compiler.
You know basic hardware: DC/AC, active devices, fundamentals of
power supplies and how to use a scope, pin numbering and reading
schematics, Electrostatic Discharge (ESD) precaution. See Chapter
1: Basic Electronics[4]
You should be able to use a Logic Analyzer and/or an Oscilloscope.
1
Microcontroller course at Lucerne University of Applied Sciences and Arts (HSLU)
2
http://www.freescale.com/cwmcu10
3
In this book the short form of C is used instead of ANSI-C
3
INTRO V1.70
You should be familiar with dierent number representations (decimal,
binary, hex), combinatorial logic (NOT, AND, NAND, etc.), truth ta-
bles and how this applies to sequential logic. See Chapter 2: Logic
Circuits[4]
You understand basic microcontroller architectures: memory, Read-
only memory (FLASH), Random Access Memory (RAM), Central Pro-
cessing Unit (CPU) registers, peripherals, Serial Peripheral Interface
(SPI), Inter-Inter Circuit (I
2
C), Bit Input and Output (I/O).
You can read and understand technical English texts, and are able to
write short texts and give short presentations in English.
c Erich Styger 4
INTRO V1.70
1.2 Problems
1.1. What are the decimal values for following hexadecimal numbers: 0x04,
0x07, 0x12, 0x?
1.2. What is the decimal value for following binary numbers: 0b0001,
0b0010, 0b1000, 0b1011?
1.3. Write following decimal numbers as 16bit hexadecimal numbers: 10,
11, 16, 28, 4096?
1.4. Determine the value of register A for following code sequence: asm
LDAA #5; asm STAA i; asm INCA; asm MULA i;
1.5. Write in C a function for the HCS08 microcontroller which takes two
16bit signed arguments and returns the sum of the two arguments.
1.6. Write in C code a single statement which only sets bit number 0 in
PORTA and let the other bits untouched (bit number 0 is the least
signicant bit).
1.7. Write in C code a single statement which only clears bit number 3 in
PORTA and let the other bits untouched (bit number 0 is the least
signicant bit).
1.8. Write in C code a single statement which changes bit number 5 in
PORTA and let the other bits untouched (bit number 0 is the least
signicant bit), in following way: if the bit is already set, it shall be
cleared; if the bit is already cleared, then it should be set.
1.9. Given a variable named i of type uint16 t (unsigned integral type,
16bit). What is the value of the variable i after execution of following
statements: i = 10; i /= 4;?
1.10. Given a variable named j of type uint8 t (unsigned integral type, 8bit).
What is the value of the variable j after execution of following state-
ments: j = 21; j %= 4;?
1.11. Given an array named A of base type uint8 t (unsigned integral type,
8bit). The array is initialized as follows: uint8 t A[2][3] = {1,2,3,4,5,6};
Which value will A[1][1] return?
1.12. Given X as 0x00EFC000. What is Y in hex for: Y = ((X >>16) &
0xFF) - 5;
c Erich Styger 5
INTRO V1.70
c Erich Styger 6
Chapter 2
Course Information
2.1 Instructor
Instructor: Prof. Erich Styger, MSc CS ETH Zurich
Email: erich.styger@hslu.ch
Oce: D311 (campus Horw, building 3, level D)
Oce Phone: +41 (41) 349 3301
Oce Hours: By drop-in or arrangement
2.2 Description
A course emphasizing applications for microcomputers and microcontrollers
to dedicated hardware functions. Handling of system architecture aspects
with focus on realtime driver and application development. A high-level
language is used, and emphasis is placed on the use of programming pe-
ripherals. Usage of open source development tools and software (Eclipse
1
,
doxygen
2
, GIT
3
, FreeRTOS
4
) is included.
2.3 Objectives
At the conclusion of this course, the successful (passing) student will be able
to demonstrate:
1
www.eclipse.org
2
www.doxygen.org
3
www.gitscm.com
4
www.freertos.org
7
INTRO V1.70
Problem solving in the context of advanced embedded systems with the
focus on software architecture and interfacing hardware with software.
Application development with ANSI-C and C++ programs emphasiz-
ing I/O and peripherals together with application aspects.
Designing and partitioning a system into software modules and oper-
ating system tasks.
Advanced ANSI-C programming techniques with preprocessing and
macro processing, enumerations and typedefs, function pointers and
advanced data structures.
Basic object oriented programming techniques in C++ for Embedded,
including the concepts of inheritance, operator and function overload-
ing, members and access control, member functions, constructor and
destructor.
Application design with drivers, hardware abstraction, middleware and
application parts.
Developing, evolving and maintaining an application congurable for
dierent CPU architectures (8, 16 and 32bit systems) with dierent
features sets, with focus on re-usability, scalability and maintainability.
Using an eclipse based IDE with editor, build tools, auto-code gen-
eration and conguration, documentation system and version system,
with the creation of Application Programming Interface (API) docu-
mentation using doxygen and dot.
Developing shared software in teams using a Version Control System
(VCS).
Using the concepts of VCS: commit, checkout, tag, branch, di, merge,
conicts, both with clients, plugins and shell extensions.
Programming techniques with interfaces and modularization.
Embedded Driver and application design with focus on footprint, per-
formance and reentrancy.
Usage of an micro kernel RTOS with timer ticks, software interrupts,
tasks, semaphore, mutex, queues, priorities and scheduling.
c Erich Styger 8
INTRO V1.70
Interprocess and inter-processor communication techniques, both wire-
less and wired.
Working with code generation of embedded components using proper-
ties, methods and events.
Implementation of position Gray Code encoders including error correc-
tion.
Implementing closed loop control with hard real time aspects to use
multiple sensor input to control a DC motor.
Implementing dierent ways to interact with users and implementing
interfaces, including LED, keyboard, buzzer, accelerometer and com-
mand line shell.
Using dierent techniques to implement nite state machines using
tables, switch functions or functions.
Implementation of event bit arrays and timer controlled triggers.
Applying multiple synchronization methods: realtime, gady and in-
terrupt.
Writing re-usable and robust drivers for LED, switches (including de-
bouncing), accelerometer sensors, serial shell, DC motor with H-Bridge.
Applying low power and low energy concepts and techniques for an
embedded hardware and software project.
Using advanced debugging techniques with breakpoints, watchpoints,
trace and data inspection for problem solving.
A reasonable degree of uency in the language of advanced microproces-
sors. In other words, the student will be able to communicate eectively
and comfortably with engineers and technologists whose expertise is in
the microprocessor area of electrical engineering technology and soft-
ware and computer science technology.
2.4 Required Entry Competencies
Operating system basics, basic C programming knowledge, microcontroller
hardware and software basics, microcontroller low level programming basics.
c Erich Styger 9
INTRO V1.70
Reading/writing and speaking of English in a software and electrical engi-
neering environment. Has passed the MC
5
module, or an equivalent one.
Practical application of learning topics acquired in the MC module: inter-
rupts, clock, timer, A/D conversion, I
2
C, Serial Communication Interface
(SCI).
2.5 Exam Admission Conditions
1. Recap: A synopsis/presentation of a previous week learning unit.
The idea is that students provide peers a way to refresh what they
have learned. Depending on the class size, up to two recap sessions are
possible (register your time slot). In case of two recaps, the students
coordinate themselves the content to avoid duplication.
What: Short recap sequence, 3-5 minutes, to repeat things learned
When: At the beginning of a new lecture
Material: You are free using any material (black/white board,
projector, ...)
Topic: What did you learn? What was the most useful thing you
have learned?
Topic: What was maybe not so clear, and how have you solved
the problem?
Quiz: Submit at least 5 quiz questions in writing. Look at the
Problems question in this book. Your quiz questions will help
your peers in the next revision of this book.
2. Wireless Motor Controller: Functional demonstration of the em-
bedded realtime application developed during the course. Acceptance
criteria is a functional demonstration of the software and hardware to
your instructor. You need to explain the system architecture and be
able to answer questions to all the hardware and software components
used.
3. Tips for next students: A written summary of tips for students
taking the next course
c Erich Styger 10
INTRO V1.70
Points Grade
220-240 A
201-219 B
182-200 C
162-181 D
144-161 E
0-143 F
Table 2.1: Grades
2.6 Exam and Grading Policy
Grading will be done with a comprehensive nal exam in writing at the end
of the semester during the normal exam period. The exam will last for four
hours and you can earn up to 240 points (with the possibility of additional
bonus points). The exam will consist of a combination of multiple choice,
problem solving, coding and general questions. The grading scale is as in
table 2.1. The will be in two parts (total of 4 hours):
Part A: 1 hour: without any material at all.
Part B: 3 hours: the only allowed material is a self-written (by hand or
with a computer) summary (maximum of 16 A4 pages (or 8 A4 sheets)
of paper.
Bring your own writing material to the exam. Paper will be provided. No
electronic devices with communication capabilities will be allowed (normal
pocket calculator is allowed).
2.7 Competencies
Operational learning goals concerning:
Professional Competencies
Knowing multiple tools, software stacks and algorithms they could
use for their own designs.
Being familiar with various synchronization methods and can ap-
ply them properly for a given problem.
5
MC: Microcontroller
c Erich Styger 11
INTRO V1.70
Knowing dierent sensors and actors typical for embedded appli-
cations and are able to integrate them into a system.
Methodological Competencies
Implementing and maintaining a complex embedded system step
by step in an engineering fashion.
Ability to deal with multiple parallel hardware and software con-
gurations, in a rapid changing environment.
Ability to deal with tight hard real time aspects, with and without
the usage of a real time operating system (Realtime Operating
System (RTOS)).
Ability to research and apply technical articles in the domain of
embedded systems.
Personal Competencies (Social Competencies)
Using team work for problem solving.
Ability to identify their own knowledge gaps and ll it with addi-
tional self studies.
2.8 Course Philosophy
It is the responsibility of the instructor to provide well-planned and
thought-out lectures and laboratory exercises to assist in the assimi-
lated course material.
It is the responsibility of the instructor to be reasonably available to
provide assistance to the class members.
It is the responsibility of the student to dig out relevant material as
needed to assist in the assimilation of course material. Not all necessary
material will be presented during the class.
It is the responsibility of the student to come to the class with the
knowledge from all relevant previous courses. Reviews are the students
job.
It is the responsibility of the student to be familiar with the contents
of the course syllabus and to monitor their own progress.
c Erich Styger 12
INTRO V1.70
2.9 How To Reach A Good Grade
In order to reach a good grade, consider following important points:
The lecture material is not the most dicult part of the course.
The slides and the script are not complete. You wont receive every
little details, so you need to collect and extend things on your own.
Try to understand things as they are handled during the course. Things
are building up on previous topics, so catch up.
You have to understand the material well enough to apply it in new
situations.
Ask questions if something is not clear.
Dont fall behind.
The lab work and exercises are critical to understand the material and
are integral part of the course.
Increase complexity to your project step by step. Make sure your design
is always functional. Make backups.
Course material is made available online. Be prepared and familiarize
yourself with the material before the lecture.
A selected number of chapters from the The Firmware Handbook
[4] are part of the course material.
A selected number of chapters from the Embedded Systems, World
Class Designs [7] are part of the course material.
Always search and look up additional information. There is plenty of
material available (campus library, online papers and articles, ...).
2.10 Course Material
Course material (handouts, data sheets, ...) are made available online on
ILIAS
6
and from the VCS. The VCS repository is used to share source and
project les. It is expected that students bring their own host development
machine (Windows operating system preferred). Following software is used
6
ILIAS is an e-learning platform and repository used at HSLU
c Erich Styger 13
INTRO V1.70
and available for Windows platform on ILIAS, but can be downloaded as
well given the links mentioned below for other supported platforms:
CodeWarrior for MCU 10.x
7
is an eclipse
8
based development sys-
tem to develop embedded software
Doxygen
9
is an open source compiler which can generate documenta-
tion from source code (e.g. C or C++).
Eclox
10
is an open source eclipse plugin
11
for doxygen and provides a
front end and user interface to create documentation from source code.
FreeRTOS
12
is an open source realtime operating system.
Git
13
is an open source distributed version control system.
Hardware is provided during the course as part of the lab material. The
material has to be returned at the end of course. Please treat the electronic
parts with care (e.g. discharge yourself rst before touching any electronics).
2.11 Laboratory Organization
The administration and faculty are concerned about the Safety of each stu-
dent in the labs. Each student is required to read the safety information
posted in the labs and comply. Universal policies include:
1. No food or drink allowed in the labs
2. Report immediately broken equipment to the lab supervisor
3. Do not remove equipment from the lab. It is possible to work with the
INTRO hardware platform outside the lab
4. Students are expected to clean up their stations before leaving the lab
7
http://www.freescale.com/cwmcu10
8
http://www.eclipse.org
9
http://www.doxygen.org
10
http://home.gna.org/eclox
11
eclipse plugin from http://download.gna.org/eclox/update
12
http://www.freertos.org
13
http://gitscm.com/
c Erich Styger 14
Chapter 3
Learning Goals
The following sections give an overview about the learning goals and topics.
Keep in mind that this is not a fully comprehensive and complete list! Ad-
ditionally learning topics and questions are provided with the les provided
for the lab sessions.
Students will be able to understand or to apply the following:
3.1 Systems and Realtime
1. Are able to describe and characterize transforming, reactive and in-
teractive systems. Can give examples and can classify a typical real
system.
2. Do know the typical characteristics of transforming, reactive and inter-
active systems and can quantify it.
3. Are aware of the realtime aspects of embedded systems and can discuss
the dierences between hard and soft realtime systems.
4. Are able to evaluate and comment on a system in respect of its realtime
capabilities.
5. Can quantify the needed reaction time of realtime systems and can
name typical examples.
6. Can successfully identify, explain and apply cafeterias for a real time
system.
15
INTRO V1.70
3.2 LED
1. Are able to use an LED successfully in an embedded design.
2. Can calculate the needed resistor for an LED based on the LED data
sheet.
3. Can implement an ecient LED driver for a microcontroller in C.
4. Are able to discuss and evaluate the dierent pros and cons of passing
parameters to methods/functions in C.
5. Are able to use bit operations and mask operations in C to access
individual bits on the hardware.
6. Know the impact of dierent basic language types and sizes on the
application performance.
7. Are able to implement a blinking LED with dierent methods of im-
plementation.
8. Are able to use typical input/output ports using Processor Expert and
C
3.3 Doxygen
1. Are able to document source code using doxygen and Eclipse.
2. Can document variables, types, functions, parameters with doxygen
and to produce HTML documentation.
3. Is using doxygen and dot can create directed graphs to enrich the
project documentation.
4. Are able to include images into the generated documentation.
5. Are able to maintain to-do lists using doxygen.
6. Are able to read doxygen information in source code and are able to
extend it.
c Erich Styger 16
INTRO V1.70
3.4 Shell
1. Are able to use a serial/RS-232/USB CDC connection for an interactive
command line user interface.
2. Understand the impact and implication of using interrupt synchroniza-
tion for an SCI/RS-232 connection.
3. Can successfully use string routines as strcmp(), strncmp(), strcat()
and .
4. Apply the concept of pointer to pointer.
5. Can apply techniques to avoid buer overow in the context of string
routines.
6. Ability to use the sizeof() macro successfully.
7. Can redirect input/output stream and can explain the concepts behind
it.
8. Is able to use a host Virtual COM port to be used for a communication
with a microcontroller.
3.5 Sequential State Machines
1. Understands and can apply the concept of State Machines.
2. Is able to use dierent state machine design patterns: functional, hier-
archical and if-elsif-else state machines.
3. Can implement a table driven FSM like the Mealy Sequential State
Machines.
4. Are able to draw a Mealy Sequential State Machine with a dot doxygen
graph.
3.6 Embedded Systems and Drivers
1. Are able to create and understand block diagrams for embedded sys-
tems.
2. Can master the usage of macros in C, both macros with and without
arguments.
c Erich Styger 17
INTRO V1.70
3. Can use macros for software conguration.
4. Are able to identify interfaces for typical cases like serial or bit I/O,
design it and implement it.
5. Can create a driver with all the needed parts like initialization, syn-
chronization and implementation.
6. Knows the reasons and meanings of volatile and const.
7. Are able to specify and dene the layers of a software model.
8. Can eectively nd errors and bugs in realtime systems.
3.7 Clock and Timer
1. Are able to evaluate processor clock settings and their impact on the
rest of the system.
2. Can discuss the pros and cons of internal vs. external clock sources for
a microcontroller.
3. Do understand the general principle of pre-scalers in a clock distribution
system.
4. Are able to congure clock and timers with the help of Processor Ex-
pert.
3.8 Synchronization and Interrupts
1. Can identify the fundamental dierences between the real world and
the computer world.
2. Can explain why a synchronization is required and can give real life
examples.
3. Know the dierence between realtime, gady and interrupt syn-
chronization methods, can explain them, compare them and apply
them.
4. Are able to identify typical synchronization methods for typical hard-
ware devices and can implement it.
5. Do know the principle of interrupts and how they are executed.
c Erich Styger 18
INTRO V1.70
6. Understand the principles of interrupt program and main program
7. Are able to discuss the problematic of shared data and shared program
code in the context of interrupt programs and main program.
8. Are able to identify and explain design criteria for interrupt programs
and can apply them.
9. Know the criteria for reentrancy and are able to implement applications
and application parts in an reentrant way.
10. Are able to identify reentrancy problems and can isolate them.
11. Are able to use implementation techniques to have application code
reentrant.
12. Understand the principles of priorities, main priorities and sub-
priorities.
13. Are able based on interruption rules to draw a system execution dia-
gram and to determine the execution time.
14. Are aware of architectural dierences in actual controller implementa-
tion in the domain of interrupts.
15. Know the problem of race conditions and are able to explain the prob-
lem with an example.
3.9 C Macros
1. Understand the principles how a compiler handles macros in the C
programming language
2. Know ways and strategies to isolate and solve problems cause by macros
in the source code.
3. Is able to use symbol concatenation and string concatenation prepro-
cessor tokens.
4. Are able to evaluate and discuss the pros and cons of macro usage in
application code.
5. Know traps and pitfalls around macros and have solutions and strate-
gies to avoid them.
c Erich Styger 19
INTRO V1.70
6. Use macros as ecient implementation method eectively.
7. Can use macros in order to congure the behavior of software.
3.10 Simple Events and Triggers
1. Are able to distribute application load between interrupt program and
main program.
2. Are able to implement dierent ecient data structures, and can justify
and explain the reasoning behind the design decisions.
3. Are able to use data types and structures which allow easy extendability
and and implementation.
4. Are able to use callbacks and functions pointers for their design and
implementation.
5. Are taken care of reentrancy in their design and implementation.
6. Can use typedefs to encapsulate data types for later enhancements
without the need to change the interface les.
7. Can explain the concept of critical sections.
8. Can implement and explain dierent methods to ensure critical sec-
tions, and can list the advantages and disadvantages.
9. Can use callbacks and function pointers to allow a exible software
implementation.
10. Can balance an implementation between memory needs and speed. Are
using appropriate bit techniques to set/clear/handle bit arrays in their
design.
11. Are able to use array of structs as a data structure.
12. Know the meaning of casting a return value to void.
13. Know the application of void pointers (void *) and can explain the
reasoning behind it.
c Erich Styger 20
INTRO V1.70
3.11 Push Buttons
1. Are able to implement correctly a push button switch in an embedded
system.
2. Can realize an interrupt synchronization method to receive input from
a push button.
3. Are able to describe the reasons behind bouncing, and how to solve the
problem.
4. Can successfully debounce one or multiple push button switches using
a state machine.
5. Can implement a polled or interrupt synchronized state machine to
debounce push buttons.
6. Understands dierent debouncing methods and can apply them.
7. Are able to implement a software driver for push button switches to
correctly recognize short and long button press, in a congurable way.
8. Is aware of the need for pull-ups and pull-downs and can implement it.
9. Understands the problem if false interrupts around interrupt triggered
input lines.
3.12 Low Power
1. Understand strategies for low power and low energy applications, both
for external and internal devices.
2. Can identify potential of external microcontroller devices for low power.
3. Understand the interlock between silicon die size, supply voltage and
clock frequency in respect to low power and low energy.
4. Understand the basic interlocks between supply voltage, clock fre-
quency and leak current and impact for low power and low energy.
5. Are able to perform simple measurements of the actual power consump-
tion in a microcontroller.
6. Are able to evaluate and discuss data sheet information with respect
to low power.
c Erich Styger 21
INTRO V1.70
7. Are able to implement a dynamic clock switching application, and can
explain the various consequences of it.
8. Are able to implement low power strategies with an RTOS like FreeR-
TOS, and can easily demonstrate it.
3.13 Sensor and Actuator, Quadrature, Mo-
tor and PID
1. Are able to design a sensor and actuator system with the timings and
inter-dependencies.
2. Can evaluate the realtime aspects of an sensor and actuator system in
respect to real time.
3. Are able to control a DC motor using direct digital control.
4. Understand the principle of a quadrature signal, and can successfully
apply this to decode it.
5. Understand the concept of Gray encoding and are able to apply it.
6. Are able to create gray codes
7. Are able to transform two complement values into gray codes and vice
versa.
8. Are able to determine the realtime aspects using gray encoders based
on data sheet information.
9. Can implement a quadrature decoder with or without error correction.
10. Know and understand the dierence between simple control and
closed loop control
11. Are able to implement a PID closed loop controller in software
12. Understand the dierent portions of a PID software closed loop con-
troller and can evaluate and predict the impact.
13. Understand the dierent terms from the control theory and can give
examples: error, set point, actual value, controller, plant, step function
and step response.
14. Can implement strategies for realtime measurement of speed based on
position information.
c Erich Styger 22
INTRO V1.70
3.14 C++
1. Has a general understanding of an object oriented language like C++.
2. Can explain the basic concepts of C++.
3. Can apply OOP technologies using classes, inheritance, data members,
methods and operators.
4. Can explain specic dierences between C and C++ with examples.
5. Is able to integrate C++ modules to a normal C application.
6. Can apply access control in the context of C++.
7. Can implement constructor and destructor for class objects.
8. Understands the concept of operator and function overloading and can
explain it with examples.
9. Is able to use C++ for things like implementing a graphical widget.
10. Can discuss the pros and cons of C++.
3.15 IEEE802.15.4 and ZigBee
1. Knows the motivation for IEEE802.15.4, the dierent layers and the
general services they provide.
2. Understand the dierences between IEE802.15.4 and ZigBee.
3. Understand the principles of Carrier Sense Multiple Access (CSMA),
CSMA-CD and CSMA-CA, and can explain it with examples.
4. Are able to dene a simple wireless communication protocol and can
apply it.
5. Are able to implement a sensor system to send sensor values over the
air.
6. Are able to identify and describe the dierent device types for
IEEE802.15.4 and ZigBee.
7. Can determine in an wireless IEEE802.15.4 or ZigBee network the dif-
ferent device types.
c Erich Styger 23
INTRO V1.70
8. Are able to draw and construct dierent wireless topologies like star,
peer to peer (P2P) or mesh networks.
9. Are able to explain strategies and ways in wireless sensor networks to
minimize energy consumption in the devices.
10. Understand the the dierent ways of data transfers in wireless networks
and can discuss the pros and cons.
3.16 RTOS, FreeRTOS and Semaphores
1. Are able to integrate and use successfully a realtime operating system.
2. Know and understands the concept of an RTOS, with the example of
FreeRTOS.
3. Can list dierent ways how a scheduling of a task can be triggered.
4. Understands the dierence between Delay() and DelayUntil() and
can successfully use it with FreeRTOS.
5. Understand the principle of semaphore and mutex, including binary
semaphore, and can apply it.
6. Understand the priority inversion problem and can explain it.
7. Know the principle of priority inheritance and priority ceiling.
8. Are able to apply the rules of priority inheritance and priority ceiling
protocols to avoid deadlocks with examples.
9. Are able apply low power for an RTOS, and how methods can be used
to nd out the system utilization.
10. Can explain the dierence between pre-emptive and cooperative sched-
ulers.
11. Can successfully create an application with multiple FreeRTOS tasks.
12. Can take advantage of FreeRTOS hooks and hooks in general to debug
or customize an RTOS.
13. Is able to use and apply the FreeRTOS API for kernel control and
semaphores.
c Erich Styger 24
INTRO V1.70
14. Can comment and construct timing diagrams for tasks and semaphore
processor.
15. Is able to implement a semaphore locking mechanism to protect shared
resources.
16. Can use semaphores for interprocess communication.
3.17 Processor Expert
1. Are able to use a rapid application and source generation utility.
2. Can add new Embedded Components to a project, congure them and
use them.
3. Can explain and apply the concept of methods, properties and events.
4. Are able to interface non-generated code with Embedded Components.
5. Are able to use Embedded Components for multiple CPUs and projects
in a portable way.
6. Are able to evaluate and discuss the pros and cons using a source
generation tool.
7. Are able to demonstrate a software architecture for embedded systems
with initialization, status and functionality using an example.
8. Can congure the system clocks and the parts of the system depending
on the system or bus clock.
3.18 Miscellaneous
1. Can read and understand engineering documents and data sheets for
software and electrical engineering.
2. Are able to use the right debugging and analysis instruments in order
to solve problems in the domain of embedded systems.
3. Are able to quickly browse and understand provided source code and
projects to get an system overview.
4. Have learned how to search and isolate errors in a system using a sys-
tematic approach.
c Erich Styger 25
INTRO V1.70
5. Remember at least one of the starter stories told at the beginning of a
lecture .
3.19 LSC I/O Software Synchronization
1. Are able to exchange data between two devices using handshaking.
2. Are able to explain the concept and needs for handshaking.
3. Are able to lit at least ve dierent examples of handshaking needs.
4. Are able to discuss the pros an cons of input/output polling and in-
put/output handshaking.
5. Are able to read timing diagrams, and as well to create a timing dia-
gram of a communication between devices.
6. Can implement a Read() and Write() handshaking using C, which
works independent of communication speed.
3.20 LSC Exploring Embedded C
1. Are able to explain the impact and meaning of the startup code in C.
2. Are able to determine the RAM and ROM size of a microcontroller
based on data sheets.
3. Using the C programming language are able to use input and output
registers on a microcontroller.
4. Can implement applications with mixed C and assembly source.
5. Know the basic data types in C and are able to identify the memory
occupied by variables.
6. Are able to use both static and automatic variables in applications
programmed in C.
7. Know how to use static and dynamic variable initialization.
8. Are able to use variables correctly with respect to visibility inside or
outside a module.
9. Can use the volatile qualier for variables in an appropriate way.
c Erich Styger 26
INTRO V1.70
10. Are able to generate an assembly listing with a compiler and to read
and understand the result.
11. Can utilize bit (and, or, xor, neg, mask) operations in C.
12. Know how to place variables at absolute addresses or to use variable
placed at specic memory locations.
13. Are able to implement interrupt service routines in C.
14. Know how to use inline assembly within C code.
15. Are able to address and use bit I/O registers with at least two dierent
methods.
16. Know both portable and non-portable (or vendor specic ways) ways
to address on-chip peripherals.
17. Are able to pass parameters to functions implemented in C or assembly.
18. Understand compiler optimizations.
19. Understand the impact of the const qualier and can use it for opti-
mizations.
3.21 LSC Interrupts using C
1. Are able to implement interrupt handlers in C
2. Know the dierent terms around interrupts and interrupt processing
and can explain them with examples.
3. Are able to use an interrupt based system in a microcontroller system.
4. Are able to determine based on data sheet information the available
interrupt sources.
5. Understand the dierent steps in an interrupt sequence and can explain
the reasons behind it.
6. Are able to demonstrate using software in C and some inline assembly
an interrupt based system.
7. Are able to enable/disable interrupts either globally or locally for a
single device on the hardware.
c Erich Styger 27
INTRO V1.70
3.22 LSC Multiple Interrupts
1. Are able to deal with multiple interrupt sources.
2. Can understand and apply the concept of synchronous and asyn-
chronous events.
3. Are able to evaluate and discuss a system with multiple and parallel
interrupts based on data sheet information.
4. Are able to implement an embedded system with multiple and parallel
interrupts.
5. Can explain the concept of interrupt priories and can apply it to an
actual software design.
3.23 LSC Bouncing Switch in C
1. Are able to explain the problem of bouncing with examples.
2. Understand the concept of debouncing using an SR-Latch and can im-
plement it in software.
3. Know typical bouncing times of switches and can measure it in a lab.
4. Know dierent debouncing strategies as presented in the Article by
Jack Ganssle[6] and can apply it.
5. Are able to implement a debouncer using busy wait.
6. Are able to implement a debouncer using a timer.
3.24 LSC Computer Operating Properly
1. Understand why a Watch Dog Timer (WDT)/Computer Operating
Properly (COP) is needed for embedded systems.
2. Can name examples of watchdog applications.
3. Can identify the usage of internal and external watchdogs, and can
explain the pros an cons of each approach.
4. Can make recommendations for the usage of WDTs in a design, or use
it in your own design.
c Erich Styger 28
INTRO V1.70
5. Understand the characteristics of a good WDT and can apply it.
6. Can apply an WDT in a multitasking or multiprocessing system.
7. Can demonstrate a WDT with input from data sheets in a C program
on a microcontroller.
3.25 LSC RS-232-C
1. Can specify the correct cable and connection for an RS-232 wire.
2. Are able to explain the reasons for the dierent voltage levels.
3. Know the dierent signals of an RS-232 connection and know their
meanings.
4. Are able to identify the dierent RS-232 signals and connections in
schematics.
5. Can apply the dierent connection methods and are able to implement
a high level software design.
6. Know the dierences between connections with and without handshak-
ing, and how this can be implemented.
3.26 LSC Analog Input Sampling
1. Are able to choose the right A/D converter based on the application
needs.
2. Can determine the resolution and transfer function of an A/D converter
based on data sheets.
3. Are able to calculate for a given A/D converter the output, the in-
put/output behavior and the timing.
4. Can determine the dynamic range of a signal based on its maximal and
minimal value.
5. Can calculate the minimal sampling rate and the maximum conversion
time.
6. Understand the impact of aperture time and error and are able to apply
possible solutions.
c Erich Styger 29
INTRO V1.70
3.27 Problems
3.1. Can you explain what is a shell and what is its purpose?
3.2. Why do we need a level shifter?
3.3. Using the shell interface, which methods can be used to print help and
status information?
3.4. What are the important settings you have to congure in the Processor
Expert component for the SCI?
3.5. Can you list some good reasons why RS-232 might be a better solu-
tion than USB? What would be the advantage of Universal Serial Bus
(USB)?
3.6. Why is it necessary to calibrate an acceleration MEMS sensor?
3.7. What kind of impact the oset has for an acceleration sensor?
3.8. What kind of impact the gain has for an acceleration sensor?
3.9. What is the dierence between ACCEL1 MeasureGetRaw() and AC-
CEL1 GetXmg()?
3.10. What is the advantage of the boot loader used with the LCD applica-
tion?
3.11. How can you program a new application with the LCD boot loader?
3.12. What is the purpose of the 0x27FF pattern at the begin and a 0x00
pattern at the end of every I
2
C message we send?
3.13. What is a prescaler and what does it?
3.14. What is the dierence between a CPU and a bus clock?
3.15. Using the MPC52259, what are the things you have to consider using
the interrupts?
3.16. Can you list dierent clock sources you can use?
3.17. Can you list at least three possibilities to reduce the energy consump-
tion in your design using hardware?
3.18. Can you list at least three possibilities to reduce the energy consump-
tion in your design using software?
c Erich Styger 30
INTRO V1.70
3.19. What is the purpose of the IdleHook() called from the IdleTask in the
context of low power and low energy?
3.20. Can you explain why we used a Pulse Width Modulation (PWM) period
of 2 ms for the motor?
3.21. The PWM signal for the motor was low active. Can you explain what
this means? At which voltage level the motor has the highest speed?
3.22. With using a direction signal and a PWM signal for a motor, what do
you have to care about if you are using -100% to +100% motor speed
approach?
3.23. Based on data sheets, can you nd the number of bits the Analog/Dig-
ital (A/D) converter of the MC13213 and MPC52259 supports?
3.24. Do you know what the abbreviation WDT stands for, and what this is
useful for?
3.25. Based on the schematics from the lab, could you describe what bit 4
on port E is used for on the MC13213?
3.26. Could you list some pros and cons of using macros?
3.27. What is the dierence in respect tho the LEDs used on the SRB and
Tower board we used?
3.28. Can you describe a very easy way to comment out a block of source
lines and C comments?
3.29. Can you list some pros and cons using Processor Expert?
3.30. Can you describe dierent strategies to store the motor speed percent-
age?
3.31. Describe how you can make the motor turning forward or backward.
3.32. In the lab we are using a task for sending trace information. This
task needs to have a priority assigned. Explain your reasoning behind
setting the priority for this task in comparison to the shell task.
3.33. Describe how you can produce trace from another module, say you
want to trace the status of the LEDs.
c Erich Styger 31
INTRO V1.70
3.34. Inspect the trace task and determine the trace buer size. What is
special about the storage of the trace buer? Could you suggest a
dierent implementation?
3.35. Can you list a reason why in a switch statement you should have as
well a default case?
3.36. Can you use a multidimensional array with dierent base types?
3.37. For what is DOT used in doxygen?
3.38. How can you limit the DOT graphs in doxygen?
3.39. How can you congure doxygen to produce call graphs?
3.40. Explain the main reason why you need synchronization.
3.41. Explain a problem of Gady synchronization.
3.42. You can choose between active waiting and interrupt synchronization.
Explain a reason why you still would use active waiting.
3.43. Explain why the realtime synchronization might be platform depen-
dant, and why not.
3.44. Why do you need pullup or pulldown resistors?
3.45. Are there dierent options to implement pullups or pulldowns?
3.46. For the HCS08, which to Embedded Components do you have available
if you just want to get the key value (low or high)?
3.47. On the HCS08, how many inputs can be connected to the KBI periph-
eral, and how many interrupts does it oer?
3.48. How do you document a function with doxygen?
3.49. List a few languages supported by doxygen?
3.50. How does doxygen integrate with eclipse?
3.51. List a few platforms on which doxygen is supported.
3.52. What is a transforming system?
3.53. How is realtime dened?
c Erich Styger 32
INTRO V1.70
3.54. Can you comment on a realtime system which delivers the correct result
too early?
3.55. What does it mean in a realtime system that things have to be delivered
independent of the current system load?
3.56. Which one do you consider to test easier: a hard realtime system or a
soft one?
3.57. What are the advantages of a version control system?
3.58. Could you think of a risk or danger using a version control tool?
3.59. If you delete a le and commit that change, will that le be deleted in
the version control system too?
3.60. In Eclipse, which views and perspectives do you have available?
3.61. From the following list of les and folders of a CodeWarrior project,
which ones are you going to put under version control: Documentation,
doxy/SRB.doxyfile, Generated Code, Project Headers, .project,
.rseHostSettingsCache.xml, .ProcessorExpert.g c?
3.62. What is the purpose of the Event.c module, and why do we need it?
3.63. What is the advantage to use an array for the events?
3.64. If a subroutine is called from an interrupt routine and from the main
program, what needs to be considered?
3.65. How can you protect a critical section?
3.66. What are you protecting in a critical section?
3.67. Where are the addresses stored of your interrupt service routines in
your application?
3.68. What is the goal of debouncing? What kind of problem has to be
solved? Describe the problem and provide a short description of the
solution.
3.69. Can you describe an approach in software to perform debouncing?
3.70. You are performing debouncing with a signal which is attached to an
interrupt pin. Is there something you need to consider?
c Erich Styger 33
INTRO V1.70
3.71. You are implementing as state machine. How can you implement it in
such a way, that it is using application provided function calls which
are only known at runtime?
3.72. You are using a state machine for your debouncing, which is called from
an interrupt service routine. How can you break-out of this interrupt
routine and continue iterating through the state machine if not in the
interrupt itself?
3.73. After a task has been created with FreeRTOS, in which state is the
task?
3.74. What are the states a FreeRTOS task can have?
3.75. What can cause a task switch in an preemptive FreeRTOS?
3.76. Can you list pros and cons of using your own idle task instead of using
the IDLE task provided by the RTOS?
3.77. Can you explain what happens if you use taskYIELD()?
3.78. What is the big advantage of using the memory scheme 3 in FreeRTOS?
3.79. What happens, if you set the parameter xTicksToWait to 0 when you
add an item to a queue?
3.80. Are queue items in FreeRTOS added by reference or by value?
3.81. What do you have to consider if you are using FreeRTOS queues from
and ISR?
3.82. What is the dierence between xQueueReceive() and xQueuePeek()?
3.83. What is a quadrature encoder?
3.84. What is the functional principle of an absolute digital angle encoder?
What could be a problem with this approach?
3.85. Can you list advantages of an optical encoder compared to a mechanical
one?
3.86. In the communication with the Tower and the LCD over I
2
C a prex
/ sux is used. Why?
3.87. How is a touch on the LCD recognized?
c Erich Styger 34
INTRO V1.70
3.88. Can you explain what is the problem of debugging the LCD applica-
tion?
3.89. In the C++ LCD application there is a Paint() method implemented.
What is the purpose of it?
3.90. Through what kind of communication channel data is sent from the
Tower to the LCD?
3.91. What are disadvantages of the Driver Low Level protection?
3.92. How does the ? operator works? Make an example.
3.93. What does sizeof("abc") return?
3.94. What does strlen("abc") return?
3.95. What can the function atoi() be used for?
3.96. What is the function of the three dierent clocks (System/CPU/Bus)?
3.97. What is the use of an external clock?
3.98. How can you specify interrupt priorities?
3.99. What is the function of a trigger?
3.100. Why should you use for example the type uint8 t instead of char or
int?
c Erich Styger 35
INTRO V1.70
c Erich Styger 36
Part II
Embedded Systems
37
Chapter 4
Introduction
Embedded Systems are around us everywhere today. We use them daily,
even if we are not aware. From the electronic alarm clock in the morning,
to the coee machine in our house up to the mobile phone we are using.
Nearly every gadget and appliance we are using every day contains or is an
embedded system. Even our credit or debit card has chip on it which is an
embedded processor. In this part of the book we will talk about systems
in general. It is true that in our context we think in systems as embedded
systems. And embedded Systems are rst and foremost systems too. The
word embedded just indicates that the the system is inside something and it
is part of the system. So embedded systems are systems in a special context.
But Systems exists for a very long time already, and most systems on our
planet do not have or need a microprocessor at all.
39
INTRO V1.70
c Erich Styger 40
Chapter 5
Project Structure
Implementing software for an embedded system typically means that a
project within an IDE is needed. Every IDE has its own special ways how to
organize the content of the software project: project les, compiler settings
and other things you need to build the application. The way how the source
les are organized is up to the developer. This chapter assumes that C/C++
with an IDE like Eclipse is used.
5.1 Header and Source Files
One common practice is to have the header (interface) les in special di-
rectory, like include, and the implementation les separated, e.g. in a
directory named src:
include
I2C.h
Application.h
...
src
I2C.c
Application.c
...
The advantage of this is
Interface and implementation les are clearly physically separated.
41
INTRO V1.70
If a library (*.lib or *.a), is generated, you can pass the header les
and the library le and no need to pass the source les (except for
debugging).
On the other side, there are some downsides too:
You need to add an additional search path to the compiler settings.
Things are not in a single place.
You might need some private interfaces. So you might need an addi-
tional place for these headers too.
In general, separating the header les is used especially in larger projects.
For smaller projects this might not be necessary or needed.
5.2 Common Files
In many cases, you want to share source les between developers and projects:
Having a set of shared les used in multiple projects. Example are
utility functions or library routines.
Sharing project les between developers: multiple engineers are work-
ing in dierent or same parts of the project.
If les are shared between multiple developers, using a VCS is the stan-
dard way. It allows to track changes between developers, revert and undo
and comparing dierent versions. Still there are multiple ways where to place
and organize the shared les.
Assume your company develops two kind of projects: a basic and low
cost router, and a high end one. For each of them you have insider your IDE
a project. Both projects probably can share functionality and source les.
How to manage this?
5.2.1 Copy Project
One way is that each project has a copy of the shared les.
Project A
Sources
main.c
c Erich Styger 42
INTRO V1.70
...
Shared
I2C.c
I2C.h
Utility.c
Utility.h
...
...
Project B
Sources
main.c
...
Shared
I2C.c
I2C.h
Utility.c
Utility.h
...
...
This means that they are not really shared any more. At the rst sight
this seems attractive:
Clean separation of products.
Changes in code base does not impact other project.
Simple.
However, especially if both products need to be developed and maintained,
there are disadvantages too:
Bug xes and improvements are not propagated.
Additional eort to merge sources from time to time.
If sources and projects need to be isolated from each other especially for a
temporary time, then again a VCS would be the right technology to be used.
Otherwise copies or multiple copies will create a maintenance headache.
c Erich Styger 43
INTRO V1.70
5.2.2 Master-Slave Project
In this approach, the shared les are placed are kept in one project. Say the
low end product was rst, and when later on the new advanced product
project was created, it simply refers to the shared of the other (master)
project.
Project A
Sources
main.c
...
Shared
I2C.c
I2C.h
Utility.c
Utility.h
...
...
Project B
Sources
main.c
...
...
The slave project would have references to the master project.
Compared to the copy method, this has the advantage of
Source les are in a single place.
Both project can benet from common xes and enhancements.
Simple, the master project can stay as it is, no changes needed.
Possible disadvantages are:
Dependency between the master and the slave project. In order to use
the slave project, the master project has to be present too.
c Erich Styger 44
INTRO V1.70
If the master project get moved on the disk, then the links from the
slave project needs to be changed.
No clean assignment what really the master should be, especially if
more projects get added. Maybe the master role needs to be moved.
While the Master-Slave approach is simple for just two projects, it is not
scalable beyond this.
5.2.3 Library Project
In this approach, shared and commonly used les are located in its own
library project or source structure outside the projects using it.
Library
include
I2C.h
Utility.h
...
src
I2C.c
Utility.c
...
...
Project A
Sources
main.c
...
...
Project B
Sources
main.c
...
This has the advantages of
c Erich Styger 45
INTRO V1.70
Scalability: this works very well with a 1 to 1 or 1 to N project rela-
tionship.
Separation: the commonly used les are clearly separated from the
projects using it.
Flexibility: both using a library/archive or using source les is possible.
That approach adds some complexity to the structure. But as for the other
ways, it requires to think about how to reference the library or the les in
the other projects.
5.3 Referencing Files and Folders
How to reference les and folders e.g. for the shared les depends on the
compiler and IDE used. Most tool chains oer the following possibilities:
1. Link to Project: This way a dependency to another project can be
made. For example a project uses another library project, and with that
link the tool chain will make sure that the depending library project
will be built rst.
2. Link to Folders: Instead of having the folder in the project, the project
information only contains a link to the folder. That way all les and
subfolder of that folder are included. Typically an IDE allows to link to
folders so you can easily browse the les in the editor. Or the compiler
has a link to folders list for the include les.
3. Link to Files: if only a subset of les in a folder shall be used, then
instead of referencing everything, a single le can be referenced. If a
new le is added to the library, then it is not automatically added to
the list of references.
4. Virtual Groups: Many IDEs (like Eclipse) oer to build virtual
groups or virtual folders: they look like folders to the IDE user, and
can contain link to les and folders. This can be used to group les and
folders. The downside is that this concept is not known to command
line based build tools which operate on physical les.
There are a few things to consider about linking les and folders:
The links in the IDE might not be taken into account for the build
tools (e.g. the compiler). In that case, you need to add the links in the
IDE, and to have the links (e.g. for the include les) in the compiler
too.
c Erich Styger 46
INTRO V1.70
Try avoid using absolute paths in links. As soon projects get moved,
the links might be broken. Use relative links instead, e.g. project,
workspace or IDE relative links. Otherwise it should be possible to use
environment variables, e.g. $COOL APP LIB/include.
Using relative include paths (e.g. #include "../../Utility.h" in
C/C++ sources might be problematic. Not every compiler might use
the same base directory used for the relative path, or the IDE might
use dierent ways to search for the le.
c Erich Styger 47
INTRO V1.70
c Erich Styger 48
Chapter 6
Your First Day at INTRO
Just for fun, lets assume you just have started your new job at INTRO
Corporation. At your rst day, you are having your morning coee in the
oce together with your working group, as Greg, the Vice President (VP) of
Marketing joins the group and discussions. As he is meeting you, Greg says:
Welcome to INTRO Corporation! Glad to have such a talented
young engineer on board. You know what? I have a great project
for you, and I already talked with your boss, and he thinks this is a
great starter project for you. The thing is this: we have some great
ideas for a product. And for this we need to control motors, us-
ing microcontrollers and other things I do not really understand
1
.
What I need for our customers is something we could show at a
trade show, something fancy, something fun! But our engineers
are busy delivering the work for their current projects, so they do
not have time to work on something new right now. And here
you come into the game: we just have received new hardware kits
which we wanted to evaluate new technologies. Why are you not
using that hardware to explore some new fun stu for us? Con-
trol motors with a microcontroller, use sensors, and use wireless
communication. That should be fun! Go and talk with your boss
about details and come back to me when you have something to
demonstrate.
And here your journey starts....
1
He says that with a big smile on his face :-)
49
INTRO V1.70
c Erich Styger 50
Chapter 7
Requirements
Learning works best if you can apply what you have learned. As such, during
the course we will spend a lot of time in the lab actually implementing
things we have learned. And to practice, we will apply the things learned
with a hypothetical system (which we will bring to reality): we are going to
implement a remote motor control system.
Your system shall have following general capabilities:
1. Control the motor with a microcontroller plus with a wireless device.
Use the hardware kits you have received.
Well, thats not really a very crisp requirement. There are not much
details. So it is up to us to rene things a little bit. Putting some details
behind the original requirements, we can come up with following:
1. The system shall control a motor.
2. Speed and direction of the motor shall be controlled.
3. In addition it shall be possible to control the system through a wireless
remote control unit.
An application of such a system could be e.g. a little fan which you can
control both locally and remotely (using a remote control unit). Or you
could use the system e.g. to open/close blinds on a window. Or you could
imagine anything which could be motor controlled and you want to have the
possibility to change speed and direction of the motor.
Given the requirements, we already can identify some parts of our system
(Fig. 7.1): There is remote control unit with a motor control unit. Both units
are connected using a wireless link. The Motor control unit has a motor for
which we can control direction and speed. As an important detail the remote
51
INTRO V1.70
Figure 7.1: INTRO System
control unit is optional, which means that the system with the motor control
unit and motor needs to be able to operate without the presence of the remote
control unit.
During the course of this book we will rene and work on the require-
ments
1
and implementation of this system.
7.1 System Requirements
In our project we will use a top-town approach. After inspecting the hardware
kits, we can nd following capabilities:
The wireless Sensor Reference Board (SRB)[17] kit has 5 LEDs, 4
push buttons, a 3-axis acceleration sensor and an external Electrically
Erasable Programmable Read Only Memory (PROM) (EEPROM). It
can communicate using wireless transceiver. Additionally there is a
SCI interface which is routed through an USB port.
The Freedom board has an ARM controller with LED and Arduino-
like headers. It has an on-board accelerometer and together with the
motor kit it can use sensors and drive up to two DC motors.
Looking at the capabilities, we can come up with following rened re-
quirements:
1. Both systems shall use buttons, LEDs and command line shell as user
interface.
2. The LEDs shall be used as a visual interface to the user (e.g. showing
status)
3. The buttons shall be used to accept input from the user.
1
This books is not about requirements management. See [7] for a good introduction to
requirements management.
c Erich Styger 52
INTRO V1.70
4. Buttons shall be used to increase and decrease the motor speed. It
shall be possible to increase the speed in small steps, but as well in
larger steps.
5. Both systems shall have the ability to be congured using a serial (ter-
minal, SCI, RS-232) connection from a host machine.
6. The SRB board shall be used as a remote controller to the motor sys-
tem. The acceleration sensor on the SRB board shall be used as addi-
tional input sensor.
7.2 Non-Functional Requirements
As nonfunctional requirements, we establish following:
1. We will use an Eclipse based development environment.
2. We will use a version control system.
3. We will develop our software in a modular way.
4. We will develop our software in a way that it should be easy to migrate
it to a dierent platform.
5. We will document the software.
And once we are done, we are going to demonstrate what we have accom-
plished.
7.3 System Decomposition
Figure 7.2: Motor System
c Erich Styger 53
INTRO V1.70
After having gathered more details about the system, it makes sense to
decompose it into smaller blocks. Figure 7.2 shows the motor system which
consist of a motor with a H-Bridge plus encoder. As input to the H-Bridge
a speed (PWM) and direction signal is used. An encoder is attached to the
motor shaft to report the relative position using an gray coded 2bit binary
signal. Both the the 2 encoder signals and the two motor signals are exposed
through a motor interface which is actually a RS-232 level shifter.
Figure 7.3: Tower System
Figure 7.3 shows the Tower components: We are using the 32bit ColdFire
CPU (MCF52259[24]). As interface to the motor we can use the on-board
RS-232 level shifter. We have two push-down switches plus 4 LEDs as user
interface available. The SCI routed to the TWR-SER board will be used
as conguration interface. As wireless transceiver we are going to use the
MC13202[19] card attached to the TWR-Radio card.
Figure 7.4: SRB System
Figure 7.4 shows the SRB system components. The SRB board can be
powered either by batteries or over USB. We can communicate to the host
using the SCI-over-USB converter present on the board we can use as ad-
ditional user interface and as well to congure the system. As main user
interface we use the 4 available push down switches, and the 5 LEDs are
used to indicate status to the user. The idea is that the user can use the
c Erich Styger 54
INTRO V1.70
push down buttons to control the motor (forward, backward, faster, slower).
Additionally the acceleration sensor shall be used to control the motor as
well. As CPU the MC13213[23] is used which is a 8bit microcontroller with
a wireless transceiver IC (MC13202[19]) in the same package.
c Erich Styger 55
INTRO V1.70
c Erich Styger 56
Chapter 8
Systems
System (from Greek (syste-ma)), whole com-
pounded of several parts or members, system, is a set of interact-
ing or interdependent system components forming an integrated
whole.
1
INTRO System
Remote
Control System
Motor Con-
trol System
Figure 8.1: INTRO System
The INTRO System (Fig. 8.1) is a system. This system can be divided
into two subsystems: the Remote Control System on the left hand side and
the Motor Control System on the right hand side:
INTRO System
Remote Control System
Motor Control System
Each system then can be divided into further subsystems. If we want to
classify such systems, we could come up with three basic classes:
1
http://en.wikipedia.org/wiki/System
57
INTRO V1.70
1. Transforming System
2. Reactive System
3. Interactive System
While such a classication is very useful and we go into the details of each
class, it is important to realize that most systems today are a combination
of dierent system classes.
8.1 Transforming Systems
Input System Output
Figure 8.2: Transforming System
A Transforming System transforms an input to an output. As the systems
does this usually in a continuous way, the input and output are as well named
input/output streams.
O(s) = P(I(s)) (8.1)
In equation 8.1 the input function I() is dening the input stream I(s) at
the time s. This input stream I(s) is processed by the system function P() to
generate the output stream O(s). The transforming systems can have many
(n) input streams and many (m) output streams (equation 8.2), where both
n,m are N. Such systems are often denoted as Multi-Channel Systems.
O
n
(s) = P(I
m
(s)) (8.2)
An important criteria for transforming systems is their processing quality,
throughput and system utilization. In the context of computer systems and
embedded systems, transforming systems usually are using some amount of
memory (to read in the values, to store them and to process them). As
memory is usually an expensive part of the system it is natural that such
systems try to optimize memory usage. Transforming systems are frequently
as well periodic systems: they sample/read the input stream with a given
frequency. For ecient system performance, the propagation delay from the
c Erich Styger 58
INTRO V1.70
time the input is read until the output is generated shall be as small as
possible.
8.2 Reactive Systems
System
Control
Measure
Figure 8.3: Reactive System
Reactive Systems (Fig. 8.3) are dierent from transforming systems as
they do not transform a stream into another stream, but rather take an
stream and react on. Typical reactive system are control or closed loop
control systems. Very often reactive systems today are systems which have
to react within a certain time. Interactive systems are central for Human
Machine Interface (HMI) systems.
8.3 Interactive Systems
System
Input
Output
Figure 8.4: Interactive System
c Erich Styger 59
INTRO V1.70
Interactive Systems (Fig. 8.4) are interacting with a human: they take
input and respond the operator or user. Typically such systems require short
response times, a high system utilization.
c Erich Styger 60
INTRO V1.70
8.4 Problems
8.1. List several systems which can be considered as transforming systems.
8.2. List several systems which can be considered as reactive systems.
8.3. List several systems which can be considered as interactive systems.
8.4. Provide examples of reactive systems. How are they dierent from
transforming systems?
8.5. Describe a transforming system with one input stream and two output
streams.
8.6. Describe an embedded system without any user interface.
8.7. Describe in your own words what characterizes an embedded system.
8.8. Most systems are a combination of transforming, reactive and inter-
active systems. Identify for a mobile phone the dierent classes or
subparts of the system.
8.9. Give an explanation why processing quality is important for transform-
ing systems.
8.10. Why are transforming systems optimized for optimal system utiliza-
tion?
8.11. Interactive systems usually require a fast response time: Could you give
typical response times for typical interactive systems? Is this response
time the same for all interactive systems you could think about?
8.12. How would you explain processing quality in the context of an audio
encoder?
8.13. Classify following system (reactive, interactive, transformative): digital
watch, airbag, radar speed measurement, re alarm system, Automated
Teller Machine (ATM), airplane fuel gauge.
8.14. List some systems which do not have any microprocessor or computer.
c Erich Styger 61
INTRO V1.70
c Erich Styger 62
Chapter 9
Realtime
In discussions about the domain of embedded systems a lot of time you will
hear the term realtime. And the term RTOS contains real time too. We
might think or use the term realtime in the context of oh, that system is
a really fast system, so it is a realtime system. Is this true? Or what does
realtime really mean?
Example: Consider a banking system which has to compute on Jan 1st
the yearly interest for each bank account. The year end documents have to
be sent to the customers by Jan 2nd. Such a system can be considered as a
realtime system.
9.1 Reality
As realtime is indicating, this has something to do with time. So realtime
has something to do how the system is performing in a time domain. As
we might recognize in the real world things are happening simultaneously.
While you are reading this, many things around you are happening the same
time: Your brain (hopefully!) is working, your heart is beating and your
eyes are following this text. Everything happens a the same time, and it
happens in a continuous way. So if you consider your body as a system,
then the system is doing many dierent things the same time, and it is done
in a continuous way. So if you look at the real world and consider this as
a system, then in this system events are happening truly parallel and in a
continuous way too.
Denition: Realtime systems can be used for the real world.
Now we need to nd the criteria to nd out if a system is realtime or not.
If you want to have a system performing as realtime, you need to specify
this as a requirement. This leads us to the following:
63
INTRO V1.70
Denition: Realtime is an requirement for systems. This requirement
can be applied to all system classes: transforming, reactive and interactive.
9.2 Timeliness
If you now connect a computer system to the real world e.g. with sensors
or actuators, then the computer system is interacting with the real world.
The computer system, however has one important dierence between the
real world: the computer time is not continuous (it is basically driven by
its clock), plus the computer can only do one thing at a time. As such,
the computer system has not only speed domain for events, it only can deal
with one thing at a time. The complication starts with the computer system
connected to the real world: it needs to comply with the real time and
parallelism of events in the real world.
This brings us to the rst fundamental part of the realtime requirement:
Denition: Realtime systems have to interact with the real world at the
right time.
If someone says this is a realtime system this does not mean it is a
fast system. It does not mean neither that the system is reacting as fast as
possible. Instead, a system can only be realtime if it responds at the right
time. So indeed the term realtime might be misleading, as righttime would
describe it much better. Another way to say this is that a realtime system
has to comply with the external time conditions. The emphasis is on external
as these are the conditions of the real world.
Example 1. Consider a railroad switch system. This system has to switch
the rails (e.g. either having the trag going to the right or to the left side).
The system has to make the switch at the right time. It does not mean that
the system shall do the switch as fast or as soon as possible it can. The
system has to make the switch at the right time: before the given train is
approaching the railroad switch.
9.3 Correctness
But right is only one part: the other one is correctness. If a system can be
used for the real world, then not only it has to act or react a the right time.
The response has to be correct too. If the system would create a wrong
response and still at the right time, this would makes the system pretty
useless.
Corollary 2. Realtime systems have to be correct.
c Erich Styger 64
INTRO V1.70
9.4 Realtime for Computer Systems
Up to now we have timeliness (at the right time) and correctness (the correct
result) identied as important for realtime Systems. In many cases today
systems include a computer attached to the system (the computer is con-
trolling the system). That means that realtime can be applied to computer
systems too.
Example 3. Consider a chemical plant doing chemical reactions (e.g. produc-
ing pharmaceutical products). Such a system consist of many pumps and
heating units. You can consider that a computer system is monitoring and
controlling that plant. If that system has to be realtime, then it is natural
that the attached computer system has to be realtime too.
Now if we consider a computer system as realtime system, the timeliness
condition is especially important for computers: as computers are running
in their own time domain (driven by the system clock), we need to make
sure that the time domain of the computer is in sync with the real time. If
the computer is very slow, the computer might not keep up with the real
world time conditions, and the result will not happen at the right time. So
such a system cannot be considered as realtime. On the other side, if the
computer is very fast, the system has to wait by any means until the right
time approaches to produce the result, within the external time conditions.
With this we can come up with following denition:
Denition 4. A real-time system is one in which the correctness of the
computations not only depends upon the logical correctness of the compu-
tation but also upon the time at which the result is produced. If the timing
constraints of the system are not met, system failure is said to have oc-
curred.
1
So in order to prove that a system is realtime, you need to prove that
the computation produces the right result, at the correct time. Proving
that the right result is computed might be already dicult (but usually
doable). But proong the correctness for time is usually dicult. The speed
or computation time of computers is typically not static: it depends on many
factors, including system load. So a realtime computer system attached to
a system needs to produce the correct result at the right time under all
conditions to be realtime.
This leads to extended denition of realtime:
1
Canonical denition from Donald Gillies[8]
c Erich Styger 65
INTRO V1.70
Denition 5. A computer is classied as Realtime if it can react on exter-
nal events in the real world: With the correct result, at the correct time,
independent of current system load, in a deterministic and foreseeable way.
Example 6. Consider a computer in a bottling plant. The bottles pass by
a computer system which has to put the cap on the bottle: there is only a
small time window when the computer can put the cap on the bottle. Given
the speed of the conveyor belt and the time needed for the operation, the
computer has to act inside this window to perform its task correctly, at the
right time. And the system has to do this under any computer system load,
and it has to do it in a foreseeable and deterministic way.
The part about deterministic and foreseeable way is here because you
need to prove that the timing constraints are met. If the system would act
randomly, it would not be deterministic and as such you cannot proof that
the system will meet the time constrains. Timing constraints are usually
specied with a timing window when the system has to react. Look at the
chart on page 157 in [4]: it shows the problem that runtime performance for
math routines varies with dierent inputs. Things like this can make the
determination of computation time very dicult.
The timeliness criteria has to be applied to all processing stages of the
computer system: from taking the input, to the processing state up to the
output state. If one of the stages cannot meet its timeliness criteria given by
the overall system timeliness, the system will fail to meet the criteria.
For the timeliness criteria there are two dierent categories:
1. Absolute Timeliness: e.g. the water irrigation system has to be
turned on at 05:30 in the morning
2. Relative Timeliness: e.g. after detection of a crash, the airbags in a
car have to be ignited 10 ms after event detection
9.5 Hard and Soft Realtime
In the context of realtime the terms hard realtime and soft realtime is
used. For hard realtime systems the condition is that they have to deliver
the correct result at a given time line, within a given window. Otherwise
the the systems is not correct. So the system has to meet both the time
conditions and the correctness condition.
Example 7. An airbag system has to inate the airbag within 20 ms after
impact detection.
c Erich Styger 66
INTRO V1.70
Such a system which has to meet hard timing constraints to deliver the
correct result to be considered as correct is named a hard realtime system.
In Fig. 9.1 the the hard realtime system always delivers the correct response
Figure 9.1: Hard Realtime System
f within the given time constraint window w.
Figure 9.2: Soft Realtime System
Soft realtime systems are system which have as well a timing constraint
to meet on average. But if the system does not meet the timing constraint
in all cases, the system does not cause a fatal consequence. However, the
system performance is considered as degraded if the timing condition is not
met. In Fig. 9.2 the the soft realtime system always cannot deliver always
the correct response f within the given time constraint window w. Given that
the system still is considered as correct even if the response is happening not
always inside the window, and that not meeting the time constraints is not
resulting into a failure of the system, this system is a soft realtime system.
Example 8. A video encoder needs to encode frames with a speed higher than
25 frames per second. If the decoding does not meet the time line, then the
system performance is degraded, while the frames are still decoded correctly.
9.6 Periodic Realtime
Realtime systems need to calculate the correct result at the correct time.
Given the fact that our real world is acting simultaneously and computers
c Erich Styger 67
INTRO V1.70
only can do one thing at a time, a realtime system needs to make sure it can
keep up with the timing constraints imposed on it. If the computer is too
slow, it already has lost. So the general misconception that realtime means
fast is not completely wrong. A computer system needs to be fast enough
to meet its deadlines. In order for a computer system to be fast (or fast
enough), this means usually that the system needs to be optimized or run
in an optimal way. Realtime systems which just have to do one or very few
tasks are rather simple to implement: just have the system doing things in
a loop, considering the timing constraints.
If for example a system shall water the plants in a house every morning
at 5:30am for 5 minutes, this could be implemented like following:
for ( ; ; ) {
i f ( ti me==530) { / s t a r t at 05: 30am /
St a r t I r r i g a t i o n ( ) ; / t urn r e l ay on /
} el se i f ( ti me==535) { / s t op at 05: 35am /
St o pI r r i g a t i o n ( ) ; / t urn r e l ay o f f /
}
}
In above example we would turn on and o a switch or relay which controls
a pump. It is rather easy to add other tasks to this kind of system, as the
system has not much to do the rest of the day. Such a system is easy to
implement, and a small microcontroller can do this easily as it has plenty
of processing power for this kind of task. But things get complicated e.g.
if you have to control the motor directly (e.g. controlling the speed and
checking the water ow). Assuming you this control is implemented in a
function ControllIrrigation() and virtually takes no execution time. If
this function has to be called periodically every 10 milliseconds, then the
implementation would change to something like this:
for ( ; ; ) {
i f ( time >=530 && time <=535) { / i r r i g a t e from 05: 30am t o
05: 35am /
Co nt r o l I r r i g a t i o n ( ) ; / c ont r ol t he wat er pump /
WaitMs ( 10) ; / wai t 10 ms /
}
}
Now assume this system has a humidity sensor which has to be checked every
5 milliseconds:
for ( ; ; ) {
i f ( time >=530 && time <=535) { / i r r i g a t e from 05: 30am t o
05: 35am /
/ c ont r ol t he wat er pump , needs t o be c a l l e d every 10 ms :
c Erich Styger 68
INTRO V1.70
/
Co nt r o l I r r i g a t i o n ( ) ;
WaitMs ( 5) ; / wai t 5 ms ( addi t i onal 5 ms wi l l be added ) /
}
MeasureHumidity ( ) ; / needs t o be c a l l e d every 5 ms /
WaitMs ( 5) ;
}
Now think about adding a little bit more, and things get easily very compli-
cated. The solution to this is the usage of an RTOS.
c Erich Styger 69
INTRO V1.70
9.7 Problems
9.1. If there is the term real time, there must be as well a unreal time?
9.2. Modern processors have many cores (multi core) which can do things
in parallel. Does this solve the problem for realtime compliance?
9.3. If you have to verify if a realtime system is correct, which realtime
system would be probably easier to verify: a soft realtime system or a
hard realtime system?
9.4. Would you classify a VoIP (Voice Over IP) system more as a hard
realtime system or as a soft realtime system?
9.5. Is a online stock trading system a hard realtime system or a soft real-
time system?
9.6. Specify typical response windows for: keyboard, window lift in a car,
touchscreen.
9.7. Is Microsoft Windows 7 a realtime operating system?
c Erich Styger 70
Chapter 10
Synchronization
Systems can be divided into subsystems, and these subsystems are naturally
connected. If two systems are interconnected, and if one system is a computer
system, then you can say that the computer system is attached to the other
system (or process). As the computer system operates on a dierent time
scale, we run into a synchronization problem, especially for realtime systems.
We have learned that a realtime system needs to deliver the correct result at
the right time: this means if the computer is slower than the realty system,
the computer system is failing. And if the computer system is too fast and
delivers the result too early, the computer system is failing too. The computer
system has to make sure it delivers the result at the correct time.
A computer system makes a lot of sense if can interact with its envi-
ronment. The systems can read in sensor values and act accordingly, e.g.
changing the lights in a room or trigger an alarm if smoke has been detected.
Reading input values and writing output values comes with a fundamental
problem: the computer system is either slower or faster than the surrounding
system. This chapter deals with ways how a computer system can synchro-
nize with its environment. One of the most important part of system design
is timing. And very often if a system fails to operate correctly it is because
of timing. Failure of the system to comply with the needed timing usually
makes the system fail. One fundamental of realtime systems is that they
have to calculate the right result at the right time. Again here the sys-
tem needs to deal with a time. Another timing aspect comes into play if the
system needs to read or write input/output (I/O): the data rate an I/O can
accept is in some cases slower than what the computer system could deliver.
In that case the system has to slow down enough to write data only as fast
as the receiver can take it. On the other hand an I/O device might deliver
the data much faster than the computer system can consume it. Then we
need to implement a way that the system can interact with the producer of
71
INTRO V1.70
that information so the data can be consumed in way that no data packet is
lost.
System
Input
Device
Output
Device
Figure 10.1: Input/Output System
Imagine a system attached to an external input and output device (Fig.
10.1). If the the input device is slower than the system can consume the data,
then the system needs to slow down or wait until the next input packet is
available. If the input device is faster than the system can accept the data,
then either the system signals the input device to wait or the system will
loose some input. On the other side the same thing happens for the output
device: if the system delivers the data faster than the output device can
accept it, then data will be lost or the output device needs to communicate
with the system in order to slow down the data rate.
Synchronization is the technique which is used to solve such scenarios.
There are many synchronization techniques in use today, and in this chapter
we will look at some.
10.1 I/O Devices
We will rst study the problem from the device point of view. As example
we are using a paper tape reading hardware device connected to a computer
(Fig. 10.2
1
). Such a device is is used e.g. in parking garages as ticket system:
you receive such a paper tape on entry of the parking garage, and you use
it to pay your parking fee and you use it as exit ticket to exit the parking
area. The reader in the device uses a sensor to read either a hole (marking
a 1 bit) or not a hole marking a zero bit. In addition to the data bits there
is as well a line of sprocket holes. The data bit values (TRUE/1 or FALSE/0)
are connected to a microcontroller input pin port (PORTA). In addition, the
sprocket hole bit is wired to the microcontroller port bit B0. Whenever the
paper moves over the sensor, the port bits reect the paper information.
The microcontroller can now read in the information while the paper ticket
is inserted with something like:
1
The parking ticket reader example it taken from [14]
c Erich Styger 72
INTRO V1.70
Figure 10.2: Parking Ticket Reader
#define NOF DATA 11
stati c uint8 t buf f e r [NOF DATA] ;
void read ( void) {
uint8 t i ;
for ( i =0; i <si zeof ( buf f e r ) ; i ++) {
buf f e r [ i ] = PORTA;
}
}
Of course we should read in data only when data is ready: means if the
sprocket whole indicates that we have a row to read. A simple but general
model would be that the device itself would signal to the microcontroller
when the data is ready. In this model, the device has three states: IDLE,
BUSY and DONE (Fig. 10.3). The device is IDLE if the device is not used.
Figure 10.3: State Diagram
c Erich Styger 73
INTRO V1.70
When a program starts to use it, it moves from IDLE to BUSY state. When
the device is through with its operation, it enters the DONE state. At this
time the program can read the date and asking the device either to make
another operation (then it goes back to BUSY state) or can ask the device to
stop and then it will enter the IDLE state again. An error condition could
put the device as well into the DONE state. In that case the device should
have a way to signal the error condition to the program. We are applying
this state diagram to our parking ticket reader: The IDLE state indicates
that the paper ticket reader is not used. If a user now inserts a ticket, the
reader goes into the BUSY state to read in the rst line of holes. If the reader
encounters an error (e.g. internal buer overow) it would return to the IDLE
state with an error condition. If the reader has read a line of bits into the
buer, it will transition from the BUSY to the DONE state. The DONE state
indicates now to the program that a data byte can be read from the device.
After the program has read the data byte, it signals a Start condition to the
device, and the device again enters the BUSY state. The device continues to
iterate between BUSY and DONE while reading the data. If our device would
be designed to read in 4 bytes of data (from the beginning of our example
ticket in Fig 10.2), then it might iterate through following states (with values
read by the program): IDLE, BUSY, DONE (0x00), BUSY, DONE (0x00), BUSY,
DONE (0x00), BUSY, DONE (0x03), IDLE. The general synchronization problem
is for a program to read the data only when the device is in the DONE state.
Additionally the program needs to check for the error conditions too. In the
next sections we will discuss dierent synchronization methods.
10.2 Realtime Synchronization
Realtime Synchronization uses a way to delay the program execution while
the device is in BUSY (see Fig. 10.3) state. The synchronization method is
named realtime synchronization because it is using real time to wait (thus
to synchronize). The delay or waiting time is either inherent to the program
execution (case 1) or explicit using some methods of waiting (case 2).
If you look at following code, then the program needs some time to iterate
through the for statement and to read the data into the buer.
void read ( void) {
uint8 t i ;
for ( i =0; i <si zeof ( buf f e r ) ; i ++) {
buf f e r [ i ] = PORTA;
}
}
c Erich Styger 74
INTRO V1.70
If this inherent execution time is matching the speed the paper ticket is
moved forward, then we can correctly read the data in. So the execution
time of the program is causing an inherent waiting.
To illustrate the second case following method could be used:
void read ( void) {
uint8 t i ;
for ( i =0; i <si zeof ( buf f e r ) ; i ++) {
j = W; while ( j ) ;
buf f e r [ i ] = PORTA;
}
}
This adds some additional overhead and delay to the for loop. The value of
W would be dened in an empirical way and needs to be adjusted, depending
on the device speed. If a higher delay is needed, then the delay loop could be
nested or extended. In our example using realtime synchronization, the pro-
gram simply reads from the device, not checking the state of the device. The
program tries to match the BUSY and DONE states using a time delta between
reading the values, and the IDLE state is the matching the time before the
program starts to read data. Using this type of realtime synchronization is
considered as bad programming by almost everyone. Just consider that the
compiler might optimize the waiting loop in a diernt way. Even worse, the
delay loop could be removed by the compiler completely as it has no eect
2
.
Additionally the timing is completely not predictable (consider DMA, dier-
ent memory access cycles, interrupts). Additionally the execution speed in
the delay loop depends on the assembly code generated from the high level
language which you cannot control
3
.
A better way would be to use a special delay routine which will wait for
a specic time. In the example below, the call to WaitMs(10) will delay the
program by 10 milliseconds. The function WaitMs() could use a timer or a
dened execution sequence to delay for the given time.
void read ( void) {
uint8 t i ;
for ( i =0; i <si zeof ( buf f e r ) ; i ++) {
WaitMs ( 10) ;
2
To prevent the compiler doing that optimization, you could dene the loop variable
as volatile.
3
The only way to deal with this would be using assembly code and controlling the code
directly.
c Erich Styger 75
INTRO V1.70
buf f e r [ i ] = PORTA;
}
}
This approach is better, but still problematic: WaitMs() will probably not
wait for the exact 10 ms as there is overhead assoziated with the function
call, and how the function is called again is subject to the compiler code
generated.
However, realtime synchronization requires the least hardware: it can
be used for any basic input or output device, without the need for further
hardware. As explained, it is very sensitive to the timing and in general not
recommended.
10.3 Gady Synchronization
start
check ag
ready?
read
yes
no
Figure 10.4: Gady Loop
The sprocket hole input in Figure 10.2 could be sensed by our device to
indicate and know when the data is available. Such a ag or information is
c Erich Styger 76
INTRO V1.70
used by the Gady synchronization method. This technique is named after
Socrates
4
.
For if you put me to death, you will not easily nd another,
who, to use a rather absurd gure, attaches himself to the city as
a gady to a horse, which, though large and well bred, is sluggish
on account of his size and needs to be aroused by stinging. I think
the god fastened me upon the city in some such capacity, and I
go about arousing, ...[4]
The principle of Gady Synchronization is to check a ag (usually a hard-
ware ag) which indicates if the device is in DONE state (Figure 10.4). This
bothering is usually implemented in a loop where the program checks the
status of this ag until it detects DONE or an error condition. Gady syn-
chronization is often called polled synchronization too, but polling means
usually sampling multiple people with the same question, and not the same
person with the same question many times.
Changing our routine to read a line from the parking ticket would change
to following using a Gady Synchronization:
void read ( void) {
uint8 t i ;
for ( i =0; i <si zeof ( buf f e r ) ; i ++) {
while (PORTB. B0) ;
while ( !PORTB. B0) ;
buf f e r [ i ] = PORTA;
}
}
This waits for a falling edge of the sprocket hole pin and waits until it raises
again. this indicates that the data is ready so data can be picked up. The
program above now shows the IDLE, BUSY and DONE states. IDLE is before
the read() routine is called. DONE is when we have read the data using
buffer[i]=PORTA;. We are in BUSY state during the gady loop.
The good thing with Gady Synchronization is that it lowers the system
latency: we are reading in the data right when it is available. However, there
is the need for a wakeup bit or similar to know that the device is ready,
compared to no such hardware ag need for the Realtime Synchronization.
Additionally we need to keep in mind that the Gady Synchronization still
needs the processor to poll that ag, so processing time is not available
4
Socrates died 399 BC after charged to death. Socrates was called the Gady of
Athens
c Erich Styger 77
INTRO V1.70
for other things to do while it waits for DONE. For this, we need to discuss
Interrupt Synchronization.
10.4 Handshaking
In addition to synchronization, a device might provide as well some means
of handshaking. For example for our parking ticket reader we could use the
PORTB.B0 bit as handshake signal between the program and the reader. The
signal could positive- or negative-logic-level asserted signal. So we could
write our program in such a way that we would pull the bit high for a short
time to request data:
void read ( void) {
uint8 t i , j ;
PORTB. DDR0 = 1; / pi n B0 as out put pi n /
for ( i =0; i <si zeof ( buf f e r ) ; i ++) {
PORTB. B0 = 1; PORTB. B0 = 0; / pul s e handshake /
j = W; while ( j ) ;
buf f e r [ i ] = PORTA;
}
}
Note that just before the realtime synchronization we pulse the signal high
for a short time, and that the signal stays low during data acquisition.
This example could be extended with a use case were we use PORTB.B0
for synchronization, which falls when data can be read. and we use a hand-
shake signal on PORTB.B1 which will be LOW to request data and returns
to HIGH after the data is read. The handshake signal will stay low until the
data is transferred.
void read ( void) {
uint8 t i ;
PORTB. DDR1 = 1; / pi n B1 as out put pi n /
PORTB. B1 = 1; / B1 i n i t i a l l y hi gh /
for ( i =0; i <si zeof ( buf f e r ) ; i ++) {
PORTB. B1 = 0; / i n i t i a t e handshaki ng wi t h s e t t i ng B1 l ow /
while ( !PORT. B0) ; while (PORT. B0) ; / s ynchroni z e /
buf f e r [ i ] = PORTA;
PORTB. B1 = 1; / end handshake /
}
}
c Erich Styger 78
INTRO V1.70
Synchronization and handshaking can be chosen independently: so you can
combine dierent methods depending on your needs.
10.5 Interrupt Synchronization
Realtime and Gady synchronizations have one big disadvantage: they re-
quire cycles on the processor while they are waiting. If the waiting time is
only very short (means: only a few processor cycles), then this might be ac-
ceptable. However, if the waiting time is rather random or might be long, it
would be a waste of CPU or Microcontroller Unit (MCU) performance. Wait-
ing is usually acceptable only in the system startup while only one thing can
be done at a time. But as soon as you have multiple things to do, you want
to use the processor cycles for something else while you have to wait for a
device (Figure 10.5).
request
data
do
something
else
get
notication
process
data
Figure 10.5: Device Synchronization without explicit waiting
The thing is now that while doing something else, we dont know how
long this will take. Imagine a system which is drawing something on a screen,
while it needs to read from an external device. You could imagine that the
system could do some drawing in the do something else state and then check
again if the data is available. However, this would be dicult because you
need to balance the amount of time spent while drawing to the screen small
enough in order not to miss a data element. Thus this approach would make
c Erich Styger 79
INTRO V1.70
things even more fragile. The idea is really that the system could continue to
do something else, and just return immediately to get process the data when
available. This mechanism has been implemented in computers as interrupts.
There are two parts of interrupts: interrupt hardware and interrupt soft-
ware. Interrupt software programming can be very tricky, and some company
software policies even disallow the usage of interrupts. Clearly, if interrupt
software programming is not done cleanly it will be a mess, causing problems
hard to nd and solve. But interrupts can be very powerful and useful for our
synchronization problem: interrupts can be used to notify our program that
data is available, so we do not need to wait time in realtime synchronization
or gady loops. For many processors the interrupt latency time is smaller
than the overhead needed for the waiting loop.
The hardware interrupt logic allows the main program (which is doing
the something else) to be branched to the program location where we can
read the data. For this, the interrupt hardware needs to perform several
steps in order to switch from the main program to the interrupt program or
Interrupt Service Routine (ISR) and back to the main program:
1. Interrupt: the cause of the interrupt gets signaled to the hardware: this
means that the hardware needs to process this signal. Additionally it
means that potentially that an already executing instruction needs to
be interrupted in the middle (depending on the architecture).
2. Save Status: the status of the currently executed program needs to be
saved. This usually includes the PC (Program Counter), the registers
with the current execution status (e.g. priority). Usually the program
stack is the place where the information is stored.
3. Set new PC: The interrupt hardware calculates the new program pro-
gram counter together with the new priority (if any). A this time the
control goes over to the interrupt service routine
4. Save other used registers: depending on the architecture, not all regis-
ters were saved in the rst step. As such, the interrupt service might
need to save other used registers.
5. Process ISR program: here the program executes the core of the ISR
routine. A part of the ISR the program usually has to acknowledge the
reason for the interrupt. This to reset the interrupt hardware so the
interrupt is not triggered again on ISR exit.
6. Exit ISR: The ISR program needs to restore register or context in the
reverse order as it has it performed at the beginning of the ISR exe-
c Erich Styger 80
INTRO V1.70
cution. As last instruction a special return from interrupt instruction
or sequence is executed.
7. Return to interrupted program: with the execution of the special re-
turn from interrupt sequence, the hardware restores the original con-
text: restores registers, program counter (PC) and status and continues
execution of the interrupted program.
The entry and exit sequence of the interrupt needs to be atomic: this
means that the save and restore operations shall not be interrupted itself.
An important aspect for realtime applications is the interrupt latency
time: this time ideally should be as small as possible, and is dened as the
time between the cause of an interrupt cause (e.g. pressing a key) and the
time when the ISR starts executing. As another general design principle it
is important that the ISR itself is executing as fast as possible in order not
to impact systems performance: just do what you have to do in the ISR and
let the heavy work be done by the main program.
Example: An application shall write a text message to Secure Digital
(SD) card whenever a button is pressed. The application has to perform
some other main tasks. The button is connected to a pin of the microproces-
sor. Whenever the button is pressed, the application gets notied with an
interrupt. Consider following ways to implement this:
The text message is written directly from the ISR.
The ISR sets a ag which is checked by the main application. If the
ag is set, the application writes text to the SD card.
The rst approach has minimal interrupt latency time. However, the writing
to the memory card cannot be considered as very fast: it might take several
hundreds of milliseconds for completion. Additionally in an operating system
environment you will need to protect concurrent access to the device which is
adding some more overhead. If your system does not allow nested interrupts
doing this approach will increase the latency of the rest of the interrupts
which is probably not acceptable.
10.6 Sharing Code
As soon as you have interrupts in your system, you likely will end up in
the situation as in gure 10.6: You start to use common code in a shared
subroutine. Using subroutines or functions which can be used from multiple
places is good programming style as it avoids code duplication. But as an
c Erich Styger 81
INTRO V1.70
Figure 10.6: Common Subroutines
interrupt might happen anytime, it might be that the execution of the com-
mon subroutine executed by the main program is interrupted too. Means
that it looks like that if the subroutine is executed the same time both by
the ISR and the main program. But this requires that the hardware actually
supports this. This is usually ensured by the hardware having the context of
the ISR routine stacked, so the ISR routine is using a private environment
(registers, program counter). This applies as well to data and parameters as
long as the hardware supports a stacking method for it
5
.
As in gure 10.6 both the main program and the ISR can call the same
function, the shared subroutine needs to be reentrant. Reentrant means
that the code can re-enter a function without interfering another portion
of the application which is already executing that code. See Chapter 16:
Reentrancy[4] and Chapter 17: Interrupt Latency[4] for a detailed dis-
cussion around reentrancy and interrupts accessing data.
10.7 Sharing Data
Interrupt programs need special care if both the ISR and the main program
are sharing (global) data as in gure 10.7. Here it is possible while the main
program is writing to the data, an interrupt might happen and the ISR is
accessing the data too. As long as both are just reading the data, that works
out ne. But as soon as one is reading the data while another is writing the
data, there might be the problem of inconsistent data.
Consider following application with the two functions Inc and Dec: Say
5
There are hardware architectures available which do not support a hardware stack for
variables. Examples for this are the STMicroelctronics ST7/ST19X, the Freescale/Mo-
torola HC05 or many of the smaller PIC cores from Microchip. They emulate a hardware
stack using normal global memory. As such, recursion or shared interrupt service routines
are usually not possible.
c Erich Styger 82
INTRO V1.70
Figure 10.7: Common Data
this application does count the number of people in a room, and the there is
an entry and an exit door.
void I nc ( void) {
b++;
}
void Dec ( void) {
b;
}
Imagine that both Inc and Dec are called from interrupt service routines.
This means that both functions could be called any time, and could be inter-
rupted too. It could be possible that your compiler would produce something
like following as assembly code:
I nc :
INC b
RETURN
Dec :
DEC b
RETURN
Lets assume that the CPU does not interrupt an assembly instruction in the
middle: both INC and DEC assembly instructions would not be interrupted.
If you would print the value of the variable, you might get get following
sequence:
0
1
2
3
2
3
2
1
0
c Erich Styger 83
INTRO V1.70
We are in good shape, as each instruction would be able to complete the
operation on the data before being interrupted. Another way to say this is
that both INC and DEC are performing the data access in an atomic way.
But it could be that such atomic instructions are not possible for your
architecture, then the generated code might look like this:
I nc :
LDA @0x10
INCA
STA @0x10
RETURN
Dec :
LDA @0x10
DECA
STA @0x10
RETURN
Now the operations are not atomic any more, and it could be that the variable
sequence could look like this:
0
1
0
2
1
4
2
1
Because accessing the data is not atomic any more, the data might end up
in an inconsistent state.
10.8 Disable and Enable Interrupts
A simple way to prevent that the access to the data is interrupted is to
disable interruption:
void I nc ( void) {
DISABLE INTERRUPTS;
b++;
ENABLE INTERRUPTS;
}
void Dec ( void) {
DISABLE INTERRUPTS;
c Erich Styger 84
INTRO V1.70
b;
ENABLE INTERRUPTS;
}
As the C programming language does not support native instructions to
disable or enable interrupts, you usually end up using macros or something
similar for this:
#define DISABLE INTERRUPTS {asm SEI ; }
#define ENABLE INTERRUPTS {asm CLI ; }
This is an ecient and straight forward solution. But the programmer
needs to be careful to disable the interrupts only for a short time in order
not to increase the interrupt latency time to an inacceptable level.
Additionally you might run into troubles if you have something like this:
void f oo ( void) {
DISABLE INTERRUPTS;
/ shared v a r i a b l e acces s /
ENABLE INTERRUPTS;
}
void bar ( void) {
DISABLE INTERRUPTS;
/ acces s t o shared v a r i a b l e s /
f oo ( ) ;
/ do somet hi ng e l s e wi t h t he shared v a r i a b l e s here /
ENABLE INTERRUPTS;
}
The programmer tried to protect the access to the shared variables in bar.
But he did not consider that the the call to foo enables interrupts again as
a side eect, thus causing the program to fail. Additionally, interrupts are
disabled longer than really needed. A solution would be to use something
like this:
void f oo ( void) {
DISABLE INTERRUPTS;
/ shared v a r i a b l e acces s /
ENABLE INTERRUPTS;
}
void bar ( void) {
DISABLE INTERRUPTS;
/ acces s t o shared v a r i a b l e s /
ENABLE INTERRUPTS;
f oo ( ) ;
DISABLE INTERRUPTS;
c Erich Styger 85
INTRO V1.70
/ do somet hi ng e l s e wi t h t he shared v a r i a b l e s here /
ENABLE INTERRUPTS;
}
10.9 Enter and Exit Critical Section
We still have a problem for following case:
void f oo ( void) {
DISABLE INTERRUPTS;
/ shared v a r i a b l e acces s /
ENABLE INTERRUPTS;
}
void bar ( void) {
/ i nt e r r up t s are di s abl ed , we wi l l enabl e them l a t e r /
f oo ( ) ;
/ Upps ! i nt e r r up t s are suddenl y enabl ed ! /
}
A solution to this problem would be use following implementation (for an
HCS08):
#define ENTER CRITICAL( ) { asm PSHA; asm TPA; asm SEI ; asm STA
CCR reg ; asm PULA; }
#define EXIT CRITICAL( ) { asm PSHA; asm LDA CCR reg ; asm TAP;
asm PULA; }
void f oo ( void) {
ENTER CRITICAL;
/ shared v a r i a b l e acces s /
EXIT CRITICAL;
}
void bar ( void) {
/ i nt e r r up t s are di s abl ed , we wi l l enabl e them l a t e r /
f oo ( ) ;
/ i nt e r r up t s remain di s ab l e d here /
}
This solution uses an additional global variable CCR reg to avoid that inter-
rupts get enabled if they were disabled previously.
Still, you need to be careful about using that approach in a nested way
like below:
void f oo ( void) {
ENTER CRITICAL;
c Erich Styger 86
INTRO V1.70
/ shared v a r i a b l e acces s /
EXIT CRITICAL;
}
void bar ( void) {
ENTER CRITICAL;
/ shared v a r i a b l e acces s /
f oo ( ) ;
EXIT CRITICAL;
}
In this chapter we discussed ways how to protect access to shared data to
make it atomic from an application point of view. We discussed ways around
disabling and enabling interrupts to create critical sections. We discussed
this in the context of no operating system (bareboard, no operating system
used). If you are using an operating system, then you have additional means
to protect concurrent access to shared resources: Semaphores and Mutex.
10.10 Priorities
The nature of microprocessors is that they need to organize the way how
interrupts can happen. As interrupts are inherently asynchronous, an actual
implementation will dene the rules. There are several dierent implemen-
tations possible and available on the market:
Master Interrupt Flag: there is a single interrupt ag in the system
which globally enables and disables the interrupts of the system. This
interrupt ag acts as a master interrupt inhibit ag. Still, each periph-
eral like SCI or USB has its own interrupt settings, but the interrupt
would not be red unless the global ag allows this.
Non-Nested Interrupts: in this implementation an interrupt service
routine will not be interrupted itself: neither from the same interrupt
source nor from another interrupt source. This means that entering
an interrupt service routine will enable a master interrupt inhibit
ag which will be cleared in the interrupt exit sequence. However,
interrupts will be pending if they happen during the execution of an
interrupt service routine.
Simple Priority List: there must be rules about which interrupt
will be serviced if multiple interrupts happen the same time. For this
a simple (and usually static) prioritization scheme can be used. In
that model each interrupt source has an assigned priority (say from 0
c Erich Styger 87
INTRO V1.70
as highest priority to 255 as lowest priority). Using that priority the
interrupt controller will have a dened execution model for interrupt
serving.
Priorities and sub priorities: a rened model using priorities is
that each interrupt source has a priority level with a sub priority. This
allows grouping of interrupt sources, and typically you as a program-
mer can assign the level and sub level, sometimes even at runtime.
Some implementations require that each interrupt source has a dis-
tinct (unique) level and sub level assigned, otherwise the behavior is
undened
6
. Other architectures implement an internal queuing and
can support multiple interrupt sources with the same priority and sub
priority.
Implementations might slightly dier from above items, and implementations
might use a combination of above items as well. What you need to keep in
mind is that the more powerful and complex the interrupt controller in a
CPU, the more it usually will cost. Or in other words: in very low cost
controllers you usually nd rather simple interrupt implementations, while
the more advanced implementations you will nd in the high-end processors.
10.11 Example Interrupt System
To illustrate how an interrupt system with main and sub priorities can work,
we could dene an architecture with following interrupt rules. In this example
we are using a main priority (e.g. 3) which can have a sub priority (e.g. 2).
The higher the number, the higher the priority. Additionally there is usually
a main program with a priority of 0 (or 0.0 if you want).
It is possible to formulate the above rules in formulas, using following
denitions:
fn: currently executed program
INT(): interrupt a program
MP(): main priority of a program or signal
SP(): sub priority or a program or signal
s: a signal
6
The Freescale ColdFire V2 is an example.
c Erich Styger 88
INTRO V1.70
ws: set of waiting signal
MAX(): maximum function of all items in a list
The rst two rules can be dened as follows: A signal with smaller priority
cannot interrupt a running program with higher priority. Such a signal will
be added to the pending list:
if(MP(s) <= MP(fn)) ws = ws s (10.1)
A signal with a higher main priority will always interrupt the currently
executed program:
if(MP(s) > MP(fn)) INT(fn) (10.2)
The next rule can be dened as follows: A signal with the same main
priority does not interrupt. The signal will be pending.
if(MP(s) <= MP(fn)) ws = ws s (10.3)
The third rule could be written as following: A signal with higher sub
priority has to wait for the termination of a program with the same main
priority, even if it was interrupted.
if(SP(s) > SP(fn)) ws = ws s (10.4)
The rule about the execution of pending sub priorities would be like
following: If multiple signals are waiting with the same main priority, then
the sub priority decides which of the waiting signals will be executed rst.
As such, the sub priority aects the execution order of the waiting signals,
independently of the time when the signal was raised.
if(ws = {}) fn(MAX(SP(ws))) (10.5)
And nally the rule about already interrupted programs would look like
this: If a signal is pending with a higher main priority than the program which
was interrupted previously, then the control is passed to the interrupted
program and immediately gets interrupted again.
if(MP(ws) > MP(in)) fn = in ws = in (10.6)
With these rules, a typical system execution path could be as in gure
10.8. The notation is that the lower edge of the ash indicates the time
when the interrupt triggers in the hardware.
c Erich Styger 89
INTRO V1.70
Figure 10.8: Interrupt System
1. The main program (with the main priority of 0) starts execution at
time zero.
2. First, a signal with priority 2.2 is raised. According to rule 10.2 the
currently running program gets interrupted and execution continues
with the new interrupt program.
3. Later on, a signal with priority 3.1 is raised. Again rule 10.2 applies and
the current program with priority 2.2 gets interrupted and execution
continues with interrupt program with priority 3.1.
4. During execution of program 3.1 a signal with priority 1.1 is raised.
Here rule 10.1 applies and the signal will be queued.
5. Then during execution of program 3.1 a signal with priority 3.3 is raised.
Again rule 10.1 is applied and the signal 3.3 is put into the pending
queue.
6. At the time program 3.1 nishes, there are two signals pending: 3.3 and
1.1, and program 2.2 has been interrupted. As the main priority of the
pending signal 3.3 is higher than the main priority of the interrupted
c Erich Styger 90
INTRO V1.70
program 2.2, rule 10.6 applies and execution continues with program
3.3.
7. During execution of program a signal with priority 1.2 is raised. As
this signal priority is smaller than the priority of the actual running
program, rule 10.1 is applied.
8. At the exit of program 3.3. we have following pending signals: 1.1, 1.2
and 2.5. But as the program 2.2 has been interrupted, according to
rule 10.4 the signal 2.5 will be still pending.
9. At the time program 2.2 terminates, the signal with priority 2.5 is the
one with the highest priority. Given the rule 10.6 the program ow
will switch to the main program but will be interrupted right away to
execute program 2.5.
10. At termination of program 2.5 signals 1.1 and 1.2 are waiting, and 1.2
will win. Again rule 10.6 is applied and program 1.2 is executed.
11. At the end of program 1.2, only signal 1.1 is pending and will be exe-
cuted as well with rule 10.6.
12. Finally at the end of program 1.1, no other signal is pending, and as
such the main program can continue execution.
10.12 Architectures
As already outlined before, there are many dierent ways and rules how an
interrupt system works. Understanding the interrupt system of a controller
is crucial for mastering the system. And dierences in the interrupt system
and how your application is using it might even be a blocking point if you
need to move your application to another controller if the new controller is
not supporting the interrupt scheme you need for your application. So special
care should be taken into investigating the interrupt system if you evaluate a
new architecture. The way how interrupts are handled greatly impact usage
of the system and impacts as well system performance. Additionally there
might not be an ideal system for every case. But if you could wish a system,
then better ask for maximum exibility for a reasonable price.
In many architectures you will nd either a vector based or a memory
stub based approach. In an vector based system as in gure 10.9 there is a
table of function pointers (vector table) mapped on a memory address.
c Erich Styger 91
INTRO V1.70
Figure 10.9: Interrupt Vector System
c Erich Styger 92
INTRO V1.70
10.13 Problems
10.1. Assume that a device does not return any error code. Draw a state
diagram similar to the one in Figure 10.3. How many states will that
digram have?
10.2. Look at your favorite microcontroller which assumable has an A/D
converter. Identify the states presented in Fig. 10.3.
10.3. Explain why modern high level language compilers can make realtime
synchronization fail.
10.4. You might have noticed that the sprocket hole in Figure 10.2 is smaller
compared to the data holes. What is the reason for this?
10.5. What is the dierence between handshaking and synchronization?
10.6. Consider a system with no real stack and no hardware stack pointer.
What are the consequences of this?
10.7. What is the reason that for interrupts the ISR might need to save/re-
store additional registers?
10.8. Why is usually a special return from interrupt instruction needed at
the end of the ISR?
10.9. Think about the example of a class room environment. For example,
the teacher wants to know if somebody has a question. How would a
polling method work in that environment? How would an interrupt
method work?
10.10. Explain why for the HCS08 the instructions to enable (CLI) and disable
(SEI) are single instructions?
c Erich Styger 93
INTRO V1.70
c Erich Styger 94
Part III
Building Blocks
95
Chapter 11
Introduction
For every system you build, it is desirable to re-use as much as you can
from previous designs. This part of the book is presenting some compo-
nents you likely might use in many designs, and which you could reuse. A
great source for additional building blocks is the book Embedded Systems
Building Blocks[13].
97
INTRO V1.70
c Erich Styger 98
Chapter 12
ANSI-C
12.1 Introduction
According to the Embedded Market Survey[28], the number one language
used for embedded systems is still C. There is no ideal programming language
for every task. Every tool has pros and cons, the same applies to C. And
this does not apply to C only, which has evolved from C89 to C99 and up to
C++.
Some advantages of using C are
It is a compiled language and has a performance advantage compared
to languages which are interpreted or compiled on the y.
The language is close to the hardware. It allows easy interfacing with
low level languages as assembly
There numerous tools available for it
You can easily nd a C compiler for nearly every architecture
Some disadvantages of C are:
The language is not type safe: you can pretty much assign everything
to everything, without to care about types.
The language is not object oriented. Implementing some coding pat-
terns will be more dicult and less elegant
Many things in the language are undened, or implementation dened
1
1
The size of int could be 8bit, 16bit or 32bit or any natural size of the target archi-
tecture.
99
INTRO V1.70
It is assumed that the reader knows the principles of the C programming
language. So the next sections deep dive on certain advanced aspects of the
programming language. The topics presented here are not to the level of
you would need if you want to write a compiler: they are kept as short and
compact as possible.
12.2 Static and Extern
In C there you might hear a lot about the term compilation unit. It is
important to understand that a C compiler has rst a pre-processing phase
where the compiler reads all the les for a *.c le and virtually creates one
big le.
Denition 9. The compilation unit is the nal sequence of tokens built
up by the preprocessor after resolving all preprocessing macros.
To illustrate this with a small example:
/ header . h : t h i s i s my header f i l e /
/ source . c /
#include header . h
/ source . c : t h i s i s my source f i l e /
If you have a le source.c which includes the header le source.h, then
the compilation unit will be the header le plus the source le.
/ source . c /
/ header . h : t h i s i s my header f i l e /
/ source . c : t h i s i s my source f i l e /
In other words: the compiler will replace the include preprocessor directive
with the header le included.
12.3 Storage Class
There are two basic storage classes: static and external. Variables with
static storage class have visibility inside the current scope (function or com-
pilation unit). To mark objects to be static storage you have to use the
static keyword.
stati c i nt myVar ; / t h i s v a r i a b l e i s v i s i b l e onl y i ns i de t h i s
compi l at i on uni t /
c Erich Styger 100
INTRO V1.70
Non-static variables have external storage class and can be references
from another compilation unit.
i nt myExternalVar ; / v a r i a b l e can be r ef er enced from anot her
compi l at i on uni t /
12.4 Declaration and Denition
In C it is important to distinguish between Declaration and Denition.
Denition 10. A Declaration introduces a name and makes it known to
the to the compiler (declares it). A Declaration does not allocate memory.
In C the keyword extern is used for explicit variable declarations. The
following lists declarations:
extern i nt myVari abl e ; / a v a r i a b l e de c l ar at i on /
extern i nt f oo ( void) ; / a f unct i on de c l ar at i on /
Denition 11. The Denition allocates memory for a named object.
Using static for variables is both declaring the variable and dening it.
stati c i nt myVari abl e ; / Var i abl e de c l ar at i on and d e f i ni t i o n .
Memory f or s i z e o f ( i nt ) i s a l l o c a t e d /
While on the other side using extern for a variable is a declaration only:
extern i nt myVari abl e ; / Var i abl e d e f i ni t i o n . Memory f or s i z e o f
( i nt ) i s not a l l o c a t e d /
If you do not specify static, then the storage class is external by default:
i nt myVari abl e ; / a v a r i a b l e d e f i ni t i o n wi t h e x t e r nal s t or age
c l a s s /
12.5 Static and Extern for Functions
Functions can be declared and dened too: the declaration declares their
name and parameters including return value, while a denition denes the
function (code). Not using the static automatically marks the function
with external scope.
c Erich Styger 101
INTRO V1.70
extern void f oo ( void) ; / f unct i on de c l ar at i on wi t h e x t e r nal
scope /
stati c void bar ( i nt ) ; / f unct i on de c l ar at i on wi t h s t a t i c scope
/
stati c void bar ( i nt a ) {
/ f unct i on d e f i ni t i o n and de c l ar at i on /
}
extern void f oo ( void) {
/ e x t e r nal f unct i on de c l ar at i on and d e f i ni t i o n /
}
void f oobar ( void) {
/ e x t e r nal f unct i on de c l ar at i on and d e f i ni t i o n ( not s t a t i c )
/
}
12.6 Source and Header Files
It is good style in programs to have interfaces for externally visible variables
and functions. Here usually the *.c les are referred as Implementation les
and the *.h header les as Interface or Header les. There are many dierent
style guides, and many companies have their own custom ones.
Most common rules are like the following:
Use header les for declarations which shall be known to other imple-
mentation les.
Do not place denitions in header les.
Use extern in header les for variable declarations.
Do not use extern for denitions in the implementation le.
Mark variables with local scope as static.
Guard header les against multiple and possibly recursive inclusion.
Use a common naming scheme (e.g. using a prex) for external vari-
ables and functions.
c Erich Styger 102
INTRO V1.70
12.6.1 Textual Inclusion
The #include is a preprocessor directive, and it means that the included le
will be textually included to build a big le (the compilation unit) to be
processed by the compiler. Thats why guarding with #ifndef ... #define
... #endif is so important.
Consider the following source les:
/ b . h /
extern i nt b ;
/ a . h /
extern i nt a ;
/ m. h /
#include b . h
/ m. c /
#include m. h
#include a . h
void f oo ( void) {}
Preprocessing m.c will then concatenate the les to this compilation unit:
/ m. c /
/ m. h /
/ b . h /
extern i nt b ;
/ a . h /
extern i nt a ;
void f oo ( void) {}
12.6.2 Recursive Includes
Because #include includes the specied header le, it is possible that this
could end up in a recursive inclusion.
Consider the following example:
/ b . h /
#include a . h
/ a . h /
#include b . h
c Erich Styger 103
INTRO V1.70
/ a . c /
#include a . h
Preprocessing a.c will cause a recursive include:
1. a.c includes a.h.
2. a.h includes b.h.
3. b.h includes a.h which again includes b.h which includes a.h and so
on.
Most compiler will report an error, but it is possible that the compiler might
even crash or cause a stack overow.
12.6.3 Guarding
To avoid the recursive include problem, the includes need to be guarded so
they are not included again. For this each header le denes a symbol ( A H
in the example below). If that symbol is not dened yet, this means that the
header le is not included yet:
/ a . h /
#i f ndef A H
#define A H
#include b . h
#endif / A H /
That way a recursive include is not possible any more. But there is still
one problem: as the #ifndef checks on a symbol, that symbol shall not
be used anywhere else, otherwise this approach will not work. Therefore a
common rule is to use a naming as in the example above to build a symbol
like <fileBaseName> H :
Symbols starting with a double underscore are considered as internal
or compiler dened (like TIME ), and typically shall not be dened
by the application sources.
Using the le name in the symbol makes it clear that it belongs to that
given le.
c Erich Styger 104
INTRO V1.70
12.6.4 Self Containment
Having well designed header les and include hierarchies is a very important
aspect of good programming practice. There are a few general but important
rules:
1. Only export in header les what needs to be published. Not more and
not less.
2. Every implementation (*.c) le includes its own header (*.h) le.
3. If a header le has a dependency on another header le, then the header
le includes that dependency header le too.
Consider the following example:
/ l e d . h /
#i f ndef LED H
#define LED H
#define LED On( ) BitIO On ( )
#endif LED H
Here the led.h is having a dependency on another header le (BitIO.h). So
an implementation le who wants to use led.h would need to include BitIO.h
too in order to have this working:
/ main . c /
#include l ed . h
#include BitIO . h / << need t o i ncl ude t h i s because l e d . h i s
usi ng i t /
void main( void) {
LED On( ) ;
}
A much cleaner approach is to have the header le resolving all its own
dependencies:
/ l e d . h /
#i f ndef LED H
#define LED H
#include BitIO . h
#define LED On( ) BitIO On ( )
#endif LED H
That way the user of led.h does not need to care about the dependencies:
/ main . c /
#include l ed . h
c Erich Styger 105
INTRO V1.70
void main( void) {
LED On( ) ;
}
An argument against this self containment is that including header les in
header les might cause unnecessary includes. But this is only a minor issue
compared to the maintenance nightmare if not using self contained header
les.
On the other end: do not include all header les in a single header le
(like platform.h) and then include that header le into every source le:
this is not necessary and creates unneeded dependencies.
12.6.5 Example
Here is an example which summaries the topics of this section:
/ dr i v e r . h /
#i f ndef DRV H
#define DRV H
extern i nt DRV global ;
void DRV Init ( void) ;
#endif / DRV H /
The header le is using #ifndef ... #define ... #endif to guard against
multiple inclusion of the le within the same compilation unit. The variable
declaration in the header le is using extern to clearly mark it as such. The
function declaration is not using extern
2
.
/ dr i v e r . c /
#include dr i ve r . h
i nt DRV global ;
stati c i nt v ;
void DRV Init ( void) {
v = 3;
DRV global = 7;
}
2
Some code guidelines however do recommend to mark external functions in header
les explicitly as extern.
c Erich Styger 106
INTRO V1.70
In above implementation, the driver includes its own header le rst. The
variables are dened and statically initialized if needed.
Finally, the les which need to access the driver functionality is including
the interface le as well. Now lets use our driver from the main module:
/ main . c /
#include dr i ve r . h
void main( void) {
DRV Init ( ) ;
for ( ; ; ) ;
}
If you forget to declare interfaces in a clean way (e.g. you may forget to
include the header le), then in most cases you are able to compile the les
anyway. This is because C allows you to do such things for backward com-
patibility with an older or unclean source base. However, it is recommended
that you congure your compiler in a way that such things are agged as
errors. Many embedded compiler allow you to do this. Because missing to
include a header le is really a programming error, and it needs to be treated
as such.
12.7 Conguration with Macros
Many times you want to keep your sources re-usable across dierent projects
or platforms. Maybe you have a low-end and a high-end version of your
product. You want to turn on or o a functionality depending on the product
you are going to build. Another use case is that during your development you
want to make sure you can turn on and o certain functionality. That way
you can focus on a certain area or simplify debugging. Or you might work on
a rather large binary, and it might be time consuming to iterate through full
compile-link-download-debug cycle. The smaller your application portion is,
the faster you might be able to run one iteration.
A recommended way to do this is that you place macros into a header le
which is included by all modules. Typically you might name such a header
le cong.h or platform.h. It might be as well a good thing to include in
this header le all hardware header les.
/ pl at f or m . h /
#include de r i va t i ve . h / d e r i v a t i v e s p e c i f i c i nf ormat i on /
/ Macros which de f i ne our pl at f orm c a p a b i l i t i e s . Set t o 0 i f
not support ed , 1 ot her wi s e . /
c Erich Styger 107
INTRO V1.70
#define PL HAS LED 1 /!< i f our pl at f or m has LEDs /
In our example we include rst a header le which contains all the things
about the derivative (hardware and port settings). Then we have a list of
PL HAS xxx denes we can turn on or o depending how we congure our
application. These denes itself might depend on other denes too. Like
only enable LEDs on IF we have support for SD cards and we are the high
end product. If you have multiple hardware platforms or boards, you can
list them with additional denes:
/ pl at f or m . h /
/ l i s t of hardware pl at f or ms support ed /
#define MC1321XSRB 1 /!< MC13212 SRB /
#define MC52259TOWER 2 /!< TOWER MCF52259 /
#define PL TARGET BOARD MC1321XSRB /!< Set s t he c ur r e nt l y used
pl at f or m /
Then you could check for the used hardware platform and enable or dis-
able portions of your code:
#i f PL TARGET BOARD==MC1321XSRB
/ s p e c i a l t hi ng s f or t he SRB board /
#e l i f PL TARGET BOARD==MC52259TOWER
/ s p e c i a l t hi ng s f or t he t ower board /
#el se
#e r r or unsupported t ar ge t !
#endif
Consequently you could implement as well a platform.c module which can
provide all the platform specic things.
/ pl at f or m . c /
#include pl at f or m . h
#i f PL HAS LED
#i nc l ude LED. h
#endif
void PL I ni t ( void) {
#i f PL HAS LED
LED Ini t ( ) ;
#endif
}
The PL Init() could then be used to initialize the hardware. Finally you could
use the PL HAS LED macro to enable and disable things in your code. Above
implementation shows a way where the guard has been put on the caller side.
c Erich Styger 108
INTRO V1.70
However, this bloats the source code and might not be preferred. Another
way to do this is to guard things inside the LED.h and LED.c les.
/ LED. h /
#include pl at f or m . h
#i f PL HAS LED
void LED Ini t ( void) ;
#el se
#de f i ne LED Ini t ( ) / not hi ng /
#endif
You need to include the header le (platform.h) in order to use the macros
dened in it. In a similar way we need to guard the implementation in the
implementation le.
/ LED. c /
#include pl at f or m . h
#i f PL HAS LED
void LED Ini t ( void) {
/ i n i t i a l i z e hardware here . . . /
}
#endif / PL HAS LED /
The implementation on the caller side looks straight forward:
/ pl at f or m . c /
#include pl at f or m . h
#include LED. h
void PL I ni t ( void) {
LED Ini t ( ) ;
}
If PL HAS LED is set to zero, then the call to LED Init() will be replaced
with a comment. So using the macros here ensures that if we do not have LED
support enabled, the compiler will be able to handle this without overhead
in the application.
12.8 Macro Comments
In ANSI-C you can not have recursive comments. Consider following source:
void f oo ( void) {
/ do somet hi ng here /
}
c Erich Styger 109
INTRO V1.70
If you want to comment out the whole function, you might think you could
use the /* ... */ around it as following:
/
voi d f oo ( voi d ) {
/ do somet hi ng here /
}
/
Unfortunately such a recursive (nested) comment is not allowed in ANSI-C.
The compiler will complain about it and will ag an error. Luckily you can
use use C++ commenting style for that problem
3
:
// voi d f oo ( voi d ) {
// / do somet hi ng here /
//}
But this is a good solution only if your editor allows you to insert a C++ com-
ment block. Otherwise this might be a lot of editing work. Another possible
solution is to comment things out using the preprocessor #if directive:
#i f 0
void f oo ( void) {
/ do somet hi ng here /
}
#endif
This allows you to simply comment out larger source blocks, even if they
contain C comments. Just change the 0 to 1 and the block is enabled
again. You can use this as well to switch between dierent versions of your
code:
#i f 0
void f oo ( void) {
/ t h i s was my o r i g i na l i mpl ement at i on /
}
#el se
void f oo ( void) {
/ t h i s one i s MUCH b e t t e r ! /
}
#endif
3
If your ANSI-C compiler is instructed to be in strict ANSI-C C89 mode, then C++
comments are not supported.
c Erich Styger 110
INTRO V1.70
12.9 Macro Traps & Pitfalls
Macros are a really nice and powerful thing in C. But as with any power,
if not used well, it might cause many problems. This section cannot not
cover all aspects of macros in C, but should help you get around of common
programming errors.
The C language is like a carving knife: simple, sharp, and
extremely useful in skilled hands. Like any sharp tool, C can
injure people who dont know how to handle it. This paper shows
some of the ways C can injure the unwary, and how to avoid
injury. (Abstract for [11])
The rst thing to remember is that the compiler will run preprocessor
rst. The preprocessor is basically an advanced search and replace engine.
Consider following source:
#define BLUE 0
#define RED 1
#define YELLOW 2
i nt ChangeColor ( i nt c ol or ) {
i f ( c ol or == BLUE) {
return RED;
}
}
The preprocessor will transform this into following:
i nt ChangeColor ( i nt c ol or ) {
i f ( c ol or == 0) {
return 1;
}
}
Note that the preprocessor has replaced BLUE with zero, as dened in the
#dene. This source then will be compiled. The same happens with the
#include preprocessor directive: it will insert the specied le into your
source code to build one large source le (the compilation unit). Using macros
and knowing about them being replaced by the preprocessor makes them a
really handy thing. It allows the compiler to produce ecient code as the
macro evaluation is performed at compile time and not at run time.
Consider following piece of code:
void f oo ( void) {
Wait ( 10) ;
}
c Erich Styger 111
INTRO V1.70
From the source, you are not sure what the argument 10 means. Is it waiting
for 10 seconds? You really cannot tell.
You can use macros to make code readable and to avoid such magic
numbers:
#define DELAY TIME MS 10
void f oo ( void) {
Wait (DELAY TIME MS) ;
}
Or you can enable or disable a feature or functionality:
#define DEBUGME 1
Or you can use it to hide hardware specic things:
#define ENABLE INTERRUPTS asm CLI ;
Macros are very powerful. But it is easy to use them in a wrong way
too. Thats why they are a common source of programming errors. Consider
following example:
#define INCI ( i ) {i nt a=0; i ++;}
void main( void) {
i nt a = 0 , b = 0;
INCI ( a ) ;
INCI ( b) ;
pr i nt f ( a i s now %d , b i s now %d\n , a , b) ;
}
Interestingly output of the program will print:
a is now 0, b is now 1
Why is that? The reason is again the fact that the preprocessor is doing
a textual replacement. Below is is what the compiler will compile as source
code after the preprocessing stage. This makes it now clear why the output
was not the expected one:
void main( void) {
i nt a = 0 , b = 0;
{i nt a=0; a++;};
{i nt a=0; b++;};
pr i nt f ( a i s now %d , b i s now %d\n , a , b) ;
}
c Erich Styger 112
INTRO V1.70
Consider following program:
#define MYDELAY 3
#define PRE DELAY 5
#define POST DELAY 2
#define DELAY PRE DELAY + POST DELAY
return t ot al Del ay ( i nt no f I t e r a t i o ns ) {
return no f I t e r a t i o ns DELAY;
}
void del ay ( void) {
Wait ( t ot al Del ay (MYDELAY) ) ;
}
Surprisingly the function totalDelay() will return 17. To solve the program-
ming error you need to put parenthesis around the DELAY macro content:
#define DELAY (PRE DELAY + POST DELAY)
Because these kind of programming errors can happen so easily, it is even
recommended to put parenthesis around every macro parameter and the
macro value itself:
#define PRE DELAY ( 53)
#define POST DELAY (2+5)
#define DELAY ( (PRE DELAY) + (POST DELAY) )
As it might be really hard for you to see what is going on in your source,
the compiler usually provides a way to produce a preprocessor listing. Using
that listing you can see what the preprocessor is doing.
Another useful (and potentially dangerous) feature of macros is line con-
tinuation: Every macro ends with a new line except there is a line continu-
ation token (\) followed by a new line.
#define MYMACRO( a , b) \
( ( a ) +(b) )
Using line continuation allows you to format macros over several lines and
potentially make it more readable, as in following example:
#define SHIFT LEFT( ) \
asm( LOAD A, s t at us ) ; \
asm( ASR A,#5) ; \
asm( STORE A, s t at us ) ;
c Erich Styger 113
INTRO V1.70
The trap could be if there is anything after the \token: the only thing allowed
is a new line (or a new line + carriage return), otherwise the macro will end
there. It gets nasty if there is a white space after the \which you might not
see in your source editor: you compile that code and strange compiler errors
might occur.
What could help here is
Check in your source that there is nothing hiding after the \
Enable your editor to show white spaces in the editor view too
Produce a preprocessor listing
Luckily many editors (as the C Development Toolkit (CDT) one in eclipse)
automatically remove spaces after a \in the sources.
12.10 String and Concatenation Directives
C oers two special directives to concatenate tokens, or to create a string
from of a token:
String Concatenation: Using the # macro a preprocessor symbol will
be transformed into a string symbol.
Symbol Concatenation: Using the ## macro token two symbols can
be concatenated to build one single symbol.
This is best explained with a simple example:
#define CONCAT( a , b) a##b
#define QUOTEME( a ) #a
void f oo ( void) {
CONCAT( Thi sI s , MyFunction) (QUOTEME( Hel l o ) ) ;
}
This will transform the function foo() into following:
void f oo ( void) {
Thi sIsMyFuncti on ( Hel l o ) ;
}
The # is very useful if you want to print the current source line. The pre-
processor denes the special token LINE which is replaced with a number
token of the actual source line.
You can use this like in the following source to printf() the current
source line number:
c Erich Styger 114
INTRO V1.70
pr i nt f ( l i n e : QUOTEME( LINE ) ) ;
If the printf() is on line 40 of your source le, the preprocessor output
will be something like this:
pr i nt f ( l i n e : 40 ) ;
Now you might wonder if this two double quoted strings are legal? An-
other useful feature in C is that two double quoted strings will be combined
into a single one. So above example even will be combined into following
source:
pr i nt f ( l i n e : 40 ) ;
This is called implicit string concatenation. This can be very useful to avoid
string construction at run time.
c Erich Styger 115
INTRO V1.70
12.11 Problems
12.1. How can you congure your compiler to ag missing declarations?
12.2. List a system/programming language which compiles on the y.
12.3. Name programming languages which are interpreted.
12.4. Give an examples which is implementation dened in ANSI-C.
12.5. What is the compiler option for the HCS08 compiler to ag missing
declarations as errors?
12.6. How can you instruct your compiler to produce a preprocessor listing?
12.7. Try out a piece of code with implicit string concatenation using the
HCS08 compiler. What happens?
c Erich Styger 116
Chapter 13
Position Encoder
13.1 Introduction
For many application types, especially for robotics, it is necessary to get
information about the current position of the system. There are dierent
ways to determine the position:
1. Using a Global Positioning System (GPS) signal for absolute position-
ing.
2. Using accelerometer or gyroscope sensors for relative positioning.
3. Using reference location and landmark information.
4. Using incremental or absolute position information either on a wheel
or on the ground.
In this chapter we are looking at wheel encoders: encoders which are mea-
suring the position of a wheel. Typically they are attached to a rotary shaft
or to wheels to determine position an speed of a robot.
13.2 Absolute Digital Angle Encoder
To determine the position of a wheel, an absolute digital angle encoder as in
Figure 13.1 can be used.
Typically such a disk is attached to the shaft of the wheel. The disk
is divided into sectors: the more sectors, the better the resolution of the
position. Each of the sector generates a digital signal if a sector has some
parts either white or black. That digital signal could be generated by a
contact or using an optical sensor. The digital signal could be sampled and
117
INTRO V1.70
Figure 13.1: Absolute Digital Angle Encoder
Sector Contact 1 Contact 2 Contact 3 Angle
1 o o o 0

to 45

2 o o on 45

to 90

3 o on o 90

to 135

4 o on on 135

to 180

5 on o o 180

to 225

6 on o on 225

to 270

7 on on o 270

to 315

8 on on on 315

to 360

Table 13.1: Digital Value to Angle


processed by a microcontroller. For Figure 13.1 three bits (n) would read the
status of each sector, producing 2
n
or 8 dierent digital values.
Based on the digital value, the angle or position can be determined. The
problem with such an approach is mechanical: it is expected that if the
contacts move from sector 8 (all on) to sector 0 (all o) that all the bits
will switch the same time from on to o. However, because of mechanical
tolerances, some bits might change earlier than others. If the microcontroller
reads the signals frequently enough, it will nd a wrong position information.
13.3 Binary-Reected Gray Code
The problem of multiple bits changing the same time is not only a problem
of such encoders: it is a general problem faced in many systems, including
communication systems. Frank Gray (at that time at Bell Labs) solved that
problem with the Gray Code, patented 1947. He invented a code where two
successive codes only dier by one bit (Hamming distance is 1). The beauty
c Erich Styger 118
INTRO V1.70
of this code is that it uses the same number of bits for the Gray Code and
for the corresponding Binary Code. Another characteristics is that the code
is using Permutation (each code is present only once in the list of codes),
and that it is Cyclic (the last code rolls over to the rst one). The codes of
G
n
are embedded in the rst half of G
n+1
(Figure 13.2).
Figure 13.2: Gray Code Embedded
13.4 Constructing n-Bit Gray Code
Due the fact that a Gray code has the previous Gray code embedded in it,
it is easy to construct a gray code for any number of bits n: It can be built
from the n-1 Gray Code recursively:
1. Reection: Build reverse n-1 list
2. Concatenate the two lists
3. Prex old entries with 0
4. Prex new entries with 1
The construction if Gray Codes starts with the rst Gray Code list (n=1):
0
1
c Erich Styger 119
INTRO V1.70
Then this list gets reected:
0
1
1
0
Next the old entries get a prex of 0, the new entries a prex of 1:
00
01
11
10
Now we have a Gray Code with n=2. The Gray Code for n=3 is constructed
the same way:
000
001
011
010
110
111
101
100
c Erich Styger 120
INTRO V1.70
13.5 Converting Binary Code into Gray
Code
The characteristics of Binary-Reected Gray Code (BRGC) suggest a simple
way to transform a Binary Code into a Gray Code: each bit is inverted if the
next higher bit of the input value is set to one. This can done with a simple
logical shift right (>>) and EXOR () operation (Formula 13.1).
V alue
g
= (V alue
b
>> 1) V alue
b
(13.1)
With Formula 13.1, the Binary Code 0b11101101
b
gets transformed into
the Gray Code 0b10011011
g
.
13.6 Converting Gray Code into Binary
Code
Converting the Gray Code into the corresponding binary code is little more
complicated. One algorithm is to perform a bit add operation:
1. Start with Most Signicant Bit (or Byte) (MSB) bit of the binary code.
That bit becomes the MSB of the Gray Code (Equation 13.2).
2. Then add to each G
x
bit the B
x+1
bit and ignore the carry bit (Equation
13.3. Repeat this for all remaining bits.
B
MSB
= G
MSB
(13.2)
B
x
= B
x+1
+ G
x
(13.3)
Figure 13.3 illustrates the algorithm with converting the Gray Code
0b10011011
g
into the Binary Code 0b11101101
b
.
13.7 Gray Absolute Angle Encoder
Now we can construct a Gray Absolute Angle Encoder which only changes
one bit from one sector to another (Figure 13.4).
While we have solved the problem of changing multiple bits, such an
encoder still needs many bits or contacts for a high resolution.
c Erich Styger 121
INTRO V1.70
1 0 0 1 1 0 1 1
1 1
copy
0 1
0+1
0 1
0+1
1 0
1+1
1 1
1+0
0 1
0+1
1 0
1+1
1 1
1+0
Figure 13.3: Gray to Binary Conversion
Figure 13.4: Gray Absolute Angle Encoder
13.8 Simple Regular Encoder
For many applications, an absolute encoder is not necessary: a regular en-
coder is all what is needed. If we properly count incremental changes from a
starting point, then we only need to know the number of steps, and not the
absolute position. With this, we could use an encoder as in Figure 13.5.
This encoder produces a 1bit Gray code (0 1 0 1 0 etc), and a micropro-
cessor can count the steps. Using a start position and knowing how many
steps the disk has for one revolution, the current sector can be determined.
But there is no way to know from the 1bit code if the wheel is turning forward
or backward.
c Erich Styger 122
INTRO V1.70
Figure 13.5: Regular Encoder Disk
13.9 Quadrature Encoder
To solve the forward/backward problem, the Grey code is extended to two
bits (Figure 13.6).
Figure 13.6: Quadrature Encoder Disk
This encoder provides dierent signal sequences depending if the wheel
is moving forward or backward (depending on the denition of forward and
backward):
Forward: 00 10 11 01
Backward: 00 01 11 10
So depending on if the rst or second bit is leading to the 11 code determines
the direction.
This encoder only provides relative position information. To get a zero
point, an additional signal (single bit) can be added which is generated once
per revolution. This allows the disk to determine the zero position.
c Erich Styger 123
INTRO V1.70
13.9.1 Quadrature Encoder Implementation
The pattern in Figure 13.6 can be scanned with any kind of sensors. In the
case of rotary switches, this can be mechanical contacts. This is suitable for
small speed. But mechanical contacts have the issue of bouncing.
For faster speed non-mechanical sensors are preferred as they are not
aected by mechanical inertia. One solution is to use magnetic hall eect
sensors which transforms the magnetic eld into a sensor signal. Such sensors
are good for a rugged environment as not aected by dirt and dust.
If dust or dirt is not a concern, then optical sensors can be used. The
optical sensors are used to generate the quadrature signal with a disk using
holes. As manufacturing a high density quadrature pattern as in Figure 13.6
is challenging, a simple tick is used: instead of creating a disk with two round
of holes, one round of holes is used, and the sensors are placed as such that
it generates the desired pattern (Figure 13.7).
Figure 13.7: Quadrature Disk with LED
This encoder now produces two sinus-like signals which are shifted by 90

(or one quadrant) (thus the name Quadrature Encoder). The disk produces
a 2bit Gray code which is dierent if the disk is turning forward (00 10 11
01) (Figure 13.8) or backward (00 01 11 10) (Figure 13.9).
Now we have
1. Direction: depending which bit is leading the pattern
2. Position: based on the number of steps. An additional signal can be
generated as a reference to know the zero point of the disk, generated
once per revolution
3. Speed: Can be calculated based on the number of steps per time
c Erich Styger 124
INTRO V1.70
C1
C2
0 1 2 3 4 5 6 7 8 9 10 11 12
Figure 13.8: Quadrature Forward Signal
C1
C2
12 11 10 9 8 7 6 5 4 3 2 1 0
Figure 13.9: Quadrature Backward Signal
Note that such quadrature encoders do not have to be necessarily on a
rotating disk. The same principle can be applied to a linear quadrature
encoder: in this case there is a quadrature pattern e.g. on a rail which then
is read by the sensor.
13.10 Realtime Aspects
With the quadrature encoder, we have two signals from the sensor. Typically
A and B or C1 and C2 are used. With a given speed or revolution per
time, the sensor signal will have a given maximum frequency. There are
several ways how the quadrature signal can be read by a microcontroller:
1. Interrupts: One signal is connected to an interrupt pin to be trig-
gered at the rising and falling (both) edges. There is no need for two
interrupt pins, as it is enough to read the other signal at interrupt time.
Additionally using an input capture (counting) register it is either pos-
sible to count the steps or to measure the duration of a quadrature
pulse. The disadvantage of this approach is that for higher speed the
interrupt might be very high. To the extend that the system does not
respond properly any more at high speed.
2. Sampling: With this method the quadrature signals are connected to
c Erich Styger 125
INTRO V1.70
normal input pins. The microcontroller samples the signal periodically
with a frequency at least twice as the quadrature signal
1
. The disad-
vantage of this method is that if the sampling is not fast enough, steps
might be missed and an error correction needs to be implemented.
3. Hardware: Some microcontroller have dedicated peripherals imple-
mented to perform quadrature decoding in hardware. This allows
higher signal frequencies compared to sampling. Carefully check the
data sheet how the hardware is dealing with decoding errors. Another
approach would be to use a small microcontroller and perform the pro-
cessing of the signal, and then provide access to the information, e.g.
with an I
2
C protocol.
In general, the sampling method is preferred over the interrupt method.
With the interrupt method there is a non-constant system load which makes
testing and reliability of the system a challenge. With the sampling method
the system load is constant which allows better system behavior prediction.
The minimum sampling frequency for an encoder disk as in Figure 13.7
is given by Equation 13.4 with N equals the number of holes in the disk and
R the number of revolutions per second.
f
sampling
> 4 N 2 R (13.4)
This means that for a encoder disk with 100 holes and a revolution of
4000 per minute the processor needs to sample the signals at least every 18
s (Equation 13.5).
t
sampling
<
1s
41002
4000
60
= 18.75s (13.5)
13.11 Quadrature Decoding
Decoding of the quadrature needs to be fast as sampling frequency can be
high. Typically the encoding is performed during an interrupt, both for the
interrupt method and for the sampling method. Therefore the decoding shall
be as fast as possible. One way to perform the decoding is to use a constant
table in Read Only Memory (ROM).
stati c const i nt 8 t QUAD Table [ 4 ] [ 4 ] =
{ / prev new /
{ / c12 c12 /
0 , / 00 00 no change /
1
See Nyquist/Shannon Theorem[10]
c Erich Styger 126
INTRO V1.70
1 , / 00 01 /
1, / 00 10 /
QUADERROR, / 00 11 er r or /
} ,
. . .
}
stati c const i nt8 t QUAD Table [ 4 ] [ 4 ] =
{ / prev new /
{ / c1 c2 c1 c2 /
0 , / 0 0 0 0 no change or mi ssed a s t ep ? /
1 , / 0 0 0 1 /
1, / 0 0 1 0 /
QUADERROR, / 0 0 1 1 error , l o s t i mpul se /
} ,
{ / c1 c2 c1 c2 /
1, / 0 1 0 0 /
0 , / 0 1 0 1 no change or mi ssed a s t ep ?
/
QUADERROR, / 0 1 1 0 error , l o s t i mpul se /
1 / 0 1 1 1 /
} ,
{ / c1 c2 c1 c2 /
1 , / 1 0 0 0 /
QUADERROR, / 1 0 0 1 error , l o s t i mpul se /
0 , / 1 0 1 0 no change or mi ssed a s t ep ?
/
1 / 1 0 1 1 /
} ,
{ / c1 c2 c1 c2 /
QUADERROR, / 1 1 0 0 error , l o s t i mpul se /
1, / 1 1 0 1 /
1 , / 1 1 1 0 /
0 / 1 1 1 1 no change or mi ssed a s t ep ?
/
}
};
The decoder is using a 4x4 table. The rst dimension is the previous
quadrature value (00, 01, 10 or 11), and the second dimension is the current
quadrature value. The table contains the result of the decoding: either 0 (no
step), 1 step forward or -1 as a step backward. The special value QUAD ERROR
indicates an error and can be used for an error counter.
The decoding routine the table to update a global step and error counter:
void QUAD Decode( void) {
i nt8 t new step ;
c Erich Styger 127
INTRO V1.70
uint8 t c12 ; / val ue of t he two sensor i nput /
c12 = ( C1 GetVal ( ) ! =0?2: 0) | ( C2 GetVal ( ) ! =0?1: 0) ;
new step = QUAD Table [ QUAD l ast quadrature val ue ] [ c12 ] ;
i f ( new step==QUADERROR) { / er r or case /
QUAD errors++;
}
QUAD l ast quadrature val ue = c12 ;
QUAD currPos += new step ;
}
Building the c12 can be time consuming. It is recommended that the bits
are organized as such that the combined value can be easily calculated.
13.11.1 Error Correction
The other consideration is the error correction: QUAD ERROR means that we
have missed at least a step. Knowing if we are moving forward or backward
it would be possible to at least compensate for the error.
Another approach would be to extend the quadrature decoding table with
an additional dimension: the quadrature value before the previous value:
stati c const i nt8 t QUAD Table [ 4 ] [ 4 ] [ 4 ] =
{ / pprev prev new /
{ / c12 c12 c12 , c1 l e adi ng i s backward , c2
l e adi ng i s f orward /
{
0 , / 00 00 00 /
1 , / 00 00 01 /
1, / 00 00 10 /
QUADERROR, / 00 00 11 error , l o s t i mpul se /
} ,
{
1, / 00 01 00 /
0 , / 00 01 01 /
2 , / 00 01 10 l o s t i mpul se , c or r e c t er r or
/
1 , / 00 01 11 /
} ,
{
1 , / 00 10 00 /
2, / 00 10 01 l o s t i mpul se , c or r e c t er r or
/
0 , / 00 10 10 /
1, / 00 10 11 /
} ,
{
c Erich Styger 128
INTRO V1.70
QUADERROR, / 00 11 00 er r or /
1, / 00 11 01 /
1 , / 00 11 10 /
0 , / 00 11 11 /
}
} ,
{ / c12 c12 c12 /
{
0 , / 01 00 00 /
1 , / 01 00 01 /
1, / 01 00 10 /
2, / 01 00 11 l o s t i mpul se , c or r e c t er r or
/
} ,
{
1, / 01 01 00 /
0 , / 01 01 01 /
QUADERROR, / 01 01 10 er r or /
1 , / 01 01 11 /
} ,
{
1 , / 01 10 00 /
QUADERROR, / 01 10 01 er r or /
0 , / 01 10 10 /
1, / 01 10 11 /
} ,
{
2 , / 01 11 00 l o s t i mpul se , c or r e c t er r or
/
1, / 01 11 01 /
1 , / 01 11 10 /
0 , / 01 11 11 /
}
} ,
{ / c12 c12 c12 /
{
0 , / 10 00 00 /
1 , / 10 00 01 /
1, / 10 00 10 /
2 , / 10 00 11 l o s t i mpul se , c or r e c t er r or
/
} ,
{
1, / 10 01 00 /
0 , / 10 01 01 /
QUADERROR, / 10 01 10 er r or /
1 , / 10 01 11 /
} ,
{
c Erich Styger 129
INTRO V1.70
1 , / 10 10 00 /
QUADERROR, / 10 10 01 er r or /
0 , / 10 10 10 /
1, / 10 10 11 /
} ,
{
2, / 10 11 00 l o s t i mpul se , c or r e c t er r or
/
1, / 10 11 01 /
1 , / 10 11 10 /
0 , / 10 11 11 /
}
} ,
{ / c12 c12 c12 /
{
0 , / 11 00 00 /
1 , / 11 00 01 /
1, / 11 00 10 /
QUADERROR, / 11 00 11 er r or /
} ,
{
1, / 11 01 00 /
0 , / 11 01 01 /
2, / 11 01 10 l o s t i mpul se , c or r e c t er r or
/
1 , / 11 01 11 /
} ,
{
1 , / 11 10 00 /
2 , / 11 10 01 l o s t i mpul se , c or r e c t er r or
/
0 , / 11 10 10 /
1, / 11 10 11 /
} ,
{
QUADERROR, / 11 11 00 er r or /
1, / 11 11 01 /
1 , / 11 11 10 /
0 , / 11 11 11 /
}
}
};
The error correction is using history information to compensate lost signals:
The table looks at the current and previous value if an error occurred. If an
error occurred (more than one bit changed), then the pprev information is
used for error correction.
Using error correction has an impact on the decoding routine too:
c Erich Styger 130
INTRO V1.70
#i f QUAD USE ERROR CORRECTION
new step = QUAD Table [ QUAD prevl ast quadrature val ue ] [
QUAD l ast quadrature val ue ] [ c12 ] ;
QUAD prevl ast quadrature val ue = QUAD l ast quadrature val ue ;
/ new st ep >1 | | new st ep <1: error , wi t h er r or c or r e c t i on i n
new st ep /
#el se
new step = QUAD Table [ QUAD l ast quadrature val ue ] [ c12 ] ;
#endif
The problem with the error correction approach is that errors typically occur
if sampling is not fast enough. But adding error correction increases the com-
putational load, so itself might result in slower performance and sampling.
13.12 Summary
Digital position encoders are very useful to estimate position in for moving
objects. Absolute digital angle encoder with a normal binary code have the
problem of multiple bits changing from one sector to another. This problem
can be solved with a Gray Code (BRGC). Gray Codes can be converted
into Binary Codes and back again. Incremental position encoders only need
two signals and a microcontroller reading the signals and decoding it into
steps. Dedicated hardware, interrupts or sampling can be used to process
the information.The step information can be used to determine position and
speed. If using sampling, it is important to read the signal with at least twice
the signal frequency (Nyquist/Shannon Sampling Theorem). Decoding of the
quadrature signal can be done with a table, using both the previous and the
current sensor values as index. Using error correction is useful in a noisy
environment, but requires more time during processing. As such, using error
correction if not able to sample fast enough will not help much.
c Erich Styger 131
INTRO V1.70
13.13 Problems
13.1. What is the fundamental problem of an absolute wheel position en-
coder?
13.2. What would be the advantage of using an input capture or interrupt
for the quadrature signal? What would be the disadvantage and why?
13.3. Why it could be a good idea to connect C1 and C2 signals to a bit 0
and bit 1 of a port??
13.4. Try the encoders with the error correction enabled. When will you get
errors in your decoding/counting algorithm??
13.5. Compare the decoder with error correction and the one without. At
which speed the one without error correction will start producing er-
rors? At which speed the one with error correction starts producing
errors? ?
13.6. Why do we need to sample the signal with at least twice of the signal
frequency? ?
c Erich Styger 132
Chapter 14
ANSI-C++
14.1 Introduction
OOP is getting more and more attention over the years. The Embedded
Market Survey[28] has one question about the next embedded project pro-
gramming language. The study shows that about 60% are going to use C,
and about 25% will use C++[28]. While C is used quite largely in this course,
it it worthwhile to spend some thoughts about using C++.
This chapter is not a full introduction to C++: it just shows some of the
interesting features and functionality for embedded systems programming,
especially for smaller systems. A recommended reading about more of the
details of C++ are the books from Stroustrup[26][27][3] and Plauger[15].
The goals in this document are following:
Introduction to C++
Knowing the main dierences between C and C++
Understand the impacts of using a language like C++
Using C++ for Embedded
Choosing the right tool to solve a problem
14.2 What is NOT Covered
C++ is a language far more complex than ANSI-C
1
, and it might need years
of practice to master it. Many even may say the language is over-complicated.
1
We discuss here mostly C89, which is supported by the Freescale HCS08 compiler.
C99 has many improvements compared to C89.
133
INTRO V1.70
Following topics will not be covered here, as they go beyond what we can
cover in a short amount of time:
Exception handling
Virtual functions
Virtual base classes
Pointer to member
Templates and Standard Template Library
C++ Standard Library
14.3 From C to C++
C++ has been evolved from C, and as such C++ is pretty much compatible
with C, at least from the syntax side. This does not mean that you can
compile normal C code just as C++: the reality is that you very likely need
to change and adopt sources. In the following sections we go trough many of
the new things introduced with C++.
14.3.1 Enabling C++ Compilation
As C++ has been evolved out of C, usually a C++ compilers is by default
a normal C compiler. As such, you can compile your C sources as well with
a C++ compiler in C mode. If you want to compile a le as C++, every
compiler vendor does its own thing
2
: Many have a special compiler option
(e.g. -C++) to enable the C++ mode. Many do as well check for the le
extensions, e.g. *.cpp, *.cxx and *.hh are treated as C++ les.
14.3.2 Additional Keywords
C++ adds new keywords to the language. The most important ones are:
1. class
2. bool
3. delete
2
You need to check the documentation of your compiler vendor.
c Erich Styger 134
INTRO V1.70
4. friend
5. inline
6. new
7. operator
8. private
9. protected
10. public
11. template
12. this
13. throw
14. catch
15. virtual
This means that any legacy C code cannot use these new C++ keywords,
as otherwise the C++ compiler will complain.
14.3.3 Comments
In C, you only could use /* with */ for comments:
/ t h i s i s a comment /
However, you are not allowed to nest comments:
/ t h i s i s a comment / wi t h a nes t ed comment / /
Thats why you see in many cases #if instead to nest comments:
#i f 0
t hi s i s a comment / wi t h a nes t ed comment /
#endif
With C++ you can use the \\ which puts everything into comment until the
end of the line:
// t h i s i s a comment / wi t h a nes t ed comment /
Because the C++ comments are so handy, most C compilers support
them as well.
c Erich Styger 135
INTRO V1.70
14.3.4 Predened Macro cplusplus
A C++ compiler denes in C++ mode the standard macro cplusplus.
That way it is possible to to dierent things either for C or C++.
#i f def c pl us pl us
// ok , we are compi l i ng as C++
#el se
/ ot herwi se , t h i s i s compi l i ng as C /
#endif
14.3.5 Void Or No Parameters
If you do not specify any parameters in C, then this means the number of
parameters is unknown: it could be any number. In C++ not specifying
any parameter means no parameters. C++ has cleaned this up, especially
because for function overloading the compiler and linker need to know the
number and type of the arguments.
void f oo ( ) ;
/ C: unknown number of paramet ers /
// C++: same as voi d f oo ( voi d )
As a consequence, specify always void for your C function arguments for
compatibility reasons.
14.3.6 Return Values
One of the advantages of C++ is that it catches some common coding errors.
In C it is legal to leave a function having a return value without a return
statement.
i nt f oo ( void) {
i nt i ;
i =3;
} / C l e g al , C++ er r or : ret urn r equi r ed . /
14.3.7 Implicit Parameter declaration
In C it is possible to call a function without having a prototype for it. As an
example, you can call the function bar() without having a declaration (e.g.
in a header le):
c Erich Styger 136
INTRO V1.70
void f oo ( void) {
bar ( 3 . 0 ) ; / not decl ar ed /
/ ==> ok i n C /
// ==> er r or i n C++
}
For implicit parameter declaration, the C compiler has to assume that
a function denition exists with the actual parameters, returning int.
For above example the compiler has to assume a call to a function int
bar(double); which might or might not be correct. If the compiler is not
correct then a corrupted stack is likely the case, as the caller might push
more arguments onto the stack than the callee is removing. With C++ the
function name can be used for methods having dierent argument (e.g. void
bar(int) and void bar(long)), thus it is critical for the compiler to match
the right callee.
14.3.8 Enumerations
In C, all enumerations (enum) are of type int. This means that you can use
enumerations like any int typed variable. This means you can e.g. perform
calculations with it:
typedef enum {RED, GREEN, BLUE} Col ors ;
i nt c ol or = RED;
/ C: RED i s l i k e an i nt /
// C++: Error
i nt mixed = GREEN+BLUE;
/ C: l i k e an i nt c al c ul at i on ,
mixed wi l l have val ue 3. /
// C++: Error
In C++, enumerations have their own type. The compiler will check if
the types are compatible. As a consequence: sizeof of an enum type in C
will return sizeof(int) for all enumerations
3
, while in C++ the size of enu-
merations might be dierent. However, it is possible to perform operations
on enumerations using C++ overloading.
3
Some compilers have the ability to reduce the type size of an enum, e.g. to the size of
a byte.
c Erich Styger 137
INTRO V1.70
14.3.9 Variable Declaration
In C89, you can write a variable declaration at the beginning of a scope
4
. A
scope starts with { and ends with }.
void f oo ( void)
{ / scope s t a r t /
i nt i ;
{ / anot her scope /
i nt j ;
} / anot her scope end /
for ( i =0; i <5; i ++)
{ / f or scope s t a r t /
i nt k ;
} / f or scope end /
} / scope end /
In C++ you can put variable declarations pretty much everywhere
5
:
void myCppFunction( i nt j ) {
j ++;
i nt k ;
for ( i nt i =0; i <5; i ++) {
}
}
14.3.10 Constants
In C, if you want to use constant (const, non-variable) value in your code,
you have to use the #define directive:
#define MYCONST 3
i nt f oo ( void) {
return MYCONST;
}
You could have written this as well as:
const i nt MyConst = 3;
i nt f oo ( void) {
return MyConst ;
4
C99 has removed that limitation.
5
Forgetting about this is one of the most common errors if you move C++ code to C:
the compiler will badly complain about it.
c Erich Styger 138
INTRO V1.70
}
But in C there is no guarantee that not a (constant) value is used: if the
compiler is smart enough (and has the information), he might produce the
same code as for the #define version.
In C++, a constant value is always used instead. Additionally you need
to initialize the constants always, while in C you dont have to:
#i f def c pl us pl us
const i nt MyConst = 3;
// C++ r e q ui r e s i n i t i a l i z a t i o n
#el se
const i nt MyConst ;
/ l e g a l f or ANSIC /
#endif
14.3.11 Constant Object Linkage
In C++, constant objects without extern have static linkage. Objects with
static linkage cannot be used in other modules. To have external linkage for
C++ constant objects, they have to be declared as extern[3, page 108].
#i f def c pl us pl us
const i nt i = 3; // d e f i ni t i o n and s t a t i c l i nk ag e
extern const i nt j ; // de c l ar at i on
const i nt j = 4; // d e f i ni t i o n and e x t e r nal l i nk ag e
stati c const i nt k = 3; // d e f i ni t i o n and s t a t i c l i nk ag e
#el se
const i nt i = 3; / d e f i ni t i o n and e x t e r nal l i nk ag e /
extern const i nt j ; / de c l ar at i on /
const i nt j = 4; / d e f i ni t i o n and e x t e r nal l i nk ag e /
stati c const i nt k = 3; // d e f i ni t i o n and s t a t i c l i nk ag e
#endif
14.3.12 New and Delete
In C you need to use malloc() or your own memory allocation routine to
reserve memory. A function named free() is used to release the memory al-
located previously with malloc(): A typical malloc() and free() interface
usually look like this:
void mal l oc ( i nt nof Bytes ) ;
void f r e e ( void memory) ;
c Erich Styger 139
INTRO V1.70
To allocate a memory block with 3 elements of int, you would use it like
this:
i nt p ; / my poi nt er /
p = ( i nt ) mal l oc ( si zeof ( i nt ) 3) ; / not e t he cas t of t he voi d
poi nt er t o an i nt poi nt er /
/ now i n i t i a l i z e t he memory we r e c e i v e d /
p [ 0 ] = 0;
p [ 1 ] = 1;
p [ 2 ] = 2;
. . .
f r e e ( p) ; / f r e e memory /
There is nothing wrong about using malloc() and free(). But C++
oers new and delete which do the same
6
.
There is another aspect which is causing (although rather small) overhead:
the new() and delete() for arrays:
long ar r = new long [ 5 ] ;
. . .
delete [ ] ar r ;
As the delete operation cannot know how many elements the array has, the
system needs to track the number of elements. This requires some overhead,
and should be considered if you are allocating many small array items.
14.3.13 Namespace
In C you need to be careful not to produce name conicts. This is especially a
problem if you are using libraries (provided by somebody else) which denes
symbols
7
in the header les: if such symbol is used, and you use the same
symbol in your application, the compiler will complain about it.
You might have following in a library header le:
/ l i b . h /
void Error ( i nt errNo ) ;
and in your own application you have:
/ app . h /
extern i nt Error ; / ac t ual er r or number /
6
There is one dierence, however: new() and delete() can cause an exception.
7
Symbols could be denes, variables or function names.
c Erich Styger 140
INTRO V1.70
Now you have two incompatible symbols with the same name, and your build
system will complain about it.
In C++ you can use a namespace to create a new scope. Within the
namespace, the names can be used like normal. To refer to an object inside
a name space from the outside, the namespace name must be qualied. In
our example, this would be MyNameSpace::Error.
namespace MyNameSpace {
extern i nt Error ; // ac t ual er r or number
}
. . .
MyNameSpace : : Error = 0;
Adding using to the namespace keyword makes it possible to avoid the
MyNameSpace:: part:
namespace MyNameSpace {
extern i nt Error ; // ac t ual er r or number
}
using namespace MyNameSpace ;
. . .
Error = 0;
Without providing a name, you can create as well a unnamed namespace.
namespace {
extern i nt Error ; // ac t ual er r or number
}
However, you cannot use the using keyword for an unnamed namespace.
14.3.14 Mixing C and C++: C Linkage and Name En-
coding
In C the linker will match functions with the same name, regardless if the
arguments or return value do match. If you have in C an implementation
like this:
void f oo ( i nt a , f l oat b) ;
and if you call it like this:
i = f oo ( 3 . 5 ) ;
c Erich Styger 141
INTRO V1.70
then the C linker has no way to detect the mismatch, as there is a reference
to the symbol foo without any further information. Thats why it is so im-
portant to enable in compilers the check for implicit parameter declaration
8
.
In C++, the compiler uses a special name encoding to encode the ar-
gument types (not the return type). As such, you can have multiple (over-
loaded) functions with the same name, but dierent argument types. The
dierent argument types will result in dierent name encoding:
extern void f oo ( void) ; // encoded as f oo Fv
extern void f oo ( i nt ) ; // encoded as f oo Fi
extern void f oo ( const char ) ; // encoded as foo FPCc
If you mix now C and C++ code, then the compiler needs to know which
encoding shall be used. To tell the compiler, the extern "C" has to be used.
In order to mark a function as implemented in C in the header le, use
something like this:
extern C void f oo ( void) ;
and then call it from your C++ le like normally (do not forget to include
the header le):
void bar ( void) {
f oo ( ) ; / c a l l s t he C f unct i on f oo ( ) , as i t has been marked
wi t h ext er n C /
}
Alternatively, you can mark multiple C functions as C enclosed in this:
extern C {
void f oo ( void) ;
void f ooBar ( void) ;
}
The same thing applies if you want to call a function in a C++ module
from a C module: you need to ensure that the C naming is used. The
following example illustrates this:
/ t e s t . h /
#i f ndef TEST H
#define TEST H
#i f def c pl us pl us
extern C {
#endif
void Test ( void) ;
8
Most compiler do support such an option, but usually it is not enabled.
c Erich Styger 142
INTRO V1.70
#i f def c pl us pl us
}
#endif
#endif / TEST H /
/ t e s t . cpp /
#include t e s t . h
void Test ( void) { }
/ main . cc /
#include t e s t . h
void main( void) {
Test ( ) ;
}
14.4 C++ Features
This section goes through some of the major features of the C++ language.
It is assumed that the reader has good knowledge of the C language
9
.
14.4.1 Classes
One important aspect of OOP is the concept of a class. A class is a way to
create user-dened data types in C++, similar to struct in C. In C a struct
has a set of data members, while a class in C++ includes as well a set of
operations that can be performed on the class. Operations are usually called
member functions too.
struct A {
i nt i ; // dat a member
void f oo ( void) {} // operat i on , member f unct i on
}
A a ; // ob j e c t a of c l a s s t ype A
void main( void) {
a . i = 5; // acces s t o dat a member
a . f oo ( ) ; // c a l l member f unct i on
9
It is very dicult to introduce the C++ language in a very linear way: some terms or
keywords will be used before they fully can be explained. They will be explained in more
details later in the tutorial.
c Erich Styger 143
INTRO V1.70
}
Class and Struct
In C++ a class type can be created with the keywords class and struct
10
.
The dierence between using the keywords class and struct lies only in
the default access control
11
of the members. Structures members and base
classes are public by default. Class members are private by default.
struct A {
i nt i ; // i i s a pub l i c member of A
};
cl ass B {
i nt i ; // i s a pr i v at e member of B
};
As such, you can either use class or struct in C++: the only dierence
is the access control.
Member Functions and this
Member functions are methods or operations which can be performed on a
class object, or functions which are declared or dened within a class scope.
In a non-static member function, the keyword this is a pointer to the object
for which the function is called.
cl ass A {
i nt i ;
void f ( i nt j ) {
this>i=j ;
}
};
It is like this is passed as hidden pointer argument to the class, so in C
you would something equivalent with this:
typedef struct {
i nt i ;
} A;
void f (A t hi s , i nt j ) {
t hi s >i=j ;
10
It is possible as well to create a class type using the keyword union.
11
Access Control is handled in details later in this document.
c Erich Styger 144
INTRO V1.70
}
Inlining
Inlining in C is subject of compiler implementation. In C++ you have the
inline keyword available. Using inline tells the compiler that the function
body shall be inlined:
i nl i ne void f oo ( i nt ) ;
Still, there is no guarantee that the function really will be inlined. As many C
compilers do not support the inline keyword, the usually dene an ANSI-C
compliant way using #pragma preprocessing directives:
#pragma INLINE
void f oo ( i nt a ) {}
You can use inline as well for member functions, as in the example
below. Another way to use implicit inlining is writing the function body into
the class declaration:
struct A {
i nl i ne i nt f oo ( void) ; // e x p l i c i t i nl i ne r e q ue s t
void g ( void) { / . . . / } // i mp l i c i t i nl i ne
};
i nt A: : f oo ( void) { return 3; }
Notice that the body of g() is implemented inside the class A. Member
functions with only a few lines of code are usually dened like this. Such
a member function is called an inline member function. It is possible as
well to separate the declaration from the implementation, outside the class
declaration. You must qualify the member function name using the scope
resolution (::) operator:
Notice the inline in the class declaration: you either have to use it for
the declaration (inline int foo(void);) or for the denition (inline int
A::foo(void) ...);
Base Class
A class can be derived from another class, which is then called a base class
of the derived class (Figure 14.1). The derived class inherits the properties of
its base classes, including its data members and member functions. In addi-
tion, the derived class can override virtual functions of its bases and declare
c Erich Styger 145
INTRO V1.70
additional data members, functions, and so on. Access to class members is
checked for ambiguity by the compiler.
Base Class
Derived
Class
Figure 14.1: Base class with derived class
struct A {
i nt i ;
}; // A cont ai ns member i .
struct B : A {
i nt j ;
}; // B cont ai ns members i ( i nhe r i t e d from A) and j .
void main( void) {
A a ;
B b ;
a . i =5;
b . i =10;
b . j =15;
}
Static Members
A data or function member of a class may be declared static in the class
declaration. There is only one copy of a static data member, shared by all
objects of the class in a program.
cl ass A {
public :
stati c i nt s ;
i nt i ;
};
i nt A: : s ; // I ns t a nt i a t i o n of t he s t a t i c member
c Erich Styger 146
INTRO V1.70
void f ( void) {
A a ;
a . i =5; // ok
a . s =10; // ok
A: : i =15; // er r or
A: : s =20; // ok
}
Notice the instantiation of the the static member which is required.
14.4.2 Member Access Control
Member access determines if a class member is accessible. Suppose m is a
member of class A. Class member m can be declared to have one of the
following levels of accessibility:
Private: m can be used only by the members and friends of class A.
Protected: m can be used only by the members and friends of class A,
and the members and friends of classes derived from class A.
Public: m can be used from anywhere without access restriction.
cl ass A {
private : i nt i ;
protected : i nt j ;
public : i nt k ;
void f ( void) ;
};
cl ass B : A { void f ( void) ; };
void A: : f ( void) {
this>i =5; // ok , pr i v at e member acces s ed by
// member f unct i on of same c l a s s
this>j =5; // ok , pr ot e c t e d member acces s ed by
// member f unct i on of same c l a s s
this>k=5; // ok , pub l i c member
}
void B: : f ( void) {
this>i =10; // error , pr i v at e member acces s ed by
// member f unct i on of d i f f e r e n t c l a s s
this>j =10; // ok , pr ot e c t e d member acces s ed by
// member f unct i on of c l a s s der i ved
this>k=10; // ok , pub l i c member
c Erich Styger 147
INTRO V1.70
}
void main( void) {
A a ;
a . i =15; // error , pr i v at e member acces s ed out s i de
a . j =15; // error , pr ot e c t e d member acces s ed out s i de
a . k=15; // ok , pub l i c member
}
Base Class Access Control
Those access speciers can also be applied to base classes.
Private Base Class: If the base class is private, the public and
protected members of the base class are private in the derived class,
the private members cannot be accessed in the derived class (Figure
14.2).
private protected public
derived as private
private private
Figure 14.2: Derived as Private
Protected Base Class: The public and protected members of the base
class are protected in the derived class, the private members cannot be
accessed in the derived class (Figure 14.3).
Public Base Class: The public members of the base class are public in
the derived class, the protected members of the base class are protected
in the derived class, the private members cannot be accessed in the
derived class (Figure 14.4).
cl ass A {
public : i nt i ;
};
cl ass B {
public : i nt j ;
c Erich Styger 148
INTRO V1.70
private protected public
derived as protected
protected protected
Figure 14.3: Derived as Protected
private protected public
derived as public
protected public
Figure 14.4: Derived as Public
};
cl ass C : public A, private B {
i nt k ;
};
void main( void) {
C c ;
c . i =5; // ok
c . j =10; // er r or
}
Friends
A friend of a class is a function that is not a member of the class but
permitted to use the private and protected member names from the class.
cl ass A {
i nt i ;
friend void f ( void) ; // f ( ) i s a f r i e nd of A
friend cl ass X; // a l l member f unc t i ons of X are f r i e nds of A
};
c Erich Styger 149
INTRO V1.70
cl ass X {
void f ( void) {
A a ;
a . i =10; // ok
}
};
void f ( void) {
A a ;
a . i =5; // ok
}
14.4.3 Special Member Functions
With C++ there are following special member functions:
Constructor: called during creation of an object.
Destructor: called during deletion of an object.
Conversions: called to convert an object into another one.
Constructors
The constructor of a class is called whenever an object of that class is created:
Constructors can be overloaded (the one without parameters is called
default constructor).
Global class objects call their constructors at the time all global objects
get initialized.
struct A {
A( void) { / f unct i on body / } // Def aul t c t r
A( i nt i ) { / f unct i on body / }
A(A &a ) { / f unct i on body / } // Copy c t r
};
struct B : A {
B( void) : A( 5) { / . . . / } // Def aul t c t r
};
void f ( void) {
A a ; // c a l l s A: : A( voi d )
A a2 ( 5) ; // c a l l s A: : A( i nt i )
B b ; // c a l l s B: : B( voi d ) , t hat c a l l s A: : A( i nt i )
c Erich Styger 150
INTRO V1.70
}
Destructors
The destructor of a class is called before an object of that class is destroyed.
Following tasks are performed:
Execute function body of destructor
Call destructors of base classes and member class objects (in reverse
declaration order)
Notes:
Destructors can not be overloaded.
Global class objects call their destructors at the end of the program
(after the main() routine nished)
struct A {
A( void) { / f unct i on body / }
};
struct B : A {
B( void) { / f unct i on body / }
};
void f ( void) {
A a ;
B b ;
}
// a ob j e c t c a l l s A: : A( voi d )
// b ob j e c t c a l l s B: : B( voi d ) , t hat c a l l s A: : A( voi d )
Conversion by Constructor
A constructor accepting a single argument species a conversion from its
argument type to the type of its class.
cl ass A {
public :
A( i nt ) ;
};
void main( void) {
c Erich Styger 151
INTRO V1.70
A a = 1; // a = A(1)
}
Conversion Functions
Conversion operators specify conversions from the owner class type to the
type specied.
cl ass A {
operator char ( ) ; // de f i ne s a convers i on from A t o char
};
Compiler Generated Functions
With C++, the compiler has to generate several special functions:
Default constructor: The default constructor is generated, if no con-
structor is declared by the programmer, and if there is a base or member
class having a constructor or there are virtual base classes or virtual
member functions.
Copy constructor: The copy constructor is generated, if no copy con-
structor is declared by the programmer.
Destructor: The default destructor is generated, if no destructor is
declared by the programmer, and if there is a base or member class
having a destructor.
Assignment operator: The assignment operator is generated, if no as-
signment operator is declared by the programmer.
Sometimes such special member functions are generated by the compiler in
several compilation units, e.g if there is a class declaration in a header le
included in several compilation units. A normal linker treats them as dierent
static linkage functions, which is not ecient (the code of the same function
exists more than once in the executable). A smart linker can merge the same
compiler generated function from several compilation units into one function.
14.4.4 Overloading
Function Overloading
Overloading allows multiple functions with the same name to be dened
provided their argument lists dier suciently for calls to be resolved.
c Erich Styger 152
INTRO V1.70
void f ( i nt i ) ;
void f ( void) ;
void g ( void) {
f ( 5) ; // c a l l f ( i nt i )
f ( ) ; // c a l l f ( voi d )
}
Operator Overloading
By overloading operators, the programmer can redene the meaning of most
C++ operators when at least one operand is a class object.
cl ass X {
X operator + ( i nt ) ;
};
void g (X x) {
X a ;
a=x+10; // c a l l X: : operat or + ( i nt )
}
Default Arguments
If an expression is specied in an argument declaration this expression is
used as a default argument. All subsequent arguments must have default
arguments supplied in this or previous declarations of this function. Default
arguments will be used in calls where trailing arguments are missing. A
default argument cannot be redened by a later declaration (not even to the
same value).
The declaration
poi nt ( i nt = 3 , i nt = 4) ;
declares a function, that can be called in any of these ways:
poi nt ( 1 , 2) ;
poi nt ( 1) ; // e q ui v al e nt t o poi nt ( 1 , 4) ;
poi nt ( ) ; // e q ui v al e nt t o poi nt (3 , 4) ;
Operator new and delete
The new operator attempts to create an object of the type specied. If the
type is a class having a constructor, the object can be created only if suitable
c Erich Styger 153
INTRO V1.70
arguments are provided or if the class has a default constructor. First, the
new operator is called, then the constructor is called, if necessary. If the
type is an array of class, the default constructor of each element is called.
Therefore the compiler generates a loop going through all array elements.
cl ass A {
/ . . . /
A( ) ;
A( int , i nt ) ;
};
void f ( ) {
char cp = new char ; // cr eat e a char ob j e c t
i nt i p = new i nt [ 3 ] ; // cr eat e an array of i nt ob j e c t
A ap = new A( 4 , 3) ; // cr eat e a A ob j e c t wi t h Const ruct or
// c a l l t o A: : A( i nt , i nt )
A aap = new A[ 3 ] ; // cr eat e an array of A ob j e c t wi t h
// d e f a u l t Const ruct or c a l l f or each
el ement
}
The new operator can be dened globally or within a class. The global
declaration is already done internally in the compiler. The member operator
new is a static member.
void operator new( s i z e t s i z e ) {
}
cl ass A {
void operator new( s i z e t s i z e ) {}
void operator new( s i z e t s i z e , i nt f l a g ) {}
};
void f ( void) {
A a = new( 10) A; // c a l l s A: : operat or new( s i z e t , i nt ) wi t h
parameter f l a g =10
A a2 = new A; // c a l l s A: : operat or new( s i z e t )
}
The delete operator destroys an object created by the new operator. If
the type of the object is a class having a destructor, the destructor has to be
called before the call of the delete operator. If the type is an array of class
having a destructor, the destructor of each element must be called. Therefore
the compiler generates a loop going through all array elements. The delete
operator can be dened globally or within a class.
cl ass A {
/ . . . /
c Erich Styger 154
INTRO V1.70
A( ) ;
};
void f ( char cp , i nt i p , A ap , A aap ) {
delete cp ; // ok
delete [ ] cp ; // ok
delete [ 3 ] cp ; // ok , i gnor i ng number of el ement s
delete i p ; // ok
delete [ ] i p ; // ok
delete [ 3 ] i p ; // ok , i gnor i ng number of el ement s
delete ap ; // ok , c a l l s once t he de s t r uc t or
delete [ ] ap ; // error , don t know , how many Des t ruct or c a l l s
delete [ 3 ] ap ; // ok , c a l l s 3 t i mes t he de s t r uc t or
}
The delete operator can be dened globally or within a class. The global
declaration is already done internally in the compiler. The member operator
delete is a static member.
void operator delete ( void p) {}
cl ass A {
public :
void operator delete ( void p) {}
};
cl ass B {
public :
void operator delete ( void p , s i z e t s i z e ) {}
};
void f ( ) {
B b ;
delete b ; // c a l l s B: : operat or d e l e t e ( voi d , s i z e t )
// wi t h s i z e=s i z e o f (B)
}
The global new and delete operators are implemented in the C++ library.
Thus a program calling new and delete needs to be linked with the ap-
propriate library, otherwise those operators must be implemented by the
programmer himself. If you dont provide any implementation of new and
delete to your program, the compiler wont complain, because there are
internal declarations of the global operators. But the linker will complain, if
it does not nd any implementation.
c Erich Styger 155
INTRO V1.70
Compiler Generated Functions
The compiler has to create default constructors if the programmer does not
provide his own implementation. Consider following class:
cl ass A {}
Although this class is empty, it still will allocate some space in memory
12
in order the address of the object can be taken. Beside of this a set of default
functions will be created:
A: : A( ) {} // d e f a u l t cons t r uct or
A: : A( const A&){} // copy cons t r uct or
A& A: : operator ( const A&) // assi gnment operat or
A: : A( ) {} // de s t r uc t or
14.5 The C++ Slider Widget
This is a tutorial about a real problem: how to implement a slider control
with C++? This tutorial is using many of the common functionality of C++:
Classes
Data members
Member functions
Inheritance
Constructors
Operator Overloading
14.5.1 The Problem
We are using an Liquid Cristal Display (LCD) for our embedded application
with touch screen capabilities. The graphics library we are using works ne,
available in source form and implemented in ANSI-C. Having the library in
C has many advantages, as it allows to use it with smaller microcontrollers.
Smaller microcontrollers usually do not have a C++ compiler. But we are
using the library with a 32bit compiler which indeed could be used with C++.
12
The amount of space is implementation specic. It has to be at least one byte.
c Erich Styger 156
INTRO V1.70
So it might be a good idea to extend the library with new graphic widgets, but
implemented in C++. For our application, we want to implement a slider
widget similar to the one in gure 14.5. Using one or more slider widgets
the user can provide an input value to the application (e.g. specifying the
speed of a motor). Such a slider widget or slider control is something used
in many Graphical User Interface (GUI). Indeed, in our example we want
to use multiple slider controls to provide input values for a motor controller
(PWM, speed, and so on).
Figure 14.5: Example Slider Widget
14.5.2 Requirements
The goal is to implement something similar as in gure 14.5. For now we
want to implement a horizontal slider widget only. But we keep in mind that
we want to extend it later on as well to a vertical slider widget. The widget
shall have following capabilities:
Position and size of the widget shall be congurable at creation time
Moving the slider knob shall increase and decrease the value
Clicking left or right of the knob shall increment and decrement the
value in steps
The minimal and maximal value of the widget shall be congurable at
creation time
The widget shall print a label (a name) and the current value of the
widget
The widget shall be usable from the application written in C
The widget shall use the graphic primitives of the LCD library written
in C
For simplicity: signed 32bit data value
It shall be possible to create multiple widgets
c Erich Styger 157
INTRO V1.70
Optional: additional attributes like color, font or dierent widget data
type
14.5.3 Touchscreen Library
We do have already graphic primitives available in our LCD/Touchscreen
libraries, things like:
Drawing a dot or a line
Drawing a box (either lled or a line box)
Drawing text
Getting events for touch
A generic widget
With this, we shall be able to implement the widget without the need of
new graphic primitives.
14.5.4 External Interface
As outlined above, our implementation will be in C++, but is embedded
inside a normal C application
13
. After some investigation, we can come up
with following external interface:
/ ! \ b r i e f c a l l e d from t he window cr eat or t o cr eat e s l i d e r
c ont r ol s /
void SLIDER CreateSl i ders ( UI1 Window window , UI1 Pi xel Di m x ,
UI1 Pi xel Di m y , UI1 Pi xel Di m w, UI1 Pi xel Di m h) ;
/ ! \ b r i e f Cal l ed f or c l i c k s and window r e f r e s h /
void SLIDER SliderW WindowCallback ( UI1 Window window ,
UI1 El ement el ement , UI1 EventCal l backKi nd kind , UI1 Pvoi d
data ) ;
/ \ b r i e f Returns s t at us of c ont r ol as s t r i ng /
void SLIDER GetCmdString ( c har t buf , s i z e t buf Si z e ) ;
13
This means that a normal C startup code is used as well. This will be a fact to be
considered, as constructors and destructors for global objects will not be called from the
startup code.
c Erich Styger 158
INTRO V1.70
The function SLIDER CreateSliders() will be called from the appli-
cation to create all the needed widgets in the area passed as actual
parameters.
The function SLIDER SliderW WindowCallback() will be used as call-
back to notify our widgets about events like touch events or events to
paint the widgets.
The SLIDER GetCmdString() is used by the application to collect the
slider values for further processing using a command line interface.
It is logical to use a le slider.cpp for the implementation and slider.h
for the interface. Using the .cpp extension will ensure for most C/C++
compilers that the le is processed as C++ le. However, the slider.h le
is more tricky: it will be used as header le both for C++ and C les. What
we need to do is to guard things with extern "C":
#i f ndef SLIDER H
#define SLIDER H
#i f def c pl us pl us
extern C {
#endif
/ i nt e r f a c e f o l l o ws here . . . /
#i f def c pl us pl us
}
#endif
#endif / SLIDER H /
Using #ifdef cplusplus it is ensured that the C naming is used if
included by a C++ le.
In a similar way, we need to use #ifdef cplusplus inside slider.cpp:
// s l i d e r . cpp
#include Sl i de r . h
extern C {
#i nc l ude UI1 . h
// ot her modul es i mpl emented i n C
}
// i mpl ement at i on f o l l o ws . . .
c Erich Styger 159
INTRO V1.70
14.5.5 Design
Knowing the basics of C++, implementing such a slider widget in C++ looks
like a good thing. As alway, it is worth to spend a few minutes with a design.
Using an OOP approach means that you think in classes and its data (or
properties) and methods (or operators or member functions). Looking
at the data, we could identify following:
Position: x, y, w, h
GUI framework: window
Widget value
Minimum and maximum value
Increment and decrement information
Label text
If we list the methods, we could come up with following:
Creating the widget
Destroying the widget
14
Painting the widget
Moving the widget knob
Increment or decrement the widget value
Clustering the data and methods, there are several ways how you could
design then classes. A proposal is the following (Figure 14.6) class organiza-
tion:
RangeValue: value and the range information
Widget: User Interface methods and properties
SliderWidget: increment/decrement and painting
14
Might not be needed
c Erich Styger 160
INTRO V1.70
RangeValue Widget
SliderWidget
Figure 14.6: Slider Classes
14.5.6 RangeValue: Data Member
The class RangeValue can be dened as:
typedef i nt 3 2 t Sl i derVal T ;
/ t ype f or s l i d e r val ue /
cl ass RangeValue {
private :
Sl i derVal T m val , m min , m max;
};
Consideration:
class for value type.
We are using at type SliderValT for the actual value, so we can change
it later on. Another approach would be to use a special class for it (which
might be an overkill)
15
. We marked the data members with private access
control: that way only the class and its member functions have access to the
data. Many C++ programming guidelines recommend to use the m prex
for data members, what we are using here as well.
14.5.7 RangeValue: Methods
It is good programming style to implement a constructor to initialize the
data values. Additionally we need access routines to our data as we have
marked it as private. So we need
Default constructor for all data values
Constructor for min and max values with consistency checks
Access methods
15
The question is about if we should support a slider value with oating point values,
or with dierent integral (8, 16, 32bit) values.
c Erich Styger 161
INTRO V1.70
Set value
Get value
Get min boundary
Get max boundary
cl ass RangeValue {
. . .
protected :
RangeValue ( void) ; // d e f a u l t cons t r uct or
void SetRange ( Sl i derVal T min , Sl i derVal T max) ;
void SetVal ( Sl i derVal T val ) ;
Sl i derVal T GetVal ( void) ;
Sl i derVal T GetMin( void) ;
Sl i derVal T GetMax( void) ;
};
Protected:
Access for itself, derived and friends.
We use protected for the member function as we only want to have them
accessible by the class itself, friends and objects having it as base class.
14.5.8 Default Constructor
The constructor transforms raw memory into a proper typed object. The
constructor is like a normal member function, but has the same name as the
class and no return type. The default constructor is a constructor with no
argument. One could implement the constructor like this:
RangeValue : : RangeValue ( void) { // d e f a u l t cons t r uct or
this>m val = 0;
this>m max = 0;
this>m min = 0;
}
Note:
Usage of this is optional.
Using the this is more a question of style, so you can write it as well
as:
RangeValue : : RangeValue ( void) { // d e f a u l t cons t r uct or
m val = 0;
m max = 0;
m min = 0;
c Erich Styger 162
INTRO V1.70
}
Caution:
Assignments vs. initialization
Not possible for const data member
16
Requires data member initialization before body
But there is a problem with above initialization inside the constructor
body
17
: as in above code, these are actually assignments, and not initializa-
tions. C++ requires that all initialization of data members are done before
entering the body of constructors
18
.
14.5.9 Initialization and Assignment
In the constructor, we need to initialize the data members. But how to
do this? Lets look at two examples, which seems to do the same thing:
construct and initialize the object x:
MyClass x ( 3) ;
MyClass x = MyClass ( 3) ;
The dierence is that in the rst case this is a direct initialization, while
the second is a copy initialization. There are two rules:
1. For direct initialization and for copy initialization where the initializer
is of the type of the initialized object: if you have an initialization of
the same type, the compiler can initialize the object directly.
2. For copy initialization in other cases: the compiler creates a tempo-
rary object with the constructor, then it initializes the object with the
object.
Looking at an example with a standard type:
i nt x ( 3) ;
i nt x = i nt ( 3) ;
16
More precisely: non-static constant and reference class members.
17
It is a common misunderstanding that initialization of data members shall be done
inside the function body.
18
The reason for this are const types: you cannot use assignments inside the body to
set their initialization values.
c Erich Styger 163
INTRO V1.70
Caution:
Check the assembly code!
The standard types do not have a constructor, but they could used as if
they have one
19
.
14.5.10 Constructor Initialization List
The better (and correct) way to initialize data members is to use an initial-
ization lists: After the constructor declaration and between the constructor
body, you can list the initialization after a ::
RangeValue : : RangeValue ( void)
: m val ( 0) , m min( 0) , m max( 0)
{}
To avoid a chicken-and-egg problem, one should initialize the members
in the order of their declaration.
14.5.11 Inlining
To make the implementation as ecient as possible, you can use inlining two
ways: either use the inline keyword or write the function body inside the
class declaration. The following shows a combination of both:
cl ass RangeValue {
private :
Sl i derVal T m val , m min , m max;
protected :
RangeValue ( void) : m val ( 0) , m min( 0) , m max( 0) {} // d e f a u l t
cons t r uct or
i nl i ne void SetRange ( Sl i derVal T min , Sl i derVal T max) ;
i nl i ne void SetVal ( Sl i derVal T val ) ;
Sl i derVal T GetVal ( void) { return m val ; }
Sl i derVal T GetMin( void) { return m min ; }
Sl i derVal T GetMax( void) { return m max; }
};
If using the inline keyword, the implementation can be outside of the
class:
i nl i ne void RangeValue : : SetVal ( Sl i derVal T val ) {
i f ( val >m max) {
val = m max;
} el se i f ( val <m min) {
19
See http://stackoverow.com
c Erich Styger 164
INTRO V1.70
val = m min ;
}
m val = val ;
}
14.5.12 Widget Class
Similar to the class RangeValue, the class Widget can be declared:
cl ass Widget {
protected :
UI1 Pi xel Di m m posX , m posY , m width , m hei ght ; // wi dget
coor di nat es
UI1 Window m window; // poi nt er t o window
protected :
Widget ( void)
: m window(NULL) , m posX( 0) , m posY( 0) , m width ( 0) ,
m hei ght ( 0) {};
bool i s I n s i d e ( UI1 Coordi nate coord ) ;
};
Notice the usage of bool
20
as new standard type available in C++.
That looks good, but why not use a own type the coordinates? Instead
of:
UI1 Pi xel Di m m posX , m posY , m width , m hei ght ; // wi dget
coor di nat es
it would be better with:
typedef struct {
UI1 Pi xel Di m x , y , w, h ;
} WidgetArea ;
cl ass Widget {
protected :
WidgetArea m area ; // wi dget coor di nat es
. . .
};
But there is now a problem: how to initialize it in the default constructor?
The logical choice would be:
20
bool might cause problems if normal C code already has an alias/typedef for it.
Additionally, the compiler might have a special option to enable bool in the language
(this is the case for the Freescale ColdFire C++ compiler which has the -bool compiler
option).
c Erich Styger 165
INTRO V1.70
cl ass Widget {
protected :
WidgetArea m area ; // wi dget coor di nat es
UI1 Window m window; // poi nt er t o window
protected :
Widget ( void)
: m window(NULL) , m area ( 0 , 0 , 0 , 0) {};
};
But the compiler will complain about it. The reason is that WidgetArea
is a struct, and structs are like a class, only with public members. The
compiler will complain because there is no constructor available for the class
WidgetArea having the matching arguments. The solution is to add the
needed constructors to the WidgetArea struct:
struct WidgetArea {
UI1 Pi xel Di m x , y , w, h ;
WidgetArea ( void)
: x ( 0) , y ( 0) , w( 0) , h( 0) {};
WidgetArea ( UI1 Pi xel Di m x , UI1 Pi xel Di m y , UI1 Pi xel Di m w,
UI1 Pi xel Di m h)
: x( x) , y( y) , w(w) , h( h) {};
};
Now we can properly an initialization list to initialize all data members:
cl ass Widget {
protected :
WidgetArea m area ; // wi dget coor di nat es
UI1 Window m window; // poi nt er t o window
protected :
Widget ( void) : m window(NULL) , m area ( 0 , 0 , 0 , 0) {};
bool i s I n s i d e ( UI1 Coordi nate coord ) ;
};
14.5.13 SliderWidget Class
Now we can build up our class SliderWidget based on the base classes Widget
and RangeValue:
typedef ui nt 16 t Sl i der St epT ; // t ype f or s l i d e r s t e ps
cl ass Sl i derWi dget : Widget , RangeValue {
private :
Sl i der St epT m steps ; // number of s t e ps
const char m l abel ; // l a b e l t e x t
WidgetArea GetKnobPosi ti on ( void) ;
c Erich Styger 166
INTRO V1.70
public :
Sl i derWi dget ( void) : m steps ( 0) , m l abel (NULL) {}
Sl i derVal T GetValue ( void) ;
void Pai nt ( void) ;
void OnClick ( UI1 Coordi nate c l i c kPos ) ;
void OnClickMove ( UI1 Coordi nate c l i c kPos ) ;
};
14.5.14 Operator Overloading
We have now pretty much everything in place. Looking at the requirements,
we have to support incrementing and decrementing the slider value in a step
fashion. Having heard about the possibility to use overloaded operators, this
might be a good thing for our SliderWidget class. This could be very useful
in the OnClick() method, as depending in if we click on the left or right
side of the slider widget knob, we want to increment or decrement the slider
value:
void Sl i derWi dget : : OnClick ( UI1 Coordi nate c l i c kPos ) {
i f ( this>i s I n s i d e ( c l i c kPos ) ) {
WidgetArea knobArea ;
knobArea = GetKnobPosi ti on ( ) ;
i f ( cl i ckPos >x < knobArea . x) {
( thi s );
( thi s ) . Pai nt ( ) ;
} el se i f ( cl i ckPos >x > knobArea . x+knobArea . w) {
( thi s )++;
( thi s ) . Pai nt ( ) ;
}
}
}
14.5.15 Operator ++ and - -
Operator overloading is done with the operator keyword preceding the op-
eration. As for normal overloading, the operators can be dened for dierent
arguments. The ++ and operators are special, as they can be used both
prex (i) or postx (i++). To distinguish between the postx and prex
usage, the postx operator has an unused dummy int argument.
cl ass Sl i derWi dget : Widget , RangeValue {
// . . .
private :
c Erich Styger 167
INTRO V1.70
Sl i derWi dget& operator++(void) ; // ++p r e f i x
Sl i derWi dget operator++(i nt unused ) ; // p o s t f i x++
Sl i derWi dget& operator(void) ; // p r e f i x
Sl i derWi dget operator(i nt unused ) ; // pos t f i x
// . . .
};
14.5.16 Prex ++
The implementation for the prex operator is straight forward, using the
available methods:
Sl i derWi dget& Sl i derWi dget : : operator++(void) { // ++p r e f i x
SetVal ( GetVal ( ) +((GetMax( )GetMin ( ) ) / m steps ) ) ;
return thi s ;
}
14.5.17 Postx ++
Sl i derWi dget Sl i derWi dget : : operator++(i nt unused ) { // p o s t f i x++
( void) unused ;
Sl i derWi dget r e s ul t = thi s ;
++(thi s ) ; // c a l l p r e f i x Sl i derWi dget : : operat or ++() ;
return r e s ul t ;
}
14.5.18 Global Object Initialization
Now we have pretty much everything together. One question remains: the
creation of the objects (as we want to have multiple sliders). As we have a
static number of sliders, we simply could have the slider objects as normal
global objects:
stati c Sl i derWi dget s l i der A , s l i de r B ;
In a normal C++ application, the C++ startup code would make sure
that the constructors of our objects will be called. However, as we are using
in our C application a normal C startup code, the constructors wont be
called. One solution would be to switch to the C++ startup code. But
if you cannot do this (or if you do not want this), you might think that
you could call the constructors yourself. However, this is not possible: the
c Erich Styger 168
INTRO V1.70
constructor is called at construction time, and C++ does not allow you to
call yourself the constructor.
But what you can do is to implement your own Init() method to imple-
ment the needed behavior:
void Sl i derWi dget : : I ni t ( UI1 Window window , UI1 Pi xel Di m x ,
UI1 Pi xel Di m y , UI1 Pi xel Di m w, UI1 Pi xel Di m h , Sl i derVal T
min , Sl i derVal T max, Sl i der St epT s t eps , const char l a be l ) {
Widget : : I ni t ( window , x , y , w, h) ;
RangeValue : : SetRange ( min , max) ;
i f ( s t e ps ==0) { // need t o have at l e a s t one s t ep !
s t e ps = 1;
}
m steps = s t e ps ;
m l abel = l a be l ;
}
14.6 Summary
Without a doubt, C++ is a very powerful language, and the ++ in the name
C++ already indicates that it is something more than plain C. C++ xes
many shortcomings or sources of C, but as well adds a lot of complexity.
Advantages of using C++ are:
OOP: classes with abstraction
21
, encapsulation
22
, inheritance
23
and
polymorphism
24
Strict syntax
Fixes many aws of C
Tools and knowledge broadly available
Ability to mix with C
Kind of superset of C
Disadvantages of using C++ are:
Rather complex and dicult to learn
No multitasking or multiprocessing support
25
21
Dealing with the meaning (semantics), rather than the implementation details
22
Hiding the data or function implementation
23
Reuse through creating collections of attributes and behaviors
24
Ability to have more than one form
25
C++11 adds support for concurrency
c Erich Styger 169
INTRO V1.70
No built-in garbage collection
Lack of fail safe functionality
No what you program is what you get
c Erich Styger 170
INTRO V1.70
14.7 Problems
14.1. What is the number of actual parameters for void foo() in C? How
many parameters if this function is compiled as C++?
14.2. If you have a struct in C++, are its members public or private by
default? What about class members?
14.3. What is an abstract class?
14.4. You have a function in a C++ module, and you want to call it from a
C module, how can you do this?
14.5. You can implement the body of a function inside the class. When would
you not use this?
14.6. Why is the usage of a #pragma a better way for a C compiler compared
to introduce an additional (non-ANSI) keyword like inline?
14.7. Does your Freescale HCS08 compiler support C++?
14.8. Can you describe dierent ways how you can enable C++ compilation
for a single le under CW for MCU10 (HCS08, ColdFire)?
c Erich Styger 171
INTRO V1.70
c Erich Styger 172
Chapter 15
LED
15.1 Limiting Current
Figure 15.1: LED Circuit
Nearly in every embedded system you will end up to use some kind of
Light Emitting Diode (LED). They are low cost, can be low power and are
really versatile and easy to use: all what you need is an output pin on
your controller. Figure 15.1 shows a typical circuit: an LED with an inline
resistor
1
. The resistor R is required to limit the current. You can limit the
current with a constant current source. A simple solution would be to place
a resistor on the anode or cathode side of the LED. The question is: how
to determine the value of the resistor R? For this you need to consult the
schematics of our Printed Circuit Board (PCB) the LED data sheet to get
following values:
U
0
: The supply voltage for the LED
1
Never connect an LED directly to the supply voltage. The reason is that with small
voltage changes there will be a big change in current.
173
INTRO V1.70
U
D
: The voltage drop of the diode
I: The desired current
Given the parameters, the resistor R calculates according to formula 15.1.
The calculated value will be rounded up to the next preferred value
2
.
R =
U
0
U
D
I
(15.1)
15.2 Digital I/O
Using your microcontroller you can turn on or o an LED really easily. Just
connect an LED with a resistor to an output pin of your microcontroller.
But there are a few things to consider:
It does not matter if you connect the anode or the cathode side to
the microcontroller pin. But this will change the logic in your driver:
Either a logical high or a logical low of the pin will illuminate the LED.
Many microcontrollers are better to sink current than to drive current.
This means that connecting the cathode side side would be better.
You need to make sure that you are not exceeding the current budget
of your microcontroller
3
: you need to consult the data sheet about how
much current a pin can drive or sink. Usually the data sheet species
a budget for each pin and an overall budget (for the whole controller
or parts of the controller). Some controllers
4
have a setting to enable a
high gain bit which allows them to drive/sink more current. But be
aware that you still might have an overall current budget to respect.
Microcontroller I/O pins usually can be congured to be either input or
output. If you are using the same pin both as input and output, then you
need to be careful not to create a shortcut. To control a LED as in gure 15.1
we could connect the cathode to a microcontroller pin which is congured
as output pin. Putting a logical zero to the port pin register will change
2
If your calculation returns a value of 108, and you can order resistors with 100 and
125, then you would pick the 125 one.
3
Students have approached me because their hardware somehow did not work. Stepping
through the code showed that enabling pins for the LEDs caused a reset of the controller,
because too much current was owing. After further investigations it turned out the there
were 8 LEDs, and each required 50mA.
4
For example the Freescale MCFJM128 microcontroller.
c Erich Styger 174
INTRO V1.70
the port pin to a voltage of 0 volt (logical zero
5
). As such, the LED will be
turned on. If you put the port register to a logical one, the pin will change to
the microprocessor voltage level as dened as high for your system. Because
in that case there is no voltage drop over the LED, no current will ow, and
the LED will be turned o.
In order to nd out if a logical low or high is turning on the LED, you
need to consult your hardware description like in Figure 15.2.
Figure 15.2: LEDs on SRB Board [17]
The schematic should give you following important information:
1. To which microprocessor pin the LED is connected.
2. If either the anode or the cathode side is connected to the micropro-
cessor pin
3. How much current the pin has to drive or sink
6
15.3 LED Driver
Now we want to implement a simple software driver for one or multiple LEDs.
There are many dierent ways how you can write such a driver. First, we
need to specify what your LED driver shall do:
1. The driver shall have a functionality to initialize and congure the
hardware
5
The voltage ranges for logical zero and logical 1 depending on the silicon technology
used.
6
You will need as well the data sheet of the LED to calculate the current.
c Erich Styger 175
INTRO V1.70
2. The driver shall provide functionality to turn LEDs on or o
3. The driver shall provide the functionality to determine if an LED is on
or OFF
Usually you will not only have a single LED in your system. So it might
be a good idea have an interface like the following one using a boolean pa-
rameter
7
.
So your LED driver could implement following interface:
void LED On( bool LED0, bool LED1, bool LED2, bool LED3) ;
As our hardware has four LEDs, We can turn on each LED individually:
void Demo( void) {
LED On(TRUE, FALSE, TRUE, TRUE) ;
}
There are several things to consider: passing a TRUE to the function
LED On() turns the LED on. Passing FALSE does not turn it o (it just
means: do nothing with this LED). So you need to specify this in your
interface description as this might be not obvious.
The other concern is that the interface needs to be changed if more or
less LEDs are used, making maintenance problematic. Just think about this
approach be used for 8 or more LEDs: the argument list gets very long, and
the generated code to pass and use all the parameters gets complicated.
Based on this, we could come up with a dierent solution using a 8bit
type uint8 t
8
as parameter. Each bit in the parameter would identify an
individual LED (0x01 for LED0, 0x02 for LED1, 0x04 for LED2 and so on).
You can do some math in order to turn multiple LEDs on as well:
void LED On( uint8 t LEDs) ;
void Demo( void) {
LED On(0 x01+0x04 ) ;
LED On(0 x02 | 0 x08 ) ;
}
Our interface can stay the same, regardless if we have one or multiple
LEDs. But if if you have more than 8 LEDs, then you are in trouble again.
A solution to this could be to use a custom user type. This type can be
used to hide the number of LEDs supported:
7
bool is not a standard type in ANSI-C. Many applications dene the type of bool
using a typedef to either a 8bit or int type.
8
uint8 t is not a standard type in C. You can easily create one with a typedef.
c Erich Styger 176
INTRO V1.70
#include pl at f or m . h
#i f PL NOF LED <= 8
typedef uint8 t LED Type ;
#e l i f PL NOF LED <= 16
typedef uint16 t LED Type ;
#e l i f PL NOF LED <= 32
typedef uint32 t LED Type ;
#el se
#e r r or too many LEDs !
#endif
void LED On( LED Type LEDs) ;
An application conguration le (platform.h) could specify the number of
LEDs as PL NOF LED macro. The interface would automatically create
the matching type for the amount of LEDs to be supported.
Controlling multiple LEDs in one single call is a useful thing. Looking at
the example below, it turns out that things are not really easy to understand:
The source is using magic numbers:
LED On(0 x02 | 0 x08 ) ;
It would be much better if we could use a more human readable way to do
the same thing. For this we could come up with a set of #dene:
#define LED LED0 0x01
#define LED LED1 0x02
#define LED LED2 0x04
#define LED LED3 0x08
void LED On( LED Type) ;
void main( void) {
LED On(LED LED0| LED LED3) ;
}
One recommended way is to make explicit that the denes are indeed in-
dividual bits, so nobody thinks he could add a LED dene with a value of
0x03. For this, the shift operator (<<) can be used:
#define LED LED0 (1<<0)
#define LED LED1 (1<<1)
#define LED LED2 (1<<2)
#define LED LED3 (1<<3)
c Erich Styger 177
INTRO V1.70
Using bits for each LED has one additional advantage: if the bit position
matches with the bit position of the microcontroller port for the LED, then
you do not need to perform any additional dispatching. Assuming that our
four LEDs are wired to the four least signicant bits of PORTA, then our
driver could look like this:
#define LED LED0 (1<<0)
#define LED LED1 (1<<1)
#define LED LED2 (1<<2)
#define LED LED3 (1<<3)
#define LED ALL (LED LED0| LED LED1| LED LED2| LED LED3)
void LED Ini t ( void) {
PORTA.DD = LED ALL; / s e t LED port pi ns as out put ( b i t s s e t
i n dat a di r e c t i on r e g i s t e r ) /
}
void LED On( LED Type l e ds ) {
PORTA.D |= l e ds ; / b i t s e t wi l l t urn l e d on /
}
If the hardware wiring on the board gets adopted (e.g. using dierent port
pins), then this can be easily changed, as long the pins are within the same
port.
Another improvement is to use a symbolic type enumeration type:
typedef enum {
LED LED0,
LED LED1,
LED LED2,
LED LED3
} LED Set ;
void LED On( LED Set LEDs) ;
void main( void) {
LED On(LED LED0| LED LED3) ;
}
This approach has the advantage that the parameter is a true symbolic type
(not an integer as in the previous designs). This improves readability of your
code during debugging. The debugger will be able to show the symbolic
name (e.g. LED LED1) instead of just a number. However, in our exam-
ple the enumerations for the LEDs will have the values 0 (LED LED0), 1
(LED LED1), 2 (LED LED2) and 3 (LED LED3). If we want to use a bit
pattern matching our port bits we need to make sure that the enumerations
have special values:
c Erich Styger 178
INTRO V1.70
typedef enum {
LED LED0 = (1<<0) ,
LED LED1 = (1<<1) ,
LED LED2 = (1<<2) ,
LED LED3 = (1<<3)
} LED Set ;
There are a few more rules to know about enumerations in C
9
:
Enumerations have the type int.
Therefore you can use enumerations as well in calculations like
(LED LED0+LED LED1)
As the type int might be an overkill for an enumeration type with
just few values, most embedded C cross compilers have the ability to
change the size of the enumeration type
15.4 One or Multiple
So far we were using an interface where we would specify multiple LEDs in
a single function call. This makes sense if you need to turn multiple LEDs
on and o at the same time. But if you access the LEDs only one by one
and possibly from dierent tasks in your system, this might not be the right
approach. Instead, you might need to consider an interface for each LED:
void LED0 On( void) ;
void LED0 Off ( void) ;
void LED1 On( void) ;
void LED1 Off ( void) ;
This works well for few LEDs, otherwise the number of interface functions
will easily explode. The advantage of this approach is that you do not need
to dispatch/decode the arguments in the LED driver function: and you can
keep the LED interfaces separate. Additionally it is more exible in case
you have a mixed hardware design (e.g. dierent anode/cathode pin wiring
to the microcontroller). But again: this comes with the cost of additional
interfaces. Because usually the number of LEDs in your system is rather
small, you likely end up using the approach af a single interface for each
9
C++ has much more restricted rules for enumerations. The enumeration is a type on
its own (not like in C), and as such you are not allowed to perform math with them (as
you can do in C).
c Erich Styger 179
INTRO V1.70
LED. In order to reduce the number of interface les, you should consider to
have the interfaces in a single interface le (e.g. led.h to provide the interface
for all the LEDs).
15.5 Eciency
Turning LEDs on and o is a rather simple thing. And you want to have it
performed as eciently as possible. But calling a normal function for turning
on a LED is rather a big overhead. What you can do is to help the compiler
to produce ecient code. One approach is to dene macros to do low level
bit manipulation on the port I/O:
#define LED1 SetVal ( ) (PORTA |= 1)
#define LED1 ClrVal ( ) (PORTA &= 1)
If you look at the assembly code generated, these macros usually trans-
forms in ecient bit set/clear instructions. With this in mind, you can dene
and use the macros in your code:
#define LED1 On( ) LED1 SetVal ( )
#define LED1 Off ( ) LED1 ClrVal ( )
If you have now dierent wirings of our LED anode and cathode, you can
cover this using macros as well:
#i f PL LED KATHODE PIN
#de f i ne LED1 On( ) LED1 ClrVal ( )
#de f i ne LED1 Off ( ) LED1 SetVal ( )
#el se
#de f i ne LED1 On( ) LED1 SetVal ( )
#de f i ne LED1 Off ( ) LED1 ClrVal ( )
#endif
But this looks like a lot of duplicated source code. Especially if you have
many LEDs. A solution to this would be to use the ## concatenation in
ANSI-C. ## concatenates two symbols to a new token. The following code
shows how using a macro you can combine the two tokens My and Function
into the MyFunction token:
#define CAT( a , b) a##b
void f oo ( void) {
CAT(My, Functi on ) ( ) ; / MyFunction ( ) ; /
}
c Erich Styger 180
INTRO V1.70
With this in mind, we end up writing up following macros for our LED
driver:
#i f PL LED KATHODE PIN
#de f i ne LED TURN ON( a ) LED##a## Cl rVal ( )
#de f i ne LED TURN OFF( a ) LED##a## SetVal ( )
#el se
#de f i ne LED TURN ON( a ) LED##a## SetVal ( )
#de f i ne LED TURN OFF( a ) LED##a## Cl rVal ( )
#endif
#define LED1 On( ) (LED TURN ON( 1) )
#define LED1 Off ( ) (LED TURN OFF( 1) )
#define LED2 On( ) (LED TURN ON( 2) )
#define LED2 Off ( ) (LED TURN OFF( 2) )
#define LED3 On( ) (LED TURN ON( 3) )
#define LED3 Off ( ) (LED TURN OFF( 3) )
15.6 Driver Interfaces
Now as we have discussed the functional driver interface design (LED On(),
LED O(), . . . ), we need to think about how we initialize and protect our
driver against concurrent access.
For this you need to implement following additional driver parts:
1. Init: The driver needs to initialize the hardware. Things like setting
up the registers, conguring the ports and putting the device into an
initial state. For our LED it could be to congure the port as output
port and have the LED turned on. The initialization is performed only
once at system startup.
2. Open: During your application runtime, you might need to share the
device with other processes or parts in your system. As such you need
to make sure you can access the device in an reentrant way. So you
have to provide some means of mutual exclusion. For this you could
provide a function to open the device and to lock it (like you would
do for accessing a le on your disk).
3. Close: This is the counterpart of Open and used to free up the device.
c Erich Styger 181
INTRO V1.70
15.7 Problems
15.1. Using a resistor inline with an LED is simple. What could be a disad-
vantage of this approach?
15.2. Determine the resistor for an LED: the supply voltage is 5V, and the
desired current through the LED is 20 mA. The desired voltage drop
over the LED is 2V.
15.3. Determine the LED current for one of the LEDs (LED1 to LED4) on
the INTRO SRB board.
15.4. Think about a solution how you can use LEDs with your microcon-
troller even if the current needed exceeds your controller pin current
budget.
15.5. List strategies and ways how you can limit the energy used for a low
energy product.
15.6. Look at your HCS08 compiler documentation: how can you aect the
size of an enumeration type?
c Erich Styger 182
Chapter 16
State Machines
16.1 Introduction
Many problems in software engineering can be solved with state machines.
They are rather easy to implement and provide a mechanical way to solve a
problem. In this chapter we will discuss multiple ways of implementing such
state machines. As additional please see following references:
The Firmware Handbook, Chapter 7, Embedded State Machine
Implementation[4]
The Firmware Handbook, Chapter 8, Hierarchical State Machines[4]
Single and Multiple Chip Microcomputer Interfacing, [14]
A B
0/a
1/c
1/b
0/d
Figure 16.1: Simple Autmation Graph
We are going not to implement in dierent ways the graph shown in gure
16.1. This graph enters the state A as initial state, and takes an input (e.g.
from a I/O port). Such a machine is called Mealy Sequential Machine[16]
and is a model for (small) digital systems.
183
INTRO V1.70
If in state A, and the input 0 is read, then the machine will issue issue
a and go to state B. This is denoted as 0/a on the edge from state A to
state B. In a similar way, if the machine is in state B and reads 1, then it
will issue b and go to state A. Looking at the graph we can identify the set
of states S:
S = {A, B} (16.1)
As input states I we can identify following:
I = {0, 1} (16.2)
And nally as output states O we have:
O = {a, b, c, d} (16.3)
To keep things simple, we can use following interface:
uint8 t Read( void) ; / read from i nput steam /
void Write ( uint8 t ) ; / wr i t e t o t he out put stream /
With the two functions Read() and Write() we can implement now the state
machine.
16.2 Conventional Implementation
You can implement the machine in gure 16.1 with normal functions like
below.
typedef enum {
A, B
} StateT ;
stati c StateT s t at e ;
void InA( void) {
uint8 t r = Read ( ) ;
i f ( r==1) {
Write ( c ) ;
} el se i f ( r==0) {
Write ( a ) ;
s t at e = B;
}
}
void InB( void) {
uint8 t r = Read ( ) ;
c Erich Styger 184
INTRO V1.70
i f ( r==1) {
Write ( b) ;
s t at e = A;
} el se i f ( r==0) {
Write ( d) ;
}
}
void Loop( void) {
i f ( s t at e==A) {
InA( ) ;
} el se i f ( s t at e==B) {
InB( ) ;
}
}
void I ni t ( void) {
s t at e = A;
Loop ( ) ;
}
This implementation is simple, but might get complicated the more states
and actions will be added.
16.3 Switch Implementation
Another way is to implement the state machine within a switch statement.
This is especially useful if there are not too many states and transitions, as
this way the implementation remains compact.
void Loop( void) {
uint8 t r ;
for ( ; ; ) {
r = Read ( ) ;
switch( s t at e ) {
case A:
i f ( r==1) {
Write ( c ) ;
} el se {
Write ( a ) ;
s t at e = B;
}
break ;
case B:
i f ( r==1) {
c Erich Styger 185
INTRO V1.70
Write ( b) ;
s t at e = A;
} el se {
Write ( d) ;
}
break ;
} / s wi t ch /
} / f or /
}
void I ni t ( void) {
s t at e = A;
Loop ( ) ;
}
16.4 Table Implementation
An even more condensed way to implement the state machine from gure 16.1
is using a table. First, we are going to build the table 16.1 with our state
S, input I and output O: Such State Machines are named Mealy Sequential
State 0 1
A B/a A/c
B B/d A/b
Table 16.1: Mealy Table
State Machines, or short Mealy State Machines. The characteristics of a
Mealy State Machine is that the output is a function of the current state
plus one or more input values. They are ideal for processing input values
and generating an output.
The following listing shows an implementation for the Mealy table in
table 16.1.
typedef enum {
A, B
} StateT ;
stati c StateT s t at e ;
stati c uint8 t t bl [ 2 ] [ 2 ] [ 2 ] =
{{{B, a } , {A, c }} ,
{{B, d} , {A, b}}};
void Loop( void) {
c Erich Styger 186
INTRO V1.70
uint8 t r ;
for ( ; ; ) {
r = Read ( ) ;
Output ( t bl [ s t at e ] [ r ] [ 1 ] ) ;
s t at e = t bl [ s t at e ] [ r ] [ 0 ] ;
}
}
void I ni t ( void) {
s t at e = A;
Loop ( ) ;
}
c Erich Styger 187
INTRO V1.70
c Erich Styger 188
Chapter 17
Events
17.1 Introduction
A key element of a real time system is the interaction with the real world:
This means with the real time of the real world. An embedded system needs
to synchronize with the events from the outside world, and the system itself
can create events. Events are things like a button pressed, a sensor reaching
a certain value, or the system agging a status to another part of the sys-
tem. Such an infrastructure you might nd in a real time operating system
(RTOS). However, you want to use that functionality in a context where an
operating system is either not desired or needed.
The other element in real time systems is realtime: once there is an
event, the system has to react in a timely manner. Not only has the system
to produce the correct result, it has to produce the correct result at the right
time. For this, we need a mechanism to perform an action at a guaranteed
time. In this chapter we are using a Trigger for this: a way to do something
at a given (relative) time.
17.2 Room Temperature Unit
To illustrate the need for events, we are going to use a simple example. A
typical asynchronous event is the handling of a key or switch pressed.
Imagine an air conditioning system (Figure 17.1) which is using a remote
device. The remote device in the room is using buttons and a display: Using
the up or down button the user can increase or decrease the desired room
temperature. If the application detects a key pressed, then it will update the
display with the new desired temperature and transmit the new desired value
to the heating system (e.g. through a wireless communication channel). In
189
INTRO V1.70
main loop
up
pressed?
increase
temper-
ature
down
pressed?
decrease
temper-
ature
no
yes
yes
no
Figure 17.1: Example System
many cases you might have an interrupt raised to detect the switch pressed.
One approach to deal with this use case is to handle everything directly
in the interrupt service routine (Figure 17.2).
This approach is simple, but has one problem: updating the display and
transmitting the new value might take some time, up to several hundreds
of milliseconds. Depending on your microcontroller and interrupt system,
all other interrupts might be holding o during the interrupt execution. So
this will greatly increase the interrupt latency time unless your system allows
nested interrupts.
Additionally it violates a fundamental design rule for interrupt service
routines:
1. Keep interrupt handlers as small and fast as possible.
2. Only do things in the interrupt handler which cannot wait.
The rst rule is about latency and performance for the main program. The
longer an interrupt handler takes to execute, the longer the main program will
be interrupted and cannot perform its normal work. Additionally it impacts
the latency of other interrupts. The latency is dened by the time it takes
from the occurrence of the interrupt (e.g. a switch pressed) upon entry of the
c Erich Styger 190
INTRO V1.70
start of
interrupt
update
LCD
display
transmit
new value
end of
interrupt
Figure 17.2: AC Room Unit ISR
corresponding interrupt (e.g. keyboard interrupt). Some systems have non-
nested interrupts: If during execution of an interrupt service routine another
interrupt happens, it needs to wait until the currently executed interrupt
service routine nishes. If the system allows nested interrupts (an interrupt
routine can be executed while another interrupt is already served), this still
means that lower priority interrupts still have to wait. Updating a display
and to do a wireless transmission is typically not simple and fast. On the
other hand: The display has not been updated at the same microsecond as
the button is pressed: for the user it should be acceptable if this happens
in the next 100 to 200 milliseconds. Even more, the wireless transmission of
the new desired room temperature can happen a few seconds later. An AC
system cannot react very fast and is a rather slow system. The second rule is
a consequence of the rst rule: to keep things fast, only do things which are
really needed and cannot wait. What we do need to do fast is to recognize
the key pressed. So we want a mechanism to recognize something fast, which
can set a ag to do the things which are not urgent. Such a ag we name
Event here. And this is what we are going to implement.
c Erich Styger 191
INTRO V1.70
17.3 Event System
We are going to implement a system which helps us handle things fast which
needs to be fast, and postponing things which can wait. For this we are going
to implement an Event module. Im going to describe rst the interface and
the high level concept, and then going into the implementation details later.
The Event module proposed here follows the idea, that the interrupt
service routine only sets an event ag. That ag is processed asynchronously
by the event handler loop (Figure 17.3).
ISR
SetEvent()
event array
event loop
GetEvent()
Figure 17.3: Event ISR System
That way the main loop or event handler does the heavy work, while
the interrupt service routine only sets a notication with the event. This
approach is not only limited to interrupts, it can be used for polled keys
(Figure 17.4) or other cases. It is possible that a single event can cause
multiple actions, or that an event can cause the creation of additional events.
That way sequence of events and actions can be created, or actions and events
can be nested.
With this in mind, we can start dening the interface for our Event mod-
ule:
Static number of events: the number and kind of events are known at
compilation time.
Singularity: an event of a kind can only exist once. It is not possible
to have multiple events of the same kind.
Static memory: as the number of events is known, we are using an
array of event descriptors. We are not using lists or dynamic memory
for eciency reasons.
c Erich Styger 192
INTRO V1.70
event loop key poll
event array
SetEvent() GetEvent()
Figure 17.4: Event Polling System
Event handle: we are using numbers as event handle or identier. As
using an array of event descriptors, this event handle is an index into
the event array.
17.4 Event Handle
First, we declare a type for the event handle:
typedef uint8 t EVNT Handle ;
/!< We support up t o 256 d i f f e r e n t event s /
Using an 8bit type allows us to use up to 256 dierent events which will be
sucient for most applications. If you are wondering about the comments
starting with /*!: These are normal comments, but treated in a special way
by the doxygen (www.doxygen.org) compiler which can generate documen-
tation based on source les.
Next we list the dierent events we are going to use:
#define EVNT INIT 0
/!< System I n i t i a l i z a t i o n Event /
#define EVNT SW1 PRESSED 1
/!< SW1 pr es s ed /
#define EVNT SW2 PRESSED 2
/!< SW2 pr es s ed /
#define EVNT SW3 PRESSED 3
/!< SW3 pr es s ed /
#define EVNT SW4 PRESSED 4
c Erich Styger 193
INTRO V1.70
/!< SW4 pr es s ed /
#define EVNT NOF EVENTS 5
/!< Must be l a s t one ! /
The rst event handle number starts with zero. We dene an initialization
event which will be set at application startup. Additionally we dene events
for the number of switches we are going to support. Additionally there
is a sentinel event number (EVNT NOF EVENTS) at the end which gives us the
number of dierent events. Alternatively we could use as well an enumeration
type:
typedef enum {
EVNT INIT, /!< System I n i t i a l i z a t i o n Event /
EVNT SW1 PRESSED, /!< SW1 pr es s ed /
EVNT SW2 PRESSED, /!< SW2 pr es s ed /
EVNT SW3 PRESSED, /!< SW3 pr es s ed /
EVNT SW4 PRESSED, /!< SW4 pr es s ed /
EVNT NOF EVENTS, /!< Must be l a s t one ! /
} EVNT Handle ;
Using an enumeration is a more elegant way. However, as enum is dened
as int in American National Standards Institute (ANSI)-C, the code might
not be as ecient. It depends on the microcontroller and compiler used. An
8bit microcontroller will handle an 8bit type more ecient, while a 32bit (or
even 16bit) controller might handle an int better. Additionally there are
many compilers for which you can set the enumeration standard type to a
user dened type (e.g. to an unsigned 8bit type).
With the fact that our events are numbered, we could use the numbering
as well with a prioritization scheme: depending on your implementation, the
lower the event number, the higher the priority of the event could be (or the
other way around).
17.5 Event Methods
The interface for our event module is straight forward: Methods to set,
clear and check events. Additionally a method which checks if there are
any pending events and which calls a provided callback:
/ !
\ b r i e f Set s an event .
\param[ i n ] event The handl e of t he event t o s e t .
/
void EVNT SetEvent ( EVNT Handle event ) ;
c Erich Styger 194
INTRO V1.70
/ !
\ b r i e f Cl ears an event .
\param[ i n ] event The event handl e of t he event t o c l e ar .
/
void EVNT ClearEvent ( EVNT Handle event ) ;
/ !
\ b r i e f Returns t he s t at us of an event .
\param[ i n ] event The event handl er of t he event t o check .
\ ret urn TRUE i f t he event i s set , FALSE ot her wi s e .
/
bool EVNT GetEvent ( EVNT Handle event ) ;
/ !
\ b r i e f Routi ne t o check i f an event i s pendi ng .
I f an event i s pending , t he event i s c l e ar e d
and t he c a l l b a c k i s c a l l e d .
\param[ i n ] c a l l b a c k Cal l back r out i ne t o be c a l l e d .
The event handl e i s passed as argument t o t he c a l l b a c k .
/
void EVNT HandleEvent ( void ( c al l bac k ) ( EVNT Handle) ) ;
/ ! \ b r i e f Event module i n i t i a l i z a t i o n /
void EVNT Init ( void) ;
17.6 Event Data Structure
With having the high level interface set, it is time to get into the details of
the implementation. As previously mentioned, we are going to implement
the events with an array of event descriptors. We do have a type to be used
as event handle (EVNT Handle), and an event can be either set or not set
(cleared). As such, all what we need is an array of bits. The number of
bits needed is dened by EVNT NOF EVENTS. With this, we can come up with
following implementation for the event array which packs the event bits into
an array of bytes:
stati c uint8 t EVNT Events [ ( ( EVNT NOF EVENTS1) /8) +1] ;
/!< Bi t s e t of event s /
This implementation has the advantage of using minimal memory. But as
we see later on, this comes with additional costs accessing the events. If
performance is a concern, you might trade in memory for additional runtime
performance. An alternative implementation would use a byte for each event
which will simplify access to the event array. As long as you do have enough
c Erich Styger 195
INTRO V1.70
RAM available and not too many events, that might be a valuable alternative
implementation. The interface proposed for our module allows to change the
implementation without impacting the application.
Figure 17.5 shows how the event handle numbers are mapped to bit num-
bers in the array of bytes. Figure 17.5 shows the rst byte of the array.
EVNT Events[] [0]
0 1 2 3 4 5 6 7
EVNT INIT
EVNT SW1 PRESSED
EVNT SW2 PRESSED
EVNT SW3 PRESSED
EVNT SW4 PRESSED
Figure 17.5: Event to Bit Mapping
To set an event, we need now to access and set the corresponding bit
number in the array, based on the event handle. This can be accomplished
with a combination of division, shift and modulo operations on the event
array:
EVNT Events [ event /8] |= 0x80>>(event %8) ;
/!< Set t he event /
Clearing an event bit is accomplished in a similar way:
EVNT Events [ ( event ) /8] &= (0 x80>>(( event ) %8) )
/!< Cl ear t he event /
And nally the implementation to determine if an event is set or not:
( bool ) ( EVNT Events [ ( event ) /8] &(0x80>>(( event ) %8) ) )
/!< Return TRUE i f event i s s e t /
With this we are now able to implement the methods for our module:
void EVNT SetEvent ( EVNT Handle event ) {
SET EVENT( event ) ;
}
void EVNT ClearEvent ( EVNT Handle event ) {
CLR EVENT( event ) ;
c Erich Styger 196
INTRO V1.70
}
bool EVNT GetEvent ( EVNT Handle event ) {
return GET EVENT( event ) ;
}
17.7 Reentrancy
One problem remains: as shown in Figure 17.3 it is possible that our event
array data structure is accessed both by our main program and by an ISR.
As a consequence, we need to protect access to the event array. Or in other
words: we need to have a way to grant mutual exclusive access to the data
structure. What we need is a Mutex. Basically the mutex can be with
something like:
1. Disable/Enable Interrupts
2. EnterCritical and ExitCritical
3. SemaphoreTake and SemaphoreGive
Disabling and enabling interrupts is simple, but does not preserve the inter-
rupt state (if interrupts are enabled or not). EnterCritical and ExitCritical
exist as macros for many microprocessors: they preserve the state of the in-
terrupts. Semaphores are something provided by an operating system and
might not be always available.
17.7.1 Disable and Enable Interrupts
As we need to protect access to the common data from any other routines,
and as such other routines could access the data from an ISR, the easiest way
is to simply disable all interrupts before accessing the data, and enable the
interrupts afterwards again. For an HCS08 microcontroller this could look
like this:
#define Enabl eI nt er r upt s ( ) asm( c l i )
#define Di s abl e I nt e r r upt s ( ) asm( s e i )
Di s abl e I nt e r r upt s ( ) ;
/ c r i t i c a l s e c t i on here /
Enabl eI nt er r upt s ( ) ;
This approach works ne and is very ecient. However if interrupts were
already disabled, they will be always enabled after the critical section.
c Erich Styger 197
INTRO V1.70
17.7.2 EnterCritical and ExitCritical
To solve the previous problem, another approach is to save and restore the
current interrupt status. For the HCS08 microcontroller this would look like
this:
#define Ent e r Cr i t i c al ( ) \
{ asm PSHA; asm TPA; asm SEI ; asm STA savedReg ; asm PULA; }
#define Exi t Cr i t i c a l ( ) \
{ asm PSHA; asm LDA savedReg ; asm TAP; asm PULA; }
Ent e r Cr i t i c al ( ) ;
/ c r i t i c a l s e c t i on /
Exi t Cr i t i c a l ( ) ;
The dierence is now that the macros are saving the previous condition
register content (which contains the interrupt mask bit) and restores it back
again at the end of the critical section. Still, you need to be careful about
where the register content is stored: if this is a global variable, then you
need to make sure that you do not nest multiple EnterCritical() and
ExitCritical(). You might consider an implementation which stores the
register value on the stack instead in global memory.
17.7.3 Semaphores
Last but not least, if you are using an operating system, you could use
the mutual exclusion and critical section protection methods oered by the
operating system. Normally every operating system oers some means of
protecting critical sections using semaphores or similar means. Compared
with previous methods they are more powerful and exible, but they are
more system resources too. As a general guidelines use them wisely, and
keep the critical sections to a minimum.
17.7.4 Implementation with Enter/ExitCritical
As we want to be independent of an RTOS, we are using EnterCritical()
and ExitCritcal() to protect our critical sections:
void EVNT SetEvent ( EVNT Handle event ) {
Ent e r Cr i t i c al ( ) ;
SET EVENT( event ) ;
Exi t Cr i t i c a l ( ) ;
}
void EVNT ClearEvent ( EVNT Handle event ) {
c Erich Styger 198
INTRO V1.70
Ent e r Cr i t i c al ( ) ;
CLR EVENT( event ) ;
Exi t Cr i t i c a l ( ) ;
}
bool EVNT GetEvent ( EVNT Handle event ) {
bool i s Se t ;
Ent e r Cr i t i c al ( ) ;
i s Se t = GET EVENT( event ) ;
Exi t Cr i t i c a l ( ) ;
return i s Se t ;
}
17.8 Event Processing
We can now set, clear and check events. Typically we will set events in
the interrupt service routine, and our main program will handle them. So
what we need is an easy way to check if there are any pending events from
the main application loop. For this we are going to implement the function
EVNT HandleEvent(). This function goes through the event array and checks
if there are any events set. If there is an event set, it clears the event and
calls a callback.
void EVNT HandleEvent ( void ( c al l bac k ) ( EVNT Handle) ) {
/ Handl e t he one wi t h t he hi g he s t p r i o r i t y .
Zero i s t he event wi t h t he hi g he s t p r i o r i t y . /
uint8 t event ;
Ent e r Cr i t i c al ( ) ;
/ do a t e s t on every event : /
for ( event =0; event<EVNT NOF EVENTS; event++) {
i f (GET EVENT( event ) ) { / event pr es ent ? /
CLR EVENT( event ) ; / c l e ar event /
break ; / get out of l oop /
}
}
Exi t Cr i t i c a l ( ) ;
i f ( event != EVNT NOF EVENTS) {
c al l bac k ( event ) ;
}
}
The method iterates thorough the array of event bits. For the rst event bit
set, it clears the bit and breaks out of the loop. As it is accessing shared
data, the routine needs to protect the critical section. If an event has been
c Erich Styger 199
INTRO V1.70
found as set, it will call the provided callback.
17.9 Integration
Now it is time to see how everything ts together. Below is an example
where a keyboard interrupt sets an event ag, which then is processed by the
main application loop. In our example below, the main() routine is setting
an initial event itself, followed by an endless loop to handle and process the
events:
void main( void) {
EVNT SetEvent (EVNT INIT) ;
for ( ; ; ) {
EVNT HandleEvent ( APP HandleEvent ) ;
}
}
With EVNT HandleEvent() we pass an additional callback function
pointer APP HandleEvent.
void APP HandleEvent ( EVNT Handle event ) {
switch( event ) {
case EVNT INIT:
/ wr i t e welcome message /
LCD Wri teStri ng ( System s t ar t up . . . ) ;
case EVNT SW1 PRESSED:
SND Beep( 300) ; / beep f or 300 ms /
/ changes de s i r e d t emperat ure /
ChangeTemperature ( 1) ; / i ncr eas e t emperat ure /
SendTemperature ( ) ; / use t r ans c e i v e r /
break ;
case EVNT SW2 PRESSED:
SND Beep( 300) ; / beep f or 300 ms /
/ changes de s i r e d t emperat ure /
ChangeTemperature(1) ; / decreas e t emperat ure /
SendTemperature ( ) ; / use t r ans c e i v e r /
break ;
} / s wi t ch /
}
What is missing is where we set the event. In our AC system an interrupt
will be raised for a key pressed. In our ISR we simply can set the event;
void i nt e r r upt KeyISR( void) {
ACK KBI INTERRUPT( ) ; / acknowl edge i nt e r r upt /
i f ( Key1Pressed ( ) ) {
EVNT SetEvent (EVNT SW1 PRESSED) ;
c Erich Styger 200
INTRO V1.70
} el se i f ( Key2Pressed ( ) ) {
EVNT SetEvent (EVNT SW2 PRESSED) ;
}
}
With our Event module we have now a way to set ags which are processed
asynchronously in the main loop. It helps us to keep the interrupt service
routines small and ecient.
c Erich Styger 201
INTRO V1.70
c Erich Styger 202
Chapter 18
Triggers
18.1 Introduction
So far we have the ability and infrastructure to ag an event and to process
it in the main loop. What is missing is a way to do something in a time
trigged fashion: for example to blink an LED every second, or to turn on an
LED 500 ms after a button has been pressed.
For this we are going to introduce the concept of a Trigger. Triggers are
sometimes as well used to denote a hardware functionality: for example a
microcontroller hardware is set up to trigger on a read or write access to halt
the processor in order to implement what is also known as watchpoint. We
are using triggers here in a little bit dierent way. We want the application
to trigger at a given time in the future.
18.2 Blinking LED
A common thing used in embedded applications is blinking an LED with a
given period. For example you might want an LED blink every 500 ms to
indicate that your application is still running. Such a blinking LED is often
called a heartbeat. An easy way to do this would be to set up a periodic timer
which then is triggered every 500 ms:
i nt e r r upt void Timer500ms ( void) {
LED Neg ( ) ; / t o g g l e t he LED /
}
That works ne, but this wastes a timer just blinking an LED. So it might
be a much better way to reuse one of your existing periodic timers to avoid
this. For example if you already have a 10 ms periodic tick timer, then you
203
INTRO V1.70
could reuse that that timer to blink the LED:
i nt e r r upt void Timer10ms ( void) {
stati c uint8 t cnt = 0;
/ b l i nk i ng LED /
cnt++; / i ncrement count er /
i f ( cnt ==500/10) { / 500 ms reached /
LED Neg ( ) ; / t o g g l e t he LED /
cnt = 0; / r e s t a r t count er /
}
/ ot her t hi ng s t o do every 10 ms f o l l o ws here . . . /
}
We are using a static local variable as a counter: Technically this is
like a normal global variable, but visible only inside the function where we
have dened that cnt variable. This solution is ne as it only adds a little
overhead to our 10 ms interrupt routine. But we need to keep in mind that
adding more and more to our interrupt service routine will increase latency
for other things in the system.
While our approach sounds ne, it might get a little bit complicated,
once you start to extend it. Having a second LED blinking with another
frequency? Flash an LED for 250 ms after a button has been pressed? Or
turn on a sounder for 500 ms? Things might get more and more complicated
with some additional if and else if in our interrupt routine. So we need
to have something implemented which is more versatile.
18.3 Design Idea
First, it would be good to collect what we need:
An infrastructure to do things in a periodic way.
Suitable for re and forget: you should be able to specify things like
do this in 850 ms and it will take care.
It should suitable be for rather small things, like blinking an LED. For
more heavy weight stu, we better would use something dierent or
even an RTOS.
It should be light weight: use little resources on the microcontroller.
It is about rather few such things we want to do: around ten or little
bit more, but not hundreds of things.
c Erich Styger 204
INTRO V1.70
It should be easy to use and to understand.
It should be suitable both with and without using an RTOS.
Having this in mind, we could maybe base our design on the Timer10ms()
periodic interrupt? This would give us a periodic interrupt and time base.
The idea is that instead we implement things directly in the interrupt routine,
we implement a trigger module which maintains the jobs or triggers we
want to perform. The application could add or set such triggers, and the
periodic timer interrupt routine simply would check if there is any pending
trigger to execute.
What we need to keep in mind is impact on the rest of our system: as we
would execute things from an interrupt, we need to be careful not to increase
the latency for the rest of the system. So again we need to do things as fast
and as ecient as possible. And we always need to keep in mind that the
triggers are executed in the context of an interrupt.
18.4 Tick Timer
So the basic idea is to have a periodic tick timer which is red say every
10 ms. This would give us a time base: the tick counter. Then we could
compare that tick counter against the tick counter of the trigger we want to
execute: if this matches, we execute that trigger and continue with the rest
of the ISR (18.1).
So it is now a good time to think about the interface. First, we want
to keep track with the number of ticks, so we dene a method to count the
ticks:
void TRG IncTicks ( void) ;
This method then would be called from our periodic timer interrupt:
i nt e r r upt void Timer10ms ( void) {
TRG IncTicks ( ) ; / i nf orm about t he new ti me /
/ ot her t hi ng s t o do every 10 ms f o l l o ws here . . . /
}
So the idea is that from the tick interrupt we call the TRG IncTicks() func-
tion, and this one would check if there are any triggers: if the time is up
to do something, it would execute it. One question remains: what should
happen with the trigger once it has been executed? Basically there are two
options:
c Erich Styger 205
INTRO V1.70
Start ISR
Increment
tick
counter
Trigger?
Execute
Trigger
Finish ISR
no
yes
Figure 18.1: Tick Timer ISR Control Flow
1. Keep the trigger so it triggers again. This is handy for periodic triggers
like ashing the LED: You set the trigger say to execute in 100 ms, it
will trigger in 100 ms and then again the next 100 ms.
2. Clear the trigger. This means that once it has been executed, it will
not trigger again. If the trigger shall be executed again, then it needs
to be activated again.
In our approach we are using the clearing approach: It should make the
implementation simpler (we will see this later on), plus if the trigger needs
to be re-installed, the trigger could do this itself too.
18.5 Trigger Interface
As we have a pretty good idea how things should work, we could come up
with following interface:
/ !
c Erich Styger 206
INTRO V1.70
\ b r i e f I n i t i a l i z e s t he t r i g g e r module
/
void TRG Init ( void) ;
/ !
\ b r i e f Increment s t he t i c k count er ,
c a l l e d from an i nt e r r upt s e r v i c e r out i ne .
Execut es any pendi ng t r i g g e r s .
/
void TRG IncTicks ( void) ;
/ !
\ b r i e f s e t s a t r i g g e r t o be execut ed .
/
void TRG SetTrigger ( uint16 t t i ckt i me , cal l backType c al l bac k ) ;
This is just an initial draft, and we need to rene it later on.
18.6 Trigger Descriptor
With this, we could start dening our data structure needed. What we need
is
The time when the trigger shall be executed. It makes sense to use the
tick counter as entity as we measure the time with ticks.
The information what to execute: A usual way to implement this is to
use a function pointer
Any optional arguments for the function pointer. To make it generic,
we could use a void data pointer to pass any kind of parameters.
typedef struct Tri ggerDesc {
uint16 t t r i g ge r Ti c ks ; / ti me t o t r i g g e r /
void ( c al l bac k ) ( void) ; / c a l l b a c k f unct i on /
void data ; / parameter f or c a l l b a c k /
} Tri ggerDesc ;
That already looks good, but is maybe not very generic. For example, we
might use a 32bit trigger counter later on. Then using uint16 t for the
triggerTicks is not a exible solution. Instead, we could come up with our
own types so they can be changed easily later:
typedef void TRG CallBackDataPtr ;
typedef void ( TRG Callback ) ( TRG CallBackDataPtr ) ;
typedef uint16 t TRG TriggerTime ;
c Erich Styger 207
INTRO V1.70
typedef struct Tri ggerDesc {
TRG TriggerTime t i c k s ;
TRG Callback c al l bac k ;
TRG CallBackDataPtr data ;
} Tri ggerDesc ;
18.7 Data Allocation
We have now a descriptor for a single trigger. Now we have to decide how
we want to store the triggers. Basically there are several ways:
Dynamic: Allocate the trigger descriptor on the heap using malloc()
or something similar.
Static: Using a xed array of descriptors.
Using a dynamic approach would allow a dynamic number of triggers. On
the other side performance impact for the allocation and deallocation is a
concern. Additionally memory fragmentation and possible memory leaks are
a concern.
The static approach is simple but is less exible. But probably this is
enough for our use cases. So we are going to implement it as a static array.
Consequently, we need to know the number of the triggers in advance to
dene our array. For our application we want to implement following three
functions:
1. Blinking an LED with a given frequency.
2. Pressing a button turns on a LED, and we want to turn o the LED
after a while.
3. We are using a buzzer which needs to be turned o after a given time.
This could be implemented with using an enumeration type to identify
the triggers:
typedef enum {
TRG LED BLINK, /!< LED b l i nk i ng /
TRG BTNLED OFF, /!< Turn LED o f f /
TRG BTNSND OFF, /!< Swi t ch sounder o f f /
TRG LAST /!< Must be l a s t ! /
} TRG TriggerKind ;
c Erich Styger 208
INTRO V1.70
stati c TRG TriggerDesc TRG Triggers [ TRG LAST] ;
/!< t r i g g e r array /
18.8 SetTrigger
It is time to implement the code to set a trigger. What we need is the trigger
to set, at which time and what call back has to be called with the optional
data. So this would give us following interface:
TRG SetTrigger ( TRG TriggerKind kind , TRG TriggerTime t i c ks ,
TRG Callback cal l back , TRG CallBackDataPtr data ) ;
The question is if the parameter ticks shall be relative to the current tick
time or absolute. I think it makes sense to use use it as a relative time, as
this is triggers are used in many cases:
Turn the LED o for the next 30 ms.
Disable buzzer in 60 ms.
After button has pressed, check status again in 100 ms.
Using a relative notion is natural for above use cases. It would be dierent
if you need something like
Sound an alarm at 6:35 pm.
Turn o water irrigation at 3:00 am.
Assuming a 16bit unsigned parameter and a 10 ms tick counter, this still
would allow us to specify a time of 65535*0.01 s = 655.35 s or about 11
minutes which should suitable for most systems.
The other question is if the ticks counter in our data structure should
be relative or absolute. If we store the relative ticks parameter as well
as relative ticks inside the TRG Triggers array, the implementation would
look like this
void TRG SetTrigger ( TRG TriggerKind kind ,
TRG TriggerTime t i c ks ,
TRG Callback cal l back ,
TRG CallBackDataPtr data )
{
TRG Triggers [ ki nd ] . t i c k s = t i c k s ; / r e l a t i v e /
TRG Triggers [ ki nd ] . c al l bac k = c al l bac k ;
TRG Triggers [ ki nd ] . data = data ;
c Erich Styger 209
INTRO V1.70
}
If you store it as absolute, you would need to change it to
void TRG SetTrigger ( TRG TriggerKind kind ,
TRG TriggerTime t i c ks ,
TRG Callback cal l back ,
TRG CallBackDataPtr data )
{
TRG Triggers [ ki nd ] . t i c k s = TRG CurrTicks+t i c k s ;
TRG Triggers [ ki nd ] . c al l bac k = c al l bac k ;
TRG Triggers [ ki nd ] . data = data ;
}
That way we need to add the current tick counter to the parameter: doable,
but comes with some overhead. To keep things simple, we rather stick with
using the relative tick counter in the data structure. One thing we have
missed so far: Our implementation needs to protect a critical section, as
both the application code and interrupt code through TRG IncTick() will
access the shared data.
void TRG SetTrigger ( TRG TriggerKind kind ,
TRG TriggerTime t i c ks ,
TRG Callback cal l back ,
TRG CallBackDataPtr data )
{
Ent e r Cr i t i c al ( ) ;
TRG Triggers [ ki nd ] . t i c k s = t i c k s ;
TRG Triggers [ ki nd ] . c al l bac k = c al l bac k ;
TRG Triggers [ ki nd ] . data = data ;
Exi t Cr i t i c a l ( ) ;
}
And to make things prepared for future extensions and error handling,
we extend our interface and implementation to return an error code:
uint8 t TRG SetTrigger ( TRG TriggerKind kind ,
TRG TriggerTime t i c ks ,
TRG Callback cal l back ,
TRG CallBackDataPtr data )
{
Ent e r Cr i t i c al ( ) ;
TRG Triggers [ ki nd ] . t i c k s = t i c k s ;
TRG Triggers [ ki nd ] . c al l bac k = c al l bac k ;
TRG Triggers [ ki nd ] . data = data ;
Exi t Cr i t i c a l ( ) ;
return ERR OK;
}
c Erich Styger 210
INTRO V1.70
18.9 IncTicks
Now we get to the implementation of TRG IncTick(), which could look like
this in pseudo code:
void TRG IncTick ( void) {
Increment Ti ck Counter ;
i f HasTri ggerForThi sTi ckCount then
removeTri gger ;
c a l l c al l bac k wi th parameter ;
end i f
}
First, we increment the tick counter by one. As we have implemented the
data structure as an array, we need to iterate through the array:
void TRG IncTick ( void) {
CurrentTi ckCounter++
for a l l el ements i n array
i f ElementTickCount == CurrentTi ckCounter then
Cal l Cal l backWi thParameter
end i f
end for
}
Then we check the condition HasTriggerForThisTickCount. Now we see
another advantage that we used a relative tick counter in our data structure.
If we would have used an absolute tick counter, then could compare that
value with the current tick counter. But what happens if our application
had just called TRG SetTrigger with a zero tick count?
TRG SetTrigger (TRG BTNLED OFF, 0 , MyLEDOff , NULL) ;
As we increment the tick counter at the beginning of TRG IncTick() we will
might miss that trigger until our tick counter makes a wrap over. To catch
this case, a solution would be to postpone the counter increment to the end
of TRG IncTick().
As we are using a relative tick counter in our data structure, we simply
could count down the tick counter for each trigger. If the count is zero we
call the callback. Additionally, as we do not need to compare against the
CurrentTickCounter, we can have it removed:
void TRG IncTick ( void) {
c Erich Styger 211
INTRO V1.70
for a l l El ements i n array
ElementTickCount
i f ElementTickCount i s 0 then
Cal l Cal l backWi thParameter
end i f
end for
}
The only remaining problem we have: how to know if a trigger is still active
or not? We could add an enabled ag to the data structure, but this would
consume additional memory. Instead, we know it from the callback function
pointer: if it is NULL, we dont have to call it. With this in mind, we nally
could come up with following implementation:
TRG Callback c al l bac k ;
TRG CallBackDataPtr data ;
TRG TriggerKind i ;
for ( i =(TRG TriggerKind ) 0; i <TRG LAST; i ++) {
i f ( TRG Triggers [ i ] . t i c k s ! =0) {
TRG Triggers [ i ] . t i c ks ;
}
i f ( TRG Triggers [ i ] . t i c k s==0
&& TRG Triggers [ i ] . c al l bac k != NULL)
{
c al l bac k = TRG Triggers [ i ] . c al l bac k ;
data = TRG Triggers [ i ] . data ;
TRG Triggers [ i ] . c al l bac k = NULL;
c al l bac k ( data ) ;
}
} / f or /
}
This implementation iterates the array and decrements the tick counter. If
the counter is zero and a valid callback, it resets the function pointer and
calls the call back with the parameter. But two problems still remain: if the
callback would set again a trigger for the relative time zero (at the current
time), we might miss it. With following implementation we can catch this
case: we call a separate function as long there are callbacks:
stati c bool CheckCal l backs ( void) {
TRG TriggerKind i ;
TRG Callback c al l bac k ;
TRG CallBackDataPtr data ;
bool cal l edCal l Back = FALSE;
for ( i =(TRG TriggerKind ) 0; i <TRG LAST; i ++) {
i f ( TRG Triggers [ i ] . t i c k s == 0
c Erich Styger 212
INTRO V1.70
&& TRG Triggers [ i ] . c al l bac k != NULL)
{
c al l bac k = TRG Triggers [ i ] . c al l bac k ;
data = TRG Triggers [ i ] . data ;
TRG Triggers [ i ] . c al l bac k = NULL;
c al l bac k ( data ) ;
cal l edCal l Back = TRUE;
}
} / f or /
return cal l edCal l Back ;
}
void TRG IncTick ( void) {
TRG TriggerKind i ;
for ( i =0; i <TRG LAST; i ++) {
i f ( TRG Triggers [ i ] . t i c k s ! =0) {
TRG Triggers [ i ] . t i c ks ;
}
} / f or /
while ( CheckCal l backs ( ) ) {}
}
18.10 Making it reentrant
One thing is missing: In case of nested interrupts and if other interrupts can
set triggers, you need insert code for critical section protection as well. First
we need to add EnterCritical() and ExitCritical() in TRG IncTick():
void TRG IncTick ( void) {
TRG TriggerKind i ;
Ent e r Cr i t i c al ( ) ;
for ( i =(TRG TriggerKind ) 0; i <TRG LAST; i ++) {
i f ( TRG Triggers [ i ] . t i c k s ! =0) {
TRG Triggers [ i ] . t i c ks ;
}
} / f or /
Exi t Cr i t i c a l ( ) ;
while ( CheckCal l backs ( ) ) {}
}
What remains is to protect the data access with EnterCritical() and
ExitCritical() in CheckCallbacks():
stati c bool CheckCal l backs ( void) {
TRG TriggerKind i ;
c Erich Styger 213
INTRO V1.70
TRG Callback c al l bac k ;
TRG CallBackDataPtr data ;
bool cal l edCal l Back = FALSE;
for ( i =(TRG TriggerKind ) 0; i <TRG LAST; i ++) {
Ent e r Cr i t i c al ( ) ;
i f ( TRG Triggers [ i ] . t i c k s == 0
&& TRG Triggers [ i ] . c al l bac k != NULL)
{
c al l bac k = TRG Triggers [ i ] . c al l bac k ;
data = TRG Triggers [ i ] . data ;
TRG Triggers [ i ] . c al l bac k = NULL;
Ex i t Cr i t i c a l ( ) ;
c al l bac k ( data ) ;
cal l edCal l Back = TRUE;
} el se {
Ex i t Cr i t i c a l ( ) ;
}
} / f or /
return cal l edCal l Back ;
}
18.11 Initialization
What is missing is the initialization of our trigger module.
void TRG Init ( void) {
TRG TriggerKind i ;
for ( i =(TRG TriggerKind ) 0; i <TRG LAST; i ++) {
TRG Triggers [ i ] . t i c k s = 0;
TRG Triggers [ i ] . c al l bac k = NULL;
TRG Triggers [ i ] . data = NULL;
}
}
Alternatively TRG Init() could as well setup the periodic interrupt which
calls TRG IncTick(). In our application this will be implemented in a
TMR Init() function which is called as part of our application startup.
18.12 Blink!
With this we are ready to use our triggers to blink the LED:
void main( void) {
c Erich Styger 214
INTRO V1.70
TMR Init ( ) ; / i n i t i a l i z e pe r i odi c t i c k t i mer /
TRG Init ( ) ; / i n i t i a l i z e module /
Enabl eI nt er r upt s ( ) ;
/ i n s t a l l t r i g g e r t o b l i nk LED /
TRG SetTrigger (TRG LED BLINK, 0 , LED HeartBeat , NULL) ;
for ( ; ; ) {} / l e t t he t r i g g e r do t he work /
}
After initializing the hardware and software module, we set a trigger to blink
our LED. We set the next trigger to trigger immediately at the next tick
interrupt. LED HeartBeat() is our callback. As we do not need an additional
data parameter, we pass NULL for it.
The LED Heartbeat() function is implemented as:
stati c void LED HeartBeat ( void p) {
( void) p ; / unused parameter /
LED1 Neg ( ) ;
TRG SetTrigger (TRG LED BLINK,
1000/TRG TICKS MS, LED HeartBeat , NULL) ;
}
At the next tick timer interrupt, TRG IncTick() will go through our trigger
list. It will nd that TRG LED BLINK is due and will call our LED HeartBeat()
method. This will negate the LED and set again the trigger to be called in
1000 milliseconds.
But what if you want to blink dierent LEDs? Here you could use the
additional parameter: The parameter ledP tells the trigger which LED has
to be used:
stati c void LED Blink ( void l edP) {
i f ( ( ( uint8 t ) l edP)==1) {
LED1 Neg ( ) ;
( ( uint8 t ) l edP)++;
} el se i f ( ( ( uint8 t ) l edP)==2) {
LED2 Neg ( ) ;
( ( uint8 t ) l edP) =1;
}
TRG SetTrigger (TRG LED BLINK,
1000/TRG TICKS MS, LED Blink , l edP) ;
}
We are passing a data pointer to our trigger. Special care needs to be taken
that the data is valid all time. The following example will not work:
void f oo ( void) {
uint8 t l ed = 1;
TRG SetTrigger (TRG LED BLINK, 0 , LED Blink , &l ed ) ;
}
c Erich Styger 215
INTRO V1.70
Here the address of a local variable is passed, and the variable led is only
available as long as we stay in the function foo(). To solve this problem we
can use a static local variable instead:
void f oo ( void) {
stati c uint8 t l ed = 1;
TRG SetTrigger (TRG LED BLINK, 0 , LED Blink , &l ed ) ;
}
18.13 Beep!
While our LED Heartbeat is a periodic trigger, we can use our infrastructure
for non-periodic triggers too. For this we are using a buzzer which we want
to turn on for a given time, and then it shall be turned o automatically
with a trigger.
stati c void Sounder ( void data ) {
uint16 t dur at i on = ( ( uint16 t ) data ) ;
i f ( dur at i on==0) { / o f f /
BUZZER Off ( ) ;
} el se {
BUZZER On( ) ;
( ( uint16 t ) data ) = 0;
TRG SetTrigger (TRGSOUNDER, durati on , Sounder , data ) ;
}
}
void SND Beep( uint16 t ms) {
stati c uint16 t ti me = ms/TRG TICK MS;
TRG SetTrigger (TRGSOUNDER, 0 , Sounder , &ti me ) ;
}
In our examples we used a static local variable to ensure that the mem-
ory address we pass to the trigger is always valid. This increases the amount
of RAM used. If we just want to pass a value as parameter, it would be
possible to pass that value directly, instead of using the address of it.
stati c void Sounder ( void data ) {
/ s i z e o f ( i nt )==s i z e o f ( voi d ) /
uint16 t dur at i on = ( i nt ) data ;
i f ( dur at i on==0) { / o f f /
BUZZER Off ( ) ; / s t op sounder /
} el se {
BUZZER On( ) ; / s t a r t sounder /
c Erich Styger 216
INTRO V1.70
TRG SetTrigger (TRGSOUNDER,
durati on , Sounder , 0) ;
}
}
void f oo ( void) {
Sounder ( ( void) 200/TRG TICK MS) ;
}
With this we can come up with a simple Beep() function. Beep() accepts
an argument how long the buzzer shall be on. It simply enables the buzzer
and sets up a trigger which will turn it o using a trigger.
stati c void SoundOff ( void p) {
BUZZER Off ( ) ; / t urn buz z er o f f /
}
void Beep( uint16 t ms) {
BUZZER On( ) ; / t urn buz z er on /
TRG SetTrigger (TRG BTNSND OFF,
ms/TRG TICKS MS, SoundOff , 0) ;
}
18.14 Realtime Aspects
With having our triggers in place, it is worth to look at some realtime aspects
of it. One thing to consider is the frequency and period of the tick timer used
for our Trigger module. As with the tick timer used in an RTOS, the tick
timer used for the Triggers dene the resolution: If you have a tick timer
with a period of 100 ms, then you have Triggers with an accuracy of 100 ms
as well. Everything will be synchronized at the tick interrupt time.
The other thing to consider: our Triggers are executed in the context of
an interrupt service routine. The interrupt service routine of the tick timer
is calling our Trigger module, which then will execute any pending Trigger.
With this in mind, you should
Keep the number of Triggers as small as possible. The more Triggers
you have, the longer it will take for the Trigger module to go through
the list. If you have many Triggers, but only few active at a time, then
consider for example a linked list.
Whatever you do in a trigger, it should be something small you would
do in an interrupt service routine otherwise. Things like toggling a
c Erich Styger 217
INTRO V1.70
pin. It is not designed to do complicated things which consume a lot of
time as this would increase the interrupt latency time. Instead consider
just setting an event ag and do the heavy lifting outside the interrupt
service routine.
As Triggers are executed from an interrupt service routine, every shared
code between interrupt service routine and main application needs to
be reentrant. In case you have shared data, you need to ensure with
critical sections that things are properly guarded against mutual access.
The core requirement for a realtime system is to produce the correct
result at the correct time. The Events and Triggers presented here help us
to achieve this. The Triggers help us to do things at a given deadline or
within the boundaries of a deadline. As the triggers are executed from a
periodic timer interrupt, that timer needs to be carefully congured to meet
the required timing. This includes the priority of the timer, but as well the
latency introduced by our implementation.
The Events help us to reduce the latency time in interrupt service rou-
tines. It can improve the responsiveness and timeliness of the system, as it
provides a way to postpone things from an interrupt service routine if it can
wait. If things are triggered by an interrupt, we can delay things outside the
actual interrupt routine reducing the load of the interrupt service routine.
Still we need to ensure that the Events are handled in a timely fashion too.
Keeping this in mind, you should be able to apply both the Events and
the Triggers Module successfully.
c Erich Styger 218
Chapter 19
Doxygen
19.1 Introduction
Every developer should somehow document what he has implemented. But
if you document your project in an external document (e.g. a Word docu-
ment), you realize that the documentation gets out of sync very fast: You
probably make changes to the source code, and you forget about updating
the documentation. The solution to this in many cases is doxygen: doxygen
is a compiler which compiles your source les and produces documentation
about it in many dierent formats. With this, your project source les are
the documentation.
19.2 Learning Goals
In this section you will learn the following:
Understand the principles of doxygen for documentation generation.
Download and install the tools needed for using doxygen in eclipse.
Document your sources with doxygen.
Using doxygen to create additional documentation for your project be-
yond the sources.
19.3 Doxygen, Graphvic and Eclox
To use doxygen, you need:
219
INTRO V1.70
doxygen: this is the compiler package to generate documentation from
your sources
In the context of eclipse, there is an eclipse plugin interfacing to doxygen, so
you can use it within eclipse: To use doxygen, you need:
eclox: an eclipse plugin which provides a front end to the doxygen
system.
Figure 19.1: Eclox Overview
eclox Overview (Source: http://home.gna.org)
Eclox (19.1) provides to edit the doxyle, and provides error parsers for
eclipse.
Finally, doxygen has really nice feature for drawing graphs, especially
useful for dependency graphs:
graphviz : a package to visualize graphs.
19.4 Installation
To install the needed parts for doxygen generated documentation for your
eclipse system (in our example CodeWarrior for MCU), execute the following
steps:
1. From http://www.doxygen.org: download and install the software
with the default options.
2. From http://www.graphviz.org: download and install the software
with the default options.
3. From http://home.gna.org/eclox/#overview: either download it as
package and use the eclipse updater with that package, or point the
eclipse updater to the eclox upater site (http://download.gna.org/
eclox/update). The following steps describe how to use the updater
site.
c Erich Styger 220
INTRO V1.70
4. Launch eclipse and select the menu Help > Install New Software (Fig-
ure 19.2).
Figure 19.2: Help > Install New Software
5. In the Available Software Dialog, press the Add button (Figure 19.3).
Figure 19.3: Available Software
6. In the Add Site Dialog, press specify any name, plus http://download.
gna.org/eclox/update as the update site (Figure 19.4) and press OK.
7. Select the eclox package and press Next (Figure 19.5).
c Erich Styger 221
INTRO V1.70
Figure 19.4: Adding a new updater site
Figure 19.5: Installing eclox
8. Proceed through the dialogs to complete the installation.
9. Restart eclipse if asked at the end of the installation.
After eclox is installed, we want to make sure it is used as the workspace
default editor. This will make sure that the source les use a doxygen aware
coloring, so you can easily spot doxygen comments.
For this, select the menu Window > Preferences(Figure 19.6). Enter doxy
as lter text (to limit the list of settings) (Figure 19.7). Select the C/C++ >
Editor page. In the settings, set the Workspace default to Doxygen (Figure
19.7), press Apply and OK.
c Erich Styger 222
INTRO V1.70
Figure 19.6: Window Preferences
Figure 19.7: Doxygen Editor Workspace Default
c Erich Styger 223
INTRO V1.70
19.5 Problems
19.1. Can you explain the concept of doxygen in a few sentences?
19.2. Can you explain the dierences between installing eclox from an up-
dater site or from an archive in a few sentences?
19.3. What is the role of the error parser which is the part of eclox?
19.4. Can you describe in a few words what are dependency graphs in doxy-
gen, and what you can do with them?
c Erich Styger 224
Part IV
Laboratory Short Courses
225
Chapter 20
Introduction
The Laboratory Short Course (LSC) provide learning content to specic
knowledge areas used in the domain of Infotronik. This short course has
been created using an adapted version of the Process Oriented Guided In-
quiry Learning (POGIL) method[12][9]. For more information visit www.
pogil.org. Additionally content from already existing POGIL material[22]
has been reused in this book.
20.1 Guidelines
Not every reader of this book has the same level of knowledge: especially in
a classroom environment were students come with dierent education and
background it is dicult to make sure that everyone has the same level of
knowledge and understanding. Infotronik is based on certain preconditions
which are usually delivered in other modules at HSLU. But things get for-
gotten easily as we all know. The LSC are here to close that gap.
The LSCs are constructed in a way to let you think about a prob-
lem (Explore part), research material and to work on problem solving
(Problem part).
They contain an introduction into the area, together with links to ad-
ditional material and information.
An important part is the exchange with your instructor and class peers:
discuss the problems with them and you will learn even more.
An important part is the Reection: what did you learn? What is
still not clear?
227
INTRO V1.70
The LSCs are self-study material so you can go through them any time
which ts your schedule best. Make sure you team up with somebody as
learning in small teams is most eective. Document your solutions, ndings,
drawings, notes, thoughts and solutions. Discuss and exchange them with
your classroom peers.
Contact your instructor if something is not clear or if you need assistance.
20.2 Report
Depending on your classroom setup, you have to choose from a number of
LSCs and to submit a report. This is usually a written report with following
information:
Name of the LSC
Author(s) of the report (name(s))
What did you learn? What was the most useful thing? This is usually
short paragraph (10-15 lines).
What is still not clear? This gives the teacher a way to get feedback
and to explain things further.
An honest estimation of time (hours/minutes per per person) you had
to spend on the LSC. This time will be used to further balance the LSC
eorts, complexity and size.
Some LSCs ask you to submit as well further material like the sources
or the project, or to demonstrate what you did.
c Erich Styger 228
Chapter 21
Exploring Embedded C
21.1 Overview
We must change some of the ways we think about programs and learn some
new tools and techniques when we change from programming a desktop ap-
plication to an embedded application. This module assumes you have learned
C in another course and will help you explore the features that have been
added to your compiler to deal with the special requirements of an embedded
application.
In this LSC we assume you are using the S08. Things are similar for the
32bit ColdFire V2 (MCF52259), but it is easier to explore things with the
8bit S08 core.
21.2 Learning Objectives
In this module you will learn some of the additional responsibilities of a
programmer writing an application for an embedded system instead of a
desktop or personal computer application. You will learn what the startup
code does and how and when to use the volatile property of a variable. You
will also learn how a C program can access I/O registers, how assembly
language programs can be mixed with C functions, and how a C program
can be written to handle interrupts.
21.3 Success Criteria
When you complete this module you will be able to explain what the C
program startup code does and will be able to show when a volatile variable
229
INTRO V1.70
must be declared. You will also be able to demonstrate that a C program
can access a control register in a xed memory location and how to use bit
set and bit clear instructions when needed.
21.4 Prerequisites
You must be able to write assembly or C programs for your microcontroller,
be able to produce a list le showing the assembly code produced by the
compiler, and be able to simulate C programs or run them on a student
learning kit in the laboratory.
21.5 Comparison of Embedded and Desktop
C Programs
Although C gives embedded system programmers a high-level language, we
must be aware of dierences between the embedded and the desktop ap-
plication worlds. In an embedded system the programmer must pay closer
attention to the memory architecture and I/O capabilities than when writ-
ing desktop applications. In particular, you should be able to answer the
following questions:
What are the locations and the number of bytes of RAM and ROM in
your microcontroller?
What I/O capabilities exist and what are the addresses of control reg-
isters?
How does the C program address a specic memory or I/O control
register location?
If an application needs an assembly language routine, how does the C
program interface with an assembly language function?
Can assembly language instructions be included in your C program? If
so, how is that done?
Can the C program address memory locations in expanded memory
where the address range is outside the normal addresses of the mi-
crocontroller?
How does the C program deal with interrupts and interrupt handlers
or interrupt service routines?
c Erich Styger 230
INTRO V1.70
What data types does your compiler support and how are they stored
in memory?
1. Find the memory map of your microcontroller and list the address
ranges of RAM and ROM
2. What data types does your compiler support and how many bits of
storage are required for each?
21.6 The Outline of an Embedded C Pro-
gram
Any C program contains the following elements:
Start-Up Code: The start-up code initializes the microcontroller hard-
ware such as the stack pointer, watchdog timer (COP), and other mi-
crocontroller features. It also initializes any variable data in RAM
either with a value as specied in your program or with zero.
void main(void): Your program must always have a main(), which is
executed after the start-up code.
Program Functions: Any well designed program will have functions in
addition to main() to do required processing.
Interrupt Handler Functions: Interrupt functions are not normally
found in desktop applications but are used frequently in embedded
systems. Special extensions to an ANSI C compiler are required.
Variables: Variables in C may be automatic or static depending on
where and how they are dened.
Static Variables: Static variables may be declared either inside or out-
side a function. They are allocated a specic memory location in RAM
and although they may or may not be globally visible, their lifetime
persists from one function call to another.
Automatic Variables: Variables that are declared inside a function but
are not also declared as static are called automatic variables. No other
function can access them and they are valid only during the functions
execution time. Automatic variables are allocated storage on the stack.
As an embedded system engineer, we must be sure the system has
enough stack storage space to accommodate the automatic variables in
a function.
c Erich Styger 231
INTRO V1.70
Volatile Variables: A volatile variable is one whose value may change
due to an outside force or event. An example is data that are read
from an I/O port. We must declare these volatile to avoid compiler
optimization that may eliminate necessary code.
1. What does scope of a variable mean?
2. A variable is dened inside a function and the compiler does not al-
locate a specic memory location in RAM for its storage. a) Is this
an automatic or static variable? b) Where is it stored? c) What is
its scope? d) Is data stored in this variable during one function call
available to the function in the next call?
3. A static variable is dened inside a function. a) What is its scope?
b) Where is storage space allocated for it? c) Is data stored in this
variable during one function call available to the function in the next
call?
4. A variable is dened outside a function. a) Is this a static or automatic
variable? b) If another separately compiled function wishes to use this
variable, what must be done in this function to do this?
21.7 Initializing Variables
Static and externally dened variables are allocated storage in RAM and
initialized by the start-up code to either zero or to an initial value given
in your program. Automatic variables are allocated storage on the stack.
Any automatic variables that must be initialized are done when a function is
entered. Automatic variables that do not have some initial value are simply
written when the code requires them to have some value.
Enter the small C program below. Choose ANSI Startup mode when
creating the project in CodeWarrior. It will allow you to explore the start-
up code provided by your compiler. Compile it and prepare to run it on your
hardware.
/ Ext ernal dat a /
char i 2 f i n a l = 0x22 ; / I n i t i a l i z e d val ue /
void main( void) {
char i 1 ; / Automatic v a r i a b l e /
stati c char i 2 ; / St a t i c v a r i a b l e /
char i 3 =3; / Automatic i n i t i a l i z e d v a r i a b l e /
stati c char i 4 =4; / St a t i c i n i t i a l i z e d v a r i a b l e /
c Erich Styger 232
INTRO V1.70
for ( i 1 =0; i 1<i 4;++i 1 ) {
i 2 = i 3 i 1 ;
}
i 2 f i n a l = i 2 ;
for ( ; ; ) {
} / wai t f or e v e r /
}
Listing 21.1: Dierent Variables
Run the program in your simulator or on your hardware. If you create
a new HCS08 project with CodeWarrior, there is a connection option to
use the simulator. Make sure that you select that option so you have teh
simulator available as debug target. Change the memory watch window
to display the RAM memory and step through the start-up code using the
assembly language single step feature.
1. In listing 21.1, where is storage allocated for the variable char i2 nal?
2. In listing 21.1, in what part of the code is i2 nal initialized with 0x22?
3. In listing 21.1, where is storage allocated for the variable char i1?
4. In listing 21.1, is i1 initialized with any value by the Startup() code?
5. In listing 21.1, where is storage allocated for the variable char i2?
6. In listing 21.1, is i2 initialized with any value by the Startup() code?
7. In listing 21.1, where is storage allocated for the variable char i3?
8. In listing 21.1, is i3 initialized with any value by the Startup() code?
If not, when is it initialized?
9. In listing 21.1, where is storage allocated for the variable char i4?
10. In listing 21.1, is i4 initialized with any value by the Startup() code?
11. In listing 21.1, what do you predict the nal value of i2 to be? Is it?
21.8 Minimal Startup
Repeat previous but this time create a new project and select the Minimal
Startup option. Alternatively you can add following line to the beginning of
the start08.c:
c Erich Styger 233
INTRO V1.70
#define ONLY INIT SP
1. With minimal startup code for the S08, you should get an error or
warnings when you make the project? What does it mean?
2. What changes must you make to your program to compensate for the
problem?
Make the changes to your program and verify that the nal value of i2 nal
is the same as in the previous example.
21.9 Plain Char
Your listing 21.1 is using plain char, and not signed char or unsigned char.
C does not specify if char is signed or unsigned, so this is implementation
dened.
1. For your HCS08 compiler, is char a signed or unsigned type?
2. If you are familiar with assembly language programming you may know
that comparing signed and unsigned numbers requires dierent assem-
bly language conditional branches. What changes would you expect
to see in the assembly code for the program if you changed all char
variables to signed char?
21.10 Volatile Variables
The value of volatile variables may change from outside the program. For
example, you may wish to read an A/D converter or a port whose value is
changing. Often your compiler may eliminate code to read the port as part of
the compilers code optimization process if it does not realize some outside
process is changing the ports value. You can avoid this by declaring the
variable volatile.
http://www.netrino.com provides a more detailed explanation.
Enter the following program using the ANSI Startup option and investi-
gate what happens when as you change the variables i and j from static char
to volatile static char. Check either the list le or the assembly window in
the debugger for each of the four combinations and complete the table below.
c Erich Styger 234
INTRO V1.70
void St a t i c Vo l a t i l e ( void) {
stati c char i ;
stati c char j ;
j = i ;
j = i ;
j = i ;
}
Table 21.1 lists the possible permutations for the variables i and j. Inspect
the code produced by the compiler for each of the combinations of static and
volatile static variables.
i j
static static
static volatile static
volatile static static
volatile static volatile static
Table 21.1: static and volatile
1. Describe the dierences in the generated code, based on your changes
for the variables i and j in table 21.1. What can you observe?
21.11 Using Individual Bits in a Memory Lo-
cation
Unlike a desktop application, your embedded application may have many
instances where it must either read or write a specic bit in a control register.
Your compiler should generate code that can modify a single bit (or bits) in
a byte.
ANSI C provides a way to dene bit elds that are addressed individually
using the bitwise inclusive OR and bitwise AND operators. Enter the following
program and verify that your compiler generates instructions that modify a
single bit in a byte.
/ Def i ne t he b i t p o s i t i o ns /
#define B0 1
#define B1 2
#define B2 4
#define B3 8
c Erich Styger 235
INTRO V1.70
#define B4 16
#define B5 32
#define B6 64
#define B7 128
void Bi t s ( void) {
stati c char var1 , var2 ;
/ These s t at ement s gener at e i ns t r uc t i o ns t o change onl y one
b i t i n t he operand /
/ St robe var1 b i t 0 /
var1 = ( char ) ( var1 | B0) ; / Set t he b i t hi gh /
var1 &= B0 ; / Set t he b i t l ow /
/ St robe var2 b i t 1 and b i t 0 /
var2 |= (B1 | B0) ; / Set t he b i t s hi gh /
var2 = ( char ) ( var2 & B1) ; / Reset b i t 1 /
}
Listing 21.2: Bit Operations
Does your compiler produce bit addressing instructions such as BSET and
BCLR?
21.12 ANSI-C Extensions
The ANSI standard for the C language was not designed for embedded con-
troller applications. It lacks standard ways to assign pointers to specic
memory locations (such as I/O registers), a way to implement interrupt ser-
vice routines or handlers, and extended addressing for microcontrollers with
paged memory architectures. Including these features is called language ex-
tensions. Two other compiler terms are useful for you to know. These are
Front End and Back End. The compiler Front End reads the source les,
does all the syntactic and semantic checking, and produces an intermedi-
ate representation of the program which is then passed on to the Back End
to generate the code for the specic microcontroller. This scheme allows a
compiler Front End to be used with a variety of back ends for dierent micro-
controllers. The HC(S)08 compiler provides a variety of language extensions
by allowing certain keywords. Except for the following, we will not explore
these extensions in this module. See compiler manual for more information.
@address: Global Variable Address Modier. Used to assign global
variables to specic addresses.
interrupt: The interrupt keyword is used to denote that a function is
an interrupt routine.
c Erich Styger 236
INTRO V1.70
asm: The asm keyword allows target processor instructions to be in-
cluded inside of C functions.
21.13 Accessing I/O Registers
In most microcontrollers the I/O registers are at xed addresses, and often we
must read from or write to these registers. Your compiler may have a special
way to dene these registers or you may use the following, more portable,
denition using a pointer:
/ Decl are p PORTB t o be a poi nt er t o t he address of Port B Data
/
#define p PORTB ( unsigned char ) 0x0002
Enter the following C program to verify your compiler can address a spe-
cic memory location. In this case we choose to use a RAM memory location
to simulate a port address. Before stepping through your program you can
enter a data value in 0x0102 by displaying the location in the debuggers
Memory pane and double clicking on the location to change the data.
#define p byt e dat a ( unsigned char ) 0x0102 / Fi xed byt e
l oc at i on /
void Poi nt erOperat i on ( void) {
stati c unsigned char t e s t c ha r ;
t e s t c ha r = p byt e dat a ;
p byt e dat a = 6;
}
Listing 21.3: I/O Pointer
21.14 CodeWarrior I/O Port and Bit Ad-
dressing
When you write programs using the CodeWarrior system, a header le for the
microcontroller you are using denes the memory addresses for all registers,
vectors and other microcontroller hardware features. If you use this header
le in your programs you do not have to look up the addresses of each of the
registers you want to access. This makes your programs easily portable to
other microcontrollers at least in the same family.
1. Create a new C project to test the byte and bit addressing of the
CodeWarrior compiler.
c Erich Styger 237
INTRO V1.70
2. Open the header le that the system included in your main.c program
and scroll down to the lines that dene the PTFD - Port F Data Reg-
ister.
(a) What does the following line of code accomplish? extern
volatile PTFDSTR PTFD @0x00000040;
(b) Explain how the structure PTFDSTR works to allow you to access
PTFD as a byte or as individual bits in the port.
3. Write a test program to illustrate how to access PTFD as a byte or
as individual bits using the denitions shown in the header le. When
you write your program include the following statements before you try
manipulating PTFD:
PTFD.Byte = 0; /* Set an initial value for Port F */
PTFDD.Byte = 0xff; /* Set Port F all bits as outputs */
21.15 Using Interrupts
Interrupts are an important part of many embedded applications. Although
an interrupt request is much like a hardware actuated function call, it diers
from a normal function call in several important ways.
Before entering the interrupt handler function, all CPU registers must
be saved on the stack.
Any transfer of information between the interrupt handler and other
parts of the program must be done with globally dened data.
A special return from interrupt instruction must be executed at the end
of the interrupt handler to restore all CPU registers from the stack.
For a CodeWarrior program an interrupt routine is identied by using
the keyword interrupt in the function denition.
void interrupt VectorNumber Vtpm1ch1 isr (void) {
...
}
The CodeWarrior linker needs to be informed of the vector address for
the interrupt. The mc9s08qe128.h header le denes the vector number
like this:
#define VectorNumber Vtpm1ch1 5
1. What makes an interrupt handler or service routine dierent than an
ordinary function?
c Erich Styger 238
INTRO V1.70
21.16 Connecting a C Program to an Assem-
bly Language Program
There are two components of a C programs assembly language interface.
The rst allows you to insert assembly language instructions in-line with
ordinary C statements. You may wish to do this for special purposes such as
unmasking or masking interrupts if your compiler does not provide a library
function to do this. There are a variety of ways in CodeWarrior to insert
in-line assembly instructions including simply writing asm followed by the
assembly language statement. Another aspect of the assembly language in-
terface arises when you wish to use an assembly language function in your C
program. This is done often for special purpose I/O or to take advantage of
assembly language features. To transfer arguments to and from the assembly
language program, the C program will use CPU registers as much as possi-
ble and use the stack for the remaining arguments. Arguments are pushed
onto the stack in left-to-right order and the last argument is transferred, if
possible, in a register. After the call, the caller removes the parameters from
the stack.
1. Does your compiler allow you to insert assembly language instructions
in-line with your C code? If so, how do you do this?
2. How does your C program transfer arguments to and from the assembly
language program?
21.17 Problem: const variables
Your ANSI C compiler uses the const declaration for a variable to specify
that the value is not to be changed. This is useful to make sure that you do
not accidentally write code that changes it. In some situations the compiler
may use this denition just like #dene (a constant known at compile-time)
and in others it may allocate (and initialize) a ROM memory location. Write
a small program that demonstrates how the compiler may use a constant
variable in these two ways. Make sure that your compiler will give an error
message if you try to change the variable.
You will nd, at least in the CodeWarrior environment, that a const
denition is used like #define in the le in which the constant is declared. In
this case no memory is allocated and immediate addressing is used when the
constant is referenced. If, however, you refer to an external constant dened
in another function, the constant will be allocated storage and initialized in
c Erich Styger 239
INTRO V1.70
ROM. Direct (or extended) memory addressing is used when the constant is
referenced.
21.18 Reection on Learning
In this module you have explored how the C language compiler creates code
for you. Are you curious about how the compiler does other things? What
strategy would you use to investigate and satisfy your curiosity?
c Erich Styger 240
INTRO V1.70
21.19 Problems
This section lists again all problems from this LSC:
21.1. Find the memory map of your microcontroller and list the address
ranges of RAM and ROM
21.2. What data types does your compiler support and how many bits of
storage are required for each?
21.3. What does scope of a variable mean?
21.4. A variable is dened inside a function and the compiler does not al-
locate a specic memory location in RAM for its storage. a) Is this
an automatic or static variable? b) Where is it stored? c) What is
its scope? d) Is data stored in this variable during one function call
available to the function in the next call?
21.5. A static variable is dened inside a function. a) What is its scope?
b) Where is storage space allocated for it? c) Is data stored in this
variable during one function call available to the function in the next
call?
21.6. A variable is dened outside a function. a) Is this a static or automatic
variable? b) If another separately compiled function wishes to use this
variable, what must be done in this function to do this?
21.7. In listing 21.1, where is storage allocated for the variable char i2 nal?
21.8. In listing 21.1, in what part of the code is i2 nal initialized with 0x22?
21.9. In listing 21.1, where is storage allocated for the variable char i1?
21.10. In listing 21.1, is i1 initialized with any value by the Startup() code?
21.11. In listing 21.1, where is storage allocated for the variable char i2?
21.12. In listing 21.1, is i2 initialized with any value by the Startup() code?
21.13. In listing 21.1, where is storage allocated for the variable char i3?
21.14. In listing 21.1, is i3 initialized with any value by the Startup() code?
If not, when is it initialized?
21.15. In listing 21.1, where is storage allocated for the variable char i4?
c Erich Styger 241
INTRO V1.70
21.16. In listing 21.1, is i4 initialized with any value by the Startup() code?
21.17. In listing 21.1, what do you predict the nal value of i2 to be? Is it?
21.18. With minimal startup code for the S08, you should get an error or
warnings when you make the project? What does it mean?
21.19. What changes must you make to your program to compensate for the
problem?
21.20. For your HCS08 compiler, is char a signed or unsigned type?
21.21. If you are familiar with assembly language programming you may know
that comparing signed and unsigned numbers requires dierent assem-
bly language conditional branches. What changes would you expect
to see in the assembly code for the program if you changed all char
variables to signed char?
21.22. Describe the dierences in the generated code, based on your changes
for the variables i and j in table 21.1. What can you observe?
21.23. Does your compiler produce bit addressing instructions such as BSET
and BCLR? Comment on your ndings.
21.24. What does the following line of code accomplish? extern volatile
PTFDSTR PTFD @0x00000040;
21.25. Explain how the structure PTFDSTR works to allow you to access
PTFD as a byte or as individual bits in the port.
21.26. What makes an interrupt handler or service routine dierent than an
ordinary function?
21.27. Does your compiler allow you to insert assembly language instructions
in-line with your C code? If so, how do you do this?
21.28. How does your C program transfer arguments to and from the assembly
language program?
21.20 Report
In your report, include the following
What did you learn? What was the most useful thing?
c Erich Styger 242
INTRO V1.70
What is still not clear to me? What should be explained better?
An estimation of time you had to spend on the LSC.
c Erich Styger 243
INTRO V1.70
c Erich Styger 244
Chapter 22
Bouncing Switch
22.1 Overview
We use switches in many of our embedded systems so users can select dierent
choices or to sense other information. Most real-world switches do not simply
close (or open) when we activate the switch. The mechanical nature of the
switch causes the switch contacts to make and break a number of times or
exhibit other analog behavior before settling down into a closed or open
steady state. This is called switch bounce and if your software is counting
switch closures (or openings) you will get multiple counts for each activation.
22.2 Learning Objectives
In this module you will learn more about switch bouncing and how to elim-
inate it using software.
22.3 Success Criteria
When you complete this module you will be able to demonstrate that switches
do bounce and that you can debounce them using software.
22.4 More Resources and Further Informa-
tion
Ganssle, Jack G., A Guide to Debouncing, http://www.ganssle.com/
debouncing.pdf, 2007[6]
245
INTRO V1.70
InstructionIntroduction Figure 22.1 shows a Single-Pole, Single-Throw
(SPST) switch. The pull-up resistor sets the logic output high when the
switch is open and when the switch is closed, the connection to ground
through the switch sets the logic output low. The SPST switch is very
common in embedded systems design: they are very cheap. But this comes
with some disadvantages we are going to discuss in this section.
Figure 22.1: SPST switch used for binary input (Source: Oxford University
Press, Inc)
Figure 22.2 shows what can happen when the switch is closed or opened.
This oscillation between high and low is called switch bounce. There are
both hardware and software techniques to get rid of these bounces.
Figure 22.2: Switch Bouncing (Source: Oxford University Press, Inc)
22.5 A Guide to Debouncing
Read A Guide to Debouncing, by Jack Ganssle, from http://www.
ganssle.com/debouncing.pdf[6].
c Erich Styger 246
INTRO V1.70
22.6 Explore 1
1. What hardware circuits are used to debounce switches based on the in-
formation in Ganssles Guide to Debouncing[6]? What kind of switches
can be used with these circuits?
2. What other debouncing information can you nd in Ganssles Guide
to Debouncing[6]?
22.7 Problem: Software Switch Debouncing
Using a Delay
There are a variety of ways to debounce a switch. On of the most simple is
to detect a change in the switchs state and then to delay until the switch
has stopped bouncing and then return the current state of the switch.
Your hardware has multiple switches and LEDs: implement a key de-
bouncer for it using the delay method:
You can use the Wait Processor Expert component to wait for a given
time.
Experiment how much you have to wait for press and release of the
button.
To show if the debouncing works, you could show this with the available
LEDs.
As you have multiple buttons: have one button using your debouncing,
and one without debouncing to show the dierence.
22.8 Stimulate 1
Any good engineer will analyze the proposed solution to a problem to under-
stand its limitations and under what conditions it might fail. Analyze the
debouncing scheme that uses a simple delay.
1. What will you have to nd out before you can use the delay method
for debouncing?
2. What are the limitations and what can go wrong with debouncing?
c Erich Styger 247
INTRO V1.70
22.9 Switch Debouncing Using an Counting
Debouncer
One of the hardware methods of debouncing a switch uses an Resistor-
Capacitor (RC) integrator circuit and a Schmitt Trigger gate. We can em-
ulate this hardware action with the following software counting algorithm.
This software routine can be implemented as a function or procedure to be
called whenever a change in the switchs state is detected.
Def i ne CLOSE BOUNCE TIME MS
Def i ne OPEN BOUNCE TIME MS
Def i ne BOUNCEDELAY
INITIALIZE Count = CLOSE BOUNCE TIME MS
WHILE ( ( Count > 0) and ( Count < CLOSE BOUNCE TIME MS +
OPEN BOUNCE TIME MS) )
DO
Delay BOUNCEDELAY
Get Swi tch Input
IF Swi tch Cl osed
THEN Decrement Count
ELSE Increment Count
ENDIF Swi tch Cl osed
ENDO
ENDWHILE ( ( Count > 0) and ( Count < CLOSE BOUNCE TIME MS +
OPEN BOUNCE TIME MS) )
IF Count = 0
THEN Swi tch i s c l os e d
ELSE Swi tch i s open
ENDIF Count = 0
This algorithm requires a 1 millisecond delay. It is not a good idea to use
a software delay such as
for ( i =0; i <number;++i ) ;
because number is a magic number that must be twiddled to get the correct
timing and it is not portable to other computers with dierent clock speeds.
Using a timer or a wait routine which is aware of clock speed and compiler
optimization should be used.
22.10 Explore 2
Analyze the pseudocode design for the integrating switch debouncer.
1. How long must the switch stay in its current state without bouncing?
c Erich Styger 248
INTRO V1.70
2. What is the value of Count at the end of the WHILE DO loop if the
switch is closed?
3. What is the value of Count at the end of the WHILE DO loop if the
switch is open?
4. What disadvantages or problems do you see in using this code?
See Ganssle[6] for a similar but more elegant solution that is called at
timer intervals and detects changes of state of the switch as well as debounc-
ing it.
22.11 Problem 2
You are to use the hardware on your laboratory hardware to demonstrate
two programs. The rst is to illustrate that switch bounce exists and is a
problem. The second should add a switch debouncer to the rst program and
demonstrate that it debounces the switch. As your hardware has multiple
switches: demonstrate one button which has implemented the debouncing,
and use another button which is not debounced. Use a method described in
[6]. You can extend the program you have developed in 22.7.
22.12 Communication - Inter-Group
Team up with another group in the laboratory and compare notes from the
research you did in this LSC. Discuss what you found interesting about the
switch bounce problem. Invite another laboratory group to try out your
debounced switch demonstration program. If they cannot make the switch
bounce, share your solution with them. If, unfortunately, your solution is not
bombproof and they make it bounce, you better x it before demonstrating
it to your laboratory supervisor.
Include into your engineering workbook your ndings and solutions.
1. A description of your solution to Problem 1.
2. Your ndings and learnings around bouncing and debouncing.
3. A listing of your solution to Problem 1.
c Erich Styger 249
INTRO V1.70
22.13 Problems
This section lists all problems for this LSC.
22.1. What hardware circuits are used to debounce switches based on the in-
formation in Ganssles Guide to Debouncing[6]? What kind of switches
can be used with these circuits?
22.2. What other debouncing information can you nd in Ganssles Guide
to Debouncing[6]?
22.3. What will you have to nd out before you can use the delay method
for debouncing?
22.4. What are the limitations and what can go wrong with debouncing?
22.5. How long must the switch stay in its current state without bouncing?
22.6. What is the value of Count at the end of the WHILE DO loop if the
switch is closed?
22.7. What is the value of Count at the end of the WHILE DO loop if the
switch is open?
22.8. What disadvantages or problems do you see in using this code?
22.14 Report
In your report, include the following
What did you learn? What was the most useful thing?
What is still not clear to me? What should be explained better?
An estimation of time you had to spend on the LSC.
The listing of your solution.
c Erich Styger 250
Chapter 23
I/O Software Synchronization
23.1 Overview
A microcontroller must be connected to external devices to be able to do any
useful work. A typical embedded application would have the microcontroller
receiving information (inputting) from an input device, modifying or making
decisions based on the information and the task at hand, and outputting
some control action or information to an output device. Often, either the
input or output device or both operate on a dierent time-scale than the
microcontroller, and we must synchronize the microcontroller with the I/O
devices timing. For example, if a human operator is setting Dual in Line Pin
(DIP) switches, we would not want the microcontroller to read the switches
until we were through. This I/O synchronization can be done in a variety of
ways and in this module you will learn how to create and use a status bit to
control the timing of data transfers.
23.2 Learning Objectives
This module will help you learn how to synchronize the transfer of data
between a microcontroller and an external device.
23.3 Success Criteria
When you have completed this module you will be able to demonstrate hand-
shaking input and output data transfer.
251
INTRO V1.70
23.4 More Resources and Further Informa-
tion
http://en.wikipedia.org/wiki/Handshaking
http://www.bjoern-koester.de/iogrundlagen (in German)
23.5 I/O Software Synchronization
Often a microcontroller can input or output data at a much higher rate than
many I/O devices and so the software must be synchronized with the I/O
device. On the other hand, sometimes the microcontroller is slower than
the I/O device. For example, the microcontroller may be busy doing some
other task and does not get around to servicing the I/O device. There are
a variety of ways to synchronize the microcontrollers timing with the I/O
device including polling status bits, handshaking, and interrupts.
23.6 Polling I/O Devices
Microntroller External Device
RDY IN
New Data Ready
Data In
Figure 23.1: Input Polling
Figure 23.1 shows a microcontroller that can read a status bit (RDY IN)
that is asserted by the external input device when the device is ready to
supply the data. The microcontroller program can monitor this bit and
when it is set, it can read the data. This process is called polling.
Figure 23.2 shows how a status bit can aect how the microcontroller
outputs data. When the external output device is ready to accept new data, it
asserts the RDY OUT signal. When the microcontroller sees RDY OUT asserted,
it outputs the new data to the device.
c Erich Styger 252
INTRO V1.70
Microntroller External Device
RDY OUT
Ready For New Data
Data Out
Figure 23.2: Output Polling
These schemes work when the microcontroller is faster than the I/O de-
vice and we assume that the status bits RDY IN and RDY OUT are asserted
long enough that the microcontroller does not miss them.
23.7 Stimulate 1
The polling scheme shown in Figure 23.1 and in Figure 23.2 does not have
any mechanism for providing feedback to the data source. For example, while
the external input device can assert RDY IN when it has data to be input, it
does not know when the microcontroller has taken the data.
1. What problems can arise due to the lack of feedback in the input polling
shown in Figure 23.1?
2. What problems can arise in the output polling shown in Figure 23.2?
23.8 Handshaking I/O Devices
Figure 23.1 and Figure 23.2 shows that two control signals are used for input
and output handshaking. These signals (and intelligence within the micro-
controller and the external device) provide handshaking data transfer. The
handshaking gives us the feedback that we do not have in the simple polling
described above. There are two situations that we must be concerned about.
In one case, the microcontroller may be faster and may request or provide
its data before the external device is ready. In the other, the external device
may be ready before the microcontroller.
c Erich Styger 253
INTRO V1.70
Microntroller External Device
RDY IN
New Data Ready
Data In
PORT RDY
Figure 23.3: Input Handshaking
23.9 Input Handshaking
If the microcontroller is faster than the input device it must wait until the
data are supplied. The microcontroller will assert PORT RDY when it needs
the data and then poll RDY IN to wait until the input device supplies it.
When the input data is ready, RDY IN is asserted. The input device main-
tains the data and continues to assert RDY IN until the microcontroller
deasserts PORT RDY indicating it has taken the data. At this time the
input device knows the data has been received by the microcontroller and so
it deasserts RDY IN to complete the handshaking transaction.
If the situation is reversed and the external device is faster than the mi-
crocontroller, the input device asserts RDY IN when the data are ready and
then waits until the microcontroller is ready. At this time the microcon-
troller asserts PORT RDY, reads the data, and then deasserts PORT RDY.
To complete the handshaking RDY IN is deasserted.
23.10 Output Handshaking
Similar timing needs are met by the DEV RDY and DATA-RDY control
signals when the microcontroller is outputting data. If the microcontroller
is faster than the output device, it must maintain the output data until the
external device signies it has received it. When the external device is faster,
it must wait until the microcontroller outputs the data and then signal that
it has received the data.
c Erich Styger 254
INTRO V1.70
Microntroller External Device
DEV RDY
Ready For New Data
Data Out
DATA RDY
Figure 23.4: Output Handshaking
23.11 Explore 1
Draw timing diagrams showing the following handshaking data transactions.
In each case show the handshaking control signals and when the data are
valid.
1. Draw a timing diagram for the case where input data transfer when
the microcontroller is faster than the external device.
2. Input data transfer when the microcontroller is slower than the external
device.
3. Output data transfer when the microcontroller is slower than the ex-
ternal device.
23.12 Stimulate 2
Please provide answers to the questions below:
1. What input devices may be slower than the microcontroller?
2. When might you nd a situation where the input device can supply
data faster than the microcontroller and read it?
3. What output devices may be slower than the microcontroller?
23.13 Problem 1
You are to join another student for the following exercises. One of you is to
play the part of a microcontroller and the other the part of an external device
c Erich Styger 255
INTRO V1.70
(which could be another microcontroller). The microcontroller will be trans-
ferring data to and from the external device for each of the four handshaking
scenarios described above. In each case you are to write an algorithm (a
software design or a sequence of actions) so that the microcontroller and the
external device assert the control signals and transfers the data in the proper
order. After each exercise, swap parts so that each of you can experience
being both the microcontroller and the external device.
1. The microcontroller (M) is inputting data from an external input device
(EI). M is faster than EI.
2. M is inputting data from EI. M is slower than EI.
3. M is outputting data to an external output device (EO). M is faster
than EO.
4. M is outputting data to EO. M is slower than EO.
23.14 Handshaking Implementation
Implement in C language the handshaking for input and output handshaking,
both for the (Figure 23.3) and output handshaking (Figure 23.4) for both
the microcontroller and the external device. You can use the names for the
variables as in the two gures. What kind of problems do you see arise? Try
to implement a solution which overcomes the issues.
23.15 Reection on Learning
Discuss with your partner the lessons learned. Do you have any questions
about the four handshaking scenarios? If you do, write them down and
submit them to your instructor to allow him or her to address the topics
again.
Especially think about:
1. What was the most useful thing you learned in this module?
2. What questions remain uppermost in your mind?
c Erich Styger 256
INTRO V1.70
23.16 Problems
This section lists all problems for this LSC.
23.1. What problems can arise due to the lack of feedback in the input polling
shown in Figure 23.1?
23.2. What problems can arise in the output polling shown in Figure 23.2?
23.3. What input devices may be slower than the microcontroller?
23.4. When might you nd a situation where the input device can supply
data faster than the microcontroller and read it?
23.5. What output devices may be slower than the microcontroller?
23.6. Draw a timing diagram for the case where input data transfer when
the microcontroller is faster than the external device.
23.7. Input data transfer when the microcontroller is slower than the external
device.
23.8. Output data transfer when the microcontroller is slower than the ex-
ternal device.
23.17 Report
In your report, include the following
What did you learn? What was the most useful thing?
What is still not clear to me? What should be explained better?
An estimation of time you had to spend on the LSC.
c Erich Styger 257
INTRO V1.70
c Erich Styger 258
Chapter 24
Serial I/O Interfaces -
RS-232-C
24.1 Overview
Most of the problems with interfacing system using an asynchronous serial
port come from not understanding the signals dened by the RS-223 stan-
dard. The operation of the SCI that we saw in the Serial I/O - The Com
Port module is probably the less tricky part of creating an asynchronous se-
rial communications interface. We still have to connect our embedded system
to another system or a personal computer. In order to make the two systems
compatible we must know the electrical specications of the interface.
24.2 Learning Objectives
In this module you will learn about the RS-232-C electrical interface that is
widely used to connect asynchronous serial interfaces.
24.3 Success Criteria
When you complete this module you will be able to specify the correct cable
to connect two asynchronous serial ports.
24.4 The Electrical Interface
When two separate microcomputer systems are connected, they must each
talk the same electrical language. In other words, a logic one in one system
259
INTRO V1.70
Figure 24.1: Noise Margin
must be interpreted as a logic one in the other. Normally, so long as signals
are transferred from one system to another on the same printed circuit board,
we do not need to be concerned about logic levels, although one should
be aware there are logic devices with dierent power supplies and dierent
dened logic levels (5 Voltage (V), 3.3 V, 2.5 V, 1.8 V, etc.). So long as the
output voltages of one device do not exceed the input voltage specications
of another and logic one or zero in the rst is interpreted as a one or zero in
the second, the systems will communicate properly. A critical part of good
electronic design in logic systems is that there be sucient noise margin on
the input signal so that when the output is a logic one (or zero) the input does
not interpret the level as a logic zero (or one) or worse in the undetermined
region between the two logic states where most anything can happen. Figure
24.1 shows the meaning of noise margin. When a gate output is logic 1, the
output voltage is higher than the minimum output voltage for a high, V
OHmin
.
When a gate input sees a voltage higher than its minimum input voltage
for a high, V
IHmin
, it detects a high voltage level or logic 1 state. As we can
see in Figure 24.1, V
IHmin
is lower than V
OHmin
so the system has a region for
error called the noise margin. When the gate output is low a similar analysis
applies. V
OLmax
is the maximum output voltage for the output of the gate
being low and V
ILmax
is the maximum allowed at the input for the input to
detect a zero. When V
ILmax
is greater than V
O
Lmax a noise margin for low
logic levels exists. Where would noise come from to perturb our signals? In
communication systems the two communicators are often far apart and must
be connected by cables. Long cables can act to pick up extraneous signals
and thus introduce noise into the system. So long as the noise voltage is less
than the noise margin as shown in Figure 24.1 we can be comfortable that
our receivers will correctly detect ones and zeros when they are sent.
c Erich Styger 260
INTRO V1.70
24.5 Explore 1: Noise Margin
Table 24.1 lists the Noise Margin - High and - Low, for 5 volts, 3.3 volt and
1.8 volt Complementary Metal Oxide Semiconductor (CMOS) logic families.
Notice that depending on the voltage family, there are dierent high and low
CMOS V
OHmin
V
IHmin
Noise
Margin
High
V
OLmax
V
ILmax
Noise
Margin
Low
5 V 4.9 V 3.85 V 1.05 V 0.1 V 1.35 V 1.34 V
3.3 V 2.8 V 2.0 V 0.8 V 0.2 V 0.8 V 0.6 V
1.8 V 1.25 V 1.1. V 0.25 V 0.45 V 0.66V 0.21 V
Table 24.1: CMOS Logic Levels
logic levels. As a consequence, the Noise Margin is dierent too.
24.6 RS-232-C Logic Levels
Driver (output)
Voltage
Receiver (input)
Voltage
Logic State SCI Signaling
Level
+5 to +15 +3 to +15 Logic 0 Space
+5 to -5 +3 to -3 Undeter-
mined
Undetermined
-5 to -15 -3 to -15 Logic 1 Mark
Table 24.2: RS-232 Logic Levels
Because the cables used to connect SCI devices together often run through
noisy environments, the noise margins for standard logic circuits you found in
section 24.5 are not sucient. The RS-232-C standard denes logic levels as
shown in Table 24.2. As you can see, the noise margins are greatly increased,
to as much as 12 volts. A disadvantage, though, is that now a bipolar voltage
supply is needed to produce the plus and minus voltage levels. Also, notice
logic zero is high and logic one is low.
24.7 Voltage Translation
You must convert or translate the signal level voltages dened in Table 24.2
to whatever voltage levels your other logic circuitry requires. This is easily
c Erich Styger 261
INTRO V1.70
done with a CMOS-to-RS-232-C level converter. This integrated circuit pro-
duces the bipolar voltage levels required by the RS-232-C interface standard
internally and thus eliminates the need for a bipolar power supply.
24.8 Explore 2
Go to the web and browse to http://www.maxim-ic.com and learn about
RS-232-C interface parts.
1. What part would you chose to include in an embedded system design
to convert from the CMOS logic levels of the SCI to RS-232-C and
provides at least two input and two output signals?
24.9 RS-232-C Device Types
The RS-232-C standard was developed to standardize the connections be-
tween terminals and modems. In those days, well before the personal com-
puter, remote users communicated with mainframe computers by using a
terminal, a modem, and a telephone line. Even on-site users used a termi-
nal connected to the computer by a serial interface. Two dierent types of
devices and interfaces were dened. These were DTE and DCE. Each of
the devices had transmitted data and received data lines and the standard
dened these signals (and more, as we shall see below), their use, and the
direction of signal ow (sourcing or receiving). It also dened the pins that
were used on a 25-pin D connector, the DB-25. Nowadays, most serial ports
use a 9-pin D connector (DE-9) because not all 25 pins are needed.
24.10 Stimulate 1
Draw a cable to connect the DTE and DCE devices shown below in Figure
24.2, 24.3 and 24.4. In each case, show the signal ow direction on each TxD
and RxD line and give the connector pin numbers for all signals.
24.11 RS-232-C Cables and Connectors
The original use of RTS and CTS was in the days of half-duplex modems
when data transmission between modems could occur in only one direction
at a time. RTS, CTS and DCD were used by the modem (DCE device) to
determine when the telephone line was free to be used, i.e. the other device
c Erich Styger 262
INTRO V1.70
DTE
DE-9
TxD
RxD
GND
DCE
DE-9
TxD
RxD
GND
Figure 24.2: RS-232-C Connection (DE-9 DTE and DE-9 DCE)
DTE
DB-25
TxD
RxD
GND
DTE
DE-9
TxD
RxD
GND
Figure 24.3: RS-232-C Connection (DB-25 DTE and DE-9 DTE)
DTE
DE-9
TxD
RxD
GND
DTE
DE-9
TxD
RxD
GND
Figure 24.4: RS-232-C Connection (DE-9 DTE and DE-9 DTE)
was not sending data. When the DTE device requested to send data by
asserting the RTS signal, the modem waited until the other modem dropped
its carrier and then turned the line around by activating its carrier and
then asserting CTS.
The original RS-232-C device specication required DB-25 connectors
1
.
As computers got smaller, manufacturers changed to the DE-9 connector
1
Describing connectors using the plug and socket terminology is replacing the older
gender-based terminology. Also, the original connector was called the DB-25. Today we
see both DB-9 and DE-9 nomenclature used to specify the 9-pin connector, but DE-9 is
the proper term to use.
c Erich Styger 263
INTRO V1.70
with only 9 pins, which were sucient for one serial port. A defacto standard
for personal computers uses a DE-9P (plug) connector for their DTE COM
ports. Thus the cable connecting two DTE COM ports uses DE-9S (socket)
connectors and connects pin 2 (TxD) to pin 3 (RxD). This cable is called
a null modem. There is no standard connector for DCE devices although
modems often used a DB-25S (socket) connector. The DCE port connector
on the board we use in INTRO is a DE-9S. To connect a DTE to a DCE
device a straight serial cable is used. In this case, the cable will have a DE-9P
at one end and a DE-9S connector at the other (probably).
24.12 Handshaking for Flow Control
DCE
DE-9
TxD
RxD
GND
3
2
5
DTE
DE-9
TxD
RxD
GND
3
2
5
Figure 24.5: DE-9 DCE and DE-9 DTE Communication
With the SCI of a typical microcontroller the receiver synchronizes itself
with the transmitted data to properly shift the data into the shift register.
There is a higher level of synchronization that we must consider. Figure
24.5 shows a DCE device (say your embedded system microcontroller) com-
municating with a DTE device (a personal computer). Depending on the
processor speeds in the two systems and on what other tasks each of them
may be doing, one of them, say the DTE personal computer, may not be
ready to receive data when the embedded DCE system is ready to send it.
Although this problem might be solved with interrupts, the signals specied
in the RS-232-C interface allow a handshaking data transmission system.
Table 24.3 shows two signals commonly used for ow control between two
devices. These are RTS - Request to Send and CTS - Clear to Send. Fig-
ure 24.6 shows how these signals are connected to provide a handshaking
interface.
24.13 Stimulate 2
c Erich Styger 264
INTRO V1.70
DCE
DE-9
TxD
RxD
GND
RTS
CTS
3
2
5
7
8
DTE
DE-9
TxD
RxD
GND
RTS
CTS
3
2
5
7
8
Figure 24.6: DE-9 DCE and DE-9 DTE Communication with Handshaking
DTE
DE-9
DTE
DE-9
TxD
RxD
GND
RTS
CTS
3
2
5
7
8
TxD
RxD
GND
RTS
CTS
3
2
5
7
8
Figure 24.7: DE-9 DTE and DE-9 DTE Communication with Handshaking
c Erich Styger 265
INTRO V1.70
DE-9 DB-25 Signal Purpose
1 PG Protective Ground. This is usually the shield in
a shielded cable. It is designed to be connected
to the equipment frame and may be connected
to external grounds.
3 2 TxD Transmitted Data. Sourced by DTE and
received by DCE. Carries data from DTE to
DCE. Data terminal equipment cannot send
unless RTS, CTS, DSR and DTR are asserted.
2 3 RxD Received Data. Received by the DTE,
sourced by DCE. Carries data from DCE to
DTE.
7 4 RTS Request to Send. Sourced by DTE, received
by DCE. RTS is asserted by the DTE when it
wants to send data. The DCE responds by
asserting CTS.
8 5 CTS Clear to Send. Sourced by DCE, received by
DTE. CTS must be asserted before the DTE
can transmit data.
6 6 DSR Data Set Ready. Sourced by DCE, received
by DTE. Indicates that the DCE has made a
connection on the telephone line and is ready to
receive data from the terminal. The DTE must
see this asserted before it can transmit data.
5 7 SG Signal Ground. Ground reference for the signal
is separate from pin 1, protective ground.
1 8 DCD Data Carrier Detect. Sourced by DCE,
received by DTE. Indicates that a DCE has
detected the carrier on the telephone line.
Originally it was used in half-duplexsystems
but can be used in full-duplex systems too.
4 20 DTR Data Terminal Ready. Sourced by DTE,
received by DCE. Indicates the DTE is ready
for sending or receiving.
9 22 RI Ring Indicator. Sourced by DCE, received by
DTE. Indicates that a ringing signal is detected.
Table 24.3: RS-232-C Signal Denitions (reprinted with permission of Oxford
University Press, Inc.)
c Erich Styger 266
INTRO V1.70
1. Write a programming algorithm (a design) for a DCE device that allows
it to transmit data only when another device is ready for it.
2. Write a programming algorithm (a design) for a DTE device that allows
it to transmit data only when another device is ready for it.
3. Write a programming algorithm (a design) for a DTE device that allows
it to signal another device it is ready to receive data.
4. Write a programming algorithm (a design) for a DTE device that allows
it to transmit data only when another device is ready for it.
5. Complete Figure 24.7 so it shows a cable needed to connect two DTE
devices, each of them implementing a ow control algorithm.
6. Draw a gure similar to Figure 24.6 that shows a cable needed to con-
nect a DCE device to a DTE device. The DTE device has implemented
ow control but the DCE device has not. The DTE device must be
allowed to send data whenever it is ready.
24.14 What Kind of Device do You have?
It is a frustrating part of interfacing RS-232-C devices that manufacture-
supplied documentation is rarely complete or accurate enough to condently
connect two devices together
2
. The problem stems from the standards deni-
tion of the DCE devices signal names. It is counterintuitive that the signal
named RxD is actually transmitting data and TxD is receiving it. Often
system documentation gives the wrong signal names to the pin connections
in the DE-9 connector. Today all personal computers that have a serial I/O
COM port are congured as DTE devices, although this was not always true.
For any other device you must carefully inspect the documentation, perhaps
even the electronic schematic diagrams, to determine which pin is actually
transmitting and which is receiving data. Figure 24.8 shows a handy and
inexpensive piece of hardware that allows you to test which signals are which
in your serial interfaces.
2
Please document properly any serial I/O interfaces you produce. The documentation
should include the type of device, DTE or DCE, the connector pin-outs, the type of
connector used (S or P), and the signal direction ow. They should also specify the serial
communication parameters (baud rate, number of data bits, type of parity, number of stop
bits). Jameco (http://www.jameco.com) and other vendors have RS-232-C testers and
DB-25 to DE-9 adapters. These are invaluable to anybody using serial I/O ports.
c Erich Styger 267
INTRO V1.70
Figure 24.8: RS-232-C Tester[2]
c Erich Styger 268
INTRO V1.70
24.15 Stimulate 3
1. Your company has designed a product with an asynchronous serial I/O
port using an SCI. It uses a DE-9 connector and is labeled as COM1
on the board. It sends its data out on pin 3 and receives it on pin 2.
Flow control handshaking has not been implemented. It is programmed
to send and receive data at 9600 baud, eight data bits, no parity, and
one stop bit. Write a technical description of this port for inclusion
in the users technical reference manual describing how to use the port
and how to connect it to other serial devices.
c Erich Styger 269
INTRO V1.70
24.16 Problems
This section lists all problems for this LSC.
24.1. What part would you chose to include in an embedded system design
to convert from the CMOS logic levels of the SCI to RS-232-C and
provides at least two input and two output signals?
24.2. Write a programming algorithm (a design) for a DCE device that allows
it to transmit data only when another device is ready for it.
24.3. Write a programming algorithm (a design) for a DTE device that allows
it to transmit data only when another device is ready for it.
24.4. Write a programming algorithm (a design) for a DTE device that allows
it to signal another device it is ready to receive data.
24.5. Write a programming algorithm (a design) for a DTE device that allows
it to transmit data only when another device is ready for it.
24.6. Draw a gure similar to Figure 24.6 that shows a cable needed to con-
nect a DCE device to a DTE device. The DTE device has implemented
ow control but the DCE device has not. The DTE device must be
allowed to send data whenever it is ready.
24.7. Complete Figure 24.7 so it shows a cable needed to connect two DTE
devices, each of them implementing a ow control algorithm.
24.8. Your company has designed a product with an asynchronous serial I/O
port using an SCI. It uses a DE-9 connector and is labeled as COM1
on the board. It sends its data out on pin 3 and receives it on pin 2.
Flow control handshaking has not been implemented. It is programmed
to send and receive data at 9600 baud, eight data bits, no parity, and
one stop bit. Write a technical description of this port for inclusion
in the users technical reference manual describing how to use the port
and how to connect it to other serial devices.
24.17 Report
In your report, include the following
What did you learn? What was the most useful thing?
What is still not clear to me? What should be explained better?
c Erich Styger 270
INTRO V1.70
An estimation of time you had to spend on the LSC.
c Erich Styger 271
INTRO V1.70
c Erich Styger 272
Chapter 25
Interrupts using C
25.1 Overview
Interrupts are important events that must be recognized and taken care of
(called serviced) by our program. The microcontroller has hardware and
software features to allow these important events. Interrupts are an impor-
tant asset when writing high performance applications. You may use them
in embedded systems to synchronize the microcontroller with slower I/O. In
some applications with a real-time operating system, interrupts are used to
carry out all processing tasks.
25.2 Learning Objectives
In this module you will learn interrupt terminology and begin to use the
interrupting capabilities of your microcontroller.
25.3 Success Criteria
When you have nished this module you will be able to demonstrate that an
external interrupt request signal can interrupt a program and be serviced.
25.4 Prerequisites
You must be able to write assembly or C programs for your microcontroller
and be able to test and run programs on a student learning kit in the labo-
ratory. You should understand that a C compiler has extensions that allow
273
INTRO V1.70
interrupt programs to be executed within the C program. You may wish to
review the Exploring Embedded C Programming module.
25.5 More Resources and Further Informa-
tion
MC9S08GB60 Reference Manual, Rev 2.3
MC9S08QE128 Reference Manual[20]
MCF51QE128 Reference Manual[21]
DEMOQE128 User Manual[18]
HC(S)08/RS08 and HC(S)12 Build Tools Utilities Manual, CWMCUB-
TURM,
Freescale Semiconductor, Inc., 3/2007
25.6 Stimulate
1. Can you give three examples of I/O devices for which interrupts could
be used to synchronize the microcontroller with the I/O?
2. Assume you are designing microcontroller systems to be used in an
automotive application. Give three examples of important events that
would lend themselves to being implemented in a microcontroller using
an interrupt system.
25.7 Interrupt Jargon
Asynchronous Event: An event that occurs that is not synchronized
with the microcontrollers internal clock. It can happen at any time in
the instruction execution cycle.
Interrupt Enable: A bit in an interrupting subsystem that enables (or
allows) the sub-system to generate an interrupt request.
Interrupt Flag Clearing: In many microcontrollers, internal sub-
systems such as the timer can generate interrupt requests. For example,
an Interrupt Request (see below) may be generated when the timer
c Erich Styger 274
INTRO V1.70
overow ag is set. When this occurs, the interrupt service routine
must reset the ag that caused the interrupt request to be generated.
Interrupt Handler: See Interrupt Service Routine.
Interrupt Latency: This is the time between when the interrupt request
is asserted and the CPU starts to execute the interrupt service routine.
Interrupt Mask: A control bit that stops (or masks) interrupt requests
from being acted upon by the CPU. The CPU will have instructions
that can mask or unmask interrupts.
Interrupt Prioritization: When multiple interrupts occur simultane-
ously the system must have a way to establish which of them is the
most important and should be serviced rst.
Interrupt Request (IRQ): This is the signal with which some device,
such as a timer overow ag or an external signal, requests that it be
serviced.
Interrupt Return: The interrupt service routine needs this special in-
struction to return to the interrupted program.
Interrupt Service Routine (ISR): The software written to deal with the
interrupt request for a particular device.
Interrupt Vector: When an interrupt occurs the CPU fetches the start-
ing address of the interrupt service routine from a specic and dedicated
location in memory. The starting address is called the vector and the
memory location where it is stored is called the vector location or vector
address.
Pending Interrupt: When an interrupt request has occurred and the
interrupt service routine for that interrupt has not been entered, the
interrupt is said to be pending.
Real-Time System: A real-time system is one that uses interrupts to
run processing tasks when they are needed.
Real-Time Operating System (RTOS): Many real-time systems use an
operating system that allows the software developer to create tasks and
to schedule their execution under interrupt control.
c Erich Styger 275
INTRO V1.70
25.8 Explore 1
1. Where in your documentation do you nd the vector locations (or vec-
tor addresses) for interrupts?
2. How does your microcontroller allow for asynchronous events to occur
and be recognized?
3. How does your microcontroller branch to the correct interrupt service
routine?
4. How does your microcontroller return to the interrupted program at
the point it was interrupted?
5. How does your microcontroller allow the programmer to globally enable
and disable all interrupts?
6. How does your microcontroller allow the programmer to enable and
disable selected interrupts?
7. How does your microcontroller disable further interrupts so the rst
can be serviced without being interrupted?
8. How does your microcontroller deal with multiple sources of interrupts?
9. How does your microcontroller deal with multiple, simultaneous inter-
rupts?
10. What can cause a pending interrupt?
11. How do you reset a ag that caused an interrupt?
12. What happens if you do not reset the ag in the interrupt service
routine?
25.9 Interrupt System
Figure 25.1 shows the software ow in a system with interrupts. On the
left, the main program, sometimes called the foreground job
1
, operates by
1
Some texts reverse the denition of the foreground and background jobs, calling the
interrupt service routine the foreground job and the interrupted program the background
job. This denition is used in the context of an RTOS where the program being interrupted
is the RTOS, which operates in the background while allowing the interrupt tasks to carry
out all processing tasks.
c Erich Styger 276
INTRO V1.70
Figure 25.1: Interrupt System (Source: Oxford University Press, Inc.)
the program owing from one block to the next and then repeating all but
the initialization block. On the right, the interrupt service routine, some-
times called the background job, is executed whenever the interrupt request
occurs. Notice that no matter when an interrupt occurs, the program con-
trol returns to the interrupted point when the interrupt service routine has
nished executing.
25.10 Interrupt Sources
Your microcontroller has a variety of interrupt sources. Most of these are
associated with internal sub-systems such as the timer, analog-to-digital con-
verter, or other modules. Some interrupt sources can be input from the ex-
ternal world through various pins on the microcontroller integrated circuit
c Erich Styger 277
INTRO V1.70
package.
25.11 Explore 2
Inspect your microcontroller documentation and identify a table showing all
interrupt sources. A good place to look for these will be the interrupt vector
table. Make sure you know whether the source is an internally or externally
generated interrupt request. Also inspect the vector address.
25.12 The Interrupt Sequence
After your software has properly initialized, enabled, and unmasked inter-
rupts, it enters the foreground jobs continuous loop. When an interrupt
request is generated the following sequence of events occurs.
1. The CPU waits until the currently executing instruction nishes.
2. The CPU determines the address of the interrupt service routine to be
executed through a vectoring system.
3. The return address is pushed onto the stack.
4. In many processors all CPU registers are pushed onto the stack.
5. The CPU interrupt mask bit is set to mask any further interrupts while
in this ISR.
6. The CPU branches to the ISR.
When the ISR has completed, the CPU executes the return from interrupt
instruction that reloads all registers from the stack (if needed), unmasks
further interrupts, and returns to the interrupted program.
It is useful to draw a time line of the instruction execution cycle and to
show that before the instruction is fetched the interrupt request signals can
be tested.
25.13 Stimulate 2
1. There is always a delay between the interrupt request and when the
CPU starts to execute the interrupt service routine. This is called the
interrupt latency. Give three components that cause interrupt latency.
c Erich Styger 278
INTRO V1.70
2. How does the CPU determine the address to return to after the ISR
has completed?
3. Does your microcontroller push all registers onto the stack when enter-
ing an interrupt service routine?
4. Give an advantage and a disadvantage of automatically pushing regis-
ters onto the stack?
25.14 Interrupt Software
The software you write to deal with interrupts has several additional com-
ponents when compared to programs you may have been writing so far.
Your main program must do the following steps:
1. Initialize the Interrupt Vector: Your software development system must
have a way to initialize the interrupt vector that you are going to use.
2. I/O Initialization: A section of your program must initialize any hard-
ware to be used for interrupts.
3. Clear Any Interrupt Flags: Before enabling and unmasking interrupts
you should clear any ags that would cause an interrupt.
4. Enable the Specic Interrupt Source: Usually a bit must be set in the
interrupting device to enable its interrupting capability.
5. Unmask Interrupts: The nal thing to do in your main program before
entering its processing loop is to unmask the CPU interrupts.
6. Enter a Process Loop: The processing done in an embedded application
is in a loop that executes forever.
Your interrupt service routine must do the following steps:
1. Reset the Interrupting Flag: If you dont reset the ag (or device)
that caused the interrupt, as soon as interrupts are unmasked it will
immediately generate another IRQ.
2. Disable Lower Priority Interrupts: If there are higher priority inter-
rupts that you would like to interrupt this interrupt service routine,
you must disable lower priority ones and then unmask global interrupts
to allow the higher priority devices to be serviced.
c Erich Styger 279
INTRO V1.70
3. Do the Specic Job Required:
(a) Re-enable Lower Priority Interrupts: You should re-enable these
if you have disabled them previously.
(b) Return from the ISR: Use the special return from interrupt in-
struction.
25.15 Explore 3
1. How does your software development system initialize the interrupt
vector you are going to use?
25.16 The C Compiler Interrupt Interface
Interrupts are an important part of many embedded applications. Although
an interrupt request is much like a hardware actuated function call, it diers
from a normal function call in several important ways.
1. Before entering the interrupt handler function, all CPU registers must
be saved on the stack.
2. Any transfer of information between the interrupt handler and other
parts of the program must be done with globally dened data.
A special return from interrupt instruction must be executed at the end of
the interrupt handler to restore all CPU registers from the stack.
25.17 Explore 4
1. Does your compiler support interrupt service routines? If so, how do
you signify to the compiler that a function should be treated as an
interrupt handler or service routine?
2. Which instruction in your microcontroller is used for unmasking inter-
rupts?
3. Which instruction in your microcontroller is used for masking inter-
rupts?
4. Which instruction in your microcontroller returning from an interrupt
service routine?
c Erich Styger 280
INTRO V1.70
5. How do you write C instructions to unmask or mask interrupts?
6. What makes an interrupt handler or service routine dierent than an
ordinary function?
25.18 Problem 1
You and your laboratory partner are to demonstrate that you understand
how to write software using the interrupt capabilities of your microcontroller.
You are to do this in several steps because when students try to do too much
in their rst interrupt program, the problem may become too complex and
dicult to trouble shoot and debug.
1. Figure 25.1 shows that there are two parts of the interrupt system -
the foreground job and the background job. You have probably done
many useful programs that can be used to demonstrate a foreground
job that can be interrupted. Before doing a complex foreground job,
however, it is a good strategy to simply use a spin loop (a loop that
does nothing other than loop on itself) as the foreground job. This will
allow you to concentrate on learning how to get an interrupt service
routine working.
2. Inspect your hardware to nd an external interrupt that you can con-
trol. Your hardware might have a switch connected to an IRQ pin
or some other port pin. When you have chosen an interrupt source,
investigate your microcontrollers documentation to determine what
registers need to be initialized to allow the interrupts to work.
3. Design a background job interrupt service routine doing something use-
ful and demonstrate that when the interrupt request is asserted the
interrupt service routine is executed.
4. Your next task is to design a foreground job that can be interrupted.
Inspect your student learning kit hardware so that the foreground job
can do something useful to allow you to demonstrate that it operates
correctly without errors when you later add an interrupt service routine
or background job.
5. Demonstrate that your foreground job works properly when there are
no interrupts. (What will you do in your program to ensure no inter-
rupts occur?)
c Erich Styger 281
INTRO V1.70
6. Now combine the foreground activity and the interrupt service routine.
Demonstrate that both work together.
c Erich Styger 282
INTRO V1.70
25.19 Problems
This section lists all problems for this LSC.
25.1. Can you give three examples of I/O devices for which interrupts could
be used to synchronize the microcontroller with the I/O?
25.2. Assume you are designing microcontroller systems to be used in an
automotive application. Give three examples of important events that
would lend themselves to being implemented in a microcontroller using
an interrupt system.
25.3. Where in your documentation do you nd the vector locations (or vec-
tor addresses) for interrupts?
25.4. How does your microcontroller allow for asynchronous events to occur
and be recognized?
25.5. How does your microcontroller branch to the correct interrupt service
routine?
25.6. How does your microcontroller return to the interrupted program at
the point it was interrupted?
25.7. How does your microcontroller allow the programmer to globally enable
and disable all interrupts?
25.8. How does your microcontroller allow the programmer to enable and
disable selected interrupts?
25.9. How does your microcontroller disable further interrupts so the rst
can be serviced without being interrupted?
25.10. How does your microcontroller deal with multiple sources of interrupts?
25.11. How does your microcontroller deal with multiple, simultaneous inter-
rupts?
25.12. What can cause a pending interrupt?
25.13. How do you reset a ag that caused an interrupt?
25.14. What happens if you do not reset the ag in the interrupt service
routine?
c Erich Styger 283
INTRO V1.70
25.15. There is always a delay between the interrupt request and when the
CPU starts to execute the interrupt service routine. This is called the
interrupt latency. Give three components that cause interrupt latency.
25.16. How does the CPU determine the address to return to after the ISR
has completed?
25.17. Does your microcontroller push all registers onto the stack when enter-
ing an interrupt service routine?
25.18. Give an advantage and a disadvantage of automatically pushing regis-
ters onto the stack?
25.19. How does your software development system initialize the interrupt
vector you are going to use?
25.20. Does your compiler support interrupt service routines? If so, how do
you signify to the compiler that a function should be treated as an
interrupt handler or service routine?
25.21. Which instruction in your microcontroller is used for unmasking inter-
rupts?
25.22. Which instruction in your microcontroller is used for masking inter-
rupts?
25.23. Which instruction in your microcontroller returning from an interrupt
service routine?
25.24. How do you write C instructions to unmask or mask interrupts?
25.25. What makes an interrupt handler or service routine dierent than an
ordinary function?
25.20 Report
In your report, include the following
What did you learn? What was the most useful thing?
What is still not clear to me? What should be explained better?
An estimation of time you had to spend on the LSC.
c Erich Styger 284
Chapter 26
Multiple Interrupts
26.1 Overview
Interrupts are important events that must be recognized and taken care of
(called serviced) by our program. The microcontroller has hardware features
to provide the interrupts and you must write the software to allow these im-
portant events. Interrupts are widely used when writing high performance
applications and you will have learned how to use them in previous modules.
In most real embedded systems, your software must deal with multiple in-
terrupting devices. We must expand our knowledge of systems with a single
interrupting device to be able to implement systems with multiple interrupt-
ing sources.
26.2 Learning Objectives
In this module you will learn about multiple interrupting sources and how
your microcontroller gives you the tools to successfully implement systems
with multiple, sequential or simultaneous interrupts.
26.3 Success Criteria
When you have nished this module you will be able to demonstrate an
interrupting system with more than one interrupt. Prerequisites: You must
be able to write C programs for your microcontroller and be able to test and
run programs in the laboratory.
285
INTRO V1.70
26.4 More Resources and Further Informa-
tion
MC9S08GB60 Reference Manual, Rev 2.3
MC9S08QE128 Reference Manual[20]
MCF51QE128 Reference Manual[21]
DEMOQE128 User Manual[18]
HC(S)08/RS08 and HC(S)12 Build Tools Utilities Manual, CWMCUB-
TURM,
Freescale Semiconductor, Inc., 3/2007
26.5 Stimulate 1
1. Assume you are designing a microcontroller system to control a mobile
robot for a competition to see whose robot can navigate through a maze
the fastest. The robot can be driven by stepper or DC motors and has
various sensors to detect the walls of the maze. Can you give three
examples of sensors that could interrupt the microcontroller to control
the robot?
26.6 Interrupt System Jargon Review
Asynchronous Event: An event that occurs that is not synchronized
with the microcontrollers internal clock. It can happen at any time in
the instruction execution cycle.
Interrupt Acknowledge: An interrupt acknowledge signal or action (like
resetting a ag) signals the end of an interrupt service routine and can
be used to reset the interrupting device.
Interrupt Enable: A bit in an interrupting subsystem, such as the timer,
that enables (or allows) the sub-system to generate an interrupt re-
quest.
Interrupt Flag Clearing: In many microcontrollers, internal sub-
systems such as the timer can generate interrupt requests. For example,
an Interrupt Request, IRQ, may be generated when the timer overow
c Erich Styger 286
INTRO V1.70
ag is set. When this occurs, the interrupt service routine must reset
the ag that caused the interrupt request to be generated.
Interrupt Handler: See Interrupt Service Routine.
Interrupt Latency: This is the time between when the interrupt request
is asserted and the CPU starts to execute the interrupt service routine.
Interrupt Mask: A control bit that stops (or masks) interrupt requests
from being acted upon by the CPU. Your microcontroller will have
instructions that can mask or unmask interrupts.
Interrupt Prioritization: When multiple interrupts occur simultane-
ously the system must have a way to establish which of them is the
most important and should be serviced rst.
Interrupt Request (IRQ): This is the signal with which some device,
such as a timer overow ag or an external signal, requests that it be
serviced.
Interrupt Return: The interrupt service routine needs this special in-
struction to return to the interrupted program.
Interrupt Service Routine (ISR): The software written to deal with the
interrupt request for a particular device.
Interrupt Vector: When an interrupt occurs the CPU fetches the start-
ing address of the interrupt service routine from a specic and dedicated
location in memory. The starting address is called the vector and the
memory location where it is stored is called the vector location or vector
address.
Nested Interrupts: In a system with multiple interrupt sources, an
interrupt from one source may occur while a previous interrupt is being
serviced.
Pending Interrupt: When an interrupt request has occurred and the
interrupt service routine for that interrupt has not been entered, the
interrupt is said to be pending.
Real-Time System: A real-time system is one that uses interrupts to
run processing tasks when they are needed.
c Erich Styger 287
INTRO V1.70
Real-Time Operating System (RTOS): Many real-time systems use an
operating system that allows the software developer to create tasks and
to schedule their execution under interrupt control.
Reset: Every microcontroller must start its operation with a known
set of initial conditions and then must be able to start executing your
program. The microcontrollers reset signal activates this process.
Simultaneous Interrupts: In a system with multiple interrupt sources,
interrupts from two or more sources may occur simultaneously - that
is, before the current instruction has nished executing and before an
interrupt service routine is entered.
26.7 Explore 1
Read the Resets, Interrupts, and General System Control chapter in your
microcontrollers reference manual. For your microcontroller, review the fol-
lowing:
1. Which program statement or assembly instruction in your microcon-
troller is used for unmasking interrupts?
2. Which program statement or assembly instruction in your microcon-
troller is used for masking interrupts?
3. Which program statement or assembly instruction in your microcon-
troller is used for returning from an interrupt service routine?
4. Which program statement or assembly instruction in your microcon-
troller is used for unmasking interrupts?
5. Which program statement or assembly instruction in your microcon-
troller is used for masking interrupts?
6. Which program statement or assembly instruction in your microcon-
troller is used for returning from an interrupt service routine?
7. How does your microcontroller allow for asynchronous events to occur
and be recognized?
8. How does your microcontroller branch to the correct interrupt service
routine?
c Erich Styger 288
INTRO V1.70
9. How does your microcontroller return to the interrupted program at
the point it was interrupted?
10. How does your microcontroller allow the programmer to globally enable
and disable all interrupts?
11. How does your microcontroller allow the programmer to enable and
disable selected interrupts?
12. How does your microcontroller disable further interrupts so the rst
can be serviced without being interrupted?
13. How does your microcontroller deal with multiple sources of interrupts?
14. How does your microcontroller deal with multiple, simultaneous inter-
rupts?
15. What can cause a pending interrupt?
16. How do you reset a ag that caused an interrupt?
17. What happens if you do not reset the ag in the interrupt service
routine?
26.8 Interrupt System
Figure 26.1 shows the software ow in a system with multiple interrupts.
Each of the ticks along the horizontal lines represents the time taken to exe-
cute an instruction. When an IRQ occurs, the current instruction completes
its execution and then the system, through the interrupt vector process,
starts to execute the interrupt service routine. We call a second interrupt
that occurs after the rst interrupt service routine has started executing a
nested interrupt. Its interrupt service routine may or may not be executed
immediately, depending on your program control. You may choose to wait
until ISR1 completes its tasks and then execute the pending ISR2, or, as
shown by the dotted ow control lines, execute it immediately, thereby inter-
rupting the rst ISR. In the case of simultaneous interrupts, IRQ1 and IRQ2
occur before the currently executing instruction nishes. Then, depending on
which of the two is the highest priority, one of the interrupt service routines
will be executed. The second IRQ remains pending and is executed when
the rst ISR is nished.
c Erich Styger 289
INTRO V1.70
Figure 26.1: Multiple Interrupt System
26.9 Interrupt Software for Multiple Inter-
rupts
You should have become familiar with the program control you need for a
system with interrupts in the Introduction to Interrupts module, but let us
review the principles. Your main program must do the following steps:
1. Initialize the Interrupt Vector: Your software development system must
have a way to initialize the interrupt vector that you are going to use.
2. I/O Initialization: A section of your program must initialize any hard-
ware to be used for interrupts.
3. Clear Any Interrupt Flags: Before enabling and unmasking interrupts
you should clear any ags that would cause an interrupt.
4. Enable the Specic Interrupt Source: Usually a bit must be set in the
interrupting device to enable its interrupting capability.
5. Unmask Interrupts: The nal thing to do in your main program before
entering its processing loop is to unmask the CPU interrupts.
c Erich Styger 290
INTRO V1.70
6. Enter a Process Loop: The processing done in an embedded application
is in a loop that executes forever.
Your interrupt service routine when a single interrupt is used must do the
following steps:
1. Reset the Interrupting Flag: If you dont reset the ag (or device)
that caused the interrupt, as soon as interrupts are unmasked it will
immediately generate another IRQ.
2. Do the Specic Job Required
3. Return from the ISR: Use the special return from interrupt instruction.
The interrupt service routine when multiple interrupting sources are
present:
1. Reset the Interrupting Flag: If you dont reset the ag (or device)
that caused the interrupt, as soon as interrupts are unmasked it will
immediately generate another IRQ.
2. Disable Lower Priority Interrupts: If there are higher priority interrupts
that you would like to interrupt this interrupt service routine, you must
disable lower priority ones.
3. Unmask Global Interrupts: This allows the higher priority devices to
be serviced.
4. Do the Specic Job Required
5. Re-enable Lower Priority Interrupts: You should re-enable these if you
have disabled them previously.
6. Return from the ISR: Use the special return from interrupt instruction.
26.10 Stimulate 2
For the nested interrupt shown in Figure 26.1:
1. What must you do in the ISR#1 to allow ISR #2 to execute as soon
as the current instruction that IRQ2 interrupts?
2. What must you do in the ISR#1 to allow ISR #2 to execute when ISR
#1 nishes?
3. What must you do in the ISR#1 to completely stop ISR #2 from
executing at all until another IRQ2 occurs?
c Erich Styger 291
INTRO V1.70
26.11 Interrupt Device Priorities - Hardware
The right side of Figure 26.1 shows two interrupt requests occurring during
one instruction execution cycle. Even though they may not occur at exactly
the same time, they are considered to be simultaneous because at the end of
that instruction both are pending and both must be serviced. In a vectored
interrupt system, where each device has its own interrupt vector, there must
be a hardware prioritization scheme built into the microcontroller to resolve
this dilemma.
26.12 Interrupt Device Priorities - Software
Figure 26.2: Software Priority Resolution
In microcontroller systems that do not use a vector for determining which
of many devices has interrupted and for resolving the priority of simultane-
ous interrupts, or a system in which several devices share a single vector, a
software polling method is used. Figure 26.2 shows a microcontroller with
three external devices asserting a single interrupt request line IRQ L. A sin-
gle vector will be allocated to this interrupt request and the interrupt service
routine must poll, or interrogate, each device by reading a status bit to see
which has generated the interrupt. The prioritization scheme is determined
by the order in which the external devices are polled.
c Erich Styger 292
INTRO V1.70
26.13 Explore 2
1. How are the various interrupting sources prioritized in your microcon-
troller?
2. Are the priorities xed in hardware or do you have some control over
them?
3. Does your microcontroller have an interrupt line that may require soft-
ware prioritization if multiple devices are connected as shown in Figure
26.2?
26.14 Stimulate 3
1. Does your microcontroller have an interrupt line that may require soft-
ware prioritization if multiple devices are connected as shown in Figure
26.2?
2. Assume you have a system with ve interrupting sources, IRQ0 - IRQ4.
IRQ0 is the highest priority and IRQ4 the lowest. Explain what you
must do in each of the interrupt service routines to allow higher priority
interrupts to be serviced and lower priority ones to remain pending until
the interrupt service routine is nished.
Consider the microcontroller system shown in Figure 26.2. Each of the
devices has an output connected to the IRQ L input of the microcontroller.
1. Each of the devices has an output connected to the IRQ L input of the
microcontroller (Figure 26.2), is this signal active-high or active-low?.
2. Each of the devices has an output connected to the IRQ L input of the
microcontroller (Figure 26.2), what kind of hardware must be used for
this signal?
3. In addition to the hardware needed in each device to assert IRQ L,
what hardware must be included in the design of each device?
26.15 Problem
You and your laboratory partner are to demonstrate that you understand
how to service two independent sources of interrupts. Using the resources of
your laboratory equipment, design an experiment to demonstrate that you
can have a system with two (or more, if you are brave) interrupts.
c Erich Styger 293
INTRO V1.70
1. The interrupt tasks you choose must have one task that is higher pri-
ority than the other, and the interrupt service routine of the lower
priority task must allow the higher priority task to be service in the
case of a nested or simultaneous interrupt.
2. Make sure you add code to the lower priority interrupt service routine
to be able to demonstrate that it can be interrupted by the higher
priority interrupt.
You should describe an approach how to demonstrate this.
1. Can you come up with a design idea how to demonstrate that problem?
Describe your approach.
26.16 Communication - Inter-Group
Compare your solution to Problem 1 with another laboratory groups solu-
tion. Have they chosen a dierent way to demonstrate their understanding
of multiple interrupts? Can you understand their program by reading the
design comments and the inserted code?
c Erich Styger 294
INTRO V1.70
26.17 Problems
This section lists all problems for this LSC.
26.1. Assume you are designing a microcontroller system to control a mobile
robot for a competition to see whose robot can navigate through a maze
the fastest. The robot can be driven by stepper or DC motors and has
various sensors to detect the walls of the maze. Can you give three
examples of sensors that could interrupt the microcontroller to control
the robot?
26.2. Which program statement or assembly instruction in your microcon-
troller is used for unmasking interrupts?
26.3. Which program statement or assembly instruction in your microcon-
troller is used for masking interrupts?
26.4. Which program statement or assembly instruction in your microcon-
troller is used for returning from an interrupt service routine?
26.5. How does your microcontroller allow for asynchronous events to occur
and be recognized?
26.6. How does your microcontroller branch to the correct interrupt service
routine?
26.7. How does your microcontroller return to the interrupted program at
the point it was interrupted?
26.8. How does your microcontroller allow the programmer to globally enable
and disable all interrupts?
26.9. How does your microcontroller allow the programmer to enable and
disable selected interrupts?
26.10. How does your microcontroller disable further interrupts so the rst
can be serviced without being interrupted?
26.11. How does your microcontroller deal with multiple sources of interrupts?
26.12. How does your microcontroller deal with multiple, simultaneous inter-
rupts?
26.13. What can cause a pending interrupt?
26.14. How do you reset a ag that caused an interrupt?
c Erich Styger 295
INTRO V1.70
26.15. What happens if you do not reset the ag in the interrupt service
routine?
26.16. What must you do in the ISR#1 to allow ISR #2 to execute as soon
as the current instruction that IRQ2 interrupts?
26.17. What must you do in the ISR#1 to allow ISR #2 to execute when ISR
#1 nishes?
26.18. What must you do in the ISR#1 to completely stop ISR #2 from
executing at all until another IRQ2 occurs?
26.19. How are the various interrupting sources prioritized in your microcon-
troller?
26.20. Are the priorities xed in hardware or do you have some control over
them?
26.21. Does your microcontroller have an interrupt line that may require soft-
ware prioritization if multiple devices are connected as shown in Figure
26.2?
26.22. For the simultaneous interrupts shown in Figure 26.1, what must you
do to ensure ISR #2 has the higher priority and executes before ISR
#1?
26.23. Assume you have a system with ve interrupting sources, IRQ0 - IRQ4.
IRQ0 is the highest priority and IRQ4 the lowest. Explain what you
must do in each of the interrupt service routines to allow higher priority
interrupts to be serviced and lower priority ones to remain pending until
the interrupt service routine is nished.
26.24. Each of the devices has an output connected to the IRQ L input of the
microcontroller (Figure 26.2), is this signal active-high or active-low?.
26.25. Each of the devices has an output connected to the IRQ L input of the
microcontroller (Figure 26.2), what kind of hardware must be used for
this signal?
26.26. In addition to the hardware needed in each device to assert IRQ L,
what hardware must be included in the design of each device?
26.27. Can you come up with a design idea how to demonstrate that problem?
Describe your approach.
c Erich Styger 296
INTRO V1.70
26.18 Report
In your report, include the following
What did you learn? What was the most useful thing?
What is still not clear to me? What should be explained better?
An estimation of time you had to spend on the LSC.
c Erich Styger 297
INTRO V1.70
c Erich Styger 298
Chapter 27
Analog Input Sampling
27.1 Overview
If you think about the real world you will realize the signals you might
measure there are analog signals. For example, when listening to your MP3
player you are hearing analog sounds even though the music is stored in the
device in a digital format. So in order to get the music (signals) stored in the
device in the rst place, the original sound must be converted to a digital
representation
1
by the analog-to-digital converter.
27.2 Learning Objectives
This module will help you understand how to choose an A/D to resolve the
information in the signal and to sample the signal frequently enough to be
able to reconstruct the analog signal in digital form in the computer.
27.3 Success Criteria
You will be able to specify an A/D suitable for any application.
27.4 Prerequisites
To successfully complete this module and program the A/D you must have
some hardware that can supply an analog voltage to one of the A/D input
channels. You must be able to write and assemble or compile the software
1
The word is digitize, not digitalize
299
INTRO V1.70
needed to initialize and start the A/D and to retrieve the converted value.
You could use the X, Y, and Z analog signals of the accelerometer present
on the MC13213 SRB board or MPC52259 Tower Board.
27.5 AD Information
Figure 27.1: Analog Input Sampling (Source: Oxford University Press, Inc.)
An A/D converter in a microcontroller can convert multiple analog signals
that an input multiplexer switches to its successive approximation converter.
The A/D conversion is started by writing to a control register or by an ex-
ternal trigger signal. Figure 27.1 shows a block diagram of a microcontroller
analog-to-digital converter
2
.
The analog input signals (AN0 - AN7) may also be used as general pur-
pose digital input and output pins and have another signal name PAD0 -
PAD7. These signal names occupy the same physical pin on the microcon-
troller. Thus, you can not use any of these pins simultaneously as an analog
input and digital input or output. You select one of these analog signal to be
converted at a time by the A/D Control Register 5 - ATDCTL5. The 8-bit
or 10-bit digital A/D conversion outputs are placed into eight, 16-bit data
registers ATDDR0H - ATDDR7H.
2
It is rather unusual for an analog input subsystem in a microcontroller to have digital
output capabilities. Modern microcontroller like the one we use have this capabilities.
c Erich Styger 300
INTRO V1.70
27.6 Analog-to-Digital Denitions
Figure 27.2: Analog Input Conversion
Denition 12. Resolution: The resolution is the smallest change in the
analog input voltage for which the converter will produce a change in the
output digital code. For a converter with n bits, the resolution is 1/2n times
the full scale value (the largest input value).
Denition 13. A/D Transfer Function: The A/D transfer function
shown in Figure 27.2 describes how the A/D converts an analog input signal
to an output binary code.
Denition 14. Conversion Time: This is the time the A/D takes to
completely convert an analog value to a digital code. This establishes the
upper frequency limit that can be converted without aliasing.
27.7 Explore 1
1. Using the data sheets or your textbook for your microcontroller, how
many bits are in the digital output?
c Erich Styger 301
INTRO V1.70
2. What is the maximum input voltage it can convert?
27.8 Stimulate 1
1. For an A/D with 8-bits and a 5 volt maximum (full scale) input, what
is the smallest change in the input signal that can be detected?
2. For an A/D with 10-bits and a 5 volt maximum (full scale) input, what
is the smallest change in the input signal that can be detected?
3. For a four-bit A/D whose transfer function is shown in Figure 2
(a) What output code results from an input voltage of 3.1 volts?
(b) What range of input voltages will produce an output code of
1000?
c Erich Styger 302
INTRO V1.70
27.9 Explore 2
1. Using the data sheets or your textbook for your microcontroller, what
is the shortest conversion time for an 8-bit conversion?
2. Using the data sheets or your textbook for your microcontroller, what
is the shortest conversion time for a 10-bit conversion?
27.10 Stimulate 2
1. What elements aect the conversion time for various A/D converters?
2. Your microcontrollers A/D may have its own clock derived from the
system clock. How is the A/D clock frequency determined?
c Erich Styger 303
INTRO V1.70
27.11 Sampling Criteria and Nyquist
Any time varying, non-sinusoidal signal is comprised of a sum of sinusoids
as given by the Fourier series or transform. To be able to reconstruct a
time-varying signal we must sample it often enough to be able to reconstruct
the frequency components in the digital domain. The Sampling Theorem,
also called Shannons Sampling Theorem, gives the sucient conditions for
sampling. This theorem states that an exact reconstruction of a time-varying
signal requires the signal to be band-limited and sampled at a frequency
greater than twice the signal bandwidth. The signal frequency in this case,
that is, one-half the sampling frequency, is called the Nyquist frequency.
27.12 Stimulate 3
1. What does bandwidth limited mean?
2. What kind of electronic lter must you use to limit the bandwidth of
a signal?
3. You wish to digitize a signal whose maximum frequency is 1 kHz with
your A/D.
(a) What is the minimum sample rate (in samples/second) that can
be used?
(b) What is the maximum conversion time?
27.13 Dynamic Range
The dynamic range of the signal is given by the ratio of the maximum signal
value divided by the smallest, or noise level signal (Equ. 27.1).
DynamicRange =
V
MAX
V
NOISE
(27.1)
c Erich Styger 304
INTRO V1.70
27.14 Stimulate 4
1. What is the dynamic range of a signal whose maximum is 26 volts and
whose noise is 26 mV?
2. Dynamic range is often expressed in decibels. What is the dynamic
range of the signal above in decibels?
27.15 Aperture Time
The aperture time is the time during which the A/D is sampling the signal
and during which a time-varying signal can change. Any change in the input
signal during this time leads to an error called aperture time error. See
Figure 27.3.
Figure 27.3: Aperture Time Error (Source: Oxford University Press, Inc.)
27.16 Stimulate 5
Consider a sinusoidal signal v(t) as shown in Figure 27.3 where V
MAX
is 5
volts and f
MAX
is 1 kHz. The aperture time of the A/D is 1s. What is the
worst-case change in voltage, as a percent of full scale that can occur?
c Erich Styger 305
INTRO V1.70
27.17 Explore 3
1. What inuences the aperture time in your microcontroller?
2. What is the minimum aperture time for your microcontroller?
c Erich Styger 306
INTRO V1.70
3. What is the maximum aperture time for your microcontroller?
27.18 A/D Errors
There are three sources of noise in the A/D conversion process.
Electronic Noise: Any analog signal in the real world will have noise.
These electronic noise sources include shot noise, quantum eects in
optical system, power supply noise, and electromagnetic interference
(EMI). The magnitude of these noise sources can often be estimated or
actually measured with an oscilloscope.
Aliasing: Aliasing can be considered a noise source because its eect is
similar to other noise sources, that is, the digital values from the A/D
will not accurately represent the true value. The eects of aliasing
are dicult to determine quantitatively and so you must include low-
pass ltering in the analog signal processing to eliminate frequency
components above the Nyquist frequency.
Aperture Time Error: While the A/D is sampling the signal, the A/Ds
aperture is said to be open. As we can see in Figure 27.3, the signal may
change during the time the aperture is open leading to an uncertainty
in what the real signal is at the sample time. This, too, is a source of
noise. Figure 27.3 shows that a sinusoidal signal can change an amount
V during the aperture time t
AP
.
c Erich Styger 307
INTRO V1.70
27.19 Quantization Noise
This noise is not associated with the signal, like electronic noise. It is the
uncertainty in how well the digital value represents the analog value. Because
the A/D quantizes the signal based on the number of bits as shown in
Figure 27.2, the digital signal has steps in it even thought the analog signal
may be smoothly varying. See Figure 27.4. When we design our system we
will choose the quantization step size (which determines the number of bits)
to give the resolution we need for the signal of interest. Then we will design
the electronics, ltering and aperture time so that these errors are less than
the quantization step size.
Figure 27.4: Quantization of an analog signal
27.20 Putting it All Together - the A/D Sys-
tem
Figure 27.5 shows an analog-to-digital conversion system. The signal condi-
tioning block contains a low pass lter to eliminate frequency components
above the Nyquist frequency. It also can amplify or attenuate and level-shift
c Erich Styger 308
INTRO V1.70
Figure 27.5: Analog to Digital Conversion
the analog input signal to match the input signal requirements of the A/D
and often can reduce the electronic noise associated with the signal. The
Sample-and-Hold
3
block contains a circuit to quickly sample the analog sig-
nal to avoid aperture time errors. Our microcontroller program must assert
the control signal Sample to hold the analog signal at a constant value for
the A/D to convert. The A/D receives the Start Convert
4
signal from the
microcontroller and starts the conversion process. After the conversion time
elapses, the A/D asserts the End Of Convert signal to inform our program
that a new digital value is ready to be read from the A/D.
27.21 Choosing the A/D
You specify an A/D by determining the number of bits needed, the conversion
speed or time, and the aperture time.
2
n

V
MAX
V
NOISE
(27.2)
2
n

V
MAX
V
SMALLESTSIGNAL
(27.3)
The number of bits, n, is determined by the dynamic range of the signal
or the dynamic range of the information needed.
Equation 27.2 gives the number of bits so that the noise, V
NOISE
, is less
than the quantization error.
Equation 27.3 gives the number of bits so the smallest analog input volt-
age change to produce a change in the digital output is less than the quan-
tization error.
The conversion time must be fast enough to be able to digitize the analog
signal and not introduce aliasing. Thus, the conversion time is related to
3
The Sample-and-Hold can be simply shown with an electronic switch and a low-leakage
capacitor.
4
I/O timing and handshaking is not covered in this chapter, this requirement to wait
until the A/D nishes the conversion is a good lead-in to that topic.
c Erich Styger 309
INTRO V1.70
the maximum frequency in the signal and must allow at least two samples
per period (equation 27.4). This tells us that the sample frequency must be
greater than twice the maximum frequency in the signal (Equation 27.5)
5
.
ConversionTime <
1
2 f
MAX
(27.4)
SampleFrequency > 2 f
MAX
(27.5)
27.22 Stimulate 6
1. A temperature transducer produces an analog voltage from 0 to 5 volts
over a range of temperatures from 0 to 100

C. When an oscilloscope
is used to look at the output of the transducer, we see a noise level of
about 1 mV peak-to-peak. How many bits are needed in the A/D so
that the electronic noise is less than the quantization level?
2. The same temperature transducer is being used to provide a tempera-
ture display of 0 to 100

C with a resolution of 1

C. How many bits


are needed in the A/D for this case?
3. You wish to digitize a 100 kHz signal.
(a) What is the minimum sample frequency?
(b) What is the maximum conversion time?
5
It is useful to know that sampling criteria gives only the upper limit of the conversion
time or the lower limit of the sample frequency. It is far better to design the system to
over sample the signal, say by 10 times.
c Erich Styger 310
INTRO V1.70
4. You look up the specications for an A/D and nd its conversion time
is 16 s. What is the maximum frequency that can be converted?
27.23 Sample-and-Hold Aperture Time
The aperture time (Equation 27.6) must be short enough that the aperture
error shown in Figure 27.3 is less than the quantization error.
t
AP

1
2f
MAX
2
n
(27.6)
The aperture time is usually very short, much shorter than the usual con-
version time for most analog-to-digital converters. Most systems that must
digitize a time-varying signal use a sample-and-hold circuit which samples the
signal in a very short time and then holds it constant during the conversion
time of the A/D.
27.24 Stimulate 7
1. Assume a signal of the form v(t) = V
MAX
sin 2f
MAX
t and derive the
formula for aperture time.
c Erich Styger 311
INTRO V1.70
2. For the shortest aperture time of the HCS08 in 8-bit mode, what is the
maximum frequency that can be sampled?
3. What is the maximum frequency that can be sampled with an 8-bit
A/D with an aperture time of 1 s?
27.25 Designing the Signal Conditional Con-
ditioning Electronics
The signal conditioning electronics must transform the voltage characteristics
of the signal with the input characteristics of the A/D. You may have to
amplify small signals or attenuate large signals
6
. Some times a level shift is
6
Op amps are often used for the signal conditioning stage. When you are asked to do a
design using an op amp you might likely to revert to what was used in your introductory
electronics classes, often the LM741 or its cousins. Although you can use this device in a
c Erich Styger 312
INTRO V1.70
needed if, for example, a bipolar signal is to be digitized by an A/D with,
say, a 0 to 5 volt input. There are two other jobs for this block in the system.
It should do the low pass ltering to limit the frequency components in the
signal to avoid aliasing and it should provide some protection against voltage
spikes that may damage the electronics.
27.26 Stimulate 9
Propose a circuit using two diodes that will limit the voltage at the input to
the A/D converter to at most one diode drop above the maximum input and
one diode drop below the minimum.
27.27 Skill Exercise
1. An audio signal is to be digitized by an A/D converter. The signal
comes from a microphone and the bandwidth is 300 Hz to 3 kHz. The
signal is AC and 300 mV peak-to-peak with 1 mV peak-to-peak noise.
The A/D input voltage range is 0 to 5 V.
(a) Specify the characteristics (low pass lter cut o, gain and oset)
for the signal conditioning block.
circuit with a single-ended supply, it works best with a bipolar (5) supply. You might
consider one of the very good rail-to-rail, single-ended power supply, op amps such as the
TLC2274.
c Erich Styger 313
INTRO V1.70
(b) How many bits are needed so that the system noise is less than
one least signicant bit?
(c) What is the maximum conversion time?
(d) What is the maximum allowable aperture time?
27.28 Communication - Inter-Group
Form groups of two and clusters of two groups each. Each group is to think
of a signal to be sampled by an A/D that the other group is to specify. Each
group is to explain to the other why they chose the A/D specications that
they did.
27.29 Reection on Learning
Think about what you have learned in this LSC:
1. Were you able to specify an A/D for the problem posed by the other
group in your cluster?
2. If not, what were you missing?
3. Was there material that you did not understand?
4. Did the other group specify the problem well enough that you could
specify the required A/D?
27.30 Report
In your report, include the following
What did you learn? What was the most useful thing?
What is still not clear to me? What should be explained better?
An estimation of time you had to spend on the LSC.
c Erich Styger 314
Chapter 28
Computer Operating Properly
28.1 Overview
Most embedded systems must operate continuously without any user input,
even if something goes wrong. Most of us have experienced having our desk-
top or laptop computer locking up and requiring a reboot of the system to
get it working again. We simply cannot aord this to happen in an embedded
system. Ideally, we would write our software so that it never crashes or fails.
This, as you can guess, is really hard to do and so our microcontroller man-
ufacturer has included a hardware feature called the Computer Operating
Properly, or COP, reset generator. If this hardware feature does not receive
a conrmation signal that our program is running properly, it will generate
a reset to restart our program from the beginning. The COP is also called a
watchdog
1
timer.
28.2 Learning Objectives
In this module we will help you learn about the COP, or watchdog timer.
28.3 Success Criteria
When you complete this module you will be able to demonstrate a program
illustrating how the COP can reset the program if it times out and that it
does not generate a restart if the COP timer is reset properly in the program.
1
The COP is also called a watchdog timer. Some documentation uses the term feeding
the COP to refer to resetting the COP timer, but frequently it is referring to it as kicking
the dog or tickling the timer.
315
INTRO V1.70
28.4 More Resources and Further Informa-
tion
MC9S08QE128 Reference Manual[20]
MCF51QE128 Reference Manual[21]
HC(S)08 and HC(S)12 Build Tools Utilities Manual, CWMCUB-
TURM, Freescale Semiconductor, Inc., 3/2007
DEMOQE128 User Manual[18]
Ganssle, Jack, Great Watchdogs [5]
28.5 Ganssle: Great Watchdogs
The next pages are from an article[5] from Jack Ganssle about how to build
a great watchdog.
28.6 Explore 1
1. What is the most usefule thing you have learned reading Jack Ganssles
Great Watchdogs[5]?
2. Make a list of all the things that could go wrong in your program that
having a COP reset would assist in making a recovery.
28.7 Basics of the COP in Microcontrollers
The COP reset circuitry guards against our program not working properly
by expecting the program to execute an instruction or a particular sequence
of instructions within an interval. If the COP does not receive this sequence
c Erich Styger 316
INTRO V1.70
before it times out, it generates a reset. This can reset all peripherals con-
nected to the reset line. The CPU then restarts the program again. When
this occurs, you may choose to enter some diagnostic routine, such as updat-
ing a counter that counts the number of COP restarts that have occurred
or lighting an LED before restarting the program. You may also wish to
leave some debugging breadcrumbs to help you understand why the COP is
resetting the program. A microcontroller typically allows you to determine
which of the many resets have occurred and act accordingly.
Note that each microcontroller system and manufacturer treats the ini-
tialization of the COP dierently. Some systems, like the Freescale Flexis
microcontrollers, enable the COP on reset. Others, such as the Freescale
HCS12 microcontrollers, disable the COP on reset.
28.8 Explore 2
Read the Computer Operating Properly (COP) Watchdog section of the Re-
sets, Interrupts and General System Control chapter in your microcontrollers
Reference Manual
2
.
1. In some processors the COP is enabled at reset and in others it is
disabled. Which is the case for your microcontroller?
2. The System Options Register 1 (SOPT1) has two bits to control the
COP. Give the name and function of each bit.
2
The Flexis documentation indicates that the bit elds in SOPT1 (with the exception
of WAITE) may be written only once. This does not imply that the bit addressing bit-
set and bit-clear instructions may be used to control these bits individually. Only one
write to the registers seems to be allowed. The same thing applies to the S08 where
the whole SOPT register needs to be written in once. The COP Reset Vector In some
microcontrollers a separate reset vector is used for the COP resets. This is not the case for
the Flexis/S08 system. When the COP timer times out it generates a processor reset and
then starts executing the reset initialization code. If you wish to include special code, such
as debugging code to indicate a COP timeout has occurred, you must check the COP bit
in the SRS register to transfer control to whatever code you would like to have executed.
c Erich Styger 317
INTRO V1.70
3. The System Options Register 2 (SOPT2) has one bit to control the
COP. Give the name and function of the bit.
4. The System Reset Status Register (SRS) has a bit associated with the
COP. What is it and what does it indicate?
5. What bits would you initialize to what value to have the COP time-out
time be approximately 256 ms with your microcontroller?
6. The SOPT1 and SOPT2 are write-once registers and once written, they
cannot be changed in your program. Why is this a good thing?
7. Even if your application will use the reset default settings of COPE,
COPCLKS, and COPT, why is it a good idea to write to SOPT1 and
SOPT2 during reset initialization?
8. How do you clear or reset the COP timer?
9. It is recommended that you do not reset the COP timer in an interrupt
service routine. Why is this so?
c Erich Styger 318
INTRO V1.70
28.9 The COP Reset Vector
In some microcontrollers a separate reset vector is used for the COP resets.
If not, then this will happen: when the COP timer times out it generates
a processor reset and then starts executing the reset initialization code. If
you wish to include special code, such as debugging code to indicate a COP
timeout has occurred, you must check the COP bit in the SRS register to
transfer control to whatever code you would like to have executed.
1. Does your system have a dedicated COP reset vector?
28.10 Problem 1
You are to verify that your microcontroller asserts the reset line signal each
time the COP times out. Come up with a plan to do this and demonstrate
it.
28.11 Problem 2
Design and write a program that demonstrates you can use the COP to
generate a reset if the program stops working for some reason. Demonstrate
the following:
1. Your program working correctly without the COP timing out when you
are resetting it properly.
c Erich Styger 319
INTRO V1.70
2. Your program is reset by the COP if you do not reset it in a timely
manner.
Your program must have some visual or audible indication showing the two
operational modes and you should test for a variety of failures such as hanging
up in a loop, memory contents being destroyed, etc.
28.12 Communication - Inter-Group
1. Compare your solution to Problem 2 with another laboratory group.
Exchange source listings of your solutions.
2. Are there any dierences in the approaches the two groups have used
to illustrate the operation of the COP?
3. Is one approach better than the other?
28.13 Reection on Learning
Think about what you have learned in this LSC, and how you can show this
to your peers:
1. Demonstrate to somebody your program that illustrates the operation
of the COP.
2. Prepare a memo for your workbook. Include comments gained during
your Inter-Group Communication where you looked at another groups
solution. Include listings of your and the other groups programs. How
does each solution compare in terms of rigorously testing for various
faults from which the COP should allow you to recover. What did you
learn from seeing the other groups solution?
28.14 Report
In your report, include the following
What did you learn? What was the most useful thing?
What is still not clear to me? What should be explained better?
An estimation of time you had to spend on the LSC.
c Erich Styger 320
Chapter 29
Nokia LCD
29.1 Overview
Many embedded systems need some kind of user interface by some means.
While this could be as simple as a ashing LED, in many cases it is desirable
to have some more advanced ways to visualize things to the user. Alphanu-
meric LCD displays are common in embedded devices. With the mass market
of mobile phones, small graphical LCD displays are getting common and in-
expensive. Such displays are very energy ecient so they are very suitable for
many even battery operated devices and provide great functionality. How-
ever the software portion for controlling and writing a graphical LCD is much
more complex compared to simple text displays. In this course we learn some
advanced techniques which will you make able to use such graphical displays.
Figure 29.1: Nokia 3310 Phone
321
INTRO V1.70
29.2 Learning Objectives
You will learn about how a graphical driver can be structured to drive a
graphical LCD display. You learn about typical capabilities of embedded
display controllers and learn how to use them. You will be able to recycle
Nokia displays for your own project.
29.3 Success Criteria
At the end of this course you will be able to use a graphical LCD display
with your microcontroller using Processor Expert. You will be able to use
graphical fonts and drawing primitives (drawing dots and lines).
Figure 29.2: Nokia LCD with S12XEP100 Board
29.4 Prerequisites
You have to be familiar with CodeWarrior for MCU10.x and Processor Ex-
pert. You should be able to read and understand schematics of the board
used. For this LSC dierent boards can be used. You can use the SRB board
or ask for a DEMOJM board.
c Erich Styger 322
INTRO V1.70
Figure 29.3: Front Side of Nokia 3310 LCD
29.5 More Resources and Further Informa-
tion
MC13213 SRB Board resources at Freescale SRB Documentation.
DEMOJM Online Resources at Freescale DEMOJM Board.
PEmicro DEMOJM User Manual, Rev. 1.0, P&E Microcomputer Sys-
tems, Woburn, MA, January 2008.
Development board DEMOJM Board Schematic.
PDC8544 Processor Expert Component site at PDC8544.
PDC8544 48x84 pixels matrix LCD controller/driver, Philips Semicon-
ductor, 12-Apr-1999 [25].
Serdisplib Project on serdisplib.sourceforge.net.
SPI Bus: Wikipedia.
29.6 Explore: First Steps
1. If you are using a board which is new for you: Locate and read the
Development Board User Manual and Schematic to get you familiar
with the board.
c Erich Styger 323
INTRO V1.70
2. Create a new project with CodeWarrior using Processor Expert for the
target processor and board.
3. Verify that you can successfully download and debug your application
on the board.
4. Depending on the connectors on your board, you will need some cables
to connect the display with your board (Figure 29.4). The LSC hard-
ware comes with some cables, but you may need to add some cables on
your own.
Figure 29.4: Nokia LCD with SRB Board
29.7 Stimulate: Research
1. There are plenty of open source and hacker projects on the web de-
scribing how to recycle a Nokia phone display which are available for
less than $10. Why those displays are so aordable compared to other
displays?
2. We are using in this lab the Philips PDC8544 display controller.
Identify on your display the pin numbering using the information on
c Erich Styger 324
INTRO V1.70
http://serdisplib.sourceforge.net/ser/pcd8544.html. The web
site lists two types of displays: what are the dierences between Type
1 and Type 2?
3. Which type of display do you have?
4. The display is equipped with a 2x5 pin connector. List the signals on
the pins 1 to 10 of the connector (Hint: the numbering corresponds to
type 1 displays).
5. Which pins of the display are NOT required to be connected with a
microcontroller system in order to have the display working?
6. The display we are using requires a supply voltage (Vdd) and logic level
of 5V. Identify the Vdd and GND pin on the 2x5 connector.
7. Browse through the pcd8544.pdf data sheet to get familiar with the
display controller. The display is using an Serial Peripheral Interface
(SPI) for communication. Who is the master, and who is the slave in
our system?
8. Map the SPI signals (SKLK, MOSI, MISO, SS explained in http://
en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus to the
PDC8544 display signals.
9. Which bit in a byte is rst transmitted in the serial protocol?
10. How many clock signals (SCLK) are needed to transmit a single byte
of data?
11. How could you attach 2 displays to your microcontroller and use them
as dual displays with minimal port pins needed? How many pins or
connectors do you need?
12. The display has an internal (on-display) charge pump which transforms
the supply voltage to the needed (higher) voltage required to change
the liquid crystal cells. What is the maximum supply voltage for the
Vdd pin?
13. The PDC8544 Nokia display can be used with dierent supply and
logic levels (e.g. 5V or 3.3V). But the logic levels are dierent for 5V
CMOS and 3.3V CMOS. How can this work?
c Erich Styger 325
INTRO V1.70
Figure 29.5: PDC8544 Properties
29.8 Explore PDC8544 Component
1. Make sure you have all the components needed for this LSC in your
CodeWarrior. You need at least Wait, PDC8544 and GenericSWSPI.
2. Add the PDC8544 display component to your project (Figure 29.5).
3. Make sure the display type matches your hardware and that the con-
trast is either 50 or 64 depending on your hardware.
4. Use the tool tip of contrast property to nd out what level of contrast
could be a good starting point.
5. Make sure you select the correct display type (e.g. LPH7677) based on
your hardware.
c Erich Styger 326
INTRO V1.70
6. If you are using the SRB board, then use PTB3 for RES, PTB4 for
SCE and PTB5 for D/C.
7. The component will ask you to add a new shared component: add a
GenericSWSPI (Figure 29.6) component.
8. Make sure you select the correct voltage level according to your hard-
ware. Check writing on the hardware, or consult the properties and
help le of the PDC8544 component.
9. For the PDC8544 component you need to specify its connection to the
hardware (RES, SCE and D/C). Refer to your board documentation
and select 3 pins which are free (and not used) on your board according
to your board documentation.
10. The display is using a serial SPI bus using a serial clock signal and a
serial data line. For the SPI component settings refer to the PDC8544
component documentation and online help. If using the SRB board,
assign PTB7 for SCLK and PTB6 for MOSI.
11. Connect the display to board using wire cables. Make sure your board
is not(!!!) powered and that you do not mix up signals/pins in order
not to damage the board and display.
12. Inspect the methods of the PDC8544 component. Write a hello world
on a new line to your display using the methods in the PDC8544 com-
ponent.
Figure 29.6: GenericSWSPI Component
c Erich Styger 327
INTRO V1.70
Hint: if using the DEMOJM board, you could un-jumper the LED pins
and use the following signal mapping:
J1, Pin1: Vdd (1)
J1, Pin3: GND (6)
J1, Pin13: PTE2: MOSI (3)
J1, Pin15: PTE3: SCLK (2)
J1, Pin25: PTF0: D/C (4)
J1, Pin27: PTF1: SCE (5)
J1, Pin53: PTC2: RES (8)
29.9 Stimulate: Implementation Details
1. Try out dierent contrast values, either using the component properties
and the SetContrast() method. What happens if you set high/low
contrast values?
2. Inspect the generated code. The component is using a variable named
table[] for writing text to the display using WriteChar(). List ad-
vantages and disadvantages of such an implementation compared to an
approach using a full graphical font.
3. What happens if you write Zrich City to the display? Explain what
happens and how you would solve it.
4. The component is using a WAIT component. What does this compo-
nent and why is it used for the LCD component?
29.10 Display Memory
Most graphical displays are using an on-chip memory to reect the display
content as in Figure 29.7. The job of the microcontroller is then write into
the on display memory (e.g. over an SPI bus, see Figure 29.8). You send an
address followed by the data (e.g. byte) and then this data byte is stored
in the display memory. As this is not practical for larger set of data, most
displays support a burst mode: You can transmit single address followed by
c Erich Styger 328
INTRO V1.70
Figure 29.7: DDRAM to display mapping[25]
Figure 29.8: SPI transmission of one byte[25]
a series of data bytes: the display will auto-increment the internal address
used to write the display memory.
In order to address the display memory correctly, it is important to know
the exact relationship between the display memory and the pixels on the
display itself:
1. Display Size: Displays have a dened number of rows and columns.
The display in Figure 29.10 has 128 columns and 64 rows.
2. Memory Display Start: At which display memory address does the
display show the content? It is possible that the display memory is
c Erich Styger 329
INTRO V1.70
Figure 29.9: Display Pixel Memory[25]
Figure 29.10: Display Pixel Column/Row Orientation[25]
larger than the display. In that case the display shows only a portion of
the display memory. This is very useful if you want to scroll through a
display portion (you do not need to update the display with new data
content) or if you want to switch between multiple dierent content
(e.g. menus)
3. Color Depth: How many bits are forming a display dot? For
monochrome displays (Figure 29.11) a 0 may turn o a dot and a 1
may turn it on. For RGB color displays the mapping may be dierent:
a certain number of bits may be used for the red portion, a number
of bits for green and a number of bits for the yellow portion. Some
displays are using a 4R-4G-4Y (12bits) mapping, some are using a e.g.
16 gray scales. Figure 29.10 shows a monochrome display with 16 gray
scale levels. 4 bits are used for a single pixel, and display bytes are
increasing in column direction, from left to right. Most signicant byte
nibble is coming rst.
c Erich Styger 330
INTRO V1.70
4. Display Orientation: where is the start of the coordination (x/y)
system? Most displays are using upper left or lower left corner as
(0,0), but this may not be always the case. Some displays allow you to
congure the zero coordination point. Additionally you may congure
the display orientation at runtime.
5. Display Bit and Byte Mapping: How are the display bytes orga-
nized? If a display byte (8bits) holds 8 monochrome pixels: does an
increase of display memory address increase the row number or the
column number? Are the bits in the byte organized the MSB rst or
Least Signicant Bit (or Byte) (LSB) rst way?
Figure 29.11 shows a monochrome display example where displays bytes
are organized in columns (a byte is lling a column space). The bytes are
increasing the from left to right into x direction (x axis from left to right).
Display bits are organized the columns are coming most signicant (MSB)
bit rst.
Figure 29.11: Monochrome Display Bit Mapping[25]
There are dierent ways how a microcontroller could deal with the display
on chip memory.
Direct Write: One way is that the microcontroller is directly ma-
nipulating the display memory (directly writes into it). This has the
advantage that the RAM needs on the microcontroller are minimal.
On the other side if the display does not allow you to read the display
RAM, then modifying the display content based on the existing content
may be dicult or impossible. E.g. to invert a portion of the display.
Drawing in non-linear (means: in non-linear-memory-address) order
may result into high communication overhead as the microcontroller
cannot use a burst mode.
c Erich Styger 331
INTRO V1.70
Display Buer: With this approach, the microcontroller maintains
a memory buer reecting the image on the display. Operations (like
drawing, set/clear pixel) are performed on this local buer. Once the
operation (which could be a large number of drawing primitives) has
been nished, the display content is submitted to the display in one
ush. That way the burst data transfer mode can be used. With the
controller always having a shadow version of the display memory lo-
cally the drawing primitives can be optimized. In order to reduce com-
munication trac, the microcontroller could only transmit the changed
content (caching). However this increases the RAM requirements on
the microcontroller side.
Which method is used depends heavily on the available RAM on the micro-
controller side and the capabilities of the display.
29.11 Explore: GDisplay
We are going to add graphic capabilities to our Nokia display. For this we
are adding the GDisplay (Graphic Display) (Figure 29.12) component to our
project. While adding the GDisplay component, Processor asks us which
display component to use with it: the PDC8544 component.
With this component you can now change individual dots on the display
using graphic primitives (set, clear, neg of a pixel). The GDisplay component
is using a display buer (DisplayBuf[]) which is used for the pixel opera-
tions. With TransferAllData() the display buer is sent to the display and
with Refresh() the image content is shown on the display. Depending on
the display type a Refresh() may not be required, but then the component
will simply do nothing.
29.12 Explore: Software Architecture
Another important aspect is the software architecture (Figure 29.13). As
might realize, there are many dierent displays and settings needed for a
display driver to operate properly.
There are a few design guidelines to consider:
Create a layered approach: Have your system designed in blocks
and partitions. In Figure 8 the system is layered into hardware (the
display controller), connection to the hardware (SPI), low level hard-
ware functions (sending commands and data), middle level primitives
c Erich Styger 332
INTRO V1.70
Figure 29.12: GDisplay Component
(set/clear dots) and high level graphics (fonts). Create clear interfaces
between the blocks. This makes the blocks exchangeable. An example
is using a generic SPI implementation using normal I/O pins if you
have no SPI hardware available. This is done with the choice of dif-
ferent SPI components (e.g. Generic SPI component which is using
general purpose I/O or using a hardware SPI component)
Let the system congure itself : Things like display width or height
are exposed by the PDC8544 component so the higher software levels
can use it. In case you exchange the underlying display this will be
automatically reected in the upper layers. Another example is how
the x and y coordinates are used: they are using typedefs (dened
by the display component): for a small display with up to 256 rows or
columns a 8bit (byte) data type is sucient. But if you have a larger
display, you want to have this changed automatically as well. See how
this is done with the PDC1 PixelDim type and how it is used in your
c Erich Styger 333
INTRO V1.70
Figure 29.13: System and Component Block Diagram
application.
If you now look carefully at the components in your system, you will
notice the PDC8544 component is not fully following the guidelines above.
Discuss what could be the reasons that it is violating one or more of above
guidelines, and what you would change. Document your ndings in your
workbook/memo.
29.13 Stimulate: Drawing Primitives
1. Use now this component to draw a single dot into each corner of the
display. Additionally draw a (horizontal or vertical) line across your
display. Implement this in a way that it is independent of the dis-
play size/orientation. Include your function/source doing this into the
report.
2. What is key if you want to implement the above functionality without
depending on the display size?
3. Inspect the code in GDisp1 SetPixel(). You will see that there are
macros used to manipulate the display buer in the microcontroller
RAM. Make sure you understand what the macros are doing. Now
rotate the display in the GDisplay component properties by 90 degree.
What happens in the generated code and macros?
4. Download the new code (display rotated by 90 degree). Is the result
matching your expectation?
c Erich Styger 334
INTRO V1.70
Figure 29.14: FontDisplay Component
5. What happens if you mix in your application both the e.g. Write-
String() (from the PDC8544 component) and the new graphic prim-
itives (e.g. SetPixel()) from the GDisplay component?
29.14 Explore: Fonts
We have now graphic primitives, but we lost the ability to write text to
your display. So we are going to add this capability again, but this time
with a bitmap font. For this we are adding the FontDisplay (Figure 29.14)
component to our project. It will as well create a new GFont (Graphical
Font) component to our project.
Using the FontDisplay component you can set a cursor to a posi-
tion on the display (SetCursor()) and write a string to this position
(WriteToLine()). If you add multiple GFont components, you can switch
fonts using SetFont().
In the GFont (Figure 29.15) properties you can specify dierent at-
tributes.
Figure 29.15: GFont Component
c Erich Styger 335
INTRO V1.70
29.15 Report
Experiment with the display using graphical fonts and the graphical methods
you have available in your system. Include a picture of your display with what
you have accomplished.
29.16 Problems
This section lists again all problems from this LSC:
29.1. There are plenty of open source and hacker projects on the web de-
scribing how to recycle a Nokia phone display which are available for
less than $10. Why those displays are so aordable compared to other
displays?
29.2. We are using in this lab the Philips PDC8544 display controller.
Identify on your display the pin numbering using the information on
http://serdisplib.sourceforge.net/ser/pcd8544.html. The web
site lists two types of displays: what are the dierences between Type
1 and Type 2?
29.3. Which type of display do you have?
29.4. The display is equipped with a 2x5 pin connector. List the signals on
the pins 1 to 10 of the connector (Hint: the numbering corresponds to
type 1 displays).
29.5. Which pins of the display are NOT required to be connected with a
microcontroller system in order to have the display working?
29.6. The display we are using requires a supply voltage (Vdd) and logic level
of 5V. Identify the Vdd and GND pin on the 2x5 connector.
29.7. Browse through the pcd8544.pdf data sheet to get familiar with the
display controller. The display is using an Serial Peripheral Interface
(SPI) for communication. Who is the master, and who is the slave in
our system?
29.8. Map the SPI signals (SKLK, MOSI, MISO, SS explained in http://
en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus to the
PDC8544 display signals.
29.9. Which bit in a byte is rst transmitted in the serial protocol?
c Erich Styger 336
INTRO V1.70
29.10. How many clock signals (SCLK) are needed to transmit a single byte
of data?
29.11. How could you attach 2 displays to your microcontroller and use them
as dual displays with minimal port pins needed? How many pins or
connectors do you need?
29.12. The display has an internal (on-display) charge pump which transforms
the supply voltage to the needed (higher) voltage required to change
the liquid crystal cells. What is the maximum supply voltage for the
Vdd pin?
29.13. The PDC8544 Nokia display can be used with dierent supply and
logic levels (e.g. 5V or 3.3V). But the logic levels are dierent for 5V
CMOS and 3.3V CMOS. How can this work?
29.14. Try out dierent contrast values, either using the component properties
and the SetContrast() method. What happens if you set high/low
contrast values?
29.15. Inspect the generated code. The component is using a variable named
table[] for writing text to the display using WriteChar(). List ad-
vantages and disadvantages of such an implementation compared to an
approach using a full graphical font.
29.16. What happens if you write Zrich City to the display? Explain what
happens and how you would solve it.
29.17. The component is using a WAIT component. What does this compo-
nent and why is it used for the LCD component?
29.18. If you now look carefully at the components in your system, you will
notice the PDC8544 component is not fully following the guidelines
above. Discuss what could be the reasons that it is violating one or
more of above guidelines, and what you would change. Document your
ndings in your workbook/memo.
29.19. Use now this component to draw a single dot into each corner of the
display. Additionally draw a (horizontal or vertical) line across your
display. Implement this in a way that it is independent of the dis-
play size/orientation. Include your function/source doing this into the
report.
c Erich Styger 337
INTRO V1.70
29.20. What is key if you want to implement the above functionality without
depending on the display size?
29.21. Inspect the code in GDisp1 SetPixel(). You will see that there are
macros used to manipulate the display buer in the microcontroller
RAM. Make sure you understand what the macros are doing. Now
rotate the display in the GDisplay component properties by 90 degree.
What happens in the generated code and macros?
29.22. Download the new code (display rotated by 90 degree). Is the result
matching your expectation?
29.23. What happens if you mix in your application both the e.g. Write-
String() (from the PDC8544 component) and the new graphic prim-
itives (e.g. SetPixel()) from the GDisplay component?
29.17 Report
In your report, include the following
What did you learn? What was the most useful thing?
What is still not clear to me? What should be explained better?
An estimation of time you had to spend on the LSC.
Include the listing of what you have implemented to write to the display.
c Erich Styger 338
Part V
Appendix
339
Glossary
callee
The callee is the function which is called by another function (the
callee is called by the callee). 113
caller
The caller is the function which calls another one (the caller calls the
callee). 113
FLASH
FLASH memory is re-programmable ROM. Typically FLASH is used
to store read-only constants and the program code to be executed. 4,
333
Infotronik
Infotronik is the name of an engineering domain which is overlapped by
electrical engineering and software engineering. To the larger extend
it describes a domain where software and computer science is used to
interface and interact with hardware and electronics. xiii, 333
341
INTRO V1.70
c Erich Styger 342
Acronyms
A/D Analog/Digital 30, 210, 347
ANSI American National Standards Institute 170,
211, 212
API Application Programming Interface 8
ATM Automated Teller Machine 58, 352
CDT C Development Toolkit 106
COP Computer Operating Properly 27, 207, 277
CPU Central Processing Unit 4, 75, 84, 298
EEPROM Electrically Erasable PROM 50
ESD Electrostatic Discharge 3
FLASH Read-only memory 4
GUI Graphical User Interface 133
HMI Human Machine Interface 57
HSLU Lucerne University of Applied Sciences and
Arts 3, 203
I
2
C Inter-Inter Circuit 4
I/O Input and Output 4, 205, 206
IDE Integrated Development Environment 3, 40,
44
INTRO Infotronik xiii, 14
ISR Interrupt Service Routine 76, 78, 79, 89, 173,
353
LCD Liquid Cristal Display 132, 134
LED Light Emitting Diode 149, 298
343
INTRO V1.70
LSC Laboratory Short Course 203, 248
MCU Microcontroller Unit 75
OOP Object Oriented Programming 3, 23, 109, 119,
136
PCB Printed Circuit Board 149
POGIL Process Oriented Guided Inquiry Learning 203
PROM Programmable Read Only Memory 50, 333
PWM Pulse Width Modulation 30, 52, 133, 347
RAM Random Access Memory 4, 206208, 217, 355
RC Resistor-Capacitor 247
ROM Read Only Memory 206, 207, 217, 331, 355
RTOS Realtime Operating System 12, 59, 65, 254
SCI Serial Communication Interface 10, 29, 51, 52,
83, 346
SD Secure Digital 77, 100
SPI Serial Peripheral Interface 4
SPST Single-Pole, Single-Throw 222
SRB Sensor Reference Board 50, 51
USB Universal Serial Bus 29, 83, 346
VCS Version Control System 8, 13, 40, 41
VP Vice President 47
WDT Watch Dog Timer 27
c Erich Styger 344
Symbols
Symbol for element of. 56
N Set of positive non-zero natural numbers (1,
2, 3, 4, ...). 56
345
INTRO V1.70
c Erich Styger 346
Index
.cpp, 134, 159
.cxx, 134
.hh, 134
#dene, 138
#pragma, 145, 171, 368
cplusplus, 136, 159
A/D, 31, 361
accelerometer, 117
array, 32, 362
bit
carry, 121
bits, 128
bool, 134, 165
boot loader, 30, 360
bouncing, 124
bus clock, 30, 360
C, 194, 229
C++, 23, 133
calibrate, 30, 360
catch, 135
class, 134, 143145, 166
clock, 30, 361
code
binary, 119
cyclic, 119
Gray, 118
CodeWarrior, 237
COM, 17
comment, 31, 361
compiler, 231
const, 18, 138, 163
constructor, 150, 162, 163
conversions, 150
critical sections, 87
CSMA, 23
delete, 134, 140, 155
destructor, 150
direction, 124
DOT, 32, 362
doxygen, 16, 17, 32, 220, 224, 362,
369
eclox, 220
edge
falling, 125
raising, 125
encoder, 117
absolute, 122
angle, 121
Gray absolute angle, 121
regular, 122
energy, 30, 361
low, 30, 31, 361
enum, 137
error, 126, 127
correction, 128, 130
extern, 139
extern C, 159
extern C, 142
FreeRTOS, 24
frequency, 125
friend, 135, 147, 149
Gady, 32, 362
347
INTRO V1.70
gain, 30, 360
graphviz, 220
Gray, 118
Frank, 118
gyroscope, 117
HTML, 16
I
2
C, 126
I
2
C, 30, 360
IEEE802.15.4, 23
inline, 135, 145, 164, 171, 368
input
capture, 125
int, 167
interrupt, 30, 32, 125, 126, 360, 362
LED, 16
level shifter, 30, 360
linkage, 139
low active, 31, 361
macro, 17, 31, 361
malloc, 139
Mealy, 17, 183, 186
motor, 31, 361
new, 135, 140, 154
null modem, 264
Nyquist, 126
oset, 30, 360
operator, 135, 167
, 167
++, 167
:, 164
::, 145
delete, 154, 155
new, 153155
overloading, 137
performance, 131
permutation, 119
pin
input, 126
position, 124
power
low, 31, 361
predictability, 126
prescaler, 30, 360
priority ceiling, 24
private, 135, 144, 147149, 161
Processor Expert, 16, 18, 30, 31, 360,
361
protected, 135, 147149, 162
public, 135, 144, 147, 148
PWM, 31, 361
Real Time, 15
realtime, 32, 33, 363
reliability, 126
return, 136
RS-232, 17, 30, 360
RTOS, 24
sampling, 126, 131
Schmitt Trigger, 248
SCI, 17
scope, 138, 232, 241, 369
semaphore, 25
sensor
hall eect, 124
magnetic, 124
optical, 117, 124
Shannon, 126
shell, 30, 31, 360, 361
signal
digital, 117
lost, 130
quadrature, 124
sizeof, 17, 137
speed, 124
startup, 158, 168
State Machine, 17
c Erich Styger 348
INTRO V1.70
static, 146
strcat, 17
strcmp, 17
strncmp, 17
struct, 143, 144, 166
synchronization, 32, 362
system
interactive, 15, 58, 60
reactive, 15, 58, 59, 61, 365
transforming, 15, 58, 61, 365
table, 126
template, 135
testing, 126
this, 135, 144, 162
throw, 135
trace, 31, 361, 362
union, 144
using, 141
virtual, 134, 135, 145
void, 136
volatile, 18, 234
WDT, 31, 361
ZigBee, 23
c Erich Styger 349
INTRO V1.70
c Erich Styger 350
Bibliography
[1] Aristotle.
Nicomachean ethics.
http://www.perseus.tufts.edu, January 2011.
WikiQuote on Aristotle, (II.1103a33) Oxford Dictionary of Scientic
Quotations (2005), 21:9., http://classics.mit.edu/Aristotle/
nicomachaen.2.ii.html.
[2] Digikey.
Digikey rs-232 tester image.
http://parts.digikey.com, January 2011.
28-Jan-2011.
[3] Margaret A. Ellis and Bjarne Stroustrup.
The annotated C++ reference manual.
Addison-Wesley Longman Publishing Co., Inc., Boston, MA, USA, 1990.
[4] Jack Ganssle.
The Firmware Handbook.
Newnes, 2004.
ISBN 9780750676069.
[5] Jack Ganssle.
Great watchdogs.
www.ganssle.com, January 2004.
http://www.ganssle.com/watchdogs.pdf.
[6] Jack Ganssle.
A guide to debouncing.
www.ganssle.com, 2007.
http://www.ganssle.com/debouncing.pdf.
[7] Jack Ganssle and Jack Ganssle.
Embedded Systems: World Class Designs.
Newnes, Newton, MA, USA, 2007.
[8] Donald Gilies.
351
INTRO V1.70
Canonical denition of realtime.
http://www.faqs.org/faqs/realtime-computing/faq, July 1998.
[18-Jan-2011].
[9] David M. Hanson.
Instructors Guide to Process-Oriented Guided-Inquiry Learning.
Stony Brook University - SUNY, Pacic Crest, www.pcrest.com, 2006.
ISBN: 1878437739.
[10] Claude Shannon Harry Nyquist.
Nyquistshannon sampling theorem.
Wikipedia:Nyquist Shannon Sampling Theorem, Dec 2013.
[11] Andrew Koenig.
C traps and pitfalls*, 1988.
[12] Clif Kussmaul.
Process-oriented guided inquiry learning (pogil) in computer science:
tutorial presentation.
J. Comput. Small Coll., 26:8384, January 2011.
[13] Jean J. Labrosse.
Embedded Systems Building Blocks.
www.cmpbooks.com, 2000.
ISBN 0879306041.
[14] Jack G. Lipovski.
Single and Multiple Chip Microcomputer Interfacing.
Prentice Hall, 1999.
[15] P. J. Plauger.
The draft standard C++ library.
Prentice-Hall, Inc., Upper Saddle River, NJ, USA, 1995.
[16] Charles H. Roth.
Fundamentals of Logic Design.
Thomson Learning, 5th edition, 2001.
[17] Freescale Semiconductor.
MC1321x Evaluation Kit (EVK) Reference Manual, Sept 2006.
Rev.1.1., MC1321xEVKRM.
[18] Freescale Semiconductor.
DEMOQE128 User Manual, DEMOQE128UM, Rev. 1.03, P&E Micro-
computer Systems, May 2007.
DEMOQE128UM.
[19] Freescale Semiconductor.
c Erich Styger 352
INTRO V1.70
MC1320x RF Daughter Card Users Guide, June 2007.
MC1320xRFCUG.
[20] Freescale Semiconductor.
MC9S08QE128 Reference Manual - HCS08 Microcontrollers, Rev. 2,
June 2007.
MC9S08QE128RM.
[21] Freescale Semiconductor.
MCF51QE128RM Reference Manual - HCS08 Microcontrollers, Rev. 2,
June 2007.
MCF51QE128RM.
[22] Freescale Semiconductor.
Freescale university program pogil material.
http://compass.freescale.net/info/172945067, January 2009.
18-Jan-2009.
[23] Freescale Semiconductor.
MC13211/212/213 Microcontroller Reference Manual, May 2010.
Rev. 1.6, MC1321xRM.
[24] Freescale Semiconductor.
MCF52259 ColdFire Integrated Microcontroller Reference Manual, May
2010.
Rev. 3.
[25] Philips Semiconductors.
Pdc8544 48x45 pixels matrix lcd controller/driver.
PCD8544.pdf, April 1999.
[26] Bjarne Stroustrup.
The design and evolution of C++.
ACM Press/Addison-Wesley Publishing Co., New York, NY, USA, 1994.
[27] Bjarne Stroustrup.
The C++ Programming Language.
Addison-Wesley Longman Publishing Co., Inc., Boston, MA, USA, 3rd
edition, 2000.
[28] www.eetimes.com.
Eetimes embedded markets study.
www.eetimes.com, April 2011.
c Erich Styger 353
INTRO V1.70
c Erich Styger 354
Afterword
Tell me and Ill forget; show
me and I may remember; in-
volve me and Ill understand.
Chinese proverbs quote
1
1
www.thinkexist.com, 7-Feb-2011
355
INTRO V1.70
c Erich Styger 356
Part VI
Problems
357
Problems
Here are all the problems are listed together.
1.1 What are the decimal values for following hexadecimal numbers: 0x04,
0x07, 0x12, 0x?
1.2 What is the decimal value for following binary numbers: 0b0001,
0b0010, 0b1000, 0b1011?
1.3 Write following decimal numbers as 16bit hexadecimal numbers: 10,
11, 16, 28, 4096?
1.4 Determine the value of register A for following code sequence: asm
LDAA #5; asm STAA i; asm INCA; asm MULA i;
1.5 Write in C a function for the HCS08 microcontroller which takes two
16bit signed arguments and returns the sum of the two arguments.
1.6 Write in C code a single statement which only sets bit number 0 in
PORTA and let the other bits untouched (bit number 0 is the least
signicant bit).
1.7 Write in C code a single statement which only clears bit number 3 in
PORTA and let the other bits untouched (bit number 0 is the least
signicant bit).
1.8 Write in C code a single statement which changes bit number 5 in
PORTA and let the other bits untouched (bit number 0 is the least
signicant bit), in following way: if the bit is already set, it shall be
cleared; if the bit is already cleared, then it should be set.
1.9 Given a variable named i of type uint16 t (unsigned integral type,
16bit). What is the value of the variable i after execution of following
statements: i = 10; i /= 4;?
359
INTRO V1.70
1.10 Given a variable named j of type uint8 t (unsigned integral type, 8bit).
What is the value of the variable j after execution of following state-
ments: j = 21; j %= 4;?
1.11 Given an array named A of base type uint8 t (unsigned integral type,
8bit). The array is initialized as follows: uint8 t A[2][3] = {1,2,3,4,5,6};
Which value will A[1][1] return?
1.12 Given X as 0x00EFC000. What is Y in hex for: Y = ((X >>16) &
0xFF) - 5;
3.1 Can you explain what is a shell and what is its purpose?
3.2 Why do we need a level shifter?
3.3 Using the shell interface, which methods can be used to print help and
status information?
3.4 What are the important settings you have to congure in the Processor
Expert component for the SCI?
3.5 Can you list some good reasons why RS-232 might be a better solution
than USB? What would be the advantage of USB?
3.6 Why is it necessary to calibrate an acceleration MEMS sensor?
3.7 What kind of impact the oset has for an acceleration sensor?
3.8 What kind of impact the gain has for an acceleration sensor?
3.9 What is the dierence between ACCEL1 MeasureGetRaw() and AC-
CEL1 GetXmg()?
3.10 What is the advantage of the boot loader used with the LCD applica-
tion?
3.11 How can you program a new application with the LCD boot loader?
3.12 What is the purpose of the 0x27FF pattern at the begin and a 0x00
pattern at the end of every I
2
C message we send?
3.13 What is a prescaler and what does it?
3.14 What is the dierence between a CPU and a bus clock?
3.15 Using the MPC52259, what are the things you have to consider using
the interrupts?
c Erich Styger 360
INTRO V1.70
3.16 Can you list dierent clock sources you can use?
3.17 Can you list at least three possibilities to reduce the energy consump-
tion in your design using hardware?
3.18 Can you list at least three possibilities to reduce the energy consump-
tion in your design using software?
3.19 What is the purpose of the IdleHook() called from the IdleTask in the
context of low power and low energy?
3.20 Can you explain why we used a PWM period of 2 ms for the motor?
3.21 The PWM signal for the motor was low active. Can you explain what
this means? At which voltage level the motor has the highest speed?
3.22 With using a direction signal and a PWM signal for a motor, what do
you have to care about if you are using -100% to +100% motor speed
approach?
3.23 Based on data sheets, can you nd the number of bits the A/D converter
of the MC13213 and MPC52259 supports?
3.24 Do you know what the abbreviation WDT stands for, and what this is
useful for?
3.25 Based on the schematics from the lab, could you describe what bit 4
on port E is used for on the MC13213?
3.26 Could you list some pros and cons of using macros?
3.27 What is the dierence in respect tho the LEDs used on the SRB and
Tower board we used?
3.28 Can you describe a very easy way to comment out a block of source
lines and C comments?
3.29 Can you list some pros and cons using Processor Expert?
3.30 Can you describe dierent strategies to store the motor speed percent-
age?
3.31 Describe how you can make the motor turning forward or backward.
3.32 In the lab we are using a task for sending trace information. This
task needs to have a priority assigned. Explain your reasoning behind
setting the priority for this task in comparison to the shell task.
c Erich Styger 361
INTRO V1.70
3.33 Describe how you can produce trace from another module, say you
want to trace the status of the LEDs.
3.34 Inspect the trace task and determine the trace buer size. What is
special about the storage of the trace buer? Could you suggest a
dierent implementation?
3.35 Can you list a reason why in a switch statement you should have as
well a default case?
3.36 Can you use a multidimensional array with dierent base types?
3.37 For what is DOT used in doxygen?
3.38 How can you limit the DOT graphs in doxygen?
3.39 How can you congure doxygen to produce call graphs?
3.40 Explain the main reason why you need synchronization.
3.41 Explain a problem of Gady synchronization.
3.42 You can choose between active waiting and interrupt synchronization.
Explain a reason why you still would use active waiting.
3.43 Explain why the realtime synchronization might be platform depen-
dant, and why not.
3.44 Why do you need pullup or pulldown resistors?
3.45 Are there dierent options to implement pullups or pulldowns?
3.46 For the HCS08, which to Embedded Components do you have available
if you just want to get the key value (low or high)?
3.47 On the HCS08, how many inputs can be connected to the KBI periph-
eral, and how many interrupts does it oer?
3.48 How do you document a function with doxygen?
3.49 List a few languages supported by doxygen?
3.50 How does doxygen integrate with eclipse?
3.51 List a few platforms on which doxygen is supported.
3.52 What is a transforming system?
c Erich Styger 362
INTRO V1.70
3.53 How is realtime dened?
3.54 Can you comment on a realtime system which delivers the correct result
too early?
3.55 What does it mean in a realtime system that things have to be delivered
independent of the current system load?
3.56 Which one do you consider to test easier: a hard realtime system or a
soft one?
3.57 What are the advantages of a version control system?
3.58 Could you think of a risk or danger using a version control tool?
3.59 If you delete a le and commit that change, will that le be deleted in
the version control system too?
3.60 In Eclipse, which views and perspectives do you have available?
3.61 From the following list of les and folders of a CodeWarrior project,
which ones are you going to put under version control: Documentation,
doxy/SRB.doxyfile, Generated Code, Project Headers, .project,
.rseHostSettingsCache.xml, .ProcessorExpert.g c?
3.62 What is the purpose of the Event.c module, and why do we need it?
3.63 What is the advantage to use an array for the events?
3.64 If a subroutine is called from an interrupt routine and from the main
program, what needs to be considered?
3.65 How can you protect a critical section?
3.66 What are you protecting in a critical section?
3.67 Where are the addresses stored of your interrupt service routines in
your application?
3.68 What is the goal of debouncing? What kind of problem has to be
solved? Describe the problem and provide a short description of the
solution.
3.69 Can you describe an approach in software to perform debouncing?
3.70 You are performing debouncing with a signal which is attached to an
interrupt pin. Is there something you need to consider?
c Erich Styger 363
INTRO V1.70
3.71 You are implementing as state machine. How can you implement it in
such a way, that it is using application provided function calls which
are only known at runtime?
3.72 You are using a state machine for your debouncing, which is called from
an interrupt service routine. How can you break-out of this interrupt
routine and continue iterating through the state machine if not in the
interrupt itself?
3.73 After a task has been created with FreeRTOS, in which state is the
task?
3.74 What are the states a FreeRTOS task can have?
3.75 What can cause a task switch in an preemptive FreeRTOS?
3.76 Can you list pros and cons of using your own idle task instead of using
the IDLE task provided by the RTOS?
3.77 Can you explain what happens if you use taskYIELD()?
3.78 What is the big advantage of using the memory scheme 3 in FreeRTOS?
3.79 What happens, if you set the parameter xTicksToWait to 0 when you
add an item to a queue?
3.80 Are queue items in FreeRTOS added by reference or by value?
3.81 What do you have to consider if you are using FreeRTOS queues from
and ISR?
3.82 What is the dierence between xQueueReceive() and xQueuePeek()?
3.83 What is a quadrature encoder?
3.84 What is the functional principle of an absolute digital angle encoder?
What could be a problem with this approach?
3.85 Can you list advantages of an optical encoder compared to a mechanical
one?
3.86 In the communication with the Tower and the LCD over I
2
C a prex
/ sux is used. Why?
3.87 How is a touch on the LCD recognized?
c Erich Styger 364
INTRO V1.70
3.88 Can you explain what is the problem of debugging the LCD applica-
tion?
3.89 In the C++ LCD application there is a Paint() method implemented.
What is the purpose of it?
3.90 Through what kind of communication channel data is sent from the
Tower to the LCD?
3.91 What are disadvantages of the Driver Low Level protection?
3.92 How does the ? operator works? Make an example.
3.93 What does sizeof("abc") return?
3.94 What does strlen("abc") return?
3.95 What can the function atoi() be used for?
3.96 What is the function of the three dierent clocks (System/CPU/Bus)?
3.97 What is the use of an external clock?
3.98 How can you specify interrupt priorities?
3.99 What is the function of a trigger?
3.100 Why should you use for example the type uint8 t instead of char or
int?
8.1 List several systems which can be considered as transforming systems.
8.2 List several systems which can be considered as reactive systems.
8.3 List several systems which can be considered as interactive systems.
8.4 Provide examples of reactive systems. How are they dierent from
transforming systems?
8.5 Describe a transforming system with one input stream and two output
streams.
8.6 Describe an embedded system without any user interface.
8.7 Describe in your own words what characterizes an embedded system.
c Erich Styger 365
INTRO V1.70
8.8 Most systems are a combination of transforming, reactive and inter-
active systems. Identify for a mobile phone the dierent classes or
subparts of the system.
8.9 Give an explanation why processing quality is important for transform-
ing systems.
8.10 Why are transforming systems optimized for optimal system utiliza-
tion?
8.11 Interactive systems usually require a fast response time: Could you give
typical response times for typical interactive systems? Is this response
time the same for all interactive systems you could think about?
8.12 How would you explain processing quality in the context of an audio
encoder?
8.13 Classify following system (reactive, interactive, transformative): digi-
tal watch, airbag, radar speed measurement, re alarm system, ATM,
airplane fuel gauge.
8.14 List some systems which do not have any microprocessor or computer.
9.1 If there is the term real time, there must be as well a unreal time?
9.2 Modern processors have many cores (multi core) which can do things
in parallel. Does this solve the problem for realtime compliance?
9.3 If you have to verify if a realtime system is correct, which realtime
system would be probably easier to verify: a soft realtime system or a
hard realtime system?
9.4 Would you classify a VoIP (Voice Over IP) system more as a hard
realtime system or as a soft realtime system?
9.5 Is a online stock trading system a hard realtime system or a soft real-
time system?
9.6 Specify typical response windows for: keyboard, window lift in a car,
touchscreen.
9.7 Is Microsoft Windows 7 a realtime operating system?
10.1 Assume that a device does not return any error code. Draw a state
diagram similar to the one in Figure 10.3. How many states will that
digram have?
c Erich Styger 366
INTRO V1.70
10.2 Look at your favorite microcontroller which assumable has an A/D
converter. Identify the states presented in Fig. 10.3.
10.3 Explain why modern high level language compilers can make realtime
synchronization fail.
10.4 You might have noticed that the sprocket hole in Figure 10.2 is smaller
compared to the data holes. What is the reason for this?
10.5 What is the dierence between handshaking and synchronization?
10.6 Consider a system with no real stack and no hardware stack pointer.
What are the consequences of this?
10.7 What is the reason that for interrupts the ISR might need to save/re-
store additional registers?
10.8 Why is usually a special return from interrupt instruction needed at
the end of the ISR?
10.9 Think about the example of a class room environment. For example,
the teacher wants to know if somebody has a question. How would a
polling method work in that environment? How would an interrupt
method work?
10.10 Explain why for the HCS08 the instructions to enable (CLI) and disable
(SEI) are single instructions?
12.1 How can you congure your compiler to ag missing declarations?
12.2 List a system/programming language which compiles on the y.
12.3 Name programming languages which are interpreted.
12.4 Give an examples which is implementation dened in ANSI-C.
12.5 What is the compiler option for the HCS08 compiler to ag missing
declarations as errors?
12.6 How can you instruct your compiler to produce a preprocessor listing?
12.7 Try out a piece of code with implicit string concatenation using the
HCS08 compiler. What happens?
13.1 What is the fundamental problem of an absolute wheel position en-
coder?
c Erich Styger 367
INTRO V1.70
13.2 What would be the advantage of using an input capture or interrupt
for the quadrature signal? What would be the disadvantage and why?
13.3 Why it could be a good idea to connect C1 and C2 signals to a bit 0
and bit 1 of a port??
13.4 Try the encoders with the error correction enabled. When will you get
errors in your decoding/counting algorithm??
13.5 Compare the decoder with error correction and the one without. At
which speed the one without error correction will start producing er-
rors? At which speed the one with error correction starts producing
errors? ?
13.6 Why do we need to sample the signal with at least twice of the signal
frequency? ?
14.1 What is the number of actual parameters for void foo() in C? How
many parameters if this function is compiled as C++?
14.2 If you have a struct in C++, are its members public or private by
default? What about class members?
14.3 What is an abstract class?
14.4 You have a function in a C++ module, and you want to call it from a
C module, how can you do this?
14.5 You can implement the body of a function inside the class. When would
you not use this?
14.6 Why is the usage of a #pragma a better way for a C compiler compared
to introduce an additional (non-ANSI) keyword like inline?
14.7 Does your Freescale HCS08 compiler support C++?
14.8 Can you describe dierent ways how you can enable C++ compilation
for a single le under CW for MCU10 (HCS08, ColdFire)?
15.1 Using a resistor inline with an LED is simple. What could be a disad-
vantage of this approach?
15.2 Determine the resistor for an LED: the supply voltage is 5V, and the
desired current through the LED is 20 mA. The desired voltage drop
over the LED is 2V.
c Erich Styger 368
INTRO V1.70
15.3 Determine the LED current for one of the LEDs (LED1 to LED4) on
the INTRO SRB board.
15.4 Think about a solution how you can use LEDs with your microcon-
troller even if the current needed exceeds your controller pin current
budget.
15.5 List strategies and ways how you can limit the energy used for a low
energy product.
15.6 Look at your HCS08 compiler documentation: how can you aect the
size of an enumeration type?
19.1 Can you explain the concept of doxygen in a few sentences?
19.2 Can you explain the dierences between installing eclox from an up-
dater site or from an archive in a few sentences?
19.3 What is the role of the error parser which is the part of eclox?
19.4 Can you describe in a few words what are dependency graphs in doxy-
gen, and what you can do with them?
21.1 Find the memory map of your microcontroller and list the address
ranges of RAM and ROM
21.2 What data types does your compiler support and how many bits of
storage are required for each?
21.3 What does scope of a variable mean?
21.4 A variable is dened inside a function and the compiler does not al-
locate a specic memory location in RAM for its storage. a) Is this
an automatic or static variable? b) Where is it stored? c) What is
its scope? d) Is data stored in this variable during one function call
available to the function in the next call?
21.5 A static variable is dened inside a function. a) What is its scope?
b) Where is storage space allocated for it? c) Is data stored in this
variable during one function call available to the function in the next
call?
21.6 A variable is dened outside a function. a) Is this a static or automatic
variable? b) If another separately compiled function wishes to use this
variable, what must be done in this function to do this?
c Erich Styger 369
INTRO V1.70
21.7 In listing 21.1, where is storage allocated for the variable char i2 nal?
21.8 In listing 21.1, in what part of the code is i2 nal initialized with 0x22?
21.9 In listing 21.1, where is storage allocated for the variable char i1?
21.10 In listing 21.1, is i1 initialized with any value by the Startup() code?
21.11 In listing 21.1, where is storage allocated for the variable char i2?
21.12 In listing 21.1, is i2 initialized with any value by the Startup() code?
21.13 In listing 21.1, where is storage allocated for the variable char i3?
21.14 In listing 21.1, is i3 initialized with any value by the Startup() code?
If not, when is it initialized?
21.15 In listing 21.1, where is storage allocated for the variable char i4?
21.16 In listing 21.1, is i4 initialized with any value by the Startup() code?
21.17 In listing 21.1, what do you predict the nal value of i2 to be? Is it?
21.18 With minimal startup code for the S08, you should get an error or
warnings when you make the project? What does it mean?
21.19 What changes must you make to your program to compensate for the
problem?
21.20 For your HCS08 compiler, is char a signed or unsigned type?
21.21 If you are familiar with assembly language programming you may know
that comparing signed and unsigned numbers requires dierent assem-
bly language conditional branches. What changes would you expect
to see in the assembly code for the program if you changed all char
variables to signed char?
21.22 Describe the dierences in the generated code, based on your changes
for the variables i and j in table 21.1. What can you observe?
21.23 Does your compiler produce bit addressing instructions such as BSET
and BCLR? Comment on your ndings.
21.24 What does the following line of code accomplish? extern volatile
PTFDSTR PTFD @0x00000040;
c Erich Styger 370
INTRO V1.70
21.25 Explain how the structure PTFDSTR works to allow you to access
PTFD as a byte or as individual bits in the port.
21.26 What makes an interrupt handler or service routine dierent than an
ordinary function?
21.27 Does your compiler allow you to insert assembly language instructions
in-line with your C code? If so, how do you do this?
21.28 How does your C program transfer arguments to and from the assembly
language program?
22.1 What hardware circuits are used to debounce switches based on the in-
formation in Ganssles Guide to Debouncing[6]? What kind of switches
can be used with these circuits?
22.2 What other debouncing information can you nd in Ganssles Guide
to Debouncing[6]?
22.3 What will you have to nd out before you can use the delay method
for debouncing?
22.4 What are the limitations and what can go wrong with debouncing?
22.5 How long must the switch stay in its current state without bouncing?
22.6 What is the value of Count at the end of the WHILE DO loop if the
switch is closed?
22.7 What is the value of Count at the end of the WHILE DO loop if the
switch is open?
22.8 What disadvantages or problems do you see in using this code?
23.1 What problems can arise due to the lack of feedback in the input polling
shown in Figure 23.1?
23.2 What problems can arise in the output polling shown in Figure 23.2?
23.3 What input devices may be slower than the microcontroller?
23.4 When might you nd a situation where the input device can supply
data faster than the microcontroller and read it?
23.5 What output devices may be slower than the microcontroller?
c Erich Styger 371
INTRO V1.70
23.6 Draw a timing diagram for the case where input data transfer when
the microcontroller is faster than the external device.
23.7 Input data transfer when the microcontroller is slower than the external
device.
23.8 Output data transfer when the microcontroller is slower than the ex-
ternal device.
24.1 What part would you chose to include in an embedded system design
to convert from the CMOS logic levels of the SCI to RS-232-C and
provides at least two input and two output signals?
24.2 Write a programming algorithm (a design) for a DCE device that allows
it to transmit data only when another device is ready for it.
24.3 Write a programming algorithm (a design) for a DTE device that allows
it to transmit data only when another device is ready for it.
24.4 Write a programming algorithm (a design) for a DTE device that allows
it to signal another device it is ready to receive data.
24.5 Write a programming algorithm (a design) for a DTE device that allows
it to transmit data only when another device is ready for it.
24.6 Draw a gure similar to Figure 24.6 that shows a cable needed to con-
nect a DCE device to a DTE device. The DTE device has implemented
ow control but the DCE device has not. The DTE device must be
allowed to send data whenever it is ready.
24.7 Complete Figure 24.7 so it shows a cable needed to connect two DTE
devices, each of them implementing a ow control algorithm.
24.8 Your company has designed a product with an asynchronous serial I/O
port using an SCI. It uses a DE-9 connector and is labeled as COM1
on the board. It sends its data out on pin 3 and receives it on pin 2.
Flow control handshaking has not been implemented. It is programmed
to send and receive data at 9600 baud, eight data bits, no parity, and
one stop bit. Write a technical description of this port for inclusion
in the users technical reference manual describing how to use the port
and how to connect it to other serial devices.
25.1 Can you give three examples of I/O devices for which interrupts could
be used to synchronize the microcontroller with the I/O?
c Erich Styger 372
INTRO V1.70
25.2 Assume you are designing microcontroller systems to be used in an
automotive application. Give three examples of important events that
would lend themselves to being implemented in a microcontroller using
an interrupt system.
25.3 Where in your documentation do you nd the vector locations (or vec-
tor addresses) for interrupts?
25.4 How does your microcontroller allow for asynchronous events to occur
and be recognized?
25.5 How does your microcontroller branch to the correct interrupt service
routine?
25.6 How does your microcontroller return to the interrupted program at
the point it was interrupted?
25.7 How does your microcontroller allow the programmer to globally enable
and disable all interrupts?
25.8 How does your microcontroller allow the programmer to enable and
disable selected interrupts?
25.9 How does your microcontroller disable further interrupts so the rst
can be serviced without being interrupted?
25.10 How does your microcontroller deal with multiple sources of interrupts?
25.11 How does your microcontroller deal with multiple, simultaneous inter-
rupts?
25.12 What can cause a pending interrupt?
25.13 How do you reset a ag that caused an interrupt?
25.14 What happens if you do not reset the ag in the interrupt service
routine?
25.15 There is always a delay between the interrupt request and when the
CPU starts to execute the interrupt service routine. This is called the
interrupt latency. Give three components that cause interrupt latency.
25.16 How does the CPU determine the address to return to after the ISR
has completed?
c Erich Styger 373
INTRO V1.70
25.17 Does your microcontroller push all registers onto the stack when enter-
ing an interrupt service routine?
25.18 Give an advantage and a disadvantage of automatically pushing regis-
ters onto the stack?
25.19 How does your software development system initialize the interrupt
vector you are going to use?
25.20 Does your compiler support interrupt service routines? If so, how do
you signify to the compiler that a function should be treated as an
interrupt handler or service routine?
25.21 Which instruction in your microcontroller is used for unmasking inter-
rupts?
25.22 Which instruction in your microcontroller is used for masking inter-
rupts?
25.23 Which instruction in your microcontroller returning from an interrupt
service routine?
25.24 How do you write C instructions to unmask or mask interrupts?
25.25 What makes an interrupt handler or service routine dierent than an
ordinary function?
26.1 Assume you are designing a microcontroller system to control a mobile
robot for a competition to see whose robot can navigate through a maze
the fastest. The robot can be driven by stepper or DC motors and has
various sensors to detect the walls of the maze. Can you give three
examples of sensors that could interrupt the microcontroller to control
the robot?
26.2 Which program statement or assembly instruction in your microcon-
troller is used for unmasking interrupts?
26.3 Which program statement or assembly instruction in your microcon-
troller is used for masking interrupts?
26.4 Which program statement or assembly instruction in your microcon-
troller is used for returning from an interrupt service routine?
26.5 How does your microcontroller allow for asynchronous events to occur
and be recognized?
c Erich Styger 374
INTRO V1.70
26.6 How does your microcontroller branch to the correct interrupt service
routine?
26.7 How does your microcontroller return to the interrupted program at
the point it was interrupted?
26.8 How does your microcontroller allow the programmer to globally enable
and disable all interrupts?
26.9 How does your microcontroller allow the programmer to enable and
disable selected interrupts?
26.10 How does your microcontroller disable further interrupts so the rst
can be serviced without being interrupted?
26.11 How does your microcontroller deal with multiple sources of interrupts?
26.12 How does your microcontroller deal with multiple, simultaneous inter-
rupts?
26.13 What can cause a pending interrupt?
26.14 How do you reset a ag that caused an interrupt?
26.15 What happens if you do not reset the ag in the interrupt service
routine?
26.16 What must you do in the ISR#1 to allow ISR #2 to execute as soon
as the current instruction that IRQ2 interrupts?
26.17 What must you do in the ISR#1 to allow ISR #2 to execute when ISR
#1 nishes?
26.18 What must you do in the ISR#1 to completely stop ISR #2 from
executing at all until another IRQ2 occurs?
26.19 How are the various interrupting sources prioritized in your microcon-
troller?
26.20 Are the priorities xed in hardware or do you have some control over
them?
26.21 Does your microcontroller have an interrupt line that may require soft-
ware prioritization if multiple devices are connected as shown in Figure
26.2?
c Erich Styger 375
INTRO V1.70
26.22 For the simultaneous interrupts shown in Figure 26.1, what must you
do to ensure ISR #2 has the higher priority and executes before ISR
#1?
26.23 Assume you have a system with ve interrupting sources, IRQ0 - IRQ4.
IRQ0 is the highest priority and IRQ4 the lowest. Explain what you
must do in each of the interrupt service routines to allow higher priority
interrupts to be serviced and lower priority ones to remain pending until
the interrupt service routine is nished.
26.24 Each of the devices has an output connected to the IRQ L input of the
microcontroller (Figure 26.2), is this signal active-high or active-low?.
26.25 Each of the devices has an output connected to the IRQ L input of the
microcontroller (Figure 26.2), what kind of hardware must be used for
this signal?
26.26 In addition to the hardware needed in each device to assert IRQ L,
what hardware must be included in the design of each device?
26.27 Can you come up with a design idea how to demonstrate that problem?
Describe your approach.
29.1 There are plenty of open source and hacker projects on the web de-
scribing how to recycle a Nokia phone display which are available for
less than $10. Why those displays are so aordable compared to other
displays?
29.2 We are using in this lab the Philips PDC8544 display controller.
Identify on your display the pin numbering using the information on
http://serdisplib.sourceforge.net/ser/pcd8544.html. The web
site lists two types of displays: what are the dierences between Type
1 and Type 2?
29.3 Which type of display do you have?
29.4 The display is equipped with a 2x5 pin connector. List the signals on
the pins 1 to 10 of the connector (Hint: the numbering corresponds to
type 1 displays).
29.5 Which pins of the display are NOT required to be connected with a
microcontroller system in order to have the display working?
29.6 The display we are using requires a supply voltage (Vdd) and logic level
of 5V. Identify the Vdd and GND pin on the 2x5 connector.
c Erich Styger 376
INTRO V1.70
29.7 Browse through the pcd8544.pdf data sheet to get familiar with the
display controller. The display is using an Serial Peripheral Interface
(SPI) for communication. Who is the master, and who is the slave in
our system?
29.8 Map the SPI signals (SKLK, MOSI, MISO, SS explained in http://
en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus to the
PDC8544 display signals.
29.9 Which bit in a byte is rst transmitted in the serial protocol?
29.10 How many clock signals (SCLK) are needed to transmit a single byte
of data?
29.11 How could you attach 2 displays to your microcontroller and use them
as dual displays with minimal port pins needed? How many pins or
connectors do you need?
29.12 The display has an internal (on-display) charge pump which transforms
the supply voltage to the needed (higher) voltage required to change
the liquid crystal cells. What is the maximum supply voltage for the
Vdd pin?
29.13 The PDC8544 Nokia display can be used with dierent supply and
logic levels (e.g. 5V or 3.3V). But the logic levels are dierent for 5V
CMOS and 3.3V CMOS. How can this work?
29.14 Try out dierent contrast values, either using the component properties
and the SetContrast() method. What happens if you set high/low
contrast values?
29.15 Inspect the generated code. The component is using a variable named
table[] for writing text to the display using WriteChar(). List ad-
vantages and disadvantages of such an implementation compared to an
approach using a full graphical font.
29.16 What happens if you write Zrich City to the display? Explain what
happens and how you would solve it.
29.17 The component is using a WAIT component. What does this compo-
nent and why is it used for the LCD component?
29.18 If you now look carefully at the components in your system, you will
notice the PDC8544 component is not fully following the guidelines
c Erich Styger 377
INTRO V1.70
above. Discuss what could be the reasons that it is violating one or
more of above guidelines, and what you would change. Document your
ndings in your workbook/memo.
29.19 Use now this component to draw a single dot into each corner of the
display. Additionally draw a (horizontal or vertical) line across your
display. Implement this in a way that it is independent of the dis-
play size/orientation. Include your function/source doing this into the
report.
29.20 What is key if you want to implement the above functionality without
depending on the display size?
29.21 Inspect the code in GDisp1 SetPixel(). You will see that there are
macros used to manipulate the display buer in the microcontroller
RAM. Make sure you understand what the macros are doing. Now
rotate the display in the GDisplay component properties by 90 degree.
What happens in the generated code and macros?
29.22 Download the new code (display rotated by 90 degree). Is the result
matching your expectation?
29.23 What happens if you mix in your application both the e.g. Write-
String() (from the PDC8544 component) and the new graphic prim-
itives (e.g. SetPixel()) from the GDisplay component?
c Erich Styger 378

You might also like