Taking a break from my series about the eZ80, “I don’t like Windows.” and “Why do you want to do/know that?”, I decided to take a look at FPGA’s to see if they could be used for my retro projects. More in particular in creating video.
A few weeks ago, @lockfarm@twtr.plus pointed me to the iCE40HX1K-EVB dev board which is an incredibly cheap (15.95 Euro at the moment of writing) little FPGA board, including 512KB of SRAM. SRAM is a lot easier to interface with and write Verilog code for (for a first time user) than the typical SDRAM or DDR Ram that is found on almost all other FPGA dev boards.
Features of the iCE40HX1K-EVB
- iCE40HX1K-VQ100 FPGA 1280 Logic cells, 64 K embedded RAM bits
- 512KB SRAM organized as 256K x 16bit 10ns
- 2MB Serial Flash
- 2 user status LEDs
- Programming successful status LED
- 2 user buttons
- Reset button
- Power jack for 5V DC external power supply
- PGM connector (all signals at PGM1 @ 3.3V DC)
- 34 pin connector bus
- 100 MHz oscillator
- Power supply DC/DC regulators
- Power supply status LED
- Dimensions: 50 x 50mm ~ (2" x 2")
Installing the toolchain
The nice thing of the FPGA used on this board (iCE40HX1K), is that it is supported by the Yosys (Yosys Open SYnthesis Suite) open source toolchain.
The Olimex documentation refers to project IceStorm for programming this FPGA chip. But this project most recent update goes back to 2018. Therefore I decided to not use project IceStorm and directly use the latest binary release from Yosys which can be found here. Just choose the release that suits the OS you’re using. For Linux this is usually oss-cad-suite-linux-x64-YearMonthDay.tgz
(releases are build every day).
Unzip the package to your preferred location and all required binaries (like iceprogduino
, icepack
, icetime
, nextpnr-ice40
, yosys
, …) can be found in the bin
subdirectory.
What remains to be done is adding this bin
directory to your PATH
environment variable so that the binaries can be found automatically. You can do so permanently but in this kind of experiments I usually prefer not to [yet]. In this case, I created a small setup.sh
file with this content:
# Use ". setup.sh" to set PATH variable once in your terminal.
export PATH='/home/koen/Documents/Projects/FPGA/oss-cad-suite/bin':$PATH
When you now execute . setup
in your terminal, the PATH
environment variable is extended with the path to the Yosys binaries but only in that terminal session. Of course, you will need to modify the above script to point to where you unpacked the Yosys release package.
Programming the iCE40HX1K-EVB
With the Yosys tools installed, we now need a way to program the FPGA.
Practically all FPGA boards have some kind of a USB to serial chip on board (typically from FDTI) for this purpose. This is not the case on this board (and helps explaining why this board is so cheap). Instead it does offer an UEXT connector which supports three kinds of serial communication interfaces - I2C, SPI and RS232. There is also 3.3V line and GND.
Olimex solution is to use an Arduino (Leonardo) for the USB to UEXT conversion, preferably using their own OLIMEXINO-32U4 (12.95 Euro at the time of writing) which conveniently also has a UEXT connector on board. Next to that, you need a 10-pin ribbon cable to connect the Arduino with the FPGA board like the CABLE-IDC10-15cm (2.00 Euro at the time of writing).
With the hardware sorted, it’s now time to program the Arduino so that it can be used to program the FPGA board. The OLIMEXINO-32U4 programmer sketch is part of the bigger iCE40HX1K-EVB repo on GitHub and can be found in the iCE40HX1K-EVB/programmer/olimexino-32u4 firmware/
path.
Unfortunately, the provided Arduino sketch has troubles with the more recent Arduino IDE (it insist that the iceprog.ino
is inside a folder with the name iceprog
). Instead of trying to fix this, I tried the platformio
way of working first with the provided platformio.ini
. and that worked without any problem for me.
Assuming you have the PlatformIO extension installing in VSCode, open PlatformIO:
Click on Open Project
and navigate to the olimexino-32u4 firmware
folder inside the iCE40HX1K-EVB
git repo:
You then should see something like this:
We can now compile the project by clicking on the small check mark
icon in the toolbar at the bottom:
The code should compile without any problems and we can now upload the code to the OLIMEXINO-32U4 board by clicking on the right arrow
icon (next to the check mark
build button):
Your OLIMEXINO-32U4
board is now ready to be used to program the FPGA. One thing we can already do is checking on which serial port your OLIMEXINO-32U4
board is connected. The default is /dev/ttyACM0
but /dev/ttyUSB0
is also possible.
Powering the OLIMEXINO-32U4 and iCE40HX1K-EVB
Both the OLIMEXINO-32U4
and iCE40HX1K-EVB
have a power jack for an external power supply but there is a simpler way to provide power to them.
The OLIMEXINO-32U4
is self-powered by the miniUSB when it is connected to a USB port of your PC, which will be the case as long as you’re working on your code.
Warning: the OLIMEXINO-32U4
board can work on both 3.3V and 5V but the iCE40HX1K-EVB
board can only work on 3.3V. E.g. 5V signals can destoy the FPGA chip. Be very sure that the jumper on the OLIMEXINO-32U4
is set to 3.3V!
Pin 1 of the UEXT connector on the OLIMEXINO-32U4
board can provide 3.3V that can be used to power the iCE40HX1K-EVB
board. Pin 1 is controlled by pin D8 of the OLIMEXINO-32U4
. The MCU can thus power on/off pin 1 of the UEXT bus. Luckily we don’t have to bother with this ourselves since the Arduino sketch which we just uploaded powers on pin 1 of the UEXT bus so that we can use this to power the iCE40HX1K-EVB
board.
Some extra information from the FAQ of the OLIMEXINO-32U4
board:
There is no 3.3V on pin #1 of the UEXT connector. Why?
The power output at the UEXT is controlled by pin D8, also
called UEXT_PWR_E. This signal is connected to a FET. You
need to drive D8 to low level to enable 3.3V on the UEXT.
Use the following code:
// UEXT power enable --> PORTB4 --> D8
pinMode(8, OUTPUT);
digitalWrite(8, LOW);
We need to do a small modification on the iCE40HX1K-EVB
board so that it can be powered via the UEXT bus. On the bottom side we see an open jumper, labelled 3.3V_E1
. With a blob of solder we close this jumper so that the board can be powered via the UEXT bus. With this setup we don’t need any external power supplies, meaning less cables on the desk as well.
Uploading a binary to the iCE40HX1K-EVB board
First thing we can do is check if we have a good connection to the iCE40HX1K-EVB
board. We can do this with the iceprogduino
command. Assuming you have installed the Yosys toolchain and its binaries can be found in your PATH.
This is the kind of output you will see when the OLIMEXINO-32U4
board is connected but not yet the iCE40HX1K-EVB
board:
[koen@manjaro-3900X ice40hx1k-evb]$ iceprogduino -tv
Test mode
Serial: /dev/ttyACM0: Success
Manufacturer ID: 0x00 / Device ID: 0x0000
Bye.
And now with the iCE40HX1K-EVB
board connected to the UEXT bus of the OLIMEXINO-32U4
board as well:
[koen@manjaro-3900X ice40hx1k-evb]$ iceprogduino -tv
Test mode
Serial: /dev/ttyACM0: Success
Manufacturer ID: 0x1C / Device ID: 0x7015
Bye.
Remark: On my PC, the OLIMEXINO-32U4
board is indeed found on the default /dev/ttyACM0
serial port. If this is not the case for you and the board appears on a different serial port, you can use the -I
command line option to specify this:
[koen@manjaro-3900X iCE40HX1K-EVB-demo]$ iceprogduino -h
iceprog -- simple programming tool for Olinuxino Nano-based Lattice iCE programmers
...
-I<serialport>
port to connect Arduino (default /dev/ttyACM0)
...
We’re now ready to upload our first binary. Luckily, there is already a pre-compiled binary in the git repository which can be found in .../demo/ice40-io-video/
as example.bin
. Uploading it is as simple as:
[koen@manjaro-3900X build]$ iceprogduino example.bin
Serial: /dev/ttyACM0: Success
file size: 32220
erase 64kB sector at 0x000000..erased
programming..
Manufacturer ID: 0x1C / Device ID: 0x7015
prog 0x007D00 +0x0DC...
Bye.
The provided example is intended to be used with the iCE40-IO board which I also have:
Compiling Verilog code
Next step is compiling the example ourselves so that we can create our own verilog code later.
Using the more recent Yosys toolchain has a small impact on the provided make file. Some executables got a different name (e.g. arachne-pnr
became nextpnr-ice40
) and some command line options are renamed as well.
Below you can find a reworked Makefile
that compiles the example.v
verilog code as it can be found in .../demo/ice40hx1k-evb
. Note that a build
directory is now created where the example.bin
file will be stored:
BUILDDIR = ./build
FPGA_TYPE = hx1k
FPGA_PKG = vq100
PCF = ice40hx1k-evb.pcf
RMDIR = rmdir
# Targets
example: $(BUILDDIR)/example.rpt $(BUILDDIR)/example.bin
$(BUILDDIR)/%.json: %.v
@mkdir -p $(@D)
yosys -ql $(subst .json,,$@).log -p 'synth_ice40 -abc9 -device u -top top -json $@' $<
%.asc: %.json
nextpnr-ice40 --${FPGA_TYPE} --package ${FPGA_PKG} --json $< --pcf ${PCF} --asc $@
%.bin: %.asc
icepack $< $@
%.rpt: %.asc
icetime -d $(FPGA_TYPE) -mtr $@ $<
all: example
clean:
rm -f $(BUILDDIR)/*.asc $(BUILDDIR)/*.bin $(BUILDDIR)/*.rpt $(BUILDDIR)/*.log $(BUILDDIR)/*.json
$(RMDIR) $(BUILDDIR)
# Uncomment this line if you want to keep the intermediate .json and .asc files
# .PRECIOUS: $(BUILDDIR)/%.json %.asc
.PHONY: all prog clean example
For convenience, I made my own copy of the iCE40HX1K-EVB/demo
folder with the adapted Makefiles and pre-build binaries which can be found here.
Now it’s your turn to start hacking on FPGA’s.