0% found this document useful (0 votes)
8 views12 pages

Embedded Firmware Development Guide

The document provides an overview of embedded firmware development, focusing on programming in assembly language and high-level languages like C. It discusses the advantages of assembly language, including precise control and compact code, as well as the benefits of high-level programming such as shorter development cycles, modular programming, and ease of use with data types and control structures. Additionally, it covers key elements of C programming, including preprocessor directives, macros, data types, and the use of pointers.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views12 pages

Embedded Firmware Development Guide

The document provides an overview of embedded firmware development, focusing on programming in assembly language and high-level languages like C. It discusses the advantages of assembly language, including precise control and compact code, as well as the benefits of high-level programming such as shorter development cycles, modular programming, and ease of use with data types and control structures. Additionally, it covers key elements of C programming, including preprocessor directives, macros, data types, and the use of pointers.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

UNIT - IV

Embedded Firmware Development:


 Overview of programming concepts - in assembly language and in high
level language ‘C’,

4.1 SOFTWARE PROGRAMMING IN ASSEMBLY LANGUAGE (ALP) AND IN HIGH-


LEVEL LANGUAGE ‘C’

4.1.1 Assembly Language Programming

Assembly language coding of an application has the following advantages:

1. The assembly codes are sensitive to the processor, memory, ports and devices hardware. It
gives a precise control of the processor internal devices and complete use of the processor-
specific features in its instruction set and its addressing modes.
2. The machine codes are compact, processor- and memory-sensitive. This is because the
codes for declaring the condition, rules and data type do not exist. The system thus needs
a smaller memory. Excess memory needed does not depend on the programmer data type
selection and rule declaration. The program is also not compiler specific and library
functions dependent.
3. Device driver codes may need only a few assembly instructions, for example, consider a
small embedded system, a timer in a microwave oven or an automatic washing machine or
an automatic chocolate-vending machine. Assembly codes for these can be compact and
precise, and are conveniently written.
4. We use bottom-up/down approach. It is an 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 a software timer, RTCSWT: run (real-time clock software timer function) unit.
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.

HIGH-LEVEL LANGUAGE PROGRAMMING

High-level language coding of source files in C, C++, or Java has great advantages and therefore
most programming is in high-level language. Basic advantages are as follows:

1. High-level program development cycle is short even for complex systems because of
the following: Use of routines (called functions in C/C++ and methods in Java), standard
library functions, use of modular programming approach, and above all design by object-
oriented design approach. Application programs are structured to ensure that the software
is based on sound software engineering principles and programmed with the given OS, file
systems, devices, and network drivers.
a. A function defines a method of operation, and sets of statements and commands are run
when that function is called.
b. Library functions are standard functions, which are readily available to a programmer and
the codes for them are not defined by the programmer. For example, square root method
of operation. The use of such standard library functions saves much time. It frees the
programmer from the burden. New sets of library functions exist in an embedded system-
specific C or C++ compiler. Exemplary library functions are delay (), wait (), and sleep ().
c. Device drivers for each serial line device (UART) are used in a number of embedded
systems. Directly programming these functions in each system would mean the repetitive
and redundant coding for each device. It is better to use the device drivers in high-level
language, which use the functions specified in the OS. Thus, the programmer simply
specifies device ID and some of the function arguments passed to the device driver
functions when needed and uses it at another instance of the device use.
d. Modular programming approach is an approach in which the building blocks are reusable
software components. A module is built as a software component. The components are
built by a set of functions. Consider an analogy in IC (integrated circuit) design. An IC has
several circuits encapsulated into a single module. A modular building block may call
several functions, and library functions. A module is then well tested for a well-defined
goal and for the well-defined data input and outputs. It should have clearly one calling
method. There should be one return point from it. It should not affect any data other than
the one it operates. This ensures that there should be data encapsulation. It must return
(report) error conditions encountered during its execution.
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. High-level language data types are easy to understand. Data declarations provide
programming ease. For example, there are four types of integers, 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 to a clock) has to be positive. We need a signed
integer for 32-bit signed arithmetic operations. An integer can also be declared as data type
short (16 bits) or long (32 bits). A template for the text and graphics for a character, another
data type is char. Each data type is an abstraction for the methods and rules for using,
manipulating, representing, and for defining a set of permissible operations on that data.
3. High-level program facilitates 'type checking' making the program less prone to
error. For example, type checking does not permit subtraction, multiplication and division
on the char data types. It permits 'plus' operator to be used for concatenation when using
char data types and lets the 'plus' operator be used for arithmetic addition when using int,
unsigned int, short and long type data. (Concatenation operation can be understood as
follows: the 'plus' operator concatenates into the same PIC microcontroller where microC
is an array of chars values and controller is another array of char values).
4. High-level program facilitates use of control structures (e.g., while-do, do-while,
break and for) and conditional statements (e.g., if, if-else, else-if and switch-case) to
specify the program flow by simple statements.
5. High-level program has portability to all microprocessor-specific codes. Therefore,
when the hardware changes, only the modules for the ISLs of devices, drivers and device
management, initialization and program-locator modules and initial boot-up record data
need modifications.

Additional advantages of C as a high-level language are as follows: It is a language between low-


(assembly) and high-level languages. Inserting the assembly language codes in-between is called
in-line assembly. A direct hardware control is thus also feasible by in-line assembly, and the
complex part of the program can be in high-level language.

High-level language programming makes the program development cycle short, enables use of the
modular programming approach and allows us to follow sound software engineering principles. It
facilitates the program development with top-down design approaches. Embedded system
programmers have since long preferred C for the following reasons: (i) The feature of embedding
assembly codes using in-line assembly. (ii) Readily available modules in C compilers for the
embedded system and library codes that can directly port into the system-programmer codes.

4.2 C PROGRAM ELEMENTS: HEADER AND SOURCE


FILES AND PREPROCESSOR DIRECTIVES
A C program has following structural elements:

1. Preprocessor declarations, definitions and statements.


2. Main function.
3. Functions, operations and ISRs.

A C program has the following preprocessor structural elements:

1. Include directive for the file inclusion.


2. Definitions for preprocessor global variables (global means throughout the program
module).
3. Definitions of constants.
4. Declarations for global data type, type declaration and data structures, macros and
functions.

The C program elements, header and source files and preprocessor directives are explained in the
following subsections.

4.2.1 Include Directive for the Inclusion of Files

Any C program first includes the header and source files that are readily available. A case study
of sending a stream of 16 bytes through a network driver card using a TCP/IP protocol is given in
Example. Its C program starts with the codes given in Example. The purpose of each included file
is mentioned in the comments within the /* and */ symbols as per the practice in C.
Example

#include "VxWorks.h" /* Include VxWorks functions*/

#include "semLib.h" /* Include Semaphore functions Library*/

#include "taskLib.h" /* Include inultitasking functions Library */

#include "msgQLib.h" /* Include Message Queue functions Library */

#include "fioLib.h" /* Include File-Device Input-Output functions Library */

# include "sysLib.c" /* Include system library for system functions */

#include "net [Link]" / Include a text file that provides the Network Driver
Configuration. It provides the frame format protocol (SLIP or PPP or Ethernet) description,
card description/make, address at the system. IP address (s) of the node (s) that drive the
card for transmitting or receiving from the network. */

#include "prctlHandlers.c" /* Include file for the codes for handling and actions as per the
network layer-protocols used for driving streams to the network. */

Include is a preprocessor directive to include the contents (codes or data) of a file. The files
that can be included are given next. Inclusion of all files and specific header files has to be
as per the requirements.

1. Including code files: These are the files for the codes already available. For example. #
include pretHandlers.c".

2. Including constant data files: These are the files for the codes and may have the extension
‘.const’

3. Including strings data files: These are the files for the strings and may have the extension
"strings" or .str.' or '.txt. For example, # include [Link]'.

4. Including initial data files: There are files for the initial or default data for the shadow
ROM of the embedded system. The boot-up program is copied later into the RAM and may
have the extension *.init". On the other hand, RAM data files have the extension, 'data'.

5. Including basic variable files: These are the files for the local or global static variables
that are stored in the RAM because they do not possess the initial (default) values. The
static means that there is a common not more than one instance of that variable address and
it has a static memory allocation. For example, system has is only one real-time clock, and
therefore only there is one instance of addresses of the clock variables. The basic variables
of the clock are stored in the file with the extension .bss".
6. Including header files: It is a preprocessor directive. which includes the contents (codes
or data) of a set of source files. These are the files of a specific module. A header file has
the extension .h". Examples are as follows. The string manipulation functions are needed
in a program using strings. These become available once a header file called [Link] is
included. The mathematical functions. square root, sin, cos, tan. atan and so on are needed
in programs using mathematical expressions. These become available by including a
header file, called math. The preprocessor directives will be '#include <string.h>' and
'#include <math.h>' for including standard library functions for the strings and
mathematical operations in the program.

Also included are the header files for the codes in assembly, and for the I/O operations
(conio.h), for the OS functions and RTOS functions. # include VxWorks.h' is directive to
the compiler, which includes VxWorks RTOS functions.

Note: Certain compilers provide for conio.h in place of stdio.h. This is when embedded
systems do not need the file functions for opening, closing, read and write operations on
the keyboard and video monitor. So when including stdio.h, it will make the code too big.

What is the difference between inclusion of a header file, and text file or data file or
constant file? Consider he inclusion of net [Link] and math.h.

(i) The header files are well-tested and debugged modules.


(ii) The header files provide access to standard libraries.
(iii) The header file can include several text files or C files.
(iv) A text file is a description of the text that contain specific information.

4.2.2 Source Files

Source files are program files for the functions of application software. The source files need to be
compiled. A source file will also possess the preprocessor directives of the application and have
the first function from where the processing will start. This function is called the main function.
Its codes start with void main(). The main calls other functions. A source file holds the codes.

4.2.3 Configuration Files

Configuration files are the files for configuration of the system. Device configuration codes can
be put in a file of basic variables and included when needed. If these codes are in the file
"serialLine_cfg.h" then # include "serialLine_cfg.h" will be the preprocessor directive.
Consider another example. # include “vas_cfg.h”; this will include vas_cfg.h header file.

4.2.4 Preprocessor Directives

Preprocessor constants, variables and inclusion of configuration files, text files, header files and
library functions are used in embedded C programs. A preprocessor directive starts with a sharp
(hash) sign. These commands in the following directives to the compiler for processing.
1. Preprocessor constant: It is used for constant, for example, in a program the IntrDisable.
IntrPortAEnable, IntrPortADisable. STAF and STAF flag are used to control enabling and
disabling the interrupts, enabling port A or disabling port A, status flag. '##define' is used
for these variables. These values remain constant. For example # define IntrEnable is
a preprocessor directive. It means it is a directive before processing to consider IntrEnable
as a constant variable, not a modifiable variable. (Volatile is a directive to the compiler not
to take this variable as a constant for assigning and optimizing the codes.)
2. Preprocessor constant for addresses: This is a preprocessor directive in an example. It
means it is a constant memory address assigned to the variable. The directive #define is
for allocating pointer (volatile unsigned char *) 0x1001. 0x1000 and 0x1000 are the
addresses fixed for port A (port A register) and PIOC (port input-output control register)
are the constants defined for the 68HC11 register addresses.

Strings can also be defined. Strings are the constants, for example, those used for an initial display
on the screen in a mobile system. For example, # define welcome "Welcome To ABC Telecom".

4.3 PROGRAM ELEMENTS: MACROS AND FUNCTIONS

Table 4.1 lists these elements and gives their uses.

Preprocessor Macros: A macro is a collection of codes that is defined in a C program by a name.


It differs from a function in the sense that once a macro is defined by a name, the compiler puts
the corresponding codes for it at every place where that macro name appears. For example,
consider the macros, enable_Maskable_Intr() and disable_Maskable_Intr(). (The pair of
brackets in the macro is optional. If it is present, it improves readability as it distinguishes a macro
from a constant.) Whenever the name enable_Maskable_Intr appears, the compiler places the
codes designed for it.
4.4 PROGRAM ELEMENTS: DATA TYPES, DATA STRUCTURES,
MODIFIERS, STATEMENTS, LOOPS AND POINTERS

4.4.1 Use of Data Types

Whenever a data is named, it will have the address(es) allocated at the memory. The number of
addresses allocated depends on the data type. For example, a data type long is declared for
numTicks (number of ticks). Then numTicks will need four memory addresses.

C allows the following primitive data types. The char (8 bits) for characters, byte (8 bits),
unsigned short (16 bits), short (16 bits), unsigned int (32 bits), int (32 bits), long double
(64 bits), float (32 bits) and double (64 bits). (Certain compilers do not take the byte as a data
type definition. The char is then used instead of byte. Most C compilers do not take a Boolean
variable as data type. The typedef is used to create a Boolean type variable in the C program.)

A data type appropriate for the hardware is used. For example, a 16-bit timer can have only the
unsigned short data type, and its range can be from 0 to 65535 only.

The typedef is also used. It is made clear by the following example. A compiler version may not
process the declaration as an unsigned byte. The unsigned character can then be used as a data
type. It can then be declared as follows:

typedef unsigned character portAdata

#define Pbyte portAdata 0xF1

4.4.2 Use of Pointers and Null Pointers

Pointers are powerful tools when used correctly and according to certain basic principles. Pointer
is a reference to a starting memory address. A pointer can refer to a variable, data structure or
function. Before a pointer, in C language symbol * is used. For example, unsigned char *0x100;
means a character of 8 bits at address 0x1000.

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.)

4.4.3 Use of Data Structures: Queues, Stacks, Lists and Trees

A data structure is a way of organizing several data elements of same types or different types
together at consecutive memory addresses. A data element in a data structure can then be
identified and accessed with the help of a few pointers and/or indices and/or functions. Marks (or
grades) of a student in the different subjects studied in a semester are put in a proper table. The
table in the mark sheet shows them in an organized way. Similarly, when there is a large amount
of data, it must be organized properly.

A data structure is an important element of any program. Few important data structures include:

 stack,
 one-dimensional array,
 queue,
 circular queue,
 pipe,
 a table (two-dimensional array),
 lookup table,
 hash table,
 list.

Following describes different data structures and how it is put in the memory blocks in an
organized way. Any data structure element can be retrieved using the pointers.

Stack

A data structure, called stack, is a special program element. A stack means an allotted memory
block from which a data element is read in a LIFO (last in first out) way and an element is popped
or pushed from an address pointed by a pointer, called SP (stack pointer) or Stop, and SP changes
on each push or pop such that it points to the top of stack.

Various stack structures may be created during processing. For handling each stack, one pointer,
which points to the stack top is needed.

Use Cases and Details:

1. Function Call and Return Handling:


o A call can be made for another routine during running of a routine.
o On completion of the called routine, the processor returns to the caller using the
return instruction address saved on the stack.
o Pushing: Save on stack and increment stack pointer.
o Popping: Retrieve saved address and decrement stack pointer.
o Nested calls: Stack stores return addresses for each nested call.
o Example: If PC address is of 4 bytes and 10 nested calls are made, 40 bytes (4 ×
10) are required.
2. Function Parameters or Input Data:
o Input data such as received call numbers are saved on stack.
o Example: Four pointers (4 bytes each), four integers (4 bytes each), four floats (4
bytes each).
 Total = 4 × 4 + 4 × 4 + 4 × 4 = 48 bytes.
3. Run-Time Stack Structures:
o Multiple data stacks may exist in different memory blocks, each with its own
pointer.
o Example: Stack 1, Stack N (Figure 5.1(c)).
4. Multitasking and Context Switching:
o Each task or thread has its own stack where its context is saved.
o Context includes return addresses for retrieval when switching back to task.
o Multiple stacks are used for saved contexts in multitasking systems.

Each processor has at least one stack pointer register so that the instruction stack can be
pointed and calling of the routines can be facilitated.
Types of Stack Pointers in Advanced Processors

1. RIP (Return Instruction Pointer):


o Stores return address of PC.
o Called Link Register (LR) in ARM.
2. SP (Stack Pointer):
o Points to memory block for stack use during context switches.
o Found in 8051, 68HC11, and 80196.
3. FP (Frame Pointer):
o Points to memory block for saving local data and variable values.
4. PFP (Previous Frame Pointer):
o Points to memory block used to save previous program frame.

Motorola MC68010 provides USP (user stack pointer) and SSP (supervisory stack pointer).
Program runs in two modes: user mode and supervisory mode.

Array

A data structure, array, is an important programming element. An array has multiple data
elements, each identifiable by an index or by a set of indices, and indices are unsigned integers.
An n-dimensional array is a special data structure at the memory. It has a pointer address that
always points to the first element of the array. For handling an n-dimensional array, one pointer
(which points to the first element) and n indices are needed.

Assume a one-dimensional array. From the first element pointer and an index of that element, an
address is constructed from which the processor can access the array elements. The index is an
integer that starts from 0 to (array-length – 1) in a given dimension. Data word can be retrieved
from any element address in the block that is allocated to the array. A processor register may also
be used for storing the index and another register for the array base pointer.

Queue

A data structure, called queue, is another important programming element. In case of array, the
reading is with the help of indices and first element address. So any element can be read or written
at any instance.

In queue, each element is read from an address next to the address from where the queue element
was last read. This reading is called deletion. In queue, it is written to an address next to the address
from where the queue element was last written. This writing is called insertion.

A queue means an allotted memory block from which a data element is retrieved in the FIFO
(First In First Out) mode. Using the queues, the bytes are sent onto a memory buffer or network
or printer.

Circular Queue
A queue is called circular queue when a pointer on reaching a limit *Qlimit returns to its
starting value *Qstart.
A circular queue means a bounded memory block allotted to a queue such that its pointer on
incrementing never exceeds the set limit and returns to start on increment beyond the limit.
From a circular queue also, the data element is retrieved in the FIFO mode but no exception is
thrown on exceeding the limit of the memory block allocated.

A circular queue is a queue in which tail and head pointers cannot increment beyond the
memory block (buffer) and reset to the starting value on insertion beyond the boundary.

Pipe

A pipe is a device that:

 Uses device driver functions.


 Insertions are from the source end.
 Deletions are at the sink (destination) end.
 Source and destination are connected by a function like pipe_connect().

A pipe is a device with insertions and deletions at distinctly defined source and destination.

Table

A table is a two-dimensional structure (matrix) and is an important data set that is allocated a
memory block.

 Always has a base pointer (points to the first element at the first row and column).
 Two indices: one for column, one for row.
 Any element can be retrieved using:
o Table base
o Column index
o Row index

Instead of a column or row pointer, a value used in an instruction is called the displacement.
Displacement can be used for either column or row.

Lookup Table

 A lookup table is a two-dimensional matrix.


 Each row has a key.
 On reading the key, the addressed data is retrieved.

Three pointers (table base, column index, destination index) or two pointers and one
displacement can retrieve any element.

Hash Table

A hash table is a data set of pairs of key and value.

 A hash has a key or name in one column.


 Corresponding value/object is in the second column.
 Keys may be at non-consecutive memory addresses.

A hash table is a data set with memory block for key and value pairs.

You might also like