I had a task to check whether OpenOCD can program a Spartan 3 series FPGA by means of FTDI-MPSSE-based JTAG adapter. There wasn't any chip available in my hands, so I had to experiment with existing hardware. I decided to solder the FTDI-based adapter to a Basys2 development board. The board has an internal JTAG programmer based on AT90USB162. Flashing firmware on this microcontroller during assembly stage requires accessing in-system programmer (ISP) connector. Here is the schematics. Luckily, three of the JTAG pins are the same as the ISP pins:
However, TMS pin is not there. By tracing the routes on the PCB, I found where TMS's route changes the layer to the outermost one:
My soldering skills are not really good, but I could solder a tiny red cable to the TMS pin:
Now we have all the pins necessary to connect an external JTAG adapter. I used a UM232H break-out board which has FT232H chip on it. This chip has a single USB-to-UART converter and an MPSSE engine which implements JTAG protocol. By putting it on a breadboard I connected the following pins to enable self-powering mode and ensuring proper voltage levels:
Then I connected Basys2's JTAG pins to the breadboard:
Basys2 has to be connected to the computer, since the power is taken from the USB port. Same goes for UM232H, so two boards are connected only using GND, TMS, TCK, TDI and TDO pins.
Basys2's JTAG Chain
Here is the JTAG chain of the Digilent Basys2 FPGA board:
The first IC (xc3s100e) is the actual FPGA chip from the Spartan 3E family. The second chip (xcf02s) is a flash memory (PROM). Let's read the ID codes of both chips using original proprietary software, called Digilent Adept Runtime and Digilent Adept Utilities. I am using Arch Linux, so let's install the software first and read the ID codes:
1 2 3 4 5 |
[johndoe@ArchLinux]% yaourt -S digilent.adept.runtime digilent.adept.utilities [johndoe@ArchLinux]% djtgcfg init -d Basys2 Initializing scan chain... Found Device ID: f5045093 # PROM, XCF02S Found Device ID: 11C10093 # Spartan 3E, XC3S100E |
These values of the ID code register will used as a reference to comparing ID codes retrieved using UrJTAG, OpenOCD and xc3sprog.
Reading ID Codes Using UrJTAG
Now let's play with UrJTAG. Firstly, install it from AUR:
1 |
[johndoe@ArchLinux]% yaourt -S urjtag-git |
For each chip the chain, JTAG-specific instructions and properties of special registers including BSR (boundary scan register) are provided in BSDL files. These files are absolutely necessary for UrJTAG and they can be retrieved from the vendor's website or from the Xilinx ISE installation. If you have Xilinx ISE already installed, check out the "xc3s100e.bsd" file located at "$XILINX_ISE_PATH/spartan3e/data/" and "xcf02s.bsd" file located at "$XILINX_ISE_PATH/xcf/data/", where $XILINX_ISE_PATH is the installation path, e.g. "/opt/Xilinx/14.7/ISE_DS/ISE/". Create a "Basys2_BSDL" directory and copy BSDL files to it:
1 2 3 4 |
[johndoe@ArchLinux]% export XILINX_ISE_PATH="/opt/Xilinx/14.7/ISE_DS/ISE/" [johndoe@ArchLinux]% mkdir Basys2_BSDL [johndoe@ArchLinux]% cp $XILINX_ISE_PATH/spartan3e/data/xc3s100e_cp132.bsd ./Basys2_BSDL [johndoe@ArchLinux]% cp $XILINX_ISE_PATH/xcf/data/xcf02s.bsd ./Basys2_BSDL |
Connect UM232H board to USB, and make sure that it is recognized:
1 2 |
[johndoe@ArchLinux]% lsusb -d 0403:6014 Bus 001 Device 013: ID 0403:6014 Future Technology Devices International, Ltd FT232H Single HS USB-UART/FIFO IC |
Now run "jtag" and execute the following commands interactively:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
[johndoe@ArchLinux]% jtag UrJTAG 0.10 #2052 Copyright (C) 2002, 2003 ETC s.r.o. Copyright (C) 2007, 2008, 2009 Kolja Waschk and the respective authors UrJTAG is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. There is absolutely no warranty for UrJTAG. warning: UrJTAG may damage your hardware! Type "quit" to exit, "help" for help. jtag> cable ft2232 vid=0x0403 pid=0x6014 Connected to libftd2xx driver. jtag> bsdl path Basys2_BSDL jtag> detect IR length: 14 Chain length: 2 Device Id: 11110101000001000101000010010011 (0xF5045093) Filename: Basys2_BSDL/xcf02s.bsd Device Id: 00010001110000010000000010010011 (0x11C10093) Filename: Basys2_BSDL/xc3s100e_cp132.bsd jtag> print chain No. Manufacturer Part Stepping Instruction Register ------------------------------------------------------------------------------------------------------------------- 0 XCF02S BYPASS BYPASS * 1 XC3S100E BYPASS BYPASS jtag> instruction IDCODE jtag> shift ir jtag> shift dr jtag> dr 00010001110000010000000010010011 (0x11C10093) jtag> part 0 jtag> print chain No. Manufacturer Part Stepping Instruction Register ------------------------------------------------------------------------------------------------------------------- * 0 XCF02S IDCODE DIR 1 XC3S100E IDCODE DIR jtag> instruction IDCODE jtag> shift ir jtag> shift dr jtag> dr 11110101000001000101000010010011 (0xF5045093) jtag> |
UrJTAG scans BSDL files, reads all opcodes and register names and automatically substitutes them when you run instruction for a specified part (chip). For example, when part "1" was selected (XC3S100E), UrJTAG substituted instruction IDCODE with 0x09 (see the xc3s100e_cp132.bsd file). For part "0", it substituted it with 0xFE.
Reading ID Codes Using OpenOCD
Open On-Chip Debugger (OpenOCD) is a powerful tool which is used to debug various chips. In order to run it with the UM232H adapter we need to specify adapter details in a configuration file. Firstly, create a directory with the name "OpenOCD":
1 |
[johndoe@ArchLinux]% mkdir OpenOCD |
Inside this directory, create two text files with the following content. The first file with the name "FT232H.cfg" is for the adapter:
1 2 3 4 5 6 7 8 9 |
# This is the content of FT232H.cfg file # ------------------------------------ interface ftdi ftdi_vid_pid 0x0403 0x6014 ftdi_layout_init 0x0088 0x008b adapter_khz 6000 transport select jtag ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400 ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800 |
The second file with the name "Basys2.cfg" contains expect ID codes for our chips in the chain:
1 2 3 4 5 6 7 |
# This is the content of Basys2.cfg file # ------------------------------------ # Test Access Port: PROM XCF02S jtag newtap prom tap -irlen 8 -expected-id 0xf5045093 # Test Access Port: Spartan3E XC3S100E FPGA jtag newtap spartan3e tap -irlen 6 -expected-id 0x11c10093 |
Now start the OpenOCD server with the newly created files:
1 2 3 4 5 6 7 8 9 10 11 |
[johndoe@ArchLinux]% openocd -f OpenOCD/FT232H.cfg -f OpenOCD/Basys2.cfg Open On-Chip Debugger 0.10.0 Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html adapter speed: 6000 kHz xc3s_get_dna Info : clock speed 6000 kHz Info : JTAG tap: prom.tap tap/device found: 0xf5045093 (mfg: 0x049 (Xilinx), part: 0x5045, ver: 0xf) Info : JTAG tap: spartan3e.tap tap/device found: 0x11c10093 (mfg: 0x049 (Xilinx), part: 0x1c10, ver: 0x1) Warn : gdb services need one or more targets defined |
Both of the devices are recognized and their ID codes match the expected ones. Now open a second terminal and login to the OpenOCD server as a client:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
[johndoe@ArchLinux]% telnet localhost 4444 Trying ::1... Connection failed: Connection refused Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Open On-Chip Debugger > scan_chain TapName Enabled IdCode Expected IrLen IrCap IrMask -- ------------------- -------- ---------- ---------- ----- ----- ------ 0 prom.tap Y 0xf5045093 0xf5045093 8 0x01 0x03 1 spartan3e.tap Y 0x11c10093 0x11c10093 6 0x01 0x03 > irscan spartan3e.tap 0x09 > drscan spartan3e.tap 0x20 0 11C10093 > irscan prom.tap 0xFE > drscan prom.tap 0x20 0 F5045093 > |
Low-level operator "irscan" is responsible for selecting opcode, setting other devices to bypass mode and shifting the opcode through the chain to a target device. OpenOCD cannot read BSDL definitions, so we have to provide all the instructions manually. Let's look inside of the xc3s100e_cp132.bsd file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
attribute INSTRUCTION_OPCODE of XC3S100E_CP132 : entity is "EXTEST (001111)," & "SAMPLE (000001)," & "PRELOAD (000001)," & -- Same as SAMPLE "USER1 (000010)," & -- Not available until after configuration "USER2 (000011)," & -- Not available until after configuration "CFG_OUT (000100)," & -- Not available during configuration with another mode. "CFG_IN (000101)," & -- Not available during configuration with another mode. "INTEST (000111)," & "USERCODE (001000)," & "IDCODE (001001)," & "HIGHZ (001010)," & "JPROGRAM (001011)," & -- Not available during configuration with another mode. "JSTART (001100)," & -- Not available during configuration with another mode. "JSHUTDOWN (001101)," & -- Not available during configuration with another mode. "BYPASS (111111)," & "ISC_ENABLE (010000)," & "ISC_PROGRAM (010001)," & "ISC_NOOP (010100)," & "ISC_READ (010101)," & "ISC_DISABLE (010110)"; |
The IDCODE instruction has value "0b001001" = 0x09, so
1 |
irscan spartan3e.tap 0x09 |
means to consider only spartan3e.tap device (others are bypassed) and shift IDCODE instruction through the chain. Once this is done, the TAP select IDCODE register as the data register and we can shift 32 bits (0x20 in hexadecimal) through the chain to retrieve the content of the data register and set TAP of the device to state "0" (not sure which one it is):
1 |
drscan spartan3e.tap 0x20 0 |
Reading ID Codes Using xc3sprog
Open-source x3sprog tool is capable of flashing *.bit files, reading DNA and writing to a connected SPI Flash. Install it from AUR:
1 |
[johndoe@ArchLinux]% yaourt -S xc3sprog-svn |
Reading ID codes is easy:
1 2 3 4 5 6 7 8 9 10 11 |
[johndoe@ArchLinux]% xc3sprog -c ft232h -j XC3SPROG (c) 2004-2011 xc3sprog project $Rev: 785 $ OS: Linux Free software: If you contribute nothing, expect nothing! Feedback on success/failure/enhancement requests: http://sourceforge.net/mail/?group_id=170565 Check Sourceforge for updates: http://sourceforge.net/projects/xc3sprog/develop JTAG loc.: 0 IDCODE: 0x11c10093 Desc: XC3S100E Rev: A IR length: 6 JTAG loc.: 1 IDCODE: 0xf5045093 Desc: XCF02S Rev: O IR length: 8 |