Alternative to FTDI

A project log for Chubby Hat

This projects goal is to design a PCB that turns the Colorlight 5A-75B into an easy to use development platform for cheap.

marblemarble 08/01/2020 at 21:210 Comments

The icebreaker uses SPI to either write the bit stream to the non-volatile flash memory or directly to the FPGA. The bit stream written to the SPI flash gets automatically loaded by the FPGA after power-on.

The Colorlight also has a SPI flash holding the bit stream, but its pins are not exposed as headers. The contributors of the chubby75 repository identified the JTAG pins, which can also be used to program the bit stream into the FPGA.

This means that the bit stream we program only resides in the volatile memory of the FPGA, which deletes when the board gets powered off.


Most Lattice iCE40 development platform use a FTx232x for programming. This is a powerful IC because of its performance and versatility. It support most common protocols out of the box, like UART, I²C, SWD, SPI and JTAG. The latter two can be used to interface with iCE40 FPGAs.

In the hacker community FTDI got a pretty bad rep. There are not one, but two cases of FTDI releasing malicious drivers with the intention to brick counterfeit ICs. Apart from the moral of this, it also poses a risk to DIY hardware, since most hobbyist can't verify the genuineness of the parts we buy, especially from sites like Aliexpress.

Also their ICs are pretty pricey, starting at 4.18€/piece for 100 pieces when sourced on mouser and 2.50€/piece on AliExpress.

While searching for open source USB JTAG implementations, I stumbled upon this fork of versaloon, which ports it to the STM32F103C8 - the micro controller of the BluePill development board.

Apart from not being subject to malicious vendor driver, it's also relatively inexpensive. You can buy them on AliExpress for about 1€/piece. They probably are clones like the CS32F103, but as long as they work, they work 😃

I checked out v1.0 of the repository and flashed it to a blue pill board. After checking that the device get recognized by my computer with dmesg and lsusb, I connected the JTAG signals and 5V power.

I tested the setup with the pin-scan example. Since I had a different version of the board than the author did, I hat to make some changes to the code.

diff --git a/5a-75b/pin-scan/Makefile b/5a-75b/pin-scan/Makefile
index 2a870ce..a8978b6 100644
--- a/5a-75b/pin-scan/Makefile
+++ b/5a-75b/pin-scan/Makefile
@@ -7,7 +7,8 @@ top.json: $(SYNTH_SRCS) name.hex        yosys -p 'read_verilog $(SYNTH_SRCS); synth_ecp5 -top top -abc9 -json $@'
 top.config: top.json top.lpf
-       nextpnr-ecp5 --25k --package CABGA381 --speed 6 --lpf top.lpf --json top.json --textcfg top.config --freq 65
+       #nextpnr-ecp5 --25k --package CABGA381 --speed 6 --lpf top.lpf --json top.json --textcfg top.config --freq 65
+       nextpnr-ecp5 --25k --package CABGA256 --speed 6 --lpf top.lpf --json top.json --textcfg top.config --freq 65
 top.svf: top.config        ecppack --input $< --svf $@
diff --git a/5a-75b/pin-scan/ b/5a-75b/pin-scan/
index 5b6d44f..365443c 100755
--- a/5a-75b/pin-scan/
+++ b/5a-75b/pin-scan/
@@ -15,7 +15,8 @@ with open(sys.argv[2], 'w') as lpf, open(sys.argv[3], 'wb') as rom:        for l in cr:                if not l[0].isdigit():                        continue
-               if not l[7].isalnum():
+               # if not l[7].isalnum():
+               if not l[9].isalnum():                        continue                if l[1][0:2] not in ('PT', 'PB', 'PL', 'PR'):                        continue
@@ -23,7 +24,7 @@ with open(sys.argv[2], 'w') as lpf, open(sys.argv[3], 'wb') as rom:                        continue
                name = l[1]
-               pad  = l[7]
+               pad  = l[9]
                lpf.write('LOCATE COMP "pads[%d]" SITE "%s";\t# %s\n' % (i, pad, name))                lpf.write('IOBUF PORT "pads[%d]" PULLMODE=UP;\n' % (i,))

I also had to copy and modify an openocd config for the target platform

transport select jtag
adapter_khz 200

jtag newtap lfe5u25 tap -expected-id 0x41111043 -irlen 8 -irmask 0xFF -ircapture 0x05

svf -tap lfe5u25.tap -quiet -progress top.svf

The programming is then done with OpenOCD.

$ sudo openocd -f interface/vsllink.cfg -f chubby.cfg
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
adapter speed: 200 kHz
Info : Versaloon(0x15)by Simon(compiled on Jul 26 2020)
Info : USB_TO_XXX abilities: 0x00000208:0x010001E3:0xC0000007
Info : clock speed 200 kHz
Info : JTAG tap: lfe5u25.tap tap/device found: 0x41111043 (mfg: 0x021 (Lattice Semi.), part: 0x1111, ver: 0x4)
Warn : gdb services need one or more targets defined   TapName             Enabled  IdCode     Expected   IrLen IrCap IrMask
-- ------------------- -------- ---------- ---------- ----- ----- ------ 0 lfe5u25.tap            Y     0x41111043 0x41111043     8 0x05  0xff
svf processing file: "top.svf"
Time used: 0m50s625ms
svf file programmed successfully for 620 commands with 0 errors
shutdown command invoked

Inititally I had some troube with the length ot the wires I used and the stupied way of routing them through the opposing holes for strin relief. At adapter_khz values over 10 I got JTAG error. probably due to bad signal integrity.

I got rid of that by shortening the wires and not doing the strain relief thing.