Anda di halaman 1dari 179

EMBEDDED SYSTEMS (A1430)

UNIT-III & IV RTOS


J. KRISHNA CHAITHANYA
Associate Professor
j.krishnachaitanya@vardhaman.org

Department of Electronics and Communication 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, alreadydebugged 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 pre-emptive 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 push-button), 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 non-atomicity)?

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
data and result depends on who
runs precisely when are called race
conditions.
20

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


resource that the other needs while waiting for
the other process to release its resource.

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
Control access to multiple resources, thus
assuming a range of nonnegative values.
24

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

27Figure

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


Include File(s) <sys/types.h>
<sys/ipc.h>
<sys/sem.h>
Summary

Return

Manual Section

int semget (key_t key,intnsems,int semflg);

Success

Failure

Sets errno

The semaphore identifier

-1

Yes

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)
(See Fig 6.18)

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 Task2(void)
{

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

!! Other things that need to be done soon.


}

void vLogError(int iErrorType)


{
AddToQueue(iErrorType);
}
static int cErrors;
void ErrorTask(void)
{
int iErrorType;
while(FOREVER)
{
ReadFromQueue(&iErrorType);
++cErrors;
!! Send cErrors and iErrorType out on network
}
}

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] =

pTemperatures[0] =
pTemperatures[1] =

iTemperatures[1] =
OSQPost(pOseQueueTemp,

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

(void*)iTemperatures);
}
}

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.
2.
3.

More than task can block waiting


The events occurs
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);

NOTE-: The function malloc is used to allocate a certain amount of memory


during the execution of a program. The malloc function will request a block of
memory from the heap. If the request is granted, the operating system will
reserve the requested amount of memory. When the amount of memory is not
needed anymore, you must return it to the operating system by calling the
function free.

To allocate space for an array in memory you use calloc()


To allocate a memory block you use malloc()
To reallocate a memory block with specific size you use realloc()
To de-allocate previously allocated memory you use free()

Interrupt Routines in an RTOS Environment

Interrupt Routines must not call any RTOS functions thatMight block the caller.
2. Might cause the RTOS to switching tasks without fair
warning
1.

Interrupt Routines in an RTOS Environment


ISR

RTOS

TaskHigh

Send message
to mailbox

TaskLow

Time

Fig. 7.14 How Interrupt Routines Should Work

Interrupt Routines in an RTOS Environment

ISR

RTOS

TaskHigh

Send Message
to mailbox

TaskLow

Time

Fig. 7.15 What Would Really Happen

Interrupt Routines in an RTOS Environment


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

Return

RTOS

TaskHigh

Send Message
to mailbox

TaskLow

Time

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.
ISR
Jump or call
RTOS

TaskHigh

Enter
interrupt
routine.

Send Message
to mailbox

TaskLow

Time

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.
RTOS schedler goes to TaskHigh
instead of finishing low-priority ISR.

High-priority
ISR

Low-priority
ISR
RTOS

TaskHigh

TaskLow

High-priority
interrupt
occurs.

Send Message
to mailbox

Time

Fig. 7.18 Nested Interrupts and the RTOS

BASIC DESIGN OF AN EMBEDDED SOFTWARE 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 assumes the RTOS

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

BASIC DESIGN OF AN EMBEDDED SOFTWARE USING RTOS


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
9600-bps 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 mproc 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, YESUML,
Testing and debugging ES requires specialized hardware tools and software
tools and techniques

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)

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)

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)

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
- More tasks means frequent calls to the RTOS functions (major overhead adds up)

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)

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

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!

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

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)

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?

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)

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 overflowdetection 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 noncontentious 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)

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

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

[pt]

DT
PT

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 printformatting 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!

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

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]
(See Fig 8.13)

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 Tn units of time
Each task worst case execution time, Cn units of time and deadline of Dn
Assume task switching time is 0 and non-blocking on semaphore
Each task has priority Pn
Question: SCn = S(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

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 nesting-level, 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

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: trade-off 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 assembly lang

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!

EMBEDDED SOFTWARE DEVELOPMENT TOOLS


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 cross-assembled, linked
(into target processor instruction set) and located into the target

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)

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 resolved, guided by
locating-tools and directives, prior to running the code (See Fig 9.3 and Fig 9.4)

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

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

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 cross-compilers (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

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)

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)

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)

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

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

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)

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!

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");
}

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 works [where vTestMain() pretends to be

the hardware sending the chars to vHandleByte()]

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;
}
.
.
}

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 inputscript and output lines into an output file
The commands in the script cause the scaffold to call routines in the B (sw-indp) component -- See Fig 10.5 and
Fig 10.6 for the cordless bar-code scanner

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 hardware-independent 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

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 scaffold 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

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)

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)

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 emulators

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)

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

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)

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

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

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

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)

Anda mungkin juga menyukai