Just a shout-out to see if anybody has any experience of an external hardware replacement for an SD Card/microSD Card.
Pros for SD Card: Cheap, GBs of storage, static, SPI bus speed to access Cons: connector corrosion, reliability to humidity/vibration
I have used FRAMs and these are great solid state storage devices BUT a bit slow and limited storage (currently 2Mbit?)
SRAM would be ideal but I am not aware of products and because they are not mainstream they are expensive.
Has anyone used a MCU with storage just as an external storage device?
OK - order to Digikey arrived today and this evening I have been able to solder the SOIC-8, actually a WSOIC-8 onto a SOIC-8 IC prototype adaptor. Trick is to bend the legs under! Not the greatest bit of soldering but it works.
The model I am testing is the W25Q128 - 128Mbits or 16M Bytes not the 128KB in Rickās example
fs.withPhysicalSize(16 * 1024 * 1024); //16MByte for W25Q128
The diagnostic tests (took a while to shut off all the trace output) timings shown below:
chip id: ef4018
starting runFullTestSuite
starting erase all flash sectors
starting format
finished format: 113441 ms
starting mount
finished mount: 740 ms
testSimple passed
testAppend passed
testDir1 passed
testWiring passed
starting write 64K in 256 byte pages
finished write 64K in 256 byte pages: 543 ms
starting read 64K in 256 byte pages
finished read 64K in 256 byte pages: 569 ms
testLarge passed
starting filesystem check
First thing to say is that it takes a fair while to erase and format the flash (which it does at the start of the benchmark Spiffs test) - just over 4 minutes. You would only do this once and not every time you turned on - so I guess that is OK. However, the 1GBit version would be over 30 minutes!! The read 64K is slow (IMO) versus SD. Maybe I need to experiment with a larger page size. It might still be too slow to read images from to TFT - will need to try different buffer sizes. I think for a simple flash based publish log then using Spiffs rather than just SPIFlash should be fine. I guess the flash could be partitioned with the log using plain SPIFlash addressing and the application using the Spiffs.
[Update] Not sure what is going on with the library but the benchmark code example on github is different from the example under SpiffsParticleRK in workbench. If I copy and load github version I get the following results - more inline with the example on Readme.txt:
0000167335 [app] INFO: starting chipErase
0000199917 [app] INFO: finished chipErase: 32582 ms
0000199917 [app] INFO: starting format
0000312789 [app] INFO: format res=0
0000312790 [app] INFO: finished format: 112873 ms
0000312790 [app] INFO: starting mount
0000313530 [app] INFO: mount res=0
0000313530 [app] INFO: finished mount: 740 ms
0000313530 [app] INFO: testing 262144 bytes in 512 byte blocks
0000314606 [app] INFO: starting write
0000316208 [app] INFO: finished write: 1602 ms
0000316209 [app] INFO: starting read
0000316942 [app] INFO: finished read: 733 ms
0000321227 [app] INFO: testing append and flush 100 bytes 5000 times
0000322304 [app] INFO: starting append
0000323172 [app] INFO: finished append: 868 ms
0000323172 [app] INFO: starting read
0000323745 [app] INFO: finished read: 573 ms
Buffer is 512 bytes so something of a speed increase.
@armor, @RWB, I have been using SPIFFS running on a STM32F103 (not a Particle device) with a 16MB NOR flash (W25Q128JV). Though SPIFFS is great, it does have a lot of overhead. I implemented a file-based circular buffer and found a couple of things:
SPIFFS slows down A LOT when you reach the end of flash and it has to start erasing pages to make room for new records.
Writing often to a file containing the buffer head and tail pointers munched through flash very quickly as SPIFFS copied and amended page and sector records.
The larger the flash, the slower SPIFFS will run over time. It must traverse the flash data looking for the active control records.
I ended up only allocating 4MB of the 16MB flash to balance the overall performance. I also ended up modifying the code to use and erase 4KB sectors instead of 64KB sectors. Also, as you found, erasing and SPIFFS-formatting a large flash takes a lot of time. These were my flash configuration settings:
W25Q128JV with 4KB sectors
#define SPIFFS_CFG_PHYS_SZ(ignore) (4*1024*1024) // 4MB of 16MB total arranged as 4096 sectors x 4KB
#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (4*1024) // Erasable sector is 4KB
#define SPIFFS_CFG_PHYS_ADDR(ignore) (0) // Start at address offset 0
#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256) // 256B page size (matches device page size)
#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (4*1024) // 4KB logical block size (matches physical sector size)
My ideal storage would be SPI-based FRAM since it is fast and non-volatile. However, it does not come in large sizes like NOR flash does. Though I suspect SPIFFS could work on FRAM, it certainly would not be optimal.
Hi @peekay123, thanks for sharing that insight. As suspected FRAM and NOR flash just arenāt obvious replacements for SD card. Iām thinking maybe SPI FRAM for a publish log (with no Spiffs) and then staying with SD or maybe microSD for the image files.
Given the limitations of Spiffs you have mentioned is this why Particle are going down the Posix route?
@armor. an SD card is essentially an entire NAND storage āsystemā designed to be fast. With SPIFFS running of the host processor, it is subject to that processorās environment. What is missing to make SPIFFS/NOR run better like on ESP32 processors is a QSPI bus. Also, moving the garbage collection to its own thread might help. However, the Gen3 devices use LittleFS which is not exposed to the user unfortunately. I do believe the Gen3 devices DO use QSPI for the external flash so having access to that would be great. The new AssetTracker will have 8MB of external flash, much of which will be available to users.
My Gen3 experience with SPI has been poor - we are now getting close to asking whatās the point in the nRF58240? Generally, I donāt understand why more flash and RAM didnāt get into the specs.
Particle chose LittleFS because it is designed to not fail in case of a power failure/reset whereas SPIFFS is not. Both implement wear-leveling, a necessity of NOR flash. Is a file system necessary for storing images?
No but it makes it much easier to access them by filename rather than having to keep a table with addresses - but given there are very few changes to the resource files not impossible.
I didn't realise that point about LittleFS versus SPIFFS - another reason not to use SPIFFS.
On my next version Iām gonna have to implement something like this but Iāll be doing lots of reading and writing⦠Itās basically a big circular buffer. What I want to do is use a small (couple kb) FRAM chip just to store the vector/position in the circular buffer and possibly some info on dead pages and a large (maybe .5gb) winbond flash for the data itself. On boot, the mcu reads the index from the fram then goes to the flash to grab the right page. Itās a little wonky but I think it would be faster lookup than spiffs and I wouldnāt have to worry about leveling so much. basically, I donāt want to be writing the buffer location to the same memory place every timeā¦
has anyone built something similar? Iād be very interested in any pitfalls that people have encounteredā¦
@ccunningham, I was working on a fixed-record-size circular buffer for NOR flash to replace SPIFFS but havenāt had the time to finish it. Storing the head, tail, record count and other data in FRAM is a great idea. The trick with circular buffers using NOR flash is what you do when you write the end of the device and need to wrap around back to the start. If your tail data is in the way, you have to āmoveā the tail to the start of the next (4KB) sector so you can erase the sector to make room for the new head data. The lost data represents the oldest data and it only gets deleted if and only if the buffer wasnāt emptied before the wrap-around. For my use-case, this was not an issue.
To make things simpler and given the fixed-size data structure, I only stored the number of structures that fit within a sector (4KB) and left the rest āblankā. That way, when I make room for a new record, I know exactly how many records were erased when I moved the tail. Not having to worry about page/sector boundaries makes the code simpler and I found the āunusedā byte count to be insignificant, especially in the 16MB device I was using.
Finally, another trick I planned on using was to add a āmagicā set of bytes at the beginning of each record. This was done to allow the code to āpeekā ahead at the first page (256 bytes) of the next sector to be written. If the magic bytes were not 0xFFās, indicating blank flash bytes, then the sector needed to be erased before writing.
@peekay123 yeah, I had similar issues with putting many files on an sd card, trick is to just size youāre buffer/files right to nearly align w the page/file boundary, so you donāt waste too much space like you said. Iāll probably do something similar. What I was more concerned about was the dead sectors, Iād like to just have a list(in fram) of āflyover countryā that I can just skip over. does the windbond spit an error for dead pages? does this occur frequently enough to even care about? Iāve never used raw flash like thisā¦
@ccunningham, the write operation to the Winbond will fail with error if it canāt write to a page. You could then mark the page (256 bytes) as bad or the entire sector. Unlike SD cards, smaller NOR devices will last a long time with even basic wear-leveling.
thx @peekay123, this is good to know, weāve recently linked a lot of our errors to the sd card, so itās good to know the nor would be more reliable. It looks like we would just forgo the fram and store that data in ram like you were doing. we should very rarely(hopefully not) lose data that way⦠If i were to reserve a few kb for dead spot addresses I think thatād be good⦠weāll see