Beginner's Corner - In-Circuit-Emulators
 |
For hints, tricks and ideas about better ways to build embedded systems, subscribe to The Embedded Muse, a free biweekly e-newsletter. No hype, just down to earth embedded talk. 23,000 other engineers subscribe. It takes just a few seconds (all we need is your email address, which is shared with absolutely no one) to subscribe to the Embedded Muse. |
Beginner's Corner - In-Circuit-Emulators
Embedded systems pose unique debugging challenges. With
neither terminal nor display (in most cases) there's no natural way to probe
these devices, to extract the behavioral information needed to find what's
wrong. This magazine is filled with ads from vendors selling quite a wide
variety of debuggers; all let us connect an external computer to the system
being debugged to enable single stepping, breakpoints, and all of the debug
resources enjoyed by programmers of desktop computers.
The In-Circuit Emulator (ICE) is one of the oldest embedded
debugging tools, and is still unmatched in power and capability. It's the only
tool that substitutes it's own internal processor for the one in your target
system. Via one of a number of hardware tricks the emulator can monitor
everything that goes on in this on-board CPU, giving you complete visibility
into the target code's operation. In a sense the emulator is a bridge between
your target and your PC, giving you both an interactive terminal peering deeply
into the target, while providing a rich set of debugging resources.
Years ago the ICE physically replaced the target processor.
Users extracted the CPU from its socket, plugging the emulator's cable in
instead. Today we're usually faced with a soldered-in surface mounted chip, so
connection strategies are more difficult. Some emulators come with an adapter
that clips over the SMT processor, tri-stating the device's core which is then
replaced by the ICE's own CPU. In other cases the emulator vendor provides
adapters that can be soldered in place of the target CPU. As chip sizes and lead
pitches shrink the range of connection approaches goes up; rest assured that
connecting the emulator is usually the most difficult and frustrating part of
using such devices. Add at least a few days to your schedule to surmount these
difficulties. Work closely with the vendors, all of whom are connections experts
anxious to share their knowledge.
Like all debuggers the emulator's most fundamental
resource is target access - the ability to examine and change the contents of
registers, memory and I/O. However, since the ICE replaces the CPU it generally
does not need working hardware to provide this capability. This makes the ICE by
far the best tool for troubleshooting new or defective systems. For example, you
can repeatedly access a single byte of RAM or ROM, creating a known and
consistent stimulus to the system that is easy to track using an oscilloscope.
Breakpoints are another important debugging resource; these
give you the ability to stop your program at precise locations or conditions
(like "stop just before
executing line 51"). Emulators also use breakpoints to implement
single stepping, since the processor's single step mode, if any, isn't
particularly useful for stepping through C code.
There's an important distinction between the two types of
breakpoints used by different sorts of debuggers: software breakpoints
(generally found on BDMs, software-only monitors, and the like) work by
replacing the destination instruction by a software interrupt or similar
instruction. Clearly, it's impossible to debug code in ROM with these.
Emulators generally offer a huge number of hardware breakpoints, which
use the unit's internal magic to compare the break condition against the
execution stream. Hardware breakpoints work in RAM or ROM, Flash or even unused
address spaces.
Complex breakpoints let us ask deeper questions of
the tool. A typical condition might be: "Break
if the program writes 0x1234 to variable buffer, but only if function get_data
was called first". Some software-only debuggers (like that supplied
with Visual C++) offer similar power, but must essentially interpret the program
at a snail-like pace while watching for the trigger condition. Emulators
implement complex breakpoints in hardware, so impose (in general) no performance
penalty.
ROM and to some extent Flash memory for program storage
leads to debugging difficulties since it's hard to impossible to download code
into these. During a typical debug session we might change and redownload code
many times an hour so it's important to have RAM-like program memory. The
ICE's emulation memory is high speed RAM inside of the emulator itself that
maps logically in place of your system's ROM. Download changes at will.
Many ICEs have programmable guard conditions for accesses
to both the emulation and target memory. Thus, it's easy to break when, say,
the code wanders off and tries to write to program space, or attempts any sort
of access to unused addresses.
Nothing prevents you from mapping emulation memory in place
of your entire address space, so you can actually debug much of the code with no
working hardware. Why wait for the designers! who will likely be late anyway?
Operate the emulator stand-alone (without the target) and start debugging code
long before engineering delivers prototypes.
Real time trace is one of the most important emulator
features, and is one practically unique to this tool. Trace captures a snapshot
of your executing code to a very large memory array, at full speed. It saves
thousands to hundreds of thousands of machine cycles, displaying the addresses,
the instructions, and transferred data. The emulator and its supporting software
translates raw machine cycles to assembly code or even C/C++ statements, drawing
on your source files and the link map for assistance.
Trace is always accompanied by sophisticated triggering
mechanisms. It's easy to start and stop trace collection based on what the
program does. An example might be to capture every instance of the execution of
an infrequent interrupt service routine. You'll see everything the ISR does,
with no impact on the real time performance of the code.
Emulators generally use no target resources. They don't
eat your stack space, memory, or effect the code's execution speed. This
"non-intrusive" feature is critical for dealing with real-time systems.
Be aware, though, that emulators face challenges that may
change the nature of the market and the products. As processors shrink it's
awfully hard to connect anything to those whisker-thin package leads. Vendors
offer all sorts of adapter options, some of which work better than others.
Skyrocketing CPU speeds create profound difficulties. At
100 MHz each machine cycle takes a mere 10 nsec; even an 18 inch cable between
your target and the ICE starts to act as a very complex electrical circuit
rather than a simple wire. One solution is to shrink the emulator, putting all
or most of the unit near the target socket. As speeds increase, though, even
this option imposes tough electrical problems.
Page through the ads in this magazine and you'll see a
wide range of emulators for 8 and 16 bit processors, the arena where speeds are
more tractable. Few ICEs exist for high end processors due to the immense cost
of providing fast emulation memory and a reliable yet speedy connection.
Oddly, one of the biggest user complaints about emulators
is their complexity of use. Too many developers never progress beyond the most
basic of ICE features. Sophisticated triggering and breakpoints invariably means
rather complex setups. Figure on reading the manual and experimenting a bit; the
up-front time will pay off big time later in the project. Can you imagine the
poor word processor user who tediously edits the same change dozens of times!
because he never learned search-and-replace? Time spent in learning tools always
gets the project done faster.
Resources:
ICE Technology Unplugged - http://www.embedded.com/1999/9910/9910sr.htm
|