All of the discussion so far has revolved around asynchronous
inputs, when the clock and data are unrelated in time. Be wary of
anything not slaved to the processor's clock. Interrupts are a
notorious source of problems.
If caused by, say, someone pressing a button, be sure that the
interrupt itself, and the vector-generating logic, don't violate the
processor's set-up and hold times.
However, in computer systems most things do happen synchronously. If
you're reading a timer that operates from the CPU's clock, it is
inherently synchronous to the code. From a metastability standpoint
it's totally safe.
Bad design, though, can plague any electronic system. Every logic
component takes time to propagate data; when a signal traverses many
devices the delays can add up significantly. If the data then goes to a
latch it's quite possible that the delays may cause the input to
transition at the same time as the clock. Instant metastability.
Designers are pretty careful to avoid these situations, though. Do
be wary of FPGAs and other components where the delays vary depending
on how the software routes the device. In addition, when latching data
or clocking a counter it's not hard to create a metastability problem
by using the wrong clock edge. Pick the edge that gives the device time
to settle before it's read.
What about analog inputs? Connect a 12 bit A/D converter to two 8
bit ports and we'd seem to have a similar problem: the analog data can
wiggle all over, changing during the time we read the two ports.
However, there's no need for an input capture register because the
converter itself generally includes a "sample and hold" block, which
stores the analog signal while the A/D digitizes. Most A/Ds then store
the digital value till we start the next conversion.
Other sorts of inputs we use all share this problem. Suppose a robot
uses a 10 bit encoder to monitor the angular location of a wrist joint.
As the wrist rotates the encoder sends back a binary code, 10 bits
wide, representing the joint's current position. An 8 bit processor
requires two distinct I/O instructions—two byte-wide reads—to get the
data. No matter how fast the computer might be there's a finite time
between the reads during which the encoder data may change.
The wrist is rotating. A "get_position" routine reads 0xff from the
low part of the position data. Then, before the next instruction, the
encoder rolls over to 0x100. "get_position" reads the high part of the
data—now 0x1—and returns a position of 0x1ff, clearly in error and
perhaps even impossible.
This is a common problem, handling input from a two-axis controller.
If the hardware continues to move during our reads, then the X and Y
data will be slightly uncorrelated, perhaps yielding impossible
results.
One friend tracked a rare autopilot failure to the way the code read
a flux-gate compass, whose output is a pair of related quadrature
signals. Reading them at disparate times, while the vessel continued to
move, yielded impossible heading data.
Next in Part 4: Dealing with
interrupt latency
To read Part 1 in this series, go to Reentrancy, atomic variables and recursion.
To read Part 2 in this series, go to Asynchronous Hardware/Firmware
Jakob
Engblom (jakob@virtutech.com)
is technical marketing manager at
at Virtutech.
He has a MSc in computer science and a PhD in Computer Systems from
Uppsala University, and has
worked with programming tools and simulation tools for embedded and
real-time systems since 1997.
He was a contributor of
material to "The Firmware Handbook," edited
by Jack Ganssle, upon which this series of articles was based and
printed
with permission from Newnes, a division of Elsevier.
Copyright 2008. For
other publications by Jakob Engblom, see www.engbloms.se/jakob.html.