Fx2tools
Introduction
Fx2tools is a collection of utilities for Linux and Windows and a custom firmware allowing you to:
- Upload SDCC-generated HEX records directly to an FX2LP chip's RAM and EEPROM
- Backup & restore factory firmware on FX2-based devices (e.g Digilent's excellent Nexys2 FPGA devkit)
- Send arbitrary commands to the chip's control endpoint
- Benchmark bulk writes to the FX2LP
> fx2loader\Release\fx2loader.exe --help
FX2Loader Copyright (C) 2009-2010 Chris McClelland
Usage: fx2loader [-h] [-v <vendorID>] [-p <productID>] <source> [<destination>]
Upload code to the Cypress FX2LP.
-v, --vid=<vendorID> vendor ID
-p, --pid=<productID> product ID
-h, --help print this help and exit
<source> where to read from (<eeprom:<kbitSize> | fileName.hex | fileName.bix | fileName.iic>)
<destination> where to write to (<ram | eeprom | fileName.hex | fileName.bix | fileName.iic>)
> ucm\Release\ucm.exe --help
USB Control Message Tool Copyright (C) 2009-2010 Chris McClelland
Usage: ucm [-ioh] [-f <fileName>] [-v <vendorID>] [-p <productID>] <bRequest> <wValue> <wIndex> <wLength>
Interact with a USB device's control endpoint.
-v, --vid=<vendorID> vendor ID
-p, --pid=<productID> product ID
-i, --in this is an IN message (device->host)
-o, --out this is an OUT message (host->device)
-f, --file=<fileName> file to read from or write to (default stdin/stdout)
-h, --help print this help and exit
<bRequest> the bRequest byte
<wValue> the wValue word
<wIndex> the wIndex word
<wLength> the wLength word
> bulk\Release\bulk.exe --help
Bulk Write Tool Copyright (C) 2009-2010 Chris McClelland
Usage: bulk [-bch] [-v <vendorID>] [-p <productID>] [-e <N>] <fileName>
Write data to a bulk endpoint.
-v, --vid=<vendorID> vendor ID
-p, --pid=<productID> product ID
-e, --endpoint=<N> endpoint to write to
-b, --benchmark benchmark the operation
-c, --checksum print 16-bit checksum
-h, --help print this help and exit
<fileName> the data to send
The Cypress FX2LP is a little USB microcontroller that can do Hi-Speed transfers.
I recently used one of these in a design which I wanted to release under the GPL licence, in the hope that others will help out with it. But the only supported toolchain seems to be the $5000 compiler from Keil, which to me is an unacceptable barrier to entry for someone wishing to contribute. It turns out that the CPU at the core of the FX2LP is that old chestnut the 8051, which is one of the targets supported by the SDCC. Unfortunately there is a lot of library code written by Cypress for the Keil toolchain, which would have to be ported to SDCC before any useful work could be done.
There's where I discovered Dennis Muhlestein's fx2lib, which is a port of the Cypress library code to SDCC, plus the associated tools for uploading code to the microcontroller over USB. However, Dennis's tools are mostly aimed at Linux developers. I guess you could get them to work on Windows, but not easily.
So I set out to write a replacement set of tools for uploading code to the microcontroller. I wanted them to be simple and portable, and I wanted them to accept the files generated by SDCC without any intermediate processing steps.
Download
You can download the fx2tools tarball, or clone the git repo here: http://github.com/makestuff/fx2tools. You can build it easily on Windows or Linux by referring to this blog post. When you build it, take care to put the code in a directory tree like the one mentioned in the README. The build process will fetch the dependencies automatically (you will need a connection to the Internet whilst building for the first time).
Building (Linux)
You need g++ and the libusb development stuff to build the host-side stuff, and SDCC for the firmware. This works for me from a fresh install of Ubuntu 10.04:
sudo apt-get install g++
sudo apt-get install libusb-dev
cd $HOME
mkdir -p sandbox/apps
cd sandbox/apps/
wget http://github.com/makestuff/fx2tools/tarball/master
gunzip -c makestuff-fx2tools-*.tar.gz | tar xf -
cd makestuff-fx2tools-*
make -f Makefile.linux
sudo apt-get install sdcc
make -f Makefile.linux firmware
Building (Windows)
You need Microsoft Visual C++ 2008 Express Edition (2010 will not work because vcbuild.exe has been deprecated), and a GNU environment. I recommend WinAVR (even if you don't do any development with Atmel AVRs). For the FX2 firmware you will need SDCC.
cd %HOMEPATH%
mkdir sandbox
cd sandbox
mkdir apps
cd apps
wget http://github.com/makestuff/fx2tools/tarball/master
gunzip -c makestuff-fx2tools-*.tar.gz | tar xf -
cd makestuff-fx2tools-*
make -f Makefile.win32
make -f Makefile.win32 firmware
Usage
I have included an example firmware modified from the ones in fx2lib. In addition to an implementation of the standard 0xA2 command for uploading and downloading to and from EEPROM, I have implemented a simple arithmetic service which accepts two numbers and returns their sum, difference, product and quotient.
When you first connect an FX2LP board to the PC, it will enumerate with some built-in firmware which only offers the standard 0xA0 command for loading the onboard RAM. You can load the supplied firmware.hex using fx2loader like this:
> fx2loader firmware.hex
Notice that there is no need to run packihx or hex2bix. The fx2loader has direct support for the unpacked I8HEX files generated by SDCC. After running that command on a 'vanilla' FX2LP board you will hear the USB "bing-bong...bong-bing" as the device renumerates.
The board is now running the supplied firmware.hex, which adds an additional two commands, the standard 0xA2 EEPROM upload/download command, and a nonstandard 'calculator' command 0x80. Let's call the calculator command:
> ucm -i 0x80 0x0010 0x0002 0x0008 | hxd
00000000 12 00 0E 00 20 00 08 00 .... ...
Here the ucm command is being used to send control command 0x80 with wValue=0x0010 and wIndex=0x0002 . The handler for 0x80 (see handle_vendorcommand() in fx2tools/firmware/app.c) takes those numbers 16 and 2 and returns eight bytes:
Their sum: 16 + 2 = 18 (0x0012)
Their difference: 16 - 2 = 14 (0x000E)
Their product: 16 * 2 = 32 (0x0020)
Their quotient: 16 / 2 = 8 (0x0008)
Note: The supplied hxd command above just dumps out the binary data returned in a tabular form.
Let's try using the 0xA2 EEPROM read/write command. First let's write to the EEPROM (make sure you've backed it up if necessary!):
> echo Hello World | ucm -o 0xA2 0x0000 0x0000 0x000b
That command means "write 11 bytes at 0x0000". Let's read it back:
> ucm -i 0xA2 0x0000 0x0000 0x000b | hxd
00000000 48 65 6C 6C 6F 20 57 6F 72 6C 64 Hello World
If you get this instead:
> ucm -i 0xA2 0x0000 0x0000 0x000b | hxd
00000000 23 23 23 23 23 23 23 23 23 23 23 ###########
...it probably means the EEPROM is not connected. Your board will have a jumper to isolate the EEPROM, which is probably not currently connected.
You could use ucm to write firmware to the EEPROM but it's a bit tedious because you have to convert SDCC's output to an iic file and then upload it 0x1000 bytes at a time. The fx2loader command will do all that for you:
> fx2loader firmware.hex eeprom
> ucm -i 0xA2 0x0000 0x0000 0x0100 | hxd
00000000 C2 00 00 00 00 00 00 01 00 04 00 00 02 01 BB 32 ...............2
00000010 00 01 00 0B 32 00 01 00 13 32 00 01 00 1B 32 00 ....2....2....2.
00000020 01 00 23 32 00 01 00 2B 32 00 03 00 33 02 07 21 ..#2...+2...3..!
00000030 00 01 00 3B 32 00 03 00 43 02 11 00 00 01 00 4B ...;2...C......K
00000040 32 00 03 00 53 02 11 00 00 01 00 5B 32 00 01 00 2...S......[2...
00000050 63 32 00 03 00 6B 02 07 24 00 03 00 73 02 03 E7 c2...k..$...s...
00000060 00 03 00 7B 02 03 FD 00 03 00 83 02 07 6C 00 03 ...{.........l..
00000070 00 8B 02 07 3C 00 03 00 93 02 07 54 00 03 00 9B ....<......T....
00000080 02 03 FE 00 03 00 A3 02 03 FF 00 03 00 AB 02 04 ................
00000090 00 00 03 00 B3 02 04 01 00 03 00 BB 02 04 02 00 ................
000000A0 03 00 C3 02 04 03 00 03 00 CB 02 04 04 00 03 00 ................
000000B0 D3 02 04 05 00 03 00 DB 02 04 06 00 03 00 E3 02 ................
000000C0 04 07 00 03 00 EB 02 04 08 00 03 00 F3 02 04 09 ................
000000D0 00 03 00 FB 02 04 0A 00 03 01 03 02 04 0B 00 03 ................
000000E0 01 0B 02 04 0C 00 03 01 13 02 04 0D 00 03 01 1B ................
000000F0 02 04 0E 00 03 01 23 02 04 0F 00 03 01 2B 02 04 ......#......+..
00000100
Notice that after running fx2loader the EEPROM has been initialised with the correct format for a C2 loader. Notice that there's no need to use packihx or hex2iic or anything...the output of SDCC can be loaded directly into the EEPROM. The fx2loader command does all the necessary conversion work for you.
You can use fx2loader to upgrade the firmware in your FX2-based devices fairly easily. Some vendors' firmware (e.g Digilent) do not support EEPROM writes (presumably to stop people inadvertently bricking their boards). To write the EEPROM in these devices it is necessary to first do a RAM-load of the supplied firmware which does support EEPROM writes, then load whatever you want into EEPROM. It's a good idea to check that the new firmware works by first loading it into RAM:
# Backup existing firmware (assuming 128kbit EEPROM):
> fx2loader eeprom:128 backup.iic
# Load new firmware into RAM and check that it works OK before proceeding:
> fx2loader donbusb.iic
# Load the fx2tools firmware into RAM:
> fx2loader firmware.hex
# Now load the new firmware into EEPROM:
> fx2loader donbusb.iic eeprom
Thanks for this great set of tools and instructions! I have been successfully programming my chip with new firmwares, used your precompiled firmware, and also can compile many other examples I have come across. When I try to compile the firmware you provide from source, however, sdcc complains: error 20: Undefined identifier 'SETUP_TYPE'. Any clue what might be going wrong? Thanks.
Hi Brian,
I'm glad you found it useful! Thanks for pointing out this bug. It looks like Dennis has made some incompatible changes to fx2lib since I last built this stuff. I just fixed my git repo; I can now successfully build the firmware on a fresh Ubuntu 10.04 installation (actually running on VirtualBox under a Windows 7 host, but that should not matter) using these commands:
Let me know if you still can't build it.
Actually I need to update this stuff anyway to conform to my new build infrastructure, and I suspect I will need to make firmware changes to cope with the Digilent Nexys2, which I've been playing with recently, so watch out for further updates.
Have you had any problems with writing images to the EEPROM on the Nexys board? If I try to restore the stock donbusb image, it appears bits get scrambled. I end up with bytes from the last few addresses of the hex file in the lower memory space of the chip. If I truncate my hex file to only write, say, the first 4KB it appears to write correctly. Could that be an unintentional limit in the fx2loader code? Your note about suspected changes in the code to handle the Nexys is intriguing.
Hi Tyler,
Sorry, I made a mistake in my last comment. It's the Nexys2 board that I've been playing with, not the Nexys. I corrected my comment. There should be no changes to the fx2loader code to work with these boards (I was thinking more about changes to my custom firmware). I will try it now and let you know how I get on.
Chris
It is really a Nexys2 that I have also. I also have the new Genesys board that I would like to poke around with too. I think the issue is that if I wish to backup the onboard EEPROM, I was piping a ucm IN to hxd and sending that to a file which I parsed with a script into an Intel hex record. From this point I tried loading that back to EEPROM with
fx2loader -src dump.ihx -dst eepromand I realized then that things weren't sitting in the right place in memory. I am not extremely familiar with the i2c bootloader mechanism so I may have a misunderstanding. It appears that maybe a straight hex .iic file may be what I wish to use for the backup image. But then that is more complicated to load back onto the device.Ah, that won't work. The output from "
ucm IN 0xA2 ..." will be the I2C records (notice that the first byte is0xC2). An I8HEX file created from that will not load back into the EEPROM properly, becausefx2loaderwill assume it's an I8HEX file of the actual program, not an I8HEX file of the I2C records. But I definitely see the value in being able to do what you're trying to do; I will implement the missing file source and destinations to allow you do to this, and I will make sure it works on my Nexys2. It will be fairly simple to do, but it will take a few days because I don't have much free time this week.