You are on page 1of 182

EMBEDDED SYSTEMS

(A1430)
UNIT-III & IV RTOS
J. KRISHNA CHAITHANYA
Associate Professor
j.krishnachaitanya@vardhaman.org

Department of Electronics and Communication


Engineering

VARDHAMAN COLLEGE OF ENGINEERING


(AUTONOMOUS)
Shamshabad, Hyderabad - 501218

3.0 INTRODUCTION TO REAL-TIME


OPERATING SYSTEMS (RTOS)
A more complex software architecture is needed to handle multiple

tasks, coordination, communication, and interrupt handling an RTOS


architecture
Distinction:
Desktop OS OS is in control at all times and runs applications, OS
runs in different address space
RTOS OS and embedded software are integrated, ES starts and
activates the OS both run in the same address space (RTOS is less
protected)
RTOS includes only service routines needed by the ES application
RTOS vendors: VxWorks (we got it!), VTRX, Nucleus, LynxOS, uC/OS
Most conform to POSIX (IEEE standard for OS interfaces)
Desirable
RTOS properties: use less memory, application
programming interface, debugging tools, support for variety of
microprocessors, already-debugged network drivers

3.1 Tasks and Task States


A task a simple subroutine
ES application makes calls to the RTOS functions to start tasks, passing

to the OS, start address, stack pointers, etc. of the tasks


Task States:
Running
Ready (possibly: suspended, pended)
Blocked (possibly: waiting, dormant, delayed)
[Exit]
Scheduler schedules/shuffles tasks between Running and Ready

states
Blocking is self-blocking by tasks, and moved to Running state via
other tasks interrupt signaling (when block-factor is
removed/satisfied)
When a task is unblocked with a higher priority over the running
task, the scheduler switches context immediately (for all preemptive RTOSs)
(See Fig 6.1)

3.1 Tasks 1
Issue Scheduler/Task signal exchange for block-unblock of

tasks via function calls


Issue All tasks are blocked and scheduler idles forever (not
desirable!)
Issue Two or more tasks with same priority levels in Ready
state (time-slice, FIFO)
Example: scheduler switches from processor-hog vLevelsTask

to vButtonTask (on user interruption by pressing a pushbutton), controlled by the main() which initializes the RTOS,
sets priority levels, and starts the RTOS
(See Fig 6.2, Fig 6.3, Fig 6.4)

3.3 Tasks and Data


Each tasks has its won context - not shared, private registers,

stack, etc.
In addition, several tasks share common data (via global data
declaration; use of extern in one task to point to another task
that declares the shared data
Shared data caused the shared-data problem without
solutions discussed in Chp4 or use of Reentrancy
characterization of functions
(See Fig 6.5, Fig 6.6, Fig 6.7, and Fig 6.8)

3.2 Tasks 2
Reentrancy A function that works correctly regardless of the

number of tasks that call it between interrupts


Characteristics of reentrant functions
Only access shared variable in an atomic-way, or when variable

is on callees stack
A reentrant function calls only reentrant functions
A reentrant function uses system hardware (shared resource)
atomically

Inspecting code to determine Reentrancy:


See Fig 6.9 Where are data stored in C? Shared, non-shared,

or stacked?
See Fig 6.10 Is it reentrant? What about variable fError? Is

printf reentrant?
If shared variables are not protected, could they be accessed

using single assembly instructions (guaranteeing nonatomicity)?

Race condition
Assume the scenario in which
process A reads the free slot (e.g.
7) but before printing, CPU
switches to process B and process
B reads the free slot ( again 7 )
and prints its file name there and
updates it to 8. In that case when
CPU switches back to process A , it
starts from the point it left off
and writes its file in 7. Thus
process B never gets the print of
its file.
Situations like this , when two
processes are using the shared
data20and result depends on who

Race condition
Semaphore is one of the ways for providing
mutual exclusion by protecting critical regions.

21

Semaphores

22

Semaphore Definition
A semaphore is a data structure that is
shared by several processes. Semaphores are
most often used to synchronize operations (to
avoid race conditions) when multiple processes
access a common, non-shareable resource.
By using semaphores, we attempt to avoid
other multi-programming problems such as:
Starvation
Occurs when a process is habitually denied access
to a resource it needs.

Deadlock
23

Occurs when two or more processes each hold a

Semaphore Definition
To indicate a process has gained access to the resource,
the process decrements the semaphore.
For events to progress correctly, the test and
decrement operation on the semaphore must be atomic
(i.e., no interruptible/indivisible).
There are two kinds of Semaphores:
Binary semaphores
Control access to a single resource, taking
the value of 0 (resource is in use) or 1
(resource is available).
Counting semaphores
24

Control access to multiple resources, thus


assuming a range of nonnegative values.

Semaphore Definition
Semaphore is a nonnegative integer that is
stored in the kernel.
Access to the semaphore is provided by a
series of semaphore system calls.

25

Creating and Accessing


Semaphore Sets
Before a semaphore set can be used, it must
be created.
The creation of the semaphore set generates
a unique data structure that the system uses
to identify and manipulate the semaphores.
A conceptual arrangement of a system
semaphore structure for a newly allocated set
of three semaphores is shown in Figure 1.
26

Creating and Accessing


Semaphore Sets

.Figure
27

1. Data structures for a set of three semaphores

Creating and Accessing


Semaphore Sets
To create a semaphore or gain access to one
that exists, the semget system call is used.
(Table 1)

28

Creating and Accessing


Semaphore Sets
2

Manual Section

< sys/typ es.


h>
< sys/ip c.h >
< sys/sem .h
>
int semget (key_t key,intnsems,int semflg);

Return

Include
File(s)

Summary

Sets errno

Failure

Success

Yes

-1

The semaphore identifier

Table 1. Summary of the semget System Call


29

3.3 Semaphores and Shared Data A new tool


for atomicity
Semaphore a variable/lock/flag used to control access to shared

resource (to avoid shared-data problems in RTOS)


Protection at the start is via primitive function, called take,
indexed by the semaphore
Protection at the end is via a primitive function, called release,
also indexed similarly
Simple semaphores Binary semaphores are often adequate for

shared data problems in RTOS


(See Fig 6.12 and Fig 6.13)

3.3 Semaphores and Shared Data 1


RTOS Semaphores & Initializing Semaphores
Using binary semaphores to solve the tank monitoring problem
(See Fig 6.12 and Fig 6.13)
The nuclear reactor system: The issue of initializing the

semaphore variable in a dedicated task (not in a competing


task) before initializing the OS timing of tasks and priority
overrides, which can undermine the effect of the semaphores
Solution: Call OSSemInit() before OSInit()
(See Fig 6.14)

3.3 Semaphores and Shared Data 2


Reentrancy, Semaphores, Multiple Semaphores, Device Signaling,
Fig 6.15 a reentrant function, protecting a shared data, cErrors,

in critical section
Each shared data (resource/device) requires a separate

semaphore for individual protection, allowing multiple tasks and


data/resources/devices to be shared exclusively, while allowing
efficient implementation and response time
Fig 6.16 example of a printer device signaled by a report-

buffering task, via semaphore signaling, on each print of lines


constituting the formatted and buffered report

3.3 Semaphores and Shared Data 3


Semaphore Problems Messing up with semaphores
The initial values of semaphores when not set properly or at

the wrong place


The symmetry of takes and releases must match or
correspond each take must have a corresponding release
somewhere in the ES application
Taking the wrong semaphore unintentionally (issue with
multiple semaphores)
Holding a semaphore for too long can cause waiting tasks
deadline to be missed
Priorities could be inverted and usually solved by priority
inheritance/promotion
(See Fig 6.17)
Causing the deadly embrace problem (cycles)

3.3 Semaphores and Shared Data 4


Variants:
Binary semaphores single resource, one-at-a time,

alternating in use (also for resources)


Counting semaphores multiple instances of resources,
increase/decrease of integer semaphore variable
Mutex protects data shared while dealing with priority
inversion problem
Summary Protecting shared data in RTOS
Disabling/Enabling interrupts (for task code and interrupt

routines), faster
Taking/Releasing semaphores (cant use them in interrupt
routines), slower, affecting response times of those tasks that
need the semaphore
Disabling task switches (no effect on interrupt routines), holds
all other tasks response

More Operating System


Services
The other features offered by
commercial RTOSs.

Contents
Message Queues, Mailboxes and Pipes
Timer Functions
Events
Memory Management
Interrupt Routines in an RTOS Environment

Message Queues, Mailboxes


and Pipes
Task must be able to communicate with one

another to coordinate their activities or to


share data.
queues, mailboxes, and pipes

Message Queues,
Mailboxes and Pipes
void Task1(void)
{

if (!!problem arises)
vLogError(ERROR_TYPE_X);

!! Other things that need to be done


soon.
}

void vLogError(int iErrorType)


{
AddToQueue(iErrorType);
}
static int cErrors;
void ErrorTask(void)
{
int iErrorType;

void Task2(void)

while(FOREVER)
{
ReadFromQueue(&iErrorType);
++cErrors;
!! Send cErrors and iErrorType out on
network
}

if (!!problem arises)
vLogError(ERROR_TYPE_Y);

!! Other things that need to be done


soon.
}

Details with Message Queues


Initialize your queues before using queue.
Have as many queues as you want
the identity of the queue
When queue is full, the RTOS must
return an error
block

Details with Message Queues


A function that will read from a queue if there is

any data
and will return error code and block if not.
Write onto a queue the number of bytes taken up
by a void pointer

Pointer and Queues


Casting the data as a void pointer
One task can pass data to one other task
Put the data into buffer
And write a pointer to the buffer onto queue

Pointer and Queues


void *apvQueue[SIZEOF_QUEUE];
void main(void)
{

pOseQueue = OSQCreate(apvQueue,
SIZEOF_QUEUE);

!!Start Task1
!!Start Task2
}
void Task1(void) {

}
void Task2(void) {

Fig. 7.2 More Realistic Use of a Queue

void vLogError(int iErrorType) {


byReturn = OSQPost(pOseQueue,
(void*)iErorType);

}
void ErrorTask(void)
{
while(FOREVER)
{
iErrorType = (int)
OSQPend(pOseQueue,
WAIT_FOREVER, &byErr);
}

Pointer and Queues


static OS_EVENT *pOseQueueTemp;
void vReadTemperaturesTask(void)
{
int *pTemperatures;

void vMainTask(void)
{
int *pTemperatures;
BYTE byErr;
while(TRUE)
{
pTemperatures =
(int*)OSQPend(pOseQueueTemp,
WAIT_FOREVER, &byErr);
if (pTemperatures[0] != pTemperatures[1])
!! Set Off howling alarm;
}

While(TRUE) {

pTemperatures =
(int*)malloc(2*sizeof*pTemperatures);
pTemperatures[0] =
pTemperatures[1] =
OSQPost(pOseQueueTemp,
(void*)pTemperatures);
}
}

Fig. 7.3 Passing Pointer on Queues

Mailboxes
Much like queues.
RTOS can
Create, write ,check and read from mail
boxes.
The number of messages in a mailbox is

limited.
User can prioritize mailbox messages.
MultiTask!
sndmsg, rcvmsg, chkmsg

Pipes
Much like queues.
RTOS can
Create, write ,check and read from pipes.

Byte-oriented.
Use fread(), fwrite()

Which should we use?


Trade-offs among
Flexibility, speed, memory space, disabled

interrupt time length


Refer to documents

Pitfalls
Passing Pointers through a queue may create
shared data bugs
void vReadTemperaturesTask(void)
{
int *pTemperatures;

void vReadTemperaturesTask(void)
{
int iTemperatures[2];

While(TRUE) {

pTemperatures =
(int*)malloc(2*sizeof*pTemperatures);

While(TRUE) {

iTemperatures[0] =
iTemperatures[1] =

pTemperatures[0] =
pTemperatures[1] =

OSQPost(pOseQueueTemp,
(void*)iTemperatures);

OSQPost(pOseQueueTemp,
(void*)pTemperatures);
}
}

}
}

Timer Functions
Must Keep track of the passage of time
Offer taskDelay() functions.
void vMakePhoneCallTask(void)
{

taskDelay(100);
vDialingToneOn(*p_chPhoneNumber 0);
taskDelay(100);
vDialingToneOff();

Events

Procedure
1. More than task can block waiting
2. The events occurs
3. The RTOS will unblock all of tasks

Form group of events and any subset of

events within the group


Need to reset events automatically or
manually

Comparison for Inter task


Comm.
Semaphore : the fastest and simplest

not much information


Events : more complicated than
semapohre
can wait several events at the
same time
take more CPU time
Queues : much information
CPU-intensive
bugs-opportunity.

Memory Management
Avoid malloc and free function
Slow and unpredictable
Use the functions that allocate and free

fixed-size buffers.
Predictable

At MultiTask! system
void *getbuf(PoolID, timeout);
void *reqbuf(PoolID);
void reluf(PoolID, *p_vBuffer);

Interrupt Routines

in an RTOS

Environment
Interrupt Routines must not call any RTOS

functions that1. Might block the caller.


2. Might cause the RTOS to switching tasks

without fair warning

Interrupt Routines
Environment

Fig. 7.14 How Interrupt Routines Should Work

in an RTOS

Interrupt Routines
Environment

Fig. 7.15 What Would Really Happen

in an RTOS

Interrupt Routines

in an RTOS

Environment
1. The RTOS intercepts all the interrupts and
then call your interrupt routine.

Fig. 7.16 How Interrupt Routines Do Work

Interrupt Routines

in an RTOS

Environment
2. Disabling the scheduler for the
duration of the interrupt routine.

Fig. 7.17 How Interrupt Routines Do Work:Plan B

Interrupt Routines

in an RTOS

Environment
3.

A separate set of functions for


interrupt routines specially
OSSemPost
OSISRSemPost for interrupt routines

Nested Interrupts
The RTOS must know
when the lower-priority interrupt
routine.

Fig. 7.18 Nested Interrupts and the RTOS

BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES)


USING RTOS
To design an ES, first pick a software architecture
Round Robin
Round Robin with Interrupts
Function-Queue-Scheduling
RTOS
ES design concept and techniques discussed in Chp 8

assumes the RTOS architecture


Key RTOS mechanisms used include tasks, task
management, intertask communication mechanisms
(semaphores,
queues,
mailboxes,
pipes),
and
interrupts

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS

8.1 Overview
Prior to design, we must construct a specification of the ES to meet

such requirements / properties as:


Completeness
Time (timing constraints - response time, reactive time, deadlines soft vs.

hard)
Properties of the target hardware (for effective design of the ES), e.g., a 9600bps serial port that receives 1200 chars per second, requires an IR that
handles interrupts 1200 times each second. If chars can be written to RAM
using DMA, IR code will be different
Knowledge of microprocessor speed can the proc run the IR 1200 times per
sec?
Need all the software engineering skill you have, plus such properties as:

structures, encapsulation, info-hiding, modularity, coupling, cohesion,


maintainability, testability
Effective use of design tools and methodologies RoseRT, OO, UML, YES-UML,

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS


8.2 Principles Design considerations
ES is interrupt-driven and ES remains dormant until
Time passes for an event to occur (timer interrupt)
A need for a response to an external request/interrupt arises

Interrupts create cascade of events, causing RTOS tasks act/behave

accordingly
ES design technique: Create all needed tasks, get them into blocked-

state or idle state waiting on interrupts (to be generated by an


external event, e.g., frame-arrival at a network port)
(See Fig 8.1 network port and serial port comm via tasks that

implement DDP and ADSP protocol stack)

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS


8.2 Principles 1
Write Short IRs:
Even lowest priority IRs are handled before the highest priority task code

(minimize task code response time)


IRs are error prone and hard to debug (due to hardware-dependent software
parts)
Parts IR code requiring immediate / quick response should be in the core of IR
code; parts needing longer processing and not-so-urgent response should be
done a task (signaled by the IR)

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS


8.2 Principles 2
Consider the ff specs:
A system responds to commands from a serial port
All commands end with a carriage-return (CR)
Commands arrive one at a time, the next arrives iff the preceding one is
processed
Serial ports buffer is 1 character long, and characters arrive quickly (at X bps)
Systems processing time per character is Y char per second
Three possible designs:
A. Let IR handle everything => long response time, big IR code, hard to debug
errors
B. Let skeletal IR code, with a command parsing task that queues commands
(with all the attendant message/data queuing problems
C. Better compromise: Let IR save chars in a mailbox-buffer until CR, then the
command parsing task can work on the buffer

(See Fig 8.2 IR and parsing-task use different parts of the mail-buffer: tail and
head)

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS

8.2 Principles 3
Problem Decomposition into Tasks How many tasks?
Considerations (+ if carefully decomposed and few tasks; and if theres no
choice):
+More tasks offer better control of overall response time
+Modularity different task for different device handling or functionality
+Encapsulation data and functionality can be encapsulated within

responsible task
- More tasks means data-sharing, hence more protection worries and long

response time due to associated overheads


- More task means intertask messaging, with overhead due to queuing,
mailboxing, and pipe use
- More tasks means more space for task stacks and messages
- More tasks means frequent context switching (overhead) and less
throughput

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS

8.2 Principles 3
Priorities (advantage of using RTOS software architecture):
Decomposing based on functionality and time criticality, separates ES

components into tasks (naturally), for quicker response time using task
prioritization high priority for time-critical ones, and low priority for others
Encapsulating functionality in Tasks
A dedicated task to encapsulate the handling of each shared device (e.g.,

printer display unit) or a common data structure (e.g., an error log)


(See Fig 8.3)
Parts of a target hardware storing data in a flash memory a single task
encapsulates the handling of permission-to-write-to-flash (set / reset of flash
at given times)
(See Fig 8.4 using POSIX standard RTOS functions: mq_open, mq_receive,
mq_send, nanosleep)

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS


8.2 Principles 4
Other Tasks ?
Need many small, simple tasks? But worry about data-sharing, intertask

comm
Need a task per stimuli? Same problems!
Recommended Task Structure
Modeled/Structured as State-Machines
Tasks run in an infinite loop
Tasks wait on RTOS for an event (expected in each tasks independent message queue)
Tasks declare their own private data to use (fully encapsulated)
Tasks block on in one place (RTOS signal), and not any other semaphore, no data

sharing
Tasks use no microprocessor time when their queues are empty

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS


8.2 Principles 5
Avoid Creating and Destroying Tasks
Creating tasks takes more system time
Destroying tasks could leave destroy pointers-to-messages, remove

semaphore others are waiting on (blocking them forever)


Rule-of-thumb: Create all tasks needed at start, and keep them if memory is
cheap!
Turn Time-Slicing Off
Useful in conventional OSs for fairness to user programs
In ESs fairness is not an issue, response-time is!
Time-slicing causes context switching time consuming and diminishes

throughput
Where the RTOS offers an option to turn time-slicing off, turn it off!

8.0 BASIC DESIGN OF EMBEDDED SOFTWARE (ES) USING RTOS


8.2 Principles 6
Restrict the use of RTOS functions/features
Customize the RTOS features to your needs (Note: the RTOS and your ES gets

linked and located together into same address space of ROM/RAM See
Chapter 9)
If possible write ES functions to interface with RTOS select features to

minimize excessive calls to several RTOS functions (increases opportunity for


errors)
Develop a shell around the RTOS functions, and let your own ES tasks call the

shell (and not the RTOS directly) improves portability since only the shell
may be rewritten fro RTOS to RTOS

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS


8.3 An Example Designing an Underground Tank Monitoring ES System
Summary of Problem Specification:
System of 8 underground tanks
Measures read:
temperature of gas (thermometer) read at any time
float levels (float hardware) interrupted periodically by the microprocessor
Calculate the number of gallons per tank using both measures
Set an alarm on leaking tank (when level slowly and consistently falls over time)
Set an alarm on overflow (level rising slowly close to full-level)
User interface: a) 16-button control panel, LCD, thermal printer
System can override user display options and show warning messages
Histories of levels and temperature over time can be requested by user (30-50 lines

long) and user can queue up several reports


Issuing commands require 2 or 3 buttons, and system can prompt the display in the
middle of a user command sequence
Buttons interrupt the microprocessor
One dedicated button turns alarm off (connected to the system) through software
The printer prints one line at a time, and interrupts the microprocessor when done
The LCD prints the most recent line; saves its display-data and doesnt need the
microprocessor to retrieve info
(See Fig 8.7)

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS

8.3 An Examples
Issues that remain incomplete specs:
What is displayed? Timing info? Print-line length?
How often is float-level read?
What is the response time on push-button user interface response?
Printer speed number of lines per second?
What is the microprocessor speed? Which kind, 8-bit? The time to set/reset alarm?
Compute-time for # of gallons? 4-5 sec? (influences code design and tasking and

kind of microprocessor if no calc is required to set overflow alarm, that saves time!)
Knowing # gallons, what is the tolerant time-interval, or response-time, to set alarm?
Is reading a pair of temperature and float-level data for one tank at a time?
How is software interface to alarm-set off done write a bit flag to memory or power
cutoff to the alarm device
Does the microprocessor come with a timer?

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS


8.3 An Example
Which Architecture?
If RTOS, meeting deadlines depends on dealing with the 4-5 secs time

required to calculate the # of gallons requires task suspensions, perhaps,


with less IRs usage; and above all, the microprocessor must support some
RTOS
If not RTOS, meeting deadlines requires the use of several interrupts (and

IRs)

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS

An Example
System Decomposition for Tasks
One low priority task that handles all # gallons calculations and detects leaks

as well (for all tanks 1 at a time)


A high priority overflow-detection task (higher than a leak-detection task)
A high priority float-hardware task, using semaphores to make the level-calc
and overflow-detection task wait on it for reading (semaphores will be
simpler, faster than queuing requests to read levels)
A high priority button handling tasks need a state-machine model (an IR?
with internal static data structures, a simple wait on button-signal, and an
action which is predicated on sequence of button signals) since semaphores
wont work
(See Fig 8.8)
A high priority display task to handle contention for LCD use
[Turning the alarm bell on/off by the level-calc, overflow, and user-button is
typically non-contentious an atomic op hence do not need a separate
alarm-bell task] However, need a module with BellOn(), BellOff() functions to
encapsulate the alarm hardware
Low priority task to handle report formatting (one line at a time), and handle
report queue
(See Table 8.2)

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS

8.3 An Example
Moving System Forward Putting it together as Scenarios
System is interrupt driven via interrupt routines responding to signals,

activating tasks to their work


User presses button, button hardware interrupts the microprocessor, the
button IR sends message to button-handling task to interpret command,
which activates display task or printer task
UML Activity Diagram
[dt]
UBT BHI

BIR

BHT

[pt]

D
T
PT

Timer interrupts, timer IR -> signal to Overflow-Detection task

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS

Moving System Forward Putting it together as Scenarios 1


User presses printer button, print IR signals print-formatting task -> which sends

first line to printer; printer interrupts for print IR to send next line to printer; when
all lines (for report) are done, print IR signals print-formatting task for next report
A level task need to read, it interrupts the level-read-hardware routine; the level is

read by the hardware and the IR interrupts the task to read the new float level
Dealing with Shared Level-Data:
Three tasks need this data: level-calc for leak detection; display task; print formatting task
Reading level data and processing it by given task takes a few msec or msec
Use semaphores: let level-calc and display tasks read and process level in critical section

(CS) and let formatting task copy level data in CS, release semaphore, and format outside
CS
See Fig 8.9 and code listing in Chap 11 Black magic and wizardry!! SEng, an Art!

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS


8.4 Encapsulating Semaphores and Queues
Encapsulating Semaphores:
Dont assume that all tasks will use semaphore correctly (take/release),

leading to errors
Protect semaphores and associated data encapsulate/hide them in a task

Let all tasks call a separate module (acting as an intermediary) to get to the

CS - this separate module/function will in turn call the task which


encapsulates the semaphore
(See Fig 8.10 the correct code)

(See Fig 8.11 the incorrect alternative, which bypasses the intermediate

function

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS

8.4 Encapsulating Semaphores and Queues


Encapsulating Queues:
Writing to or reading from a flash memory using queues to enqueue

messages, the correctness of Fig 8.4 implementation depends passing the


correct FLASH_MSG type
Can a message meant for the FLASH be enqueued elsewhere
Exposing the flash queue to inadvertent deletion or destruction
Extra layer of data queue for holding data read from the FLASH could this

auxiliary queue be referenced wrongly? Type compatible with the FLASH


content?
Solution Encapsulate the Flash Queue structure inside a separate module,

flash.c; with access to it only through intermediate task vHandleFlashTask,


which is supported by auxiliary functions vReadFlash and vWriteFlash. [The
handle-task provides an interface for all other tasks to get to the queue]

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS


8.5 Hard Real-Time Scheduling Considerations
Guaranteeing that the system will meet hard deadlines comes from

writing fast code


Issues: fast algorithms, efficient data structures, code in assembly (if

possible)
Characterizing real-time systems:
Made of n tasks that execute periodically every T n units of time
Each task worst case execution time, C n units of time and deadline of Dn
Assume task switching time is 0 and non-blocking on semaphore
Each task has priority Pn
Question: Cn = (Dn + Jn) < Tn, where Jn is some variability in tasks time
Predicting Cn is very important, and depends on avoiding variability in

execution times for tasks, functions, access time of data structures/buffers,


semaphore blocking any operation that cant be done in the same time units
on each execution/access

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS


8.6 Saving Memory Space
Considerations of limited memory space for ES systems
Code is stored in ROM (loaded into RAM for execution), Data is stored in RAM

(except for initialization/shadowing. The two memory space types are not
interchangeable
Trade-offs: packed data saves RAM space, but unpacking code takes ROM

space
Estimate space by:
A. Tasks take stack space, fewer tasks take less RAM space, inspect code to

estimate stack-bytes per task local variables, parameters, function nestinglevel, worst-case nesting of interrupt routines, space for the RTOS (or select
features) from the manual
B. Experimental runs of the code not easy and wont reflect worst-case

behavior

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS

8.6 Saving Memory Space 1


Techniques / Suggestions:
Substitute or eliminate large functions, watch for repeated calls to large

functions
Consider writing your own function to replace RTOS functions, watch RTOS
functions that call several others
Configure or customize the RTOS functions to suit only the needs of the ES
Study assembly listing of cross-compilers, and rework your C code or write
your own assembly unit/task
Use static variable instead of relying on stack variables (push/pop and
pointering takes space)
Copy data structures passed to a function, via a pointer, into the functions
local, static variables process the data and copy back into structures: tradeof code is slower
For an 8-bit processor, use char instead of int variable (int takes 2-bytes and
longer in calculations than 1-byte chars)
If ROM is really tight, experiment with coding most functions/tasks in

8.0 BASIC DESIGN OF AN EMBEDDED SOFTWARE (ES) USING RTOS

Saving Power
Some embedded systems run on battery, turning battery off for some

or all devices is good


Generally, how to do you save power?

Look for the power-saving modes (enablers) which the manufacturers provide
Software can put microprocessor in one the modes via special instruction or

writing a code to special register in the processor. The software must be


fast!!
Power saving modes: sleep, low-power, idle, standby, etc.
Typical: uproc stops running, all built-in devices, and clock circuit (but leave
static RAM power on since the wattage is very small)
Waking uproc up is done by special circuitry and software (to avoid restart and
reset write special code to RAM address and let software check if it is cold
start or restart from power saving mode)
Alternative: uproc stops running but all devices stay alive, uproc is resume by
interrupt (this is less a hassle that stopping all devices)
If software turns power of devices back on, status data for resumption must
be in EEROM, and for those devices
Turn off built-in devices that signal frequently from hi-low, low-hi power
hungry!

9.0 EMBEDDED SOFTWARE DEVELOPMENT TOOLS


9.1 Introduction
Application programs are typically developed, compiled, and run on host

system
Embedded programs are targeted to a target processor (different from the
development/host processor and operating environment) that drives a device
or controls
What tools are needed to develop, test, and locate embedded software into
the target processor and its operating environment?
Distinction
Host: Where the embedded software is developed, compiled, tested,

debugged, optimized, and prior to its translation into target device. (Because
the host has keyboards, editors, monitors, printers, more memory, etc. for
development, while the target may have not of these capabilities for
developing the software.)
Target: After development, the code is cross-compiled, translated crossassembled, linked (into target processor instruction set) and located into the
target

9.0 EMBEDDED SOFTWARE DEVELOPMENT TOOLS


9.1 Introduction 1
Cross-Compilers
Native tools are good for host, but to port/locate embedded code to target,

the host must have a tool-chain that includes a cross-compiler, one which
runs on the host but produces code for the target processor
Cross-compiling doesnt guarantee correct target code due to (e.g.,
differences in word sizes, instruction sizes, variable declarations, library
functions)
Cross-Assemblers and Tool Chain
Host uses cross-assembler to assemble code in targets instruction syntax for

the target
Tool chain is a collection of compatible, translation tools, which are pipelined
to produce a complete binary/machine code that can be linked and located
into the target processor
(See Fig 9.1)

9.0 EMBEDDED SOFTWARE DEVELOPMENT TOOLS

9.2 Linker/Locators for Embedded Software


Native linkers are different from cross-linkers (or locators) that perform

additional tasks to locate embedded binary code into target


processors

Address Resolution
Native Linker: produces host machine code on the hard-drive (in a named
file), which the loader loads into RAM, and then schedules (under the OS
control) the program to go to the CPU.
In RAM, the application program/codes logical addresses for, e.g.,

variable/operands and function calls, are ordered or organized by the linker.


The loader then maps the logical addresses into physical addresses a
process called address resolution. The loader then loads the code
accordingly into RAM (see Fig 9.2). In the process the loader also resolves the
addresses for calls to the native OS routines

Locator: produces target machine code (which the locator glues into the

RTOS) and the combined code (called map) gets copied into the target ROM.
The locator doesnt stay in the target environment, hence all addresses are

9.0 EMBEDDED SOFTWARE DEVELOPMENT TOOLS

Locating Program Components Segments


Unchanging embedded program (binary code) and constants must be

kept in ROM to be remembered even on power-off


Changing program segments (e.g., variables) must be kept in RAM
Chain tools separate program parts using segments concept
Chain tools (for embedded systems) also require a start-up code to be

in a separate segment and located at a microprocessor-defined


location where the program starts execution
Some cross-compilers have default or allow programmer to specify

segments for program parts, but cross-assemblers have no default


behavior and programmer must specify segments for program parts
(See Fig 9.5 - locating of object-code segments in ROM and RAM)

9.0 EMBEDDED SOFTWARE DEVELOPMENT TOOLS


Locating Program Components Segments 1
Telling/directing the locator where (which segments) to place parts
E.g., Fig 9.6
The Z tells which segments (list of segments) to use and the start-address of

the first segment


The first line tells which segments to use for the code parts, starting at
address 0; and the second line tells which segments to use for the data parts,
starting at x8000
The proper names and address info for the directing the locator are usually in
the cross-compiler documentation
Other directives: range of RAM and ROM addresses, end of stack address
(segment is placed below this address for stack to grow towards the end)
Segments/parts can also be grouped, and the group is located as a unit

9.0 EMBEDDED SOFTWARE DEVELOPMENT TOOLS


Initialized Data and Constant Strings
Segments with initialized values in ROM are shadowed (or copied into

RAM) for correct reset of initialized variables, in RAM, each time the
system comes up (esp. for initial values that are take #define
constants, and which can be changed)
In C programs, a host compiler may set all uninitialized variable to zero

or null, but this is not generally the case for embedded software crosscompilers (unless the startup code in ROM does so
If part(s) of a constant string is(are) expected to be changed during

run-time, the cross-compiler must generate a code to allow shadowing


of the string from ROM

9.0 EMBEDDED SOFTWARE DEVELOPMENT TOOLS


Locator Maps and Executing Out of RAM
Output file of locators are Maps list addresses of all segments
Maps are useful for debugging
An advanced locator is capable of running (albeit slowly) a startup

code in ROM, which (could decompress and) load the embedded code
from ROM into RAM to execute quickly since RAM is faster, especially
for RISC microprocessors
(See Fig 9.7 Maps)

9.0 EMBEDDED SOFTWARE DEVELOPMENT TOOLS


9.3 Getting Embedded Software into Target System
Moving maps into ROM or PROM, is to create a ROM using hardware

tools or a PROM programmer (for small and changeable software,


during debugging)
If PROM programmer is used (for changing or debugging software),

place PROM in a socket (which makes it erasable for EPROM, or


removable/replaceable) rather than burnt into circuitry
PROMs can be pushed into sockets by hand, and pulled using a chip

puller
The PROM programmer must be compatible with the format

(syntax/semantics) of the Map


(See Fig 9.8)

9.0 EMBEDDED SOFTWARE DEVELOPMENT TOOLS


9.3 Getting Embedded Software into Target System 1
ROM Emulators Another approach is using a ROM emulator

(hardware) which emulates the target system, has all the ROM
circuitry, and a serial or network interface to the host system. The
locator loads the Map into the emulator, especially, for debugging
purposes.
Software on the host that loads the Map file into the emulator must

understand (be compatible with) the Maps syntax/semantics


(See Fig 9.9)

9.0 EMBEDDED SOFTWARE DEVELOPMENT TOOLS


9.3 Getting Embedded Software into Target System 2
Using Flash Memory
For debugging, a flash memory can be loaded with target Map code using a

software on the host over a serial port or network connection (just like using
an EPROM)
Advantages:
No need to pull the flash (unlike PROM) for debugging different embedded code
Transferring code into flash (over a network) is faster and hassle-free
New versions of embedded software (supplied by vendor) can be loaded into flash

memory by customers over a network - Requires a) protecting the flash programmer,


saving it in RAM and executing from there, and reloading into flash after new version is
written and b) the ability to complete loading new version even if there are crashes and
protecting the startup code as in (a)
Modifying and/or debugging the flash programming software requires moving it into

RAM, modify/debug, and reloading it into target flash memory using above methods

10.0 DEBUGGING TECHNIQUES


Introduction
Rule of Thumb: Write good, bug-free code from start if you could
Testing/Debugging embedded software is more difficult than application

software
Post-shipment application problems are more tolerable than embedded

(real-time or life-critical) software

10.0 DEBUGGING TECHNIQUES


10.1 Testing on Host Machine
Some reasons why you cant test (much, if any) on target machine:
Test early (target may not ready or completely stable)
Exercise all code, including exceptions (real situations may be difficult

to exercise)
Develop reusable, repeatable test (difficult to do in target environment,

and likelihood of hitting the same bug is low)


Store test results (target may not even have disk drive to store results)

10.0 DEBUGGING TECHNIQUES


10.1 Testing on Host Machine 1
Basic Techniques
Fig 10.1
Target system on the left: (hardware-indep code, hardware-dep code, hw)
Test system (on host) on the right: (hardware-indep code same, scaffold

rest)
Scaffold provides (in software) all functionalities and calls to hardware as in
the hardware-dep and hardware components of the target system more like
a simulator for them!

10.0 DEBUGGING TECHNIQUES


10.1 Testing on Host Machine 2
Basic Techniques
Fig 10.2
Radio.c -- hardware independent code
Radiohw.c hardware dependent code (only interface to hw: inp() and

outp() supporting vTurnOnTransmitter() and vTurnOffTransmitter() functions


Inp() and outp() must have real hardware code to read/write byte data
correctly - makes testing harder!!
Fig 10.3
Replace radiohw.c with scaffold, eliminating the need for inp() and outp()

both are simulated in software a program stub!!

Figure 10.2 A Poor Plan for Testing


/* File: radio.c */
void vRadioTask (void)
{
.
.
.
!! Complicated code to determine if turning on the radio now
!! is within FCC regulations.
.
.
.
!! More complicated code to decide if turning on the radio now
!! makes sense in our protocol.
If (!! Time to send something on the radio)
{
vTurnOnTransmitter (FREQ_NORMAL);
!! Send data out
vTurnOffRadio ();
}
}
----------------------------------------------(continued)

Figure 10.2 (continued)


/* File: radiohw.c */
void vTurnOnTransmitter (int iFrequencyValue)
{
BYTE byPower;
/* Byte read from device controlling power. */
int
i;
/* Turn on main power for the radio. */
disable_interrupts ();
byPower = inp (PWR_CONTROL_ADDR);
byPower |= PWR_CONTROL_RADIO_MAIN;
outp (PWR_CONTROL_ADDR, byPower);
enable_interrupts ();
/* Shift the frequency value out to hardware. */
for (i = 0; i < 16; ++i)
{
/* Send out the lowest bit of iFrequencyValue */
if (iFrequencyValue & 0x0001)
{
/* The data is a binary 1 */
/* Put a '1' on the data line; pulse the clock line. */
outp (FRQ_CONROL, DATA_1 & CLOCK_LOW)
outp (FRQ_CONROL, DATA_1 & CLOCK_HIGH);
}
(continued)

Figure 10.2 (continued)


else
{
/* The data is a binary 0 */
/* put a '0' on the data line; pulse the clock line. */
outp (FRQ_CONROL, DATA_0 & CLOCK_LOW)
outp (FRQ_CONROL, DATA_0 & CLOCK_HIGH);
}
/* Shift iFrequencyValue to get the next lowest bit. */
iFrequencyValue >>= 1;
}
/* Turn on the receiver. */
byPower = inp (PWR_CONTROL_ADDR);
byPower |= PWR_CONTROL_RADIO_RECEIVER;
outp (PWR_CONTROL_ADDR, byPower);
enable_interrupts ();
}
void vTurnOffRadio (void)
{
BYTE byPower;
/* Byte read from device controlling power. */
/* Turn off main power for the radio. */
disable_interrupts ();
byPower = inp (PWR_CONTROL_ADDR);
byPower &= ~PWR_CONTROL_RADIO_MAIN;
outp (PWR_CONTROL_ADDR, byPower);
enable_interrupts ();
}
-------------------------------------------

(continued)

Figure 10.2 (continued)


/* File: test.c */
void outp (int Address, BYTE byData)
{
#ifdef LET_USER_SIMULATE_HARDWARE
PRINTF ("program wrote %02x to %04x.", byData, iAddress);
#endif
#ifdef SIMULATE_HARDWARE
!! Remember that software wrote byData to iAddress
!! Update state of simulated hardware.
#endif
}
BYTE inp (int iAddress)
{
int iData;
#ifdef LET_USER_SIMULATE_HARDWARE
PRINTF ("program wrote %02x to %04x. Enter value.",
iAddress);
scanf ("%x", &iData);
#endif
#ifdef SIMULATE_HARDWARE
!! Figure out what the real hardware would return
#endif
return ((BYTE) iData);
}

Figure 10.3 Better Plan for Testing


/* File: radio.c */
void vRadioTask (void)
{
.
.
.
!! Complicated code to determine if turning on the radio now
!! is within FCC regulations.
.
.
.
!! More complicated code to decide if turning on the radio now
!! makes sense in our protocol.
If (!! Time to send something on the radio)
{
vTurnOnTransmitter (FREQ_NORMAL);
!! Send data out
vTurnOffRadio ();
}
}
----------------------------------------------(continued)

Figure 10.3 (continued)


/* File: test.c */
static BOOL
fRadionOn;
static int
iRadioFrequencyValue;
void vTurnOnTransmitter (int iFrequencyValue)
{
/* Record the state of the radio. */
fRadionOn = TRUE;
iRadioFrequencyValue = iFrequencyValue;
/* Tell the user */
printf ("Radio turned on with frequency %04x", iFrequencyValue);
}
void vTurnOffRadio (void)
{
/* Record the state of the radio. */
fRadioOn = FALSE;
/* Tell the user */
printf ("Radio now off");
}

10.0 DEBUGGING TECHNIQUES

10.1 Testing on Host Machine 3


Calling Interrupt Routines
Embedded systems are interrupt-driven, so to test based on interrupts
1) Divide interrupt routines into two components
A) a component that deals with the hardware
B) a component of the routine which deals with the rest of the system

2) To test, structure the routine such that the hardware-dependent component

(A) calls the hardware-independent part (B).


3) Write component B in C-language, so that the test scaffold can call it
E.g., Fig 10.4
Hw component (A) is vHandleRxHardware(), which reads characters from the

hw
Sw component (B) is vHandleByte, called by A to buffer characters, among
others
The test scaffold, vTestMain(), then calls vHandleByte(), to test if the system

Figure 10.4 Dividing Interrupt Routines into Two Parts


/* File: serial.c */
#define CR 0x0d
#define SIZEOF_CMD_BUFFER
200
BYTE a_byCommandBuffer[SIZEOF_CMD_BUFFER];
/* Queue to send message to command-handling task. */
extern unsigned long
qidCommands;
void interrupt vHandleRxHardware (void)
{
BYTE byChar;
/* The character we received */
int
iHwError;
/* Hardware error, if any */
iHwError = !! Get status from hardware;
if (iHwError == CHARACTER_RXD_OK)
{
/* We received a character; deal with it. */
byChar = !! Read byte from hardware;
vHandleRxByte (byChar);
}
else
!! Deal with hardware error
!! Reset the hardware as necessary.
!! Reset interrupt controller as necessary.
}

(continued)

Figure 10.4 (continued)


void vHandleRxByte (BYTE byReceived)
{
static BYTE
*p_byCommandBufferTail = a_ byCommandBuffer;
extern BYTE
*p_byCommandBufferHead;
unsigned long a_ulMessage[4];
/* Message buffer. */
/* Advance the tail pointer and wrap if necessary */
++ p_byCommandBufferTail;
if (p_byCommandBufferTail == &a_ byCommandBuffer
[SIZEOF_CMD_BUFFER])
p_byCommandBufferTail = a_ byCommandBuffer;
/* If the buffer is not full . . . . */
if (p_byCommandBufferTail != p_byCommandBufferHead)
{
/* Store the character in the buffer. */
*p_byCommandBufferTail = byReceived;
/* If we got a carriage return, wake up the command-handling task. */
if (*p_byCommandBufferTail == CR)
{
/* Build the message . . . */
a_ulMessage[0] = MSG_COMMAND_ARRIVED;
a_ulMessage[1] = 0L;
a_ulMessage[2] = 0L;
a_ulMessage[3] = 0L;
(continued)

Figure 10.4 (continued)


/* . . . and send it. */
q_send (qidCommands, a_ulMessage);
}
}
else
{
/* Discard the character; move the pointer back. */
if (p_byCommandBufferTail == a_ byCommandBuffer)
p_byCommandBufferTail ==
&a_ byCommandBuffer[SIZEOF_CMD_BUFFER];
-- p_byCommandBufferTail;
}
}
-------------------------------------------/* File: test.c */
void vTestMain (void)
{
BYTE

a_byTestCommand[] = "THUMBS UP\x0dSIMON SAYS THUMBS UP\x0d";

BYTE *p_by;
.
.
/* Send each of the characters in a_byTestCommand */
p_by = a_byTestCommand;
while (*p_by)
{
/* Send a single character as though received by the interrupt */
vHandleRxByte (*p_by);
/* Go to the next character */
++p_by;
}
.
.

10.0 DEBUGGING TECHNIQUES


10.1 Testing on Host Machine 4
Calling the Timer Interrupt Routine
Design the test scaffold routine to directly call the timer interrupt routine,

rather than other part of the host environment, to avoid interruptions in the
scaffolds timing of events
This way, the scaffold has control over sequences of events in the test which
must occur within intervals of timer interrupts
Script Files and Output Files
To let the scaffold test the system in some sequence or repeated times, write

a script file (of commands and parameters) to control the test


Parse the script file, test system based on commands/parameters, and direct
output intermixture of the input-script and output lines into an output file
The commands in the script cause the scaffold to call routines in the B (swindp) component -- See Fig 10.5 and Fig 10.6 for the cordless bar-code
scanner

10.0 DEBUGGING TECHNIQUES


10.1 Testing on Host Machine 5
More Advanced Techniques
Making the scaffold automatically control sequence of events e.g., calling

the printer interrupt many times but in a controlled order to avoid swamping
Making the scaffold automatically queue up requests-to-send output lines, by
automatically controlling the button interrupt routine, which will cause
successive pressing of a button to let the next output line be received from
the hardware (the printer interrupt routine). In this way, the hardwareindependent software is controlled by the scaffold, where the button
interrupts serve as a switch
The scaffold may contain multiple instances of the software-independent
code, and the scaffold serves as a controller of the communication between
the instances where each instance is called by the scaffold when the
hardware interrupt occurs (e.g., the scanner or the cash register). In this way,
the scaffold simulates the hardware (scanner or register) and provides
communication services to the software-independent code instances it calls.
See Fig 10.7

10.0 DEBUGGING TECHNIQUES


10.1 Testing on Host Machine 6
Objections, Limitations, and Shortcomings
1) Hard to test parts which are truly hardware dependent, until the

target system is operational. Yet, good to test most sw-independent


parts on host (see Fig 10.8)
2) Time and effort in writing scaffold even if huge, it is worthwhile
3) Having the scaffold run on the host and its RTOS scaffold can run

as low priority task within the RTOS and have nicely integrated testing
environment
4) The hard to justify limitations cant tell in scafold until the actual

test
Writing to the wrong hardware address software/hardware interactions
Realistic interrupt latency due to differences in processor speeds (host v.

target)
Real interrupts that cause shared-data problems, where real enable/disable is
the key
Differences in network addressing, size of data types, data packing schemes
portability issues

10.0 DEBUGGING TECHNIQUES


10.2 Instruction Set Simulators
Using software to simulate:
The target microprocessor instruction set
The target memory (types - RAM)
The target microprocessor architecture (interconnections and components)

Simulator must understand the linker/locator Map format, parse and

interpret it
Simulator takes the Map as input, reads the instructions from simulated
ROM, reads/writes from/to simulated registers
Provide a user interface to simulator for I/O, debugging (using, e.g., a macro
language)

10.0 DEBUGGING TECHNIQUES


10.2 Instruction Set Simulators 1
Capabilities of Simulators:
Collect statistics on # instructions executed, bus cycles for estimating actual

times
Easier to test assembly code (for startup software and interrupt routines) in
simulator
Easier to test for portability since simulator takes same Map as the target
Other parts, e.g., timers and built-in peripherals, can be tested in the
corresponding simulated versions in the simulated microprocessor
architecture
What simulators cant help:
Simulating and testing ASICs, sensors, actuators, specialized radios (perhaps,

in future systems!!)
Lacking I/O interfaces in simulator to support testing techniques discussed
(unless additional provision is made for I/O to support the scaffold; and scripts
to format and reformat files between the simulator, simulated memory, and
the scaffold)

10.0 DEBUGGING TECHNIQUES


10.3 The assert Macro
The assert is used (with a boolean-expression parameter) to check

assumptions
If the expression is TRUE nothing happens, if FALSE, a message is

printed and the program crashes


Assert works well in finding bugs early, when testing in the host

environment
On failure, assert causes a return to the host operating systems (cant

do on target, and cant print such message on target may not have
the display unit)
Assert macro that runs on the target are useful for spotting problems:
1) disabling interrupts and spin in infinite loop effectively stopping the

system
2) turn on some pattern of LEDs or blinking device
3) write special code memory for logic analyzer to read
4) write location of the instruction that cause problem to specific memory for
logic analyzer to read (the Map can help isolate which source code is the
culprit!)
5) execute an illegal op or other to stop the system e.g., using in-circuit

10.0 DEBUGGING TECHNIQUES


10.4 Using Laboratory Tools Hardware-focused
Lab tools help reveal hard-to-find, very infrequently occurring bugs
Types useful to software engineers:
Voltmeters (measure voltage diff); Ohmmeters (measure

resistance/connectedness)
Oscilloscopes (scopes) test events that repeat periodically monitoring one or
two signals (graph of time v. voltage), triggering mechanism to indicate start
of monitoring, adjust vertical to know ground-signal, used as voltmeter (flat
graph at some vertical relative to ground signal), test if a device/part is
working is graph flat? Is the digital signal coming through expecting a
quick rising/falling edge (from 0 VCC or VCC 0) if not, scope will show
slow rising/falling indicating loading, bus fight, or other hardware problem
(See Fig 10.10, Fig 10.11, Fig 10.12, Fig 10.13, Fig 10.14)

10.0 DEBUGGING TECHNIQUES


10.4 Using Laboratory Tools Hardware-focused - 1
Logic Analyzer
Like storage scopes that (first) capture many signals and displays them

simultaneously
It knows only of VCC and ground voltage levels (displays are like timing
diagrams) Real scopes display exact voltage (like analog)
Can be used to trigger on-symptom and track back in stored signal to isolate
problem
Many signals can be triggered at their low and/or high points and for how long
in that state
Used in Timing or State Mode

10.0 DEBUGGING TECHNIQUES


10.4 Using Laboratory Tools Hardware-focused 2
Logic Analyzers in Timing Mode
Find out if an event occurred did cordless scanner turn on the radio?
Measure how long it took software to respond to an interrupt (e.g., between a

button interrupt signal and activation signal of a responding device to turn


off an bell)
Is the software putting out the right pattern of signals to control a hardware
device looking back in the captured signal for elapsed time
(See Fig 10.15 on response time)
(See Fig 10.16 on elapsed time)

(See Fig 10.17 a typical Logic Analyzer with on-screen button, mouse,

keyboard, network adaptor, disk storage for storing configurations/settings,


ribbon cables)

10.0 DEBUGGING TECHNIQUES


10.4 Using Laboratory Tools Hardware-focused 3
Logic Analyzers in State Mode
Captures signals only on clock-event occurring from the attached hardware
Typical use: instructions read/fetched by microprocessor, data read from or

written to ROM, RAM, or I/O devices


To do so, connect LA to address and data signals and RE/ signal on the ROM
(or RAM)
If triggering is on rising edge of RE/ pin, address and data signals will be
captured
Output of LA, called trace, is stored for later analysis see Fig 10.18
LA can be triggered on unusual event occurrences, then capture signals

therefrom especially for debugging purposes (e.g., writing data to wrong


address, tracking a rarely occurring bug, filtering signals for select devices or
events)
LA cant capture all signals, e.g., on fetch from caches, registers, un-accessed
memory

10.0 DEBUGGING TECHNIQUES


10.4 Using Laboratory Tools Hardware-focused 4
In-Circuit Emulators (ICE)
Replaces target microprocessor in target circuitry (with some engineering)
Has all the capabilities of a software debugger
Maintains trace, similar to that of an LAs
Has overlay memory to emulate ROM and RAM for a specified range of

address within the ICE (rather than the systems main ROM or RAM)
facilitates debugging
ICE v. LA
LAs have better trace and filtering mechanism, and easier to detail and find problems
LAs run in timing mode
LAs work with any microprocessor ICE is microprocessor-specific
LAs support many but select signals to attach, ICE requires connecting ALL signals
ICE is more invasive

10.0 DEBUGGING TECHNIQUES


10.4 Using Laboratory Tools Hardware-focused 5
Hardware Peculiarities that Make Debugging Difficult
Inter-pin distances/intervals for attaching probes getting smaller
Providing sockets for debugging hardware simply increases product size
ASICs encase signals that are hard to probe and track using LAs or ICEs
Use of RISC architectural designs makes it difficult to track when read/write

happen in on-board (microprocessor) caches different from the external RAM


or ROM
Increasingly necessary to know the lab tool chain as it influences the design
of product

10. DEBUGGING TECHNIQUES

10.4 Using Laboratory Tools Hardware-focused 6


Software-Only Monitors
Monitors allow running an embedded system in the target environment, while

providing debugging interfaces on both the host and target environments


A small portion of the Monitor resides in the target ROM (debugging kernel or
monitor):
The codes receives programs from serial port, network, copies into targets RAM, and

run it with full debugging capabilities to test/debug the programs


Another portion of monitor resides on host provides debugging capability

and communicates with the debugging kernel over serial port or network,
without hardware modifications
Compiled, linked (may be located into Map) code is downloaded from the host
(by the portion on the host) to the target RAM or flash (received by the kernel)
Other designs: ROM Emulator interface and JPAG comm. port on the
target processor
(See Fig 10.19)