You are on page 1of 72

EMBEDDED SYSTEMS DESIGN

C. A. Maynard (C) 2015!


Lecturer: Wei Wong
1

REACTIVE SYSTEMS

Embedded Systems react to changes to their inputs to


create new output values.!
New input values are obtained in two ways:!
Polling!
Interrupts

POLLING FOR INPUT


C.A.Maynard 2013-2014

POLLING FOR INPUT


Polling is one of the basic techniques for getting data
into a system.!
The simplest process is a loop of execution where
each possible source of data is checked and if there is
new data the necessary code is executed to deal with
the information.!
In an embedded system the loop continues to execute
as long as the program is running. An infinite loop.
4

A PROGRAM
FLOWCHART

THE POLLING PROCESS


If a new value is available from the input source then
execute the required process.!
Go to the next input and repeat as necessary.!
After the last input perform any general processing
required then go back and start again.!
The restart of the polling process MAY be subject to a
time constraint which has not been shown in the
flowchart.
6

A GENERIC INPUT
Initialise a port/subsystem so that it is ready to
return input values.!
Check if a new value is available and process that
value as required.!
What variable type should be used for an input?!
Unless there are specific characteristics associated
with the data an unsigned variable of the required
number of bits is the best choice.
7

SEPARATION OF
CONCERNS
A Software Engineering philosophy.!
Separate initialisation from use!
Separate information about the existence of a new value from
the value itself.!
Historically in C this was not done and the major C software
libraries reflect that original philosophy.!
Separate the user from details of the interface requirements.!
For the next lab you need to understand the TimeTest.h
file so that you can use the functions but you do not (in
principle) need to understand the details of the functional
implementations provided.

A SWITCH INPUT
Generally two functions required:
// Initialise the interface
void switchesInit(void)
!

// Get the value


// Return true (and the value) if a new value has
been found and false if there is no new value
enum bool switchesGet(uc_8 *value)
enum bool provides an explicit boolean variable
not provided in the definition of C.
What does standard C use for this
requirement?
9

REVISION OF C

uc_8 *value
is a pointer to an 8 bit unsigned character variable.
A pointer variable holds the address of a variable of
the specified type.

10

A LED DISPLAY OUTPUT


Generally two functions required:
// Initialise the interface
void LEDsInit(void)
!

// Output a new value to the interface


enum bool LEDsPut(uc_8 value)
// The more general solution returns a
success or failure flag to the main
program.
11

A SEVEN SEGMENT
DISPLAY OUTPUT
Generally two functions required:
// Initialise the interface
void sevenSegInit(void)
!

// Output a new value to the interface


enum bool sevenSegPut(uc_8 segID, uc_8 value)
// The more general solution returns a success or
failure flag to the main program.

12

MORE PHILOSOPHY
Use an Object-Operation sequence
in your naming convention.!
This has advantages in
development environments which
actively provide the available
functions as you type.
13

VARIABLE NAMING

Generally a global to specific naming sequence is


considered the best.!

Example:!
! Variable and function names are defined with the first
words being descriptive of broad ideas, and later words
narrowing down to specifics. For instance:
Universe_Galaxy_System_Planet.

14

THE CONVENTION:

Timer_0_Data, Timer_0_Overflow, and


Timer_0_Capture. !

This convention quickly narrows variables to particular


segments of the program.

15

CONVENTION
CONTINUED:

Never assume that a verb must be first, as often seen


when naming functions.

Open_Serial_Port and Close_Serial_Port

These do a much poorer job of grouping variable


names than the better alternative of

Serial_Port_Open and Serial_Port_Close

16

WHERE TO FIND IT:

A Firmware Development Standard

Version 1.4, Updated May 2007

Ganssle Group publication... Free on the web

17

PRAGMATICS
As mentioned before, there is no boolean variable built into C
so we introduce an enumerated variable to support this
requirement. !
See the clic3.h header file.!
/* Ensure that flags(Boolean variables) can only be true or
false */!
enum bool {false,true};!
This is compatible with the classic C usage that zero is false
and non zero true.
18

A PROGRAM
FLOWCHART REVISITED
The diamond represents !
a decision about whether !
there is a new input or not.!
Our drivers return the !
information for that test.!
Often we do not need to!
save that information !
simply act on it.

19

INPUT 1 OPERATIONS
!

// Get the switch input and display!


if( switchesGet(&value)) {
temp = LEDsPut(value)
}

Revision:!
& is the address of operator so the
function is provided with the location of
the returned variable (A pointer).
20

INPUT 2 OPERATIONS
!

// Get the keypad input and display!


if( keypadGet(&value)) {
temp = sevenSegPut(segID, value)
}

Background information:!
There are two seven segment displays on the
clic3 board and the segID variable
identifies which one to use.
21

KEYPAD INPUT

In the previous slide we have assumed that we have


already defined:!
void keypadInit(void)!
enum bool keypadGet(uc_8 &value)

22

THE MAIN PROGRAM


void
uc_8
uc_8
enum

main (void) {
value;
segID = 0;
bool temp;!

// System initialisation goes here


Initialise();!

// Peripheral initialisation
switchesInit();
LEDsInit();
keypadInit();
sevenSegInit();

// main loop goes here


}

23

THE MAIN LOOP


// main loop
while (true) {
// Get the switch input and display
if( switchesGet(&value)) {
temp = LEDsPut(value);
}
// Get the keypad input and display
if( keypadGet(&value)) {
temp = sevenSegPut(segID,value);
segID++;
if (segID > 1) { segID = 0;}
}
// Anything else to be done
}

24

WHAT HAVE WE DONE?


We have written the main polling program without
any consideration of the details of each of the
peripherals we are using. !
We only needed to define interface functions.!
Separation of Concerns has been applied.!
For some interfaces the functions may seem too
complex for others they can hide a lot of complexity.

25

SEPARATION OF
CONCERNS
The writer of the main code makes the basic
assumption that when an interface is asked for a new
value only genuinely changed values will be returned
and flagged as true.!
In the previous code only displays are updated BUT in
general a significant amount of computation may
depend on only receiving new (updated) values.!
The writer of the library code should take this
expectation into consideration when writing the code.
26

SWITCHES
void switchesInit(void) { }!
// The switchesGet function returns true if a new
value has been found.!
// Simplest version assumes there is always a new
value.!!
enum bool switchesGet(uc_8 &value) {!
!*value = Switches;!
!return true;!
}
27

SWITCHES LEGACY
HARDWARE SUPPORT
enum bool switchesGet(uc_8 *value) {!
BusAddress = SwitchesAddr;!
BusRead();!
*value = BusData;!
return true;!
}
28

IS THE INTERFACE
VALID?
Every time that switchesGet is executed it will return
a value claimed to be new.!
In reality this is very unlikely.!
We need to change the internal functionality of
switchesGet to match the users expectation.

29

THE FIRST TIME


The first time the switchesGet function is executed it
needs to retrieve a value and return it.!
The function needs to be able to recognise that this is
the first execution.!
Normal variables in a function are created and
destroyed each time the function is called but
static variables can hold information between
invocations.
30

THE FIRST TIME


Create and initialise a static variable.!
static enum bool first = true;!
In the execution start by testing the value of first:!
if(first) { first execution code and
set............
first = false; }!
else { every other execution goes here }

31

REMEMBER THE VALUE

We need a static variable to remember the Switches


value.!
static uc_8 old_Switches;!
The first time we read the switches, we save in
old_Switches and return the value (and true).

32

REMEMBER THE VALUE

All other invocations read the Switches, compare


with old_Switches........if they are the same simply
return false.........(There is no new value to return).!
if they are different a switch has been operated
so........save the new reading in old_Switches (for the
next invocation), return the value and true.

33

LEDS
void LEDsInit(void) { }!
// LEDsPut returns true if a new value can be
stored in the interface!
// As there is no way for the system to know just
return true.!
enum bool LEDsPut(uc_8 value) {!
!Leds = value;!
!return true;!
}
34

LEDS LEGACY
HARDWARE SUPPORT
enum bool LEDsPut(uc_8 value) {!
BusAddress = LedsAddr;!
BusData = value;!
BusWrite();!
return true;!
}
35

LEDS FUNCTIONALITY
As there is no hardware readback capability for the
LEDs interface a default true return is valid.!
Should a new hardware interface with readback be
implemented for the LEDs in the future the interface
code remains valid but new internal code for the
function will need to be created.!
This is a good approach to interface function design.

36

KEYPAD STUB
// Get a new value from the keypad if there is
one otherwise return false!
// Returns true if a new value has been found!
enum bool keypadGet(uc_8 &value) {!
!*value = 3; // Random choice for a stub return!
!return true;!
}

37

STUBS

Stubs are functional skeletons used to allow


compilation of a system and execution but providing
minimal if any actual functionality.!
In this case there is no keypad code only the return of
an arbitrary value (3 in this case) as the new value.

38

SEVEN SEGMENT
DISPLAY

// Initialise the Seven Segment Display interface!


void sevenSegInit(void) { }

39

7 SEGMENT CONTD.
// Send a new value to the selected display and
return true otherwise return false if this could not
be achieved. DispID chooses the display (o or 1).
value is the selector for what is to be displayed.!
enum bool sevenSegPut(uc_8 DispID,uc_8 value) {!
!if(DispID) { Seg1 = LookupSeg[value]; }!
!else { Seg2 = LookupSeg[value]; }!
!return true; !
}
40

7 SEGMENT DISPLAY

0 1 2 3 4 5 6 7 -> Bits
To turn on a segment the pin must be pulled down to!
ground. A common anode configuration.
To show a 0 all segments must be at zero except g!
%0100 0000 or 0x40
41

7 SEGMENT CONTD.
const uc_8 LookupSeg[MaxSegs]=
{0x040, 0x079, 0x024, 0x030, 0x019, 0x012, 0x002, 0x078,
0x000, 0x018, 0x008, 0x003, 0x046, 0x021, 0x006, 0x00E,!
0x027, 0x009, 0x07B, 0x060, 0x047, 0x023, 0x00C, 0x02F,
0x041, 0x011, 0x03F, 0x07F};!
/* Beyond index 0x0F (for the hex character "F")!
the values represent the characters:
c , H , i , J , L , o , P , r , U , Y , - , blank!
With hexadecimal indices

10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1A, 1B

42

*/

7 SEGMENT CONTD.
Is the return value of true appropriate for the code?!
There is no readback of output so for a valid display
value then true is appropriate.!
What if the value is beyond the maximum value
allowed?!
An appropriate thing to do is not to update the
display and to return false.

43

EXERCISE

Modify the sevenSegPut function to limit output to


the valid range of values and to return false if an
attempt is made to display a value beyond the limit
defined in the .h file.

44

A FINITE STATE
MACHINE

http://www.eetimes.com/design/embedded/4008260/Using-finite-state-machines-to-design-software

45

SAMPLE CODE
int main(void)!
{ enum states { before, inside, after} state;!
int c;!
state = before;!
for(;;) {!
switch(state) {!
case before:!
if(c == '\n') { putchar('\n');!
} else if(c != ' ') {!
putchar(c);!
state = inside;!
}!
break;!
case inside:!
switch(c) {!
case ' ': state = after; break;!
case '\n':!
putchar('\n');!
state = before;!
break;!
default:
putchar(c);!
}!
break;!
case after:!
if(c == '\n') {!
putchar('\n');!
state = before;!
}!
}!
}!
}
46

TIMING FUNCTIONS
C.A.Maynard 2012-2014

47

TIMING IN EMBEDDED
SYSTEMS
Timing of execution is one of the critical aspects of
embedded system design when compared to
desktop programming.!
The laboratory will introduce timing techniques in a
simple program environment.!
An empty for loop will be timed.!
You are provided with comprehensive notes to
execute the measurements in the lab sheet.
48

TIMING EXECUTION
It is often necessary to find out how long things take to
execute in an embedded system. How do we find this
out?!
There are three common ways with different attributes:
1.To determine execution time of a function run it in the
simulator and note the cycle counts before and after.
With this information and the system clock rate the
execution time can be determined. Often this execution
time is not fixed so execution with worst case paths
through the code and associated data needs to be
done.
49

TIMING EXECUTION
2.Activate an output pin at the beginning of execution of the
code and clear it at the end. Using repeated execution the
time can then be measured on a CRO and the jitter in this
time represents the variation in execution if variable data is
being provided to the code. There will be some tolerance in
the value due to the time taken to execute the output pin
changing code.!
3.Using predefined functions to capture the time of execution
and compensate for their own execution times (which should
be as short as possible). These can collect average and
extreme execution times (minimum and maximum) into a
structure for subsequent evaluation.

50

THE PROGRAM CORE


main (void) {!
ui_16 i, j; //unsigned int in a 16 bit variable!

for(i=0;i<10;i++) {!
for(j=0;j<10;j++) {} // Something to time test!
}!
}
51

THE TEST
FUNCTIONS
TimeTestStart(&TT);!
TimeTestEnd(&TT);
Port 4 bit 3 toggle!
(NOTE the flowchart shows
toggling bit 7 of port P (as
used last year)

52

ADDING THE TEST


FUNCTIONS
for(i=0;i<10;i++) {!
TimeTestStart(&TT); // Start time measurement!
P4OUT ^= BIT3; // Exclusive OR bit 3 of PORT P4!
for(j=0;j<10;j++) {} // Something to time test!
P4OUT ^= BIT3; // Exclusive OR bit 3 of PORT P4!
TimeTestEnd(&TT); // End time measurement!
}
53

SUPPORT CODE CONTD

static TimeTest TT = {0, 0, 65535, 0, 0, 0, 0};!


This is the initialisation of the structure that holds
the timing data.!
In main we then can have!
ui_16 i, j; // from MISRA C

54

STRUCTURES IN C
A struct in C is a structured type that aggregates a fixed
set of labelled objects, possibly of different types, into a
single object.

A struct declaration consists of a list of fields,
each of which can have any type. The total storage
required for a struct object is the sum of the
storage requirements of all the fields, plus any
internal padding.!

55

THE STRUCTURE
typedef struct {
ui_16 oldtcnt;
ui_16 count;
ui_16 min;
ui_16 mincount;
ui_16 max;
ui_16 maxcount;
ui_32 totaltime;
} TimeTest ;
!

/* Structure must be initialised as follows


* { 0, 0, 65535, 0, 0, 0, 0}
56

THE STRUCTURE VALUES


The structure values returned:
* Last starting TCNT. Not of value after execution
stopped
* Provides a count of the number of code
executions .count
* The minimum time execution in cycles and count: .min
and .mincount
* The maximum time execution in cycles and count: .max
and .maxcount
* The total time of all measurements: .totaltime
* So average time is this .totaltime/.count

57

ACCESSING THE
MEMBERS OF THE STRUCT
There are two ways to access the members
(component parts of the structure)!
/* Define a variable t of type TimeTest */!
TimeTest t;!
t.mincount = 23; //Place the value 23 in the timetest
structure under the mincount label.!
t->mincount = 23; // An alternative way of writing
it.
58

BEFORE MOVING ON!

You should understand the code to be tested.!


You need not understand the details of the timing
functions at this stage but we will investigate the
general use of structures (struct) and unions in C
later.

59

C - W H AT D O W E N E E D T O K N O W ?
60

C - A SYSTEMS DESIGN
LANGUAGE
The designers of C wanted to give themselves
sufficient flexibility to use it for almost anything from
system drivers through to user applications.!
They were very successful and that is why C is still in
use.!
What particular aspects are important for embedded
systems design?..........Revision

61

GLOBAL AND LOCAL


VARIABLES
Global variables are declared outside of all
functions, accessible by all, and exist throughout
the execution of the program.!
Local variables are declared inside functions and
usually are stored on the stack (or sometimes in
registers)

62

STORAGE KEYWORDS
extern: declared and defined in another code file.!
auto: the default type generally on the stack!
static: similar to auto but stored at specified locations in RAM (not on the stack).
Very good for functions needing to remember aspects of their execution.!
register: asks the compiler to use a processor register if possible for overall
efficiency of execution. !
const: a variable that does not change so usually in ROM!
volatile: locations which can be changed outside of the main program execution
such as input ports or through interrupt routines

63

OPERATORS

Review the available functionality.!


In particular:!
bitwise operations!
unary operations

64

FUNCTIONS

An independent body of code written to perform a


specific task.!
main is the function called first BUT any initial
conditions need to be established (not explicitly seen
in many situations including embedded code)

65

HEADER FILES
C has preconstructed libraries which are accessed by
#include <header.h>!
You can add your own header files by
#include myheader.h!
By default your own files need to be in the same
folder as your main.c file. There are ways of changing
this but generally run with the default.

66

CONDITIONAL
COMPILATION DIRECTIVES

Compiler directives: #include, #define,


#undef. #line, #error and #pragma!
Conditional directives: #if, #ifdef,
#ifndef, #else, #elif, and #endif

67

GUIDELINES

Guidelines are meant to be followed most of the time, !

and they are meant to be broken when you get better


results by breaking them!!

Note: The right to break the rules is not given freely!!!


The right is accompanied by the need for increased
documentation and justification.

68

SPECIFIC GUIDELINES

Guidelines for the use of the C Language in Vehicle


Based Software!

MISRA C!

There are 2 copies in the closed reserve in the library.!

The tests are built into the IAR embedded workbench


software used in the laboratory.

69

MISRA C
The MISRA C rules and guidelines should be followed as much
as possible.!
In this unit an attempt will be made to consistently follow
them BUT you will find places where there are deviations and
sometimes where comments are made to say this breaks the
guidelines but that should be expected.!
In particular the MISRA C rules will be followed except 109
and 110. (Investigate these rules)!
IARs own library files do not necessarily follow the MISRA
C rules.
70

THE MISRA C GUIDELINES


18TH RULE:

Numeric constants should be suffixed to indicate


type,where an appropriate suffix is available.

Discuss the need for this rule and indicate why


it is considered necessary. In ANSI C the
suffixes available are f or F, l or L, u or U.

Example:

#define fred (273u)

71

MISRA C RULE 46
STATES:

The value of an expression shall be the same under


any order of evaluation that the ANSI C standard
permits.

Example:

c = 5;
f = (c++)*c;

What is the resulting value for f?

72

You might also like