View on GitHub

FPGA tutorial


We’ll be working in the verilog directory.


  1. You will need Verilog setup from the previous step. Remember to also initialize the Git submodule with libraries:

    git submodule update --init
  2. Then, install the Icestorm toolchain. The easiest way is using the apio project:

    pip3 install --user apio
    apio install icestorm

    This will download and unpack the necessary software in your home directory (under ~/.apio). If you want to run the tools directly (not only from Makefile), add the toolchain to your PATH, for instance in your .bashrc:

    export PATH="$HOME/.apio/packages/toolchain-icestorm/bin/:$PATH"
  3. Under Linux, add yourself to the dialout group so that you can connect to the chip without sudo: (TODO: This doesn’t seem to work for everyone, use USE_SUDO=1)

    sudo adduser $USER dialout

    You will need to log out and log in again.

  4. Now try uploading a design. Connect the Icestick board, and run:

    make flash V=blinky_icestick.v

    If for some reason you need sudo, append USE_SUDO=1.

    If you encounter problems under Mac OS X, see Project IceStorm – Notes for Installing on OSX. You will probably need to unload Apple’s FTDI driver:

    sudo kextunload
  5. For the TinyFPGA BX board, you need to additionally do the following:

    pip3 install --user tinyprog
    apio drivers --serial-enable

Building and flashing

To upload a design, use make flash. For example:

make flash V=blinky_icestick.v

For the TinyFPGA BX module, you need to set BOARD=bx flag:

make flash V=blinky_bx.v BOARD=bx

Same for the IceBreaker module:

make flash V=blinky_icebreaker.v BOARD=icebreaker

(Append USE_SUDO=1 if you need to use sudo).

The build process has the following steps:

  1. Logic synthesis, using yosys. This produces a .blif file with your design compiled down to components available on the FPGA chip (look-up tables, flip-flops, block RAMs, etc.)
  2. Place and route, using arachne-pnr. This produces .asc and then .bin files containing the final chip configuration (a bitstream).
  3. Programming the chip, using iceprog / tinyprog. This uploads the .bin to the chip over USB.


You can find the available pins in fpga-tools/pcf directory. Your module will need to reference these.

Here are the pinouts for reference:


Here is a list of ideas that you can implement. You will find some hints regarding different parts in the next section.


Here are some parts you can use in your projects.


The Icestick has a 12 MHz clock signal, the BX a 16 MHz one. For changes that a human can notice, you will need to divide it to create a slower clock. See the blinky example.

It’s also possible to get a faster clock using a PLL, but I haven’t tried that yet. The icetime tool should tell you the maximum frequency for your design (run make time). Use icepll to generate the right parameters for the PLL module.


The Icestick has 5 LEDs, the BX has one. You can turn them on and off just by specifying the pins in module output.

You can connect your own LEDs as well, just make sure to connect the right resistors. The voltage on pins is 3.3 V.

Buttons and switches

You will need a pull-down or pull-up resistor. See for instance the button example for Arduino.

You can also use a an internal pull-up from FPGA. See button.v on how to do that.

Seven-segment display

Here is a spec sheet for the display. Ours has a common anode for all 4 digits. You will need to display the digits one at a time. Here is a blog post on multiplexing 7 segment display.

(TODO add more info once we try that)

You can use the chip on Icestick to communicate with your computer over a serial connection (exposed as a second USB device; visible under /dev/ttyUSB1 under Linux).

See uart_hello.v for a simple program that sends “Hello, world!” repeatedly. You can use to receive the data. Here is the documentation for pySerial library. Remember to set the baud rate correctly on both ends!

You can also use a serial terminal such as gtkterm (see for instance Communicate with hardware using USB cable for Ubuntu).

Note that the module we’re using, uart.v, is a third-party software developed by Tim Goddard.

OLED displays

I have two OLED screens:

See oled_pattern.v and oled_pattern_color.v for details on how to use.

You might want to load some initial data into memory. You can use the $readmemh function to do that.