IceCram & IceFlash
lib/v2.1 Pico2-Ice Programs for Pico2-Ice: configure the FPGA hardware logic from the program running on the RP2350B.
Introduction
The Pico2-Ice combines an RP2350B MCU and a Lattice Semi iCE40UP5K FPGA on a single board. That is, we can add additional hardware logic to the system by configuring the FPGA by simply storing a corresponding bitfile. Either directly in the FPGA's configuration RAM, on an on-board flash chip specifically dedicated to the FPGA, ie. a second flash memory in addition to the one used by the RP2350, from where the FPGA can load the configuration data.[1]
Since working with N. Wirth's RISC5 processor, I have been quite intrigued by the power and possibilities of FPGAs. Not sure if the whole RISC5 system, or at least part of it, could be realised on the iCE, which has just over 100k logic cells, but comparable to the Xilinx Artix XC7A100T and Altera's Cyclone IV/V. The iCE for sure has less block RAM. But I digress. :)
To create FPGA hardware logic configurations, either Lattice's Radiant software can be used, or one of the open source solutions. Radiant is free for this FPGA.
Description
IceCram
This example program stores the FPGA bitstream configuration file into the FPGA's configuration RAM, using IceCfgCram.ConfigCram. This procedure implements the direct CRAM configuration method as specified in Technical Note iCE40 Programming and Configuration, FPGA-TN-02001-3.4, section 13.
The bitstream file, which implements a hardware RGB blinker in the FPGA, is rgb_blink.bin in the program directory. This bitstream has been converted into a resource file IceData.res using gen-bin-res, and there is its accompanying Oberon module IceData.mod. The latter is imported into the program module, and the Astrobe linker adds it to the program binary. Module BinRes is used to access the binary resource to store it into the iCE's CRAM via SPI. If this configuration process succeeds, the FPGA's RGB LEDs will start their dance.
IceFlash
This example program stores the FPGA bitstream configuration file into the dedicated flash memory, from where the iCE will load it into CRAM upon start-up, as described in the aforementioned Technical Note, section 9.
The bitstream file is included as resource as outlined above.
Wiring Set-up
UARTs
Since the Pico2-Ice is not pin-compatible with the Pico2,[2] the serial terminal needs to be connected to different RP2350 pins (pins 32 and 33 for terminal 1, 36 and 37 for terminal 2, even though terminal 2 is not used here). The "standard" UART GPIO pins (pins 0 and 1 for terminal 1, 4 and 5 for terminal 2) are connected to different hardware points on the board, among them to the FPGA.
SPI
Here's a diagram of the SPI connections on the board related to configuring the FPGA:
+-------------+ +-------------+
| iCE SPI | | SPI flash |
| tx |-----+----------------| rx |
| rx |-----|--+-------------| tx |
| sclk |-----|--|--+----------| sclk |
| cs |-----|--|--|----+-----| cs |
+-------------+ | | | | +-------------+
| | | |
+---------------+
| tx rx sclk cs |
| SPI0 |
| RP2350B |
+---------------+
Both the iCE and the RP2350 are wired as controllers ("masters") to the flash memory, which works for programming the flash chip by the MCU, as well as for reading the configuration data from the flash memory by the iCE.
For writing directly into the iCE's CRAM, however, the RP2350 is not wired correctly, with the latter's tx pin connected to the former's tx pin, and analogously for the rx pins. We can solve this problem by either using a PIO-based SPI transmitter on the RP2350's SPI0 rx pin, or by using a patch wire from the RP2350's tx pin to the ICE's rx pin. The iCE's SPI rx pin is not used if it is in peripheral mode ("slave") to receive the data into CRAM, in fact, the pin is kept hi-z. In the same vein, we can keep the RP2350's rx pin in hi-z mode. Module ICE40UP5K defines pin 35 as SPI tx pin used for CRAM configuration, but that's an arbitrary choice – any SPIO tx pin works.[3]
The SPI serial clock (sclk) pins, as well as the chip select pins (cs) are wired usefully in both cases.
Configuration Times
Also depending on the SPI serial clock frequency:
- writing iCE's CRAM takes about 180 to 300 ms;
- writing the flash memory takes about 750 to 900 ms.
That is, it is basically feasible to change the hardware at run-time. :)
Repository
lib/v2.1<repo>/examples/v2.1/tvi/pico2-ice
The configuration data can also be programmed into a non-volatile memory inside the FPGA, but that's a one-time operation, since that memory can not be erased. This feature is meant to be used for the manufacturing of products on a large scale. ↩︎
For starters, the board has a double row of hardware pins, and uses PMOD connectors, which you may or may not want to use – four straight pin headers work as well, of course. The RP2350B has 48 GPIO pins, and there are all the iCE pins as well that need to be accessible. ↩︎
Including pin 7, which is hardwired to iCE's
txpin, as outlined above. If you use pin 7 for CRAM configuration, you need to remove the patch wire for flash memory programming, obviously. ↩︎
Last updated: 7 July 2025