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.
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
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/gen_lpf.py b/5a-75b/pin-scan/gen_lpf.py index 5b6d44f..365443c 100755 --- a/5a-75b/pin-scan/gen_lpf.py +++ b/5a-75b/pin-scan/gen_lpf.py @@ -15,7 +15,8 @@ with open(sys.argv, 'w') as lpf, open(sys.argv, 'wb') as rom: for l in cr: if not l.isdigit(): continue - if not l.isalnum(): + # if not l.isalnum(): + if not l.isalnum(): continue if l[0:2] not in ('PT', 'PB', 'PL', 'PR'): continue @@ -23,7 +24,7 @@ with open(sys.argv, 'w') as lpf, open(sys.argv, 'wb') as rom: continue name = l - pad = l + pad = l 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 init scan_chain svf -tap lfe5u25.tap -quiet -progress top.svf shutdown
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 http://openocd.org/doc/doxygen/bugs.html 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" 95% 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.