博客首页 | 排行榜 |

设计我最赞的博客

个人档案
博文分类
构建一个USB的GPIO口(Construct a USB GPIO Pod (Part 2))  2009-05-12 14:28
在这个系列文章的第一部分中,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 OVERVIEW
The 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 MODULE
To 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 CIRCUIT
I 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 DEMO
Now 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 USES
You 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.

RESOURCES
Bin7 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.

SOURCE
R8C Microcontroller
Renesas Technology Corp. | www.renesas.com/en/r8ctiny
WebPack Software and XC9500 family of CPLDs
Xilinx, Inc. | www.xilinx.com
类别:嵌入式开发 |
上一篇:二十一世纪的磁盘操作系统(DOS in the 21st Century) | 下一篇:智能铅酸电池电量计(Smart Lead-Acid Battery Meter)
以下网友评论只代表其个人观点,不代表本网站的观点或立场