在这个系列文章的第一部分中,DJ呈现了一个通用目标输入输出模块(GPIO),它能够插入一个USB接口。现在他将描述如何下载一个JTAG编程应用以及如何为一个CPLD电路进行编程。
USB JTAG Module
In the first part of this article series, DJ presented a
general-purpose input/output (GPIO) pod that can plug into a USB
port. Now he describes how to download a JTAG programming
application and program a CPLD circuit.
As I explained in the first part of this article series, you can
use a general-purpose input/output (GPIO) module that plugs into a
USB port on your computer to make up for the lack of a parallel
port. While the flexibility of having a microcontroller in this pod
enables you to do many things, the real advantage is that you can
put a lot of logic—even entire applications—in the microcontroller.
This month, I’ll explain how to download an entire JTAG programming
application into the module. I’ll then describe how to use it to
program a simple CPLD circuit from a Verilog program from my Linux
workstation.
There are commercial devices that let you program JTAG devices over
USB from Linux. Then again, there are devices that do a lot of the
things you learn to do in Circuit Cellar, but it’s no fun if you
don’t do it yourself, right? The module I built is a pure
do-it-yourself solution. You can use it for more than just this one
task, which saves money in the long run, too.
JTAG OVERVIEWThe Joint Test Action Group (JTAG) is a specification created for
testing densely populated circuit boards. In addition to testing,
many chips have extended their JTAG interface to include other
operations, such as rogramming or debugging. The JTAG interface
consists of five logic signals: Reset (optional), Clock, Mode
Select, Data In, and Data Out. The signals are abbreviated TRST,
TCK, TMS, TDI, and TDO. There are three types of operations, which,
in combination, yield all the operations the chip defines.
Not all chips include a TRST pin because it isn’t always needed.
When it is included, you can reset the chip’s JTAG module by
pulsing TRST low. When it is not present, the JTAG module can be
reset by clocking in a reset command to the TMS port. Note that
this doesn’t reset the chip, just the JTAG interface.
The TMS pin controls a state machine, which selects the mode in
which the interface operates. Chips that support JTAG use the same
state machine, so a project with multiple JTAG chips can tie all
the JTAG interfaces together—TRST, TCK, and TMS (in parallel) and
TDI and TDO (chained in series)—and control all the chips at once.
The state machine is designed so that a reset sequence of clocking
five 1 bits on TMS always returns it to the idle state, regardless
of where it started. Other combinations of clocked 1 and 0 bits
maneuver the state machine into other states, where it can stay as
long as the TMS bit remains low. Two of these states are key. One
lets you shift bits into the instruction register via TDI (and
shift its previous value out via TDO). The other lets you shift
bits through the data register. In most chips, the instruction
register selects which data registers (out of many) are used and
allows a wide range of functionality.
After a register is selected (either the instruction register or
one of the data registers), you can access it through the TDI and
TDO pins. The state machine first loads the register with data from
elsewhere on the chip. Then, much like a SPI port, the old data is
clocked out of TDO while new data is clocked into TDI. Once this is
done, the state machine stores the register’s data elsewhere in the
chip, performing whichever action is indicated.
Aside from a few well-defined common functions, each chip has its
own set of registers and functions that it documents. However, they
all follow the standard JTAG interface for accessing those
registers and functions. Chip manufacturers will often provide a
configuration file that describes these functions. Software that
uses JTAG to talk to these chips will often read these
configuration files to understand how to access these functions.
When multiple devices are in the JTAG chain (TDO chained to TDI),
programming utilities can use the configuration for the chips
they’re not programming to learn how to bypass those chips and
access the one they’re interested in.
Do you really need to know all this to use JTAG? Not really. Aside
from telling inputs from outputs, you don’t even need to know this
to port the programming application to the pod. However, it helps
you understand that there is a lot of bit twiddling going on.
JTAG POD MODULETo simplify connections to the project, I created a JTAG
programming module for the USB-GPIO pod (see Photo 1). Aside from
bringing out the specific JTAG signals I needed, there are two
other functions this module provides.
Photo 1—A closeup of the JTAG adapter. Most of the complexity is in the
software; the adapter serves to manage the wiring itself. My
project doesn’t use TRST, so it is left unconnected.
First, I added a couple of LEDs to provide some visual feedback of
what the JTAG protocol is doing. After all, I can’t have a project
without blinky lights, and the LED on the pod itself is used to
give feedback about the hardware flow control used by the serial
port software. Second, I needed to be able to monitor the target
circuit’s supply voltage (see Figure 1).
Figure 1—The JTAG adapter module is simple. R5 and R6 feed half the target
VCC to P1.0, which is an ADC input on the pod. The rest is just
blinky lights and connections.
Because the pod can run at either 3.3 or 5 V, and the target
circuit can run at any voltage, I used one of the pod’s ADCs to
compare the target’s voltage with the pod’s voltage. The reference
voltage is set by the pod to its own supply voltage. I used a pair
of resistors to divide the target’s supply voltage in half and feed
it into the ADC. If the voltages match, the resulting ADC value
should be about 128 (on a scale of 0–255, or an 8-bit conversion).
If the pod is running at 3.3 V and the target at 5 V, the result
will be 5/3.3 times higher, or around 194. If the voltages are the
other way, the result will be 3.3/5 times as high, or around 84. If
the target is not yet powered up, the result will be zero. While
the R8C/20 does not have 5-V-tolerant inputs when running at 3.3 V,
this at least enables me to find out quickly if the voltages are
mismatched. Mostly, it just checks to see if the target is powered
up at all, protecting the target from damage.
The pod’s software is a port of the JTAG programming application,
as provided in Xilinx’s 2007 application note titled “Xilinx
In-System Programming Using an Embedded Microcontroller” (XAPP058).
I used the core files as-is, but wrote my own version of ports.h
and ports.c to correspond to my pod’s hardware. I had to provide
two interfaces.
First, I had to provide a source for the CPLD data. This data was
created by the Xilinx WebPack utility, which produces (among other
things) a Xilinx Serial Vector Format (XSVF) file. The file is a
set of binary commands describing how to program the CPLD. The host
application feeds this data across the USB link, so the port on the
pod has a serial UART driver that reads this data.
The second interface is the I/O for the JTAG signals. I simply
mapped these to GPIO signals on port 3. Conveniently, I’d used the
SPI pins to allow for future use of the SPI peripherals on the R8C
to drive the JTAG interface even faster.
At first, I ported XAPP058 to run on the host, using a simple
serial protocol to toggle the output bits and read the input bits.
It was slow, clocking at only a few kilohertz (one serial byte per
logic pin change). By running the application on the pod and
sending only the XSVF data across the USB link, I avoided the
overhead. The serial port was configured to support full hardware
flow control, so no special host application was required. I could
use any terminal emulator with a “send raw file” option. However, I
wrote a small utility to automate the communication. It resets the
pod, which gives control to the pod’s initialization function. That
let me check that the power supplies match. Once they matched, I
sent a command to turn control over to the XSVF application, and
started sending the .xsvf file across. When the programming was
done, control returned to my pod function and it sent the
completion status to the host utility.
How much of a difference does it make? Running the application on
the host and sending each change output or read input over the USB
interface turns out to be expensive. Programming the XC9500XL,
which has only a 28-KB bit file, takes almost 8 minutes! Varying
the pod’s CPU clock, or the data rate between the FT232R and the
R8C, has almost no effect on this time. It’s all USB packet
overhead for all those bit changes. Moving the application to the
pod’s CPU makes the bit twiddling fast, especially if I inline the
pod-specific instructions, which saves even the function call
overhead. By avoiding the overhead, the programming time is reduced
to 12 s, about 40 times faster.
SAMPLE CPLD CIRCUITI got the idea for the circuit from a Usenet posting. The original
poster was asking for the best way to turn an 8-bit binary number
(0 – 255) into three seven-segment digits (000 through 256).
Although there were other suggestions involving ROMs or special TTL
chips, I suggested an inexpensive CPLD. At that point, it occurred
to me that such a project would be a useful way to teach myself
about CPLDs and Verilog. The project was well defined —eight binary
inputs representing a number from 0 to 255, and 21 logic outputs to
directly drive three seven-segment LED displays. Other pins would
be used for other features if I had space in the chip.
After some searching, I chose the Xilinx XC9500 family of CPLD
chips.They were available with a variety of voltage requirements,
packages, and logic cell counts. Also, they were inexpensive. The
smallest member of the family was only $1 per chip and available
online. It turned out that the smallest chip wasn ’t big enough for
this project, so I chose the second smallest —the XC9572XL. It is a
3.3-V part with 72 logic cells that ’s available in a 44-pin TQFP.
While the definition of logic cell varies from manufacturer to
manufacturer, in general each cell includes some form of flip flop
and a wide range of combinatorial logic (AND and OR gates,
multiplexers, and so on). The program you download into the chip
decides which gates and other signals are connected to each other.
Another advantage of this family is that the program is stored in
the chip itself, so no other supporting logic is required once the
chip is programmed.
I chose Verilog to describe the circuit I wanted, again, as a way
to learn Verilog. Alternatives to Verilog are VHDL and schematics,
but Verilog was simpler for this project than VHDL and more
powerful than schematics. The full Verilog sources for this project
are posted on the Circuit Cellar FTP site. There are three source
files, which correspond to two independent modules and the logic
that ties them together. Each source file defines one or more logic
blocks in the form of modules. Like software functions, each logic
block has a set of parameters that represent its inputs and
outputs. Unlike software functions,these inputs and outputs are
electrical connections, representing wires. To use one logic block
in another module, you instantiate a copy of the block in your own
logic. When you do this, you give each instance its own name and
specify which signals in your module will connect to which inputs
and outputs in that instance.Think of modules as a definition of a
chip, and instantiating one as buying a chip to use.
First, I needed a way of decoding the binary number into a
three-digit decimal number. In bcd.v there is a large case table,
with one entry for each input combination. Each case describes the
three output digits. I actually used a script to generate this,
rather than type it all in by hand, but at least I didn’t need to
try to figure out the logic behind each output bit—the Xilinx tools
did it all for me.
Next, I needed a way to map the binary encoding of a digit into a
seven-segment encoding for that digit. There are two of these in
sevenseg.v, as the hundreds digit has only three possible values.
Adding a smaller table for that digit reduces the amount of
internal logic needed. Again, I used a case table to describe each
combination, with default entries (not all binary inputs are valid)
of “don’t care” to help reduce the logic needed.
The last module is the top-level module for this chip,
unimaginatively named top.v (see Listing 1). The other two modules
had inputs and outputs, but they existed only for referencing from
other modules. For the top-level module, the inputs and outputs are
the pins on the chip. There are eight inputs for the binary number,
and 21 outputs for the LED segments. There were enough pins and
logic cells left over to add a pair of latch enable pins, two types
of blanking (display and leading zero), and an output polarity
control pin.
While Verilog looks like generic software programming code, it’s
describing hardware. You can follow the interconnections in top.v,
as I coded the logic blocks from the input pins through to the
output pins. First, I latched the input pins into a register called
ibinh (input binary, held). I connected this register to the BCD
decoder b0, returning the three digits as bcd2, bcd1, and bcd0.
Next, I added logic to detect when leading zeros were present (lz2,
lz1—the third digit is always on) and to compute the blanking
signals blank2 through blank0.
I also connected (note that I write “connected” instead of
“passed”—I’m talking about wires here) the three BCD values to
three instances of the seven-segment decoder. I used two of the
full decoders and the one partial one for the hundreds digit. The
results of these decoders each have to pass through modules to
determine if they’re inverted, noninverted, or tristated (blanked).
The results of these last modules are connected to the chip’s
output pins. Programmable logic uses a constraint file to determine
which internal signals go to which pins. In this case, bin7.ucf
maps all the pins to their signals. But if your layout is flexible,
you can let the tools choose which pins get which signals based on
the internal layout of the design and how it relates to the
available pins. Some pins, for example, are connected to the chip’s
internal clock grid, and the I/O pins each have an associated logic
cell block that they prefer to be connected to. As long as the chip
permits it, you can even fix board layout problems by going back to
the chip and moving or redefining pins. An added bonus is that you
can migrate the design to a different package just by writing a new
constraint file and rebuilding.
PROGRAMMING DEMONow that I’ve covered all the parts, let’s focus on how they fit
together. I built the CPLD circuit (“the circuit”) on some
protoboard (see Photo 2). I plugged the JTAG adapter module into
the USB pod and wired it into the protoboard, matching TDI to TDI,
TCK to TCK, and so on. I labeled mine to match the pin names, but
keep in mind that if you have to chain two or more devices
together, you connect TDO to TDI, with the pod’s TDI connected to
the first device in the chain, and its TDO to the last.
Photo 2—My CPLD prototype. At the top is a 3.3-V power supply. On the left
are two DIP switches to provide manual input to the CPLD, shown
center-mounted on a DIP adapter. At the right is the LED display,
and above that is the pod with the JTAG adapter module. Having
programmable pins on the CPLD means wiring up the circuit the
easiest way, which can be seen here as short, neat connections.
While the JTAG module connects to the circuit’s VDD bus, it neither
powers the circuit nor draws power from it. The VDD pin on the
module only measures the VDD through a resistor divider and an ADC.
Our CPLD does not use the TRST pin, so I have not connected it to
anything.
The R8C tristates all I/O pins at reset, so it’s relatively safe to
connect the pod to the circuit before you program the pod. If you
haven’t done so already, build the JTAG application and program it
into the pod. This only has to be done once, unless you put some
other application into the pod (see Listing 2). If you haven’t
built the host-side application, build that too. This builds a
small host-side program called xsvf that does nothing but send the
CPLD bitstream to the pod:
$ cd ../../host/xsvf ; make
Many of the pod applications will be built this way—some software
that runs on the pod, and some software that runs on the host. As
this example shows, minimizing the amount of data that needs to go
over the USB bus can yield amazing performance gains.
To build the CPLD image, you’ll need to download and install the
Xilinx WebPACK application. This includes everything you’ll need to
program CPLDs. I used the GUI to do the initial design, and then
wrote a Makefile to automate it. There are additional instructions
on the FTP site; but in a nutshell, compile the Verilog into a
standard intermediate form, compile that file to the specific chip,
and then convert that file to the format needed for programming. In
my case, I used the XSVF format. SVF is a standard vector format,
but it’s a text file. XSVF is a binary format that’s specifically
designed to be easily interpreted by a small application. That
small application is the one I put in my pod. Building the XSVF
file is simple with makefiles:
$ cd ../../cpld ; make
This created a bitstream file bin7.xsvf with binary-encoded
instructions on how to program the CPLD to do what I wanted it to
do. After all the parts were built and the pod was programmed, I
could use it to program the CPLD:
$ sudo ../host/xsvf/xsvf bin7.xsvf
What exactly happened here? Well, the sudo command provided access
to the USB hardware, needed by the FTDI libraries. The xsvf host
program used the FTDI libraries to open a channel to the pod and
take it out of reset, which started the pod’s program. The host
sent a few commands to tell the pod to check the circuit’s VDD and
verify that it matched the pod’s VDD. The host then read the XSVF
bistream file and sent it across the USB line to the pod, which
interpreted those instructions so as to use the JTAG lines to
program the CPLD. Note that the pod and host used hardware flow
control to control the datastream, and the pod had a 256-byte
buffer to hold incoming data.
Once the programming was done, the host program read any diagnostic
text from the pod and printed it, and the pod released the CPLD.
The CPLD, of course, started running the logic design programmed
into it. Once programmed, I could disconnect the pod from the
circuit. Done!
The first time you do all this, there’s a lot of set up. However,
edits to the Verilog need only a make flash command to have the
Makefile build a new bitstream and send it to the CPLD chip. The
Makefile rebuilds whatever is needed and runs the host xsvf program
to send it to the CPLD.
MORE USESYou now know how to use the CPU in the USB GPIO module to offload
processing in order to optimize performance for a task-oriented
purpose. More than just fiddling bits, it enables you to put
intelligence close to your circuit in order to take advantage of
the R8C’s speed and peripherals. I also showed you how the host and
pod programs work together to create smart peripheral modules, like
the JTAG controller. And last, but not least, I described an
example of how a smart pod can be used in a real-life
circuit—programming a CPLD chip.
Can you think of another use for the pod? Experimenting with LCD
interfaces, testing SPI chips, preprogramming I2C EEPROMs—the
possibilities are limited only by your needs!
DJ Delorie (
dj@delorie.com), who has been designing electronic circuits since high school,
earned an ECE degree at Clarkson University. After holding jobs
designing PC motherboards and network management software, he now
writes embedded development tools for Red Hat. DJ is also the
creator of DJGPP and one of the contributors to the gEDA project.
RESOURCESBin7 Project Page,
www.delorie.com/electronics/bin2seven/.
Xilinx, Inc., XAPP058 Source Files,
ftp://ftp.xilinx.com/pub/applications/xapp/xapp058.zip.
———, “Xilinx In-System Programming Using an Embedded
Microcontroller,”
XAPP058, 2007,
www.xilinx.com/support/documentation/application_notes/xapp058.pdf.
SOURCER8C Microcontroller
Renesas Technology Corp. |
www.renesas.com/en/r8ctinyWebPack Software and XC9500 family of CPLDs
Xilinx, Inc. |
www.xilinx.com