STM32 based Drag N Drop iCE40 SPI Bitstream loader.

Similar projects worth following
iCEBlaster is the USB Drag and Drop Bitstream loader for iCE40 FPGA. Using STM32 as Mass storage device class glued with internal Flash memory as a USB disk (on iCEBlaster v1) or Virtual File system based on FAT12 (iCEBlaster VFS).


iCEBlaster is a Drag and Drop firmware loader via SPI for iCE40 FPGA. The brain of this project is based on STM32 Arm Cortex microcontroller. 

How it works?

Original iCEBlaster (v1) version :

By using USB-FS library working as USB Mass storage device class (USB MSC) and with interface I/O code with internal Flash. Working together as USB Disk pre formatted with FAT12 file system with 1024 Bytes per sector, 64total sectors, 3 sectors reserved for master boot record (sector 0) and File allocation tables(sector 1-2). And using total of 64 internal Flash pages (1Kbytes per page, page 64 to 127, total of 64KBytes). This version of iCEBlaster only support iCE40 with 1K LUTs 

By copying the iCE40 FPGA Bitstream to the disk, 2 while loops help to locate the physical address of Bitstream on the internal Flash (for spi tx pointer) and to figure out the Bitstream size (for spi tx size). After that the Bitstream loading sequence begin. 

When done, The MCU release CRESET to let FPGA run the firmware that we just flash. Then perform the internal flash reformat to have a new and ready to Drag and Drop USB Disk.

VFS Version :

In the VFS version of iCEBlaster. Virtual file system is based on FAT12 and no internal flash was used. The switch case is used to handle all possible sector number to return the correct data (e.g. FAT file system and FAT signature in boot sector, Volume label). And state machine is used for match-detecting the Bitstream from data packet sent from USB Host. And immediately send the Bitstream over SPI in the chunk of 512 Bytes. VFS FAT12 has 512 Bytes sector, Total of 512 sectors, 3 sectors (0-2) reserved for FAT file system and FAT table. Volume label start at the beginning of sector 3. Total of roughly 160Kbytes virtual disk space.

The Bitstream transfer happen after STM32 receive data from USB Host. 

The benefit of using VFS is that you can send virtually any Bitstream size. This allow iCEBlaster to not only support just iCE40LP1K and UL1K. But other higher density iCE40 can now be used with iCEBlaster. Plus, when not rely on Internal flash. This doesn't wear out the flash and kills the STM32 fast.  

Bitstream locator (iCEBlaster v1)

with while loop and nested if-statement to check for magic word (or preamble) 0x7EAA997E. This is the beginning of the Bitstream. Another while loop check for 0x010600 which indicates the end of Bitstream (and It's actually a wake up command to wake the iCE40 up).

iCE40 Bitstream Loading sequence.

// Enter Slave SPI mode.

1. Set SPI CE pin to LOW.

2. Set CRESET pin to LOW.

3. Wait for 2ms.

4. Set CRESET pin to HIGH.

5. wait for 200ms to let CRAM clear itself.

// Send Bitstream

6. Send Bitstream Via SPI, 8 bit and MSB first.

7. Send additional 12 dummy bytes (96 clock cycles).

8. (optional) send additional 7 dummy (56 clock cycles), this will allow configuration SPI pins to reuse as user PIO.

// End of Bitstream loading.

9. Set SPI CE pin to HIGH.

  • 1 × Maple Mini or Any STM32F103CBT6 board.

  • iCEBlaster is here!

    TinLethax02/17/2023 at 11:57 0 comments

    I finally built the version 1.0 of iCEBlaster !

    This is the first "real" iCEBlaster board. 

  • iCEBlaster board !

    TinLethax07/07/2022 at 06:46 0 comments

    Yesterday I'm thinking about making a actual USB stick board to be the actual iCEBlaster. Right now the iCEBlaster with VFS is virtually works on any STM32 that have USB MSC. Then I recalled that there's the 20 pins STM32F042F6P6. And it might work with the original code. But need to do some code shrinking to fit the 32kBytes flash and 6kBytes SRAM. Code is done but untested. I also designed the PCB for iCEBlaster too. 

    Anyway, I'm now sure that the tricky delay still work or not. But in order to make the code fit in 32k. I need to optimize the code (I selected the optimize for debug). Hope that it won't mess up while(cnt--); delay.

  • VFS is now working properly*

    TinLethax07/06/2022 at 05:58 0 comments

    Yesterday. I tried to implement the Virtual File System similar to DapLink programmer and STLink on many STM32 evaluation board( Which is also based on DapLink). My Implementation is still using FAT12 instead of FAT16 or 32 (Might change for larger Bitstream size). For now the VFS version of iCEBlaster is working correctly with a catch. Before talking about that catch. Let me explain how VFS works.


    Inside USB_DEVICE/App/usbd_storage_if.c is where user implement the Input and Output (i/o) operation with what ever device they try to glue with USB. 

    Above pic shows the 2 important functions that implement the I and O.

    For example, I want to make the world worst flash drive. So I implement the SPI driver of 32KBytes FRAM that I have 3 laying around. So I implemented the FRAM_read() and FRAM_write() to do the I/O operation with FRAM. 

    Before VFS :

    From above FRAM example, USB MSC is automatically calling the FRAM_read() from STORAGE_Read_FS() function and FRAM_write() from STORAGE_Write_FS() within usbd_storage_if.c, This happend when USB host send/request data to/from the STM32. Since I configured the STORAGE_BLK_SIZ (in usbd_storage_if.c) to 512 bytes. The STORAGE_Read_FS() and STORAGE_Write_FS() always read 512 bytes and write 512 bytes. The STORAGE_BLK_SIZ (most of the time) is equal to the block erase size of media. The previous version of iCEBlaster is utilizing internal flash as the media for the USB MSC. It has 1024 Bytes erase size. Which means that to modify a single byte, you copy 1024 bytes (1 flash page), modify single byte, erase whole page, rewrite it back. This is the reason to set STORAGE_BLK_SIZ to the same as erase size.

    Using VFS :

    When come to VFS. It's different story. Since the read function of VFS that I implemented is based on switch case of sector number. I need to consider of every possibility case of which sector do what, so the switch case can handle all. Below pic is actual code of implementing the read function of VFS

    And the writing function of VFS is quite tricky. I'll show you the pics first.

    Long code. I'll explain. The only thing that this function do is to receive 512 bytes from USB host (passed from STORAGE_Write_FS() ) and to keep checking for preamble of iCE40 Bitstream. Due to the complexity. State machine is involved (learning state machine on FPGA is helpful for microcontroller too!). If the preamble is found. That data packet will be sent out with SPI immediately in multiple chunks of 512 bytes. Most of the time I spend on this code is not to make VFS functional, VFS is easy. But the thing that took most of the time is the iCE40 Reset sequence. It requires to wait auto 200ms before SPI TX start. First I simply use HAL_Delay(200);. But that cause USB to hang. Another method I use to to keep return USBD_BUSY until time passed at least 200ms. But for some reason the USBD_BUSY implementation of STM32 code is kind of buggy. The USB host just ignore and assume that data is written to STM32. Last method I use is to use while loop as delay. And it works ! with a big * . The iCEBlaster original version set the optimization level to optimize for size. That optimization still remain to the same code I did the VFS (It's the same code). Whit that option , optimization optimized out the while(cnt--);  and mess up the delay timing. By setting the optimization to NONE or For debug make delay works again. 

    Since to make the reset sequence work properly and not depend on compiler thing. I need to find the better way of creating the non blocking delay. I tried the pipelining method but that didn't work (at least not yet). But until then, this is the latest code on GitHub iCEBlaster

  • First version released!

    TinLethax05/19/2022 at 09:38 0 comments

    The first version of iCEBlaster (v1.0) are now available over GitHub! 

    iCEBlaster stable

View all 4 project logs

Enjoy this project?



jemuhammad wrote 07/13/2023 at 00:21 point

Can the ICEBlaster be switched back and forth from being a VFS FPGA Drag and Drop firmware loader to just a STM32 uC / USB-C dev board?

  Are you sure? yes | no

kubabuda wrote 05/08/2023 at 14:14 point

2 photo in gallery (with Maple mini) - purple PCB is target FPGA breakout? What board is that?

  Are you sure? yes | no

TinLethax wrote 05/08/2023 at 15:03 point

Hi, It's breakout board for the iCE40LP1K-CM36. I got lucky with 2 layers fabbed by OSHPark. Right now I have iCEStamp FPGA board (Not yet on the but soon). You might want to check it out over my twitter.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates