pico-ice
RaspberryPi Pico with an iCE40 FPGA
Programming the iCE40

The FPGA normally boots from a dedicated serial NOR flash. This flash can be programmed by the Pico processor which exposes the flash to the host OS as either a removable drive or a DFU endpoint.

On Windows, while the RaspberryPi guide mentions using Visual Studio Code with a plugin a an IDE, better results were obtained by using the WSL2 environment.

Using a drag and drop file copy

You would need a compiler toolchain installed for building the UF2 Utils on your system. On Windows, you can use https://github.com/microsoft/uf2 instead, which contains uf2conv.py.

Out of the box, the default firmware should already be present on your board. You can skip step 1 if this is the case.

  1. If you changed the default firwmare, program it again onto the RP2040. You can also integrate the FPGA programming code in your own firmware with ice_usb.
  2. Install or build the UF2 Utils, and a blinky example for any iCE40 board.
  3. Convert the binary bitstream rgb_blink.bin into an UF2 rgb_blink.uf2 with the UF2 Utils:
    $ bin2uf2 -o rgb_blink.uf2 rgb_blink.bin
    
  4. Connect the pico-ice via USB and lookup the USB drive named pico-ice. Open it.
  5. You can copy the rgb_blink.uf2 file to that drive you just attached. As soon as you copy the file over,t he pico-ice will reboot and allow the FPGA to come up depending on the code running in the Pico processor.

Using the DFU mode

  1. If you changed the default firwmare, program it again onto the RP2040. You can also integrate the FPGA programming code in your own firmware with ice_usb.
  2. Install the DFU utilities.

    a. For Windows, yosys-hq tabby-cad: double-clicking on start.bat on the OSS CAD Suite installation opens a prompt with the dfu-util command available.

    b. For other systems you can install the dfu-util package.

  3. Check whether the Pico is recognized as a DFU device: dfu-util -l. This should list the pico-ice as a DFU device:
    Found DFU: [1209:b1c0] ver=0100, devnum=105, cfg=1, intf=0, path="1-4.4", alt=0, name="iCE40 DFU (flash)", serial="DE62A435436F5939"
    Found DFU: [1209:b1c0] ver=0100, devnum=105, cfg=1, intf=0, path="1-4.4", alt=1, name="iCE40 DFU (CRAM)", serial="DE62A435436F5939"
    
  4. Download the FPGA bin file to the pico-ice. The Pico can be rebooted as soon as the download succeeds with the -R flag.
    $ dfu-util --alt 0 --download rgb_blink.bin --reset  # to flash
    $ dfu-util --alt 1 --download rgb_blink.bin          # to volatile memory
    

Using APIO

The APIO project is a command line tool to fetch and use the oss-cad-suite FPGA toolchain based on Yosys.

It will bring an up-to-date build environment running quickly.

On Windows, you will first need to setup the libusbK driver for pico-ice DFU (CRAM) with Zadig or with UsbDriverTool (doc).

# Download the latest APIO dev version (with pico-ice support):
pip3 install git+https://github.com/FPGAwars/apio

# Download and install oss-cad-suite
apio install -a

# Build a new directory with a "blinky" example project inside
mkdir pico-ice-blinky; cd pico-ice-blinky
apio examples -f iCE40-UP5K/blink

# Set the board to "pico-ice"
apio init --sayyes --board pico-ice

# Build the project using yosys/nextpnr
apio build

# Plug your pico-ice board and upload the blinky project to it
apio upload

If apio upload fails, it is also possible to convert the .bin file to .uf2 with uf2-utils or uf2conv.py: doc.

Using OSS CAD Suite

The OSS CAD Suite project is a pre-compiled package of several tools. It provides a complete solution for building, debugging, simulating, uploading Hardware Description Language (HDL). It is based on Yosys.

As explained on the installation instructions, you can download it and extract it to a directory of your choice.

Several pico-ice-sdk examples rely on a $OSS_CAD_SUITE variable set to the full path where you extracted these files.

On Windows, you can run these examples from the cygwin environment, under which you can navigate to the example repositories and try them.

You can access the utilities directly from a shell environment after adding the $OSS_CAD_SUITE to the $PATH.

If you used apio to install OSS CAD Suite:

export OSS_CAD_SUITE="$HOME/.apio/packages/tools-oss-cad-suite"
export PATH="$PATH:$OSS_CAD_SUITE/bin"

Troubleshooting

Checking the CDONE pin

Once the FPGA bitfile transfers over using the DFU protocol, the Pico will check for whether the DONE pin goes high indicating a successful boot. This would make the CDONE green LED bright. If this doesnt happen for whatever reason, the DFU utility will throw an error indicating that this did not succeed.

Booting the FPGA with custom firmware

The user writing a custom firmware with the pico-ice-sdk should take care of starting the FPGA from the MCU. Review the pico_fpga example for how this can be done, as well as the ice_fpga library documentation. The USB DFU provided as part of the pico-ice-sdk must also be enabled for the DFU interface to show-up. The pico_usb_uart example project have it enabled by default.

Cannot open DFU device 1209:b1c0 found on devnum 61 (LIBUSB_ERROR_NOT_FOUND)

This error might occur when a communication error occurs.

  • On Windows operating system, the device needs to be declared with Zadig as described here. Make sure to select the pico-ice device on the list rather than any other to avoid erasing your system's USB drivers.
  • On Linux operating system, it might need to be allowed with an udev rule, or dfu-util might need to be run as super user.

To create an udev rule, add a file named /etc/udev/rules.d/99-pico-ice.rules with this content:

SUBSYSTEM=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="b1c0", MODE="0666"

Then reboot or run the following commands:

sudo udevadm control --reload-rules
sudo udevadm trigger

dfu-util has multiple devices

For devices with multiple DFU devices connected, the --device 1209:b1c0 flag is needed:

dfu-util --alt 0 --download rgb_blink.bin --reset --device 1209:b1c0

Alternatively, the dfu-util --list result will allow selecting a device per number:

dfu-util --alt 0 --download rgb_blink.bin --reset --devnum 0

dfu-util is stuck while uploading before anything could be sent

This could be due that there was no response from the flash chip, and the RP2040 is endlessy waiting the write confirmation. If you had an earlier board, it could be due to the fact the TX and RX pins were swapped, and do not work for the old board anymore.

Flashing an UF2 file does not change the memory neither restart the board

The UF2 file format contains the destination addresses of each block. In case you used other tools than those provided, it is possible that that the addresses were outside the valid range of the flash chip. Try to copy the CURRENT.UF2 to NEW.UF2 upon that same directory, and unmount the device. This should trigger a restart of the device. This restart device should appear from the debug UART: board_dfu_complete: rebooting.

Device's firmware is corrupt. It cannot return to run-time (non-DFU) operations.

This message sometimes comes from dfu-util when the -R flag is not used. With the -R flag, the pico-ice will reboot at the end of the transfer, and DFU-util should not complain anymore.