### Quick links
+ [Intro](#link_0)
### Intro
For years I wanted to test FPGAs, but I did not find the right access, especially because the tools were proprietary and every producer had another approach. Then I bought a book from Jörg Rippel (in German). Jörg uses only open source tools to program the FPGAs and the book is easy to read. The open source toolchain helps to better understand whats going on. He uses an IceZero board (ICE40HX, Lattice) and a Tang Nano 9k board (Gowin-GW1NR-LV9).
In the French Mag Hackable Magazine nr 35 I found in 2020 a cool article to use cheap LED control boards named Colorlight 5A-75B with an ECP5 FPGA as development board. I have two of this boards.
So first I will document my progress with the book and then I will use hopefully my knowledge to program the Colorlight FPGAs.
### Preparing a Raspberry Pi as development hardware
Using a Raspi as base is a good idea because it's always available for my FPGA development and nothing is altered by updates like on my desktop computer. The Raspberry 5 is fast enough to be used as computer and with VNC I'm able to use my usual keyboard, screen and mouse.
So for Christmas I get a new Raspi 5 with cooler, NVMe hat and a 1TB NVMe. How to set the Raspi up is described here: . The SSD makes the access to the disk 10 times faster (844MB/s) then with the SD card! Test it with:
sudodf# to get the name of the NVMesudohdparm-t--direct/dev/nvme0n1p2
### Installing the toolchain for the Tang Nano 9k board
The IceZero board is cool because it uses directly the Raspberry pi pins to access the FPGA. It is based on a board by Black Mesa Labs, but unfortunately it is no more available (trenz-electronic.de) until mid 2025.
So I will test the examples with the Tang Nano 9k board from [Sipeed](https://wiki.sipeed.com/hardware/en/tang/Tang-Nano-9K/Nano-9K.html).
We can download the material of the book to our Raspi with:
After unzipping the file (GUI) we find a script called: `toolchain_tang_nano_install.sh` and run it with:
cdfpga
./toolchain_tang_nano_install.sh
As you see the script installs first some packages with `apt` and WiringPi from github, if not already installed. After this the following tools are installed from there github repos or with pip in a virtual environment (Apicula).
+ Yosys: Yosys is a framework for Verilog RTL synthesis. Translates the Verilog code in a netlist for the FPGA.
+ Apicula: Apicula is an open-source alternative toolset for Gowin FPGAs including tools for converting netlists to bitstreams, placing and wiring designs, analysing timing and resource usage and analysing timing and resource consumption.
+ nextpnr-gowin: Nextpnr is a portable FPGA place and route tool. It supports various architectures and is known for its good support of Gowin, Ice40 and ECP5 FPGAs.
+ openFPGALoader: OpenFPGALoader is a universal utility for flashing FPGA boards.It aims to provide a standardised interface for flashing FPGAs from different manufacturers.
Manually you could use the following commands:
### First test: Running light
Now let's test ou toolchain with a simple running light.
Connect the Sipeed board with an USB cable to your Raspi. Test with the following commands:
dmesg
ls-l/dev/ttyUSB*
openFPGALoader--detect
We see that we get 2 FTDI serial devices (ttyUSB0 and ttyUSB1) belonging to the group `plugdev`. The standard user is normally in this group (`grep plugdev /etc/group`). If `openFPGALoader` finds the GWIN(R)-9C the toolchain is ok. If there is a problem, try reducing the JTAG frequency:
openFPGALoader--detect--freq=2000000
Now we extract the zip file `gowin_blinky.zip` in `~/fpga/src/tangnano9k` and `cd` to this directory. Zhen we run a script, that loads the bitstream to the FPGA:
cd~/fpga/src/tangnano9k/gowin_blinky
shblinky.sh
### Running light in detail
#### The Verilog code
Now let's do the same thing step by step on our own. First we look at the Verilog file (ending `.v`). We rename it to `running_light.v` and copy it to our project directory (e.g. `fpga/tang_nano_9k/running_light`).
I changed the Verilog code a little bit to make it clearer for me.
moduleled(inputsys_clk,// in system clockinputsys_rst_n,// in reset active lowoutputreg[5:0]led// out 6 LEDS pin);parameterCOUNTER_MAX=24'd1349_9999;// for 0.5s delay, clk = 27MHzreg[23:0]counter;always@(posedgesys_clkornegedgesys_rst_n)beginif(!sys_rst_n)counter<=24'd0;elseif(counter==COUNTER_MAX)counter<=24'd0;elsecounter<=counter+1'b1;endalways@(posedgesys_clkornegedgesys_rst_n)beginif(!sys_rst_n)led<=6'b111110;elseif(counter==COUNTER_MAX)led<={led[4:0],led[5]};endendmodule
Our modul is called `led` and contains two inputs, the system clock and a reset button (S1 ob the Sipeed board) and an output with the 6 LEDs organized in a register (first variable).
The second variable (24 bit) contains a counter that is needed to get our delay of 0.5 s. The system clock is 27 MHz (27000000 Hz). Half of the frequency gives us the value of 13499999 for the counter test, so that we react twice a second.
The always loops react on the positive edge of the system clock and the negative edge of a reset. A reset sets the counter to zero (1 loop) and illuminates the first LED (negative logic, 2 loop). The positive edge of the clock increments the counter if the number 13499999 is not reached and sets it to 0 if this is the case (1 loop). In the second loop the positive edge of the clock shifts effectively the bits of the led vector to the left by one position, with the highest bit (led[5]) being moved to the lowest position (led[0]) if the number 13499999 is reached.
This is done with a concatenation (combining) operation, that is used to combine multiple bits or bit vectors into a single bit vector. The concatenation operator is the curly brace {}. The concatenation {led[4:0], led[5]} creates a new 6-bit vector where the bits from led[4:0] are placed in positions 5 down to 1, and led[5] is placed in position 0.
#### The constraints file
Every FPGA project needs a physical constraint file defining to which real pins of the chip or board the in- and output signals are wired up. Unfortunately every producer of FPGAs uses a different ending and syntax for this file. For the Tang Nano the files ending is `.cst`. So let's look at the file `tangnano9k.cst`. We see that the file is provided by gowin and defines the physical constraints of the Sipeed board.
To understand this we need to look at the schematic of the board. We find it [here](https://dl.sipeed.com/shareURL/TANG/Nano%209K).
The 6 LEDs are connected to 1.8 V. So clearly they are active low (neg logic). And they are connected to the 1.8 V bank (left bank IOL, Bank 3) of the FPGA. The pin numbers of the FPGA are 10, 11, 13, 14, 15 and 16 and are defined with `IO_LOC`. The `IO_PORT` definition also specifies a pull-Up resistance for the negative logic.
The 2 buttons are connected to FPGA pin 3 and 4. They have 10 kΩ pull-ups to 1.8 V and are also active low.
The system clock can be found on pin 52 of the FPGA. The definition `IO_TYPE`=LVCMOS33 gives information of the type of voltage. The pin uses a Low Voltage CMOS signal with 3.3 V (right Bank 1). It has a pull-up and is connected to the crystal of 27 MHz.
More infos to our pins can also be found in the `tangnano9k.cst`-file in the folder `src/tangnano9k/`.
We save the file with the name `running_light.cst` to our project folder.
#### The make file
We use the well known make system to get the bitstream and load it to the FPGA. Here a makefile for our project:
# project name (no comments behind assignment lines because spaces are added!)PROJ=running_light
# constraints file (same as projectname)PIN_DEF=$(PROJ).cst
DEVICE=GW1NR-LV9QN88PC6/I5
DEVICE_FAMILY=GW1N-9C
# Verilog file (same as projectname)SOURCE=$(PROJ).v
# board name for OpenFPGALoaderBOARD=tangnano9k
# where should the code reside: "SRAM" or "FLASH"TARGET?=SRAM
$(infoPROJ=$(PROJ))# Print variables for debuggingall:$(PROJ).fs# final bitstream file$(PROJ)-yosys.json:$(SOURCE)# synthesizes Verilog-source to JSON using Yosysyosys-q-p"synth_gowin -json $@"$(SOURCE)$(infoBuilding$(PROJ)-yosys.json)$(PROJ)-nextpnr.json:$(PIN_DEF)$(PROJ)-yosys.json# Create place and route JSON file from Yosys JSON filenextpnr-gowin--json$(PROJ)-yosys.json--write$@--device$(DEVICE)--family$(DEVICE_FAMILY)--cst$(PIN_DEF)$(PROJ).fs:$(PROJ)-nextpnr.json# pack the NextPNR JSON-file to final Gowin pack-filePATH="$(HOME)/Programme/apycula_env/bin:$$PATH"gowin_pack-d$(DEVICE_FAMILY)-o$@$(PROJ)-nextpnr.json
prog:$(PROJ).fs# load bitstream fs-file to SRAM or FLASH ifeq ($(TARGET),FLASH)openFPGALoader-f--freq2000000-b$(BOARD)$(PROJ).fs
elseopenFPGALoader-m--freq2000000-b$(BOARD)$(PROJ).fs
endifclean:# clean the files that are needed no morerm-f*.json*.fs
.PHONY:allprogclean
# EOF
The names of the device can be found on github: and the device family can be found with the following command: `openFPGALoader --list-boards`
Apicula has a Folder in our home directory called `Programme/apycula_env`. In the bin directory resides the needed gowin_pack program.
The file is named `Makefile` (no extension) and must reside in our project folder. Then we use this file to get the bitstream and load it with this 3 `make` commands:
If everything works, try reducing the delay of the running light :).
The code is loaded to SRAM, so it is no more available after repowering the board.
If you want to load it to FLASH, you must use `sudo` for the OpenFPGALoader or install an UDEV rule in `/etc/udev/
`99-openfpgaloader.rules`
#### Using VScode and TerosHDL
We need python (already installed on the Raspi) and pip to install programs that are not in the Raspi repo. On the Raspi the Python environment is managed externally, which means you can't install Python packages directly using pip. We need a virtual environment. We call it `venv` and use a hidden directory (dot in front). We create the environment and activate it with:
python-mvenv.venv
source.venv/bin/activate
Now we can install the packages needed by the TerosHDL addon:
pipinstallvunit-hdledalizeyowasp-yosyscocotb
sudoaptinstallcode
Install your favorite tools: Quartus Pro, ModelSim, Yosys, GHDL, Vivado... For open-source tools, we recommend downloading OSS CAD Suite (https://github.com/YosysHQ/oss-cad-suite-build/releases). OSS CAD Suite is a binary software distribution for a number of open source software used in digital logic design. You will find tools for RTL synthesis, formal hardware verification, place & route, FPGA programming, and testing with support for HDLs like Verilog, Migen, and Amaranth.
? sudo apt-get install gtkwave
? sudo apt-get install verilator
? sudo apt-get install iverilog
https://github.com/phdussud/pico-dirtyJtag/releases/tag/V1.04
Second test: UART
For a next project I will need a serial communication with the FPGA with a bitrate of 12 MBit/s! Let's start slower :).