Unit 4
Unit 4
Unit 4
EMBEDDED PROGRAMMING
1. The development cycle is short for complex systems due to the use of functions
(procedures),standard library functions, modular programming approach and top
down design. Application programs are structured to ensure that the software is
based on sound software engineering principles.
(a) Let us recall Example 4.8 of a UART serial line device driver. Direct use of this
function makes the repetitive coding redundant as this device is used in many
systems. We simply change some of the arguments (for the variables) passed
when needed and use it at another instance of the device use.
(b) Should the square root codes be written again whenever the square root of
another value (argument) is to be taken? The use of the standard library
function, square root ( ), saves the programmer time for coding. New sets of
library functions exist in an embedded system specific C or C++ compiler.
Exemplary functions are the delay ( ), wait ( ) and sleep ( ).
(c) Modular programming approach is an approach in which the building blocks
are reusablesoftware components. Consider an analogy to an IC (Integrated
Circuit). Just as an IC has several circuits integrated into one, similarly a
building block may call several functions and library functions. A module
should however, be well tested. It must have a well-defined goal and the well-
defined data inputs and outputs. It should have only one calling procedure.
There should be one return point from it. It should not affect any data other
than that which is targeted. [Data Encapsulation.] It must return (report) error
conditions encountered during its execution.
(d) Bottom up design is a design approach in which programming is first done for
the sub-modules of the specific and distinct sets of actions. An example of the
modules for specific sets of actions is a program for a software timer,
RTCSWT:: run. Programs for delay, counting, finding time intervals and many
applications can be written. Then the final program is designed. The approach
to this way of designing a program is to first code the basic functional modules
and then use these to build a bigger module.
(e) Top-Down design is another programming approach in which the main
program is first designed, then its modules, sub-modules, and finally, the
functions.
2. Data type declarations provide programming eas e. For example, there are four
types ofintegers, int, unsigned int, short and long. When dealing with positive only
values, we declare a variable as unsigned int. For example, numTicks (Number of
Ticks of a clock before the timeout) has to be unsigned. We need a signed integer,
int (32 bit) in arithmetical calculations. An integer can also be declared as data
type, short (16 bit) or long (64 bit).To manipulate the text and strings for a
character, another data type is char. Each data type is an abstraction forthe
methods to use, to manipulate, to represent, and for a set of permissible operations.
3. Type checking makes the program less prone to error. For example, type checking
does notpermit subtraction, multiplication and division on the char data types.
Further, it lets + be used for concatenation. [For example, micro + controller
concatenates into microcontroller, where micro is an array of char values and
controller is another array of char values.]
4. Control Structures (for examples, while, do - while, break and for) andConditional
Statements(for examples, if, if- else, else - if and switch - case) make the program-
flow path design tasks simple.
5. Portability of non-processor specific codes exists. Therefore, when the hardware
changes,only the modules for the device drivers and device management,
initialization and locator modules [Section 2.5.2] and initial boot up record data
need modifications.
170 Embedded Systems
Table 4.1
Uses of the Various Sets of Instructions as the Program Elements
Saves Feasibility
Program Uses context of
nesti
Element on the stack ng one
before its withi anoth
start n er
and
retrieves
them on
return
Saves Feasibility
Program Uses context of
nestin
Element on the stack g one
before its withi anoth
start n er
and retrieves
them on
return
Yes
Reentrant Refer Section 5.4. 6 (ii) Yes to
anoth
function er
reentrant
functi
on
only
Declarations of functions and data types,
Interrupt typedef, and Yes To higher
Executes a named set of codes. Must be priorit
Service short so that y
other sources of interrupts are also sourc
Routine or serviced within the es
Device deadlines. Must be either a reentrant
Driver routine or must
have a solution to the shared data
problem.
Refer Section 8.2. Must either be a
Task reentrant routine or Yes None
must have a solution to the shared data
problem.
A function that calls itself. It must be a
Recursive reentrant Yes Yes
function also. Most often its use is
function avoided in
embedded systems due to memory
constraints. [Stack
grows after each recursive call and its
may choke
the memory space availability.]
How does a macro differ from a function? The codes for a function are compiled once
only. On calling that function, the processor has to save the context, and on return restore
the context. Further, a function may return nothing (void declaration case) or return a
Boolean value, or an integer or any primitive or reference type of data. [Primitive means
similar to an integer or character. Reference type means similar to an array or structure.]
The enable_PortA_Intr ( ) and disable_PortA_Intr ( ) are the function calls in Example
4.5. [The brackets are now not optional]. Macros are used for short codes only. This is
because, if a function call is used instead of macro, the overheads (context saving and
other actions on function call and return) will take a time, T overheads that is the same order
of magnitude as the time, Texec for execution of short codes within a function. We use a
function when the Toverheads<< Texec, and a macro when Toverheads ~= or > Texec.
! Macros and functions are used in C programs. Functions are used when the
requirement is that the codes should be compiled once only. However, on calling a
function, the processor has to save the context, and on return, restore the context.
Further, a function may return nothing (void declaration case) or return a Boolean
value, or an integer or any primitive or reference type of data. Macros are used when
short functional codes are to be inserted in a number of places or functions.
Table 5.2
Uses of the Various Data Structures in a Program Element
Data
Example (s) of its
Structure Definition and when used use
marks_weight [4] =
of the structure is to be given a distinct marks_weight [0];
identity by an index Weight of
for easy operation. Index stars from 0 and is marks in the subject with
+ve integers. index 4
is assigned the same
as in the
subject with index 0.
It is a structure with a series of elements each Handling a matrix or
Multi- having another tensor.
dimension sub-series of elements. Each element is Consider a pixel in an
al accessible by image
identifier name and two or more indices. It is frame. Consider
array used when Quarter-CIF
every element of the structure is to be given a image pixel in 144 x
distinct 176 size
identity by two or more indices for easy image frame. [Recall
operation. The Section
dimension of an array equals the number of 1.2.7.] pixel [108, 88]
indices that are will
needed to distinctly identify an array-element. represent a pixel at
Indices start 108-th
horizontal row and
from 0 and are +ve integers. 88-th
vertical column. #See
following
note also.
Each element has a pointer to its next element. A series of tasks
List Only the first which are
element is identifiable and it is done by list- active Each task has
top pointer pointer for
(Header). No other element is identifiable and the next task. Another
hence is not example
accessible directly. By going through the first is a menu that point to
element, and a
then consecutively through all the succeeding
elements, an submenu.
element can be read, or read and deleted, or
can be added to
a neighbouring element or replaced by another
element.
Data
Structur
e Definition and when used Example (s) of its use
An instruction, ‘portA ++;’ will make the portA pointer point to the next address
and to which is the PIOC.
4. Consider, unsigned byte portAdata; unsigned byte *portA = &portAdata. The first
statement directs the compiler to allocate one memory address for portAdata
because there is a byte each at an address. The & (ampersand sign) means ‘at the
address of’. This declaration means the positive number of 8 bits (byte) pointed by
portA is replaced by the byte at the address of portAdata. The right side of the
expression evaluates the contained byte from the address, and the left side puts that
byte at the pointed address. Since the right side variable portAdata is not a declared
pointer, the ampersand sign is kept to point to its address so that the right side
pointer gets the contents (bits) from that address. [Note: The equality sign in a
program statement means ‘is replaced by’].
5. Consider two statements, ‘unsigned short *timer1;’ and ‘timer1++;’. The second
statement adds 0x0002 in the address of timer1. Why? timer1 ++ means point to
next address, and unsigned short declaration allocated two addresses for timer1.
[timer1 ++; or timer1 +=1 or timer = timer +1; will have identical actions.]
Therefore, the next address is 0x0002 more than the address of timer1 that was
originally defined. Had the declaration been ‘unsigned int’ (in case of 32 bit timer),
the second statement would have incremented the address by 0x0004.
When the index increments by 1 in case of an array of characters, the pointer to the
previous element actually increments by 1, and thus the address will increment by
0x0004 in case of an array of integers. For array data type, * is never put before the
identifier name, but an index is put within a pair of square brackets after the
identifier. Consider a declaration, ‘unsigned charportAMessageString [80];’. The
port A message is a string, which is an array of 80 characters.Now,
portAMessageString is itself a pointer to an address without the star sign before it.
[Note: Array is therefore known as a reference data type.] However,
*portAMessageString will now refer to all the 80 characters in the string.
portAMessageString [20] will refer to the twentieth element (character) in the
string. Assume that there is a list of RTCSWT (Real Time Clock interrupts
triggered Software Timers) timers that are active at an instant. The top of the list
can be pointed as ‘*RTCSWT_List.top’ using the pointer. RTCSWT_List.top is
now the pointer to the top of the contents in a memory for a list of the active
RTCSWTs. Consider the statement ‘RTCSWT_List.top ++;’ It increments this
pointer in a loop. It will not point to the next top of another object in the list
(another RTCSWT) but to some address that depends on the memory addresses
allocated to an item in the RTCSWT_List. Let ListNow be a pointer within the
memory block of the list top element. A statement ‘*RTCSWT_List. ListNow
=*RTCSWT_List.top;’ will do the following. RTCSWT_List pointer is now
replaced byRTCSWT list-top pointer and now points to the next list element
(object). [Note: RTCSWT_List.top ++ for pointer to the next list-object can only be
used when RTCSWT_List elements are placed in an array. This is because an array
is analogous to consecutively located elements of the list at the memory. Recall
Table 5.2.]
6. A NULL pointer declares as following: ‘#define NULL (void*) 0x0000’. [We can
assign any address instead of 0x0000 that is not in use in a given hardware.] NULL
pointer is very useful. Consider a statement: ‘while (* RTCSWT_List. ListNow -
>state != NULL) { numRunning++;’. When a pointer to ListNow in a list of
software timers that are running at present is notNULL, then only execute the set of
statements in the given pair of opening and closing curly braces. One of the
important uses of the NULL pointer is in a list. The last element to point to the end
of a list, or to no more contents in a queue or empty stack, queue or list.
Figure 5.1
Programming Model for multiple function calls in ‘main ( )’ function.
Embedded Systems
Example 5.4
typedef unsigned char int8bit;
# define int8bit boolean
# define false 0
# define true 1
void main (void) {
/* The Declarations of all variables, pointers, functions here and also initializations
here */
unsigned char *portAdata;
boolean charAFlag;
boolean checkPortAChar ( );
void inPortA (unsigned char *);
void decipherPortAData (unsigned char *);
void encryptPortAData (unsigned char *);
void outPortB (unsigned char *);
.
while (true) {
/* Codes that repeatedly execute */
/* Function for availability check of a character
at port A*/ while (charAFlag != true)
checkPortAChar ( );
/* Function for reading PortA character*/
inPortA (unsigned char *portAdata);
/* Function for deciphering */
decipherPortAData (unsigned char *portAdata);
/* Function for encoding */
encryptPortAData (unsigned char *portAdata);
/* Function for retransmit output to PortB*/
outPort B (unsigned char *portAdata);
};
}
Now, let the * sign be put before the function. ‘* checkPortAChar’ will now refer to all
the compiled form statements in the memory that are specified within the curly braces.
Consider a declaration in the example, ‘void inPortA (unsigned char *);’.
1. inPortAmeans a pointer to the statements of the function. Inside the bracket, there
is anunsigned character pointed by some pointer.
2. *inPortA will refer to all the compiled form statements of inPortA.
3. (* inPortA) will refer to calls to the statements of inPortA.
4. What will a statement, ‘void create (void (*inPortA) (unsigned char *), void
*portAStack, unsigned char port Apriority);’ mean?
(a) First modifier ‘void’ means create function does not return any thing.
(b) ‘create’ is another function.
(c) Consider the argument of this function ‘void (*inPortA) (unsigned char
*portAdata)’. (*inPortA) means call the statements of inportA the argument of
which is ‘unsigned char *portAdata’.
(d) The second argument of create function is a pointer for the portA stack at the
memory.
(e) The third argument of create function is a byte that defines the portA priority.
An important lesson to be remembered from above discussion is that a returning data
type specifi-cation (for example, void) followed by ‘(*functionName)
(functionArguments)’ calls the statements of the functionName using the
functionArguments, and on a return it returns the specified data object. We can thus use
the function pointer for invoking a call to the function.
When there are multiple ISRs, a high priority interrupt service routine is executed first
and the lowest priority, last. [Refer Section 4.6.4.] It is possible that function calls and
statements in any of the higher priority interrupts may block the execution of low priority
ISR within the deadline. How is the deadline problem for low priority routines to be
solved? One solution is by using the function pointers in the routines, and forming a
queue for them. The functions are then executed at a later stage. [Refer to exemplary
codes in Section 5.5.3].
! Pointers are needed in number of situations, for example, port bit manipulation and
read or write. Software designers must learn the uses of pointers in depth. An
innovative concept is use of function queues and the queues of the function pointers
built by the ISRs. It reduces significantly the ISR latency periods. Each device ISR
is therefore able to execute within its stipulated deadline.
(iv Operators in C++ can be overloaded like in method overloading. Recall the
) following statements
and expressions in Example 5.8. The operators ++ and ! are overloaded to perform
a set of
operations. [Usually the++ operator is used for post-increment and pre-increment
and the !
operator is used for a not operation.]
const OrderedList & operator ++ ( ) {if (ListNow != NULL) ListNow = ListNow -
> pNext;
return *this;}
boolean int OrderedList & operator ! ( ) const {return (ListNow != NULL) ;};
[Java does not support operator overloading, except for the + operator. It is used for
summation as well string-concatenation.]
There is struct that binds all the member functions together in C. But a C++ class has
object features. It can be extended and child classes can be derived from it. A number of
child classes can be derived from a common class. This feature is called polymorphism.
A class can be declared as public or private. The data and methods access is restricted
when a class is declared private. Struct does not have these features.
2. What are then the disadvantages of C++ ?
Program codes become lengthy, particularly when certain features of the standard C++ are
used.
Examples of these features are as follows:
(a) Template.
(b) Multiple Inheritance (Deriving a class from many parents).
(c) Exceptional handling.
(d) Virtual base classes.
(e) Classes for IO Streams. [Two library functions are cin (for character (s) in) and
cout (for character (s) out). The I/O stream class library provides for the input and
output streams of characters (bytes). It supports pipes, sockets and file management
features. Refer to Section 8.3 for the use of these in inter task communications.]
3. Can optimization codes be used in Embedded C++ programs to eliminate the
disadvan-tages?
Embedded system codes can be optimised when using an OOP language by the following
(a) Declare private as many classes as possible. It helps in optimising the generated
codes.
(b) Use char, int and boolean (scalar data types) in place of the objects (reference data
types) as arguments and use local variables as much as feasible.
(c) Recover memory already used once by changing the reference to an object to
NULL.
A special compiler for an embedded system can facilitate the disabling of specific
features provided in C++. Embedded C++ is a version of C++ that provides for a
selective disabling of the above features so that there is a less runtime overhead and less
runtime library. The solutions for the library functions are available and ported in C
directly. The IO stream library functions in an embedded C++ compiler are also
reentrant. So using embedded C++ compilers or the special compilers make the C++ a
signifi-cantly more powerful coding language than C for embedded systems.
GNU C/C++ compilers (called gcc) find extensive use in the C++ environment in
embedded soft-ware development. Embedded C++ is a new programming tool with a
compiler that provides a small runtime library. It satisfies small runtime RAM needs by
selectively de-configuring features like, tem-plate, multiple inheritance, virtual base class,
etc. when there is a less runtime overhead and when the less runtime library using
solutions are available. Selectively removed (de-configured) features couldbe template,
run time type identification, multiple Inheritance, exceptional handling, virtual base
classes, IO streams and foundation classes. [Examples of foundation classes are GUIs
(graphic user interfaces). Exemplary GUIs are the buttons, checkboxes or radios.]
An embedded system C++ compiler (other than gcc) is Diab compiler from Diab Data. It
also provides the target (embedded system processor) specific optimisation of the codes.
[Section 5.12] The run-time analysis tools check the expected run time error and give a
profile that is visually interactive.
! Embedded C++ is a C++ version, which makes large program development simpler
by providing object-oriented programming (OOP) features of using an object, which
binds state and behavior and which is defined by an instance of a class. We use
objects in a way that minimises memory needs and run-time overheads in the
system. Embedded system programmers use C ++ due to the OOP features of
software re-usability, extendibility, polymorphism, function overriding and
overloading along portability of C codes and in-line assembly codes. C++ also
provides for overloading of operators. A compiler, gcc, is popularly used for
embedded C++ codes compila-tion. Diab compiler has two special features: (i)
processor specific code optimisation and (ii) Run time analysis tools for finding
expected run-time errors.
Disadvantages of C++
Program codes become lengthy particularly when certain features of the standard C++
are used. Example of these features are as follows;
a. Template
b. Multiple inheritance
c. Exceptional handling
d. Virtual base classes
e. Classes for IO streams
Embedded system codes can be optimized when using the OOP language
i. Declare private as many classes as possible. It helps in optimizing the generated codes
ii. Use ‘char’, int and Boolean in place of the objects as arguments and use local
variables as much as feasible
iii. Recover memory already used once by changing the reference to an object to NULL
A Special compiler for an embedded system can facilitate the disabling of specific
features provided in C++. The solution for the library functions are available and ported
in C directly. The IO stream library function is an embedded C++ compiler are also
reentrant. So using embedded C++ compilers or the special compilers make the C++
significantly more powerful coding language than C for embedded systems
4.9 C Program compilers and cross compilers
Two compilers are needed. One is c program compiler and the other one is cross
compiler. Compiler is for the host computer which does the development and design and
also the testing and debugging.
The second compiler is the cross compiler. The cross compiler runs on the host but
develops the machine codes for a targeted system. There is a popular free ware called
GNU. A GNU compiler is configurable both as host compiler as well as cross compiler.
A compiler generates an object file. For compilation of the host alone the compiler can be
turbo C, turbo C++ and Borland C++. The target system specific or multi choice cross
compilers that are available commercially may be used. These are available for most of
the embedded systems, microprocessor and microcontrollers. The host runs the cross
compilers that offer an integrated development environment. It means that a target system
can emulate and simulate the application system on the host.
Use of appropriate compilers and cross compilers is essential in any embedded
software development
The components making up a program performance analysis are not universal; they
depend on the organization's industry, strategy, and environment. But we'll cover the basic
idea. There are a variety of metrics to perform, and planned values should be estimated
beforehand.
Return on Investment
Using a return on investment metric, a monetary value is attached to all the data
relating to the net benefits of the project. Where B represents net benefits and C represent
costs,
Return on Investment (ROI) = B/C x 100
These benefits can be in the form of savings on costs, profit contributions, surplus in
quantity of output and monetized quality improvements. Cost can be for maintenance, design
and development, resources, project management improvement costs, traveling expenditures,
training, and overhead. The outcome of the metric will be a percentage returning the rate of
return on the investment.
Productivity
A productivity metric measures the amount of output produced per unit of the input.
Basically, is the program generating its money's worth? A common way to measure
productivity is to calculate the revenue per employee. Dividing the revenue per employee by
the main salary per employee will get you a 'productivity ratio'. Other forms of productivity
could be the lines of codes written per employee or the number of projects completed per
employee.
Cost of Quality
Cost of quality represents the money lost due to defective goods or offering of
services. It is calculated by dividing the cost of quality by the actual cost. Total materials,
labour and overhead costs are directly linked to imperfections concerning the processes for
delivery of services or products falling short of expectations. Some examples are damage to
reputation, scrapping rejects, rework, inspection, repeat jobs, loss of customers, replacements
and refunds.
Cost Performance
Cost performance is a metric representing the cost efficiency of the program. It is
calculated by dividing the earned value of the project by the actual costs incurred in its
accomplishment. Once an organization is able to forecast its costs accurately, it is able to
reliably allocate capital, decrease financial risk and minimize the cost of capital.
Schedule Performance Index (SPI)
The schedule performance index (SPI) represents a ratio of the originally authorized,
full duration to the actual final project duration.
SPI= Earned value/Planned value
The ability to achieve time-to-market windows for a project is dependent on the
ability to forecast the project's schedule accurately. A small variant of this metric is the SPI
Standard Deviation, which facilitates the assessment of the schedule estimations accuracy.
Customer Satisfaction
The customer satisfaction metric represents an estimation of how pleased customers
are based on their expectations. The customer satisfaction index is made up of hard measures
like customer use or buying behavior and soft measures like customers' feelings or opinions.
This index is weighted according to how important the individual values are in
achieving the entire customer satisfaction. An example might be lost and repeat customers
(30%), sales from existing customers (15%), customer satisfaction interview results (20%),
market share (15%), project-specific surveys (10%), and returns/complaints (10%).
Requirements Performance
Requirements performance is a parameter that includes:
quality requirements - performance, usability and durability.
SCHOOL OF ELECTRICAL AND ELECTRONICS ENGINEERING
SATHYABAMA
INSTITUTE OF SCIENCE AND TECHNOLOGY
functional requirements - the ability of the product achieving the expected function.
Validation Report– The software is evaluated as per user specifications and a proper
validation report is submitted in order to cross-check the evaluations along with
getting an estimated date and round -off for the bug removal and for the system to
start functioning properly.
Incorporation of changes–Incorporate the changes that have been validated in the
last stage.
Types of validation testing
Validation testing types a V-shaped testing pattern, which includes its variations and all the
activities that it consists of are:
1. Unit Testing – It is an important type of validation testing. The point of the unit testing is
to search for bugs in the product segment. Simultaneously, it additionally confirms crafted by
modules and articles which can be tried independently.
2. Integration testing -This is a significant piece of the validation model wherein the
interaction between, where the association between the various interfaces of the pertaining
component is tried. Alongside the communication between the various pieces of the
framework, the connection of the framework with the PC working framework, document
framework, equipment, and some other programming framework it may cooperate with, is
likewise tried.
3. System testing – System testing is done when the whole programming framework is
prepared. The principal worry of framework testing is to confirm the framework against the
predefined necessities. While doing the tests, the tester isn’t worried about the internals of the
framework however checks if the framework acts according to desires.
4. User acceptance testing – During this testing, the tester actually needs to think like the
customer and test the product concerning client needs, prerequisites, business forms and
decide if the product can be given over to the customer or not.