Couple days ago. I was able to do some little upgrade to the iCEBlaster (Recapping : iCEBlaster is Drag and Drop Bitstream loader for iCE40 FPGA using stm32f103 MCU). The first version of iCEBlaster utilize internal flash as storage medium with USB MSC. While it’s working just fine. Write and erase internal flash frequently is not healthy to STM32 and it will die quick. I recalled that my STLink on my STM32F3 Disco board also has Drag and Drop feature. But I wondered how they did that. It turns out that the STLink probably based on ARM Embed DAPLink programmer. I took some look at the source code and it seems that DAPLink didn’t use internal flash as storage medium. But they have functions that handle each sector read/write request of USB MSC. I really want to use DAPLink source code with iCEBlaster. But It was too complex and I want to do everything by my self.
Implementing VFS is tricky. The term VFS (Virtual File System) is not a new type of file system. It’s a way to kind of “mimic” formatted storage. The first version of iCEBlaster is formatted with FAT12 to use with internal flash through USBD_storage_if.c disk interfacing. The USB Host actually read and write to physical storage medium. And there’s file system on that storage medium. But with VFS. There’s no actual storage medium to store data. The file system itself still based on FAT12 (But I’ll tell you the magic later). But the disk interfacing is actually just some switch case (USB Host read from STM32) and simple state machine (USB Host write to STM32).
There’s 2 functions in USBD_storage_if.c that glue USB MSC to storage medium stuffs (SPI flash, Internal flash, SD card, etc…). With the function STORAGE_Read_FS() -> Host read from STM32 and STORAGE_Write_FS() -> Host Write to STM32.
All you have to do is to implement I/O function and put inside these 2. There’re 2 things in both function that we care about. *buf which is pointer to the buffer of USB MSC. Default value (of MSC_MEDIA_PACKET) is 512 Bytes. The blk_addr or sector number, this is where I used switch case to deal with reading.
The reason that I don’t care about blk_len is because it’s fixed buffer length. Which is 512 Bytes (MSC_MEDIA_PACKET). Host send 1 byte, blk_len is still telling us 512 bytes.
I wrote 2 functions for each I/O function. One named usb_vfs_read(). This function take sector number into switch case. By default, Sector 0 is reserved and called Boot sector. This is where the description of FAT file system lives. In this case it’s FAT12 and it has 4 reserved sectors, the volume label starts at the beginning at the start of sector 4.
There’s nothing much happening in usb_vfs_read(). But with usb_vfs_write() is more complex and tricky.
In VFS write function. At the state machine step 0, every 512 bytes data packet coming into this function will be scanned for 0x7EAA997E A.K.A iCE40 Bitstream preamble. After the preamble is detected. First 512 bytes chunk is sent via SPI at 3MHz to iCE40, then the state machine now switch from step 0 to 1. In Step 1 in state machine, every data packet is scanned for 0x010600 A.K.A Bitstream ending. Normally, this won’t detect the ending until (of course) ending of Bitstream. 512 bytes will just send over SPI. But when the ending is detected. There will be extra step that will send 19 dummy byte to kick start the FPGA and release CE pin. This also send reset flag to the code running in main loop to do USB reconnect.
I still couldn’t believe that I did all of this in just 1 day. And Yes, I ended up going to bed at mid night. Got up next morning to do git commit.
With the VFS is working (Tested). I proceed to design the actual hardware of iCEBlaster. Since iCEBlaster no longer used internal flash. I can use cheaper (not today tho) STM32 such as STM32F103C8 or STM32F103T8. But I went with STM32F042F6P6. This 20 pins TSSOP MCU is more than enough to be used as iCEBlaster. The code isn’t tested but might work.
Problem with VFS implementation
When come to ARM CPU. Optimization is impacting how code is functioning. I created new STM32CubeIDE project to experiment on the VFS. Since I need 200ms delay before start SPI TX. HAL Delaying in USB code breaks them. Then I tried while loop decrement while(cnt–); as a delay and it works! But when I copied to the iCEBlaster project. It stopped working. So, what the heck ?!?!?!
It turned out that the Optimization affected the delay. As if the while loop is optimized (I set the optimization to optimize for size). I found that by setting it to optimized for debug or not optimize at all. This allows while loop delay to function properly as I wanted. So next time your code don’t work as expected when created new code project. Try checking on Optimization.
Advantage of VFS
Since VFS technique doesn’t use internal flash. It doesn’t wear out as quick as first version of iCEBlaster. Plus, VFS doesn’t use real storage medium. So we can fake our drive capacity. From 64kBytes. This is now 32MBytes. With this “virtual” capacity. iCEBlaster now can take larger Bitstream size of larger iCE40 (2K 4K and 8K LUTs variants). This expands the usage of iCEBlaster with more iCE40 FPGA!
For the hardware and software source.
I’ll update later. It’s here : https://github.com/TiNredmc/iCEBlaster