VFS is now working properly*

A project log for iCEBlaster

STM32 based Drag N Drop iCE40 SPI Bitstream loader.

TinLethaxTinLethax 07/06/2022 at 05:580 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