Shop OBEX P1 Docs P2 Docs Learn Events
P2 uSD Card Driver — FAT32 Filesystem (spin2/pasm2) — Parallax Forums

P2 uSD Card Driver — FAT32 Filesystem (spin2/pasm2)

Stephen MoracoStephen Moraco Posts: 426
edited 2026-02-26 01:18 in Propeller 2

New P2 uSD Card Driver — FAT32 Filesystem with Smart Pin SPI

Version 1.0.0

This is the first public release of a new FAT32-compliant microSD card filesystem driver for the P2. It started as a study of Chris Gadd's OB4269 driver from OBEX and evolved into a complete rewrite — smart pin SPI, streamer DMA, multi-file handles, multi-cog access, and a full set of card utilities you can run directly from the P2 with no PC tools needed.

What's in the box

  • Driver (micro_sd_fat32_fs.spin2) — FAT32 read/write with smart pin SPI + streamer DMA, dedicated worker cog, hardware lock serialization, up to 6 simultaneous file/directory handles, per-cog working directories
  • Card Formatter — Format any SDHC/SDXC card as FAT32 directly from the P2. Cross-OS compatible (Windows, macOS, Linux can read the result)
  • Filesystem Repair — 4-pass fsck with auto-repair: structural integrity, chain validation, lost cluster recovery, FAT sync. Plus a separate read-only audit (41 checks)
  • Benchmark & Characterizer — Measure raw sector and filesystem throughput, read card registers to identify manufacturer, capacity, speed class, and SD spec version
  • Demo Shell — Interactive terminal with dir, cd, type, format, fsck, audit, bench, and more
  • Example Programs — Four compilable examples: basic read/write, data logger with sync, directory walk, and multi-cog concurrent access
  • Tutorial — See SD Card Driver — Tutorial

20 cards tested across 9 manufacturers — see the Card Performance Guide for ranked comparisons, purchase recommendations, and card sizing guidance.

Testing: 345+ automated regression tests across 19 test suites, all validated on hardware.

Known limitations:

  • 8.3 filenames only (no LFN)
  • SPI mode only, 25 MHz maximum
  • Tested with cards up to 128 GB; driver goal is full 2 TB support (FAT32/SDXC maximum) in an upcoming release
  • Currently compiles with pnut/pnut-ts. Flexspin and Spin Tools IDE compile will be supported in next release.

Hardware: P2 Edge Module (has built-in microSD socket), or any P2 board with the microSD Add-on Board (#64009). The default pin configuration is base pin 56 (P2 Edge).

Visit the P2 microSD FAT32 Filesystem repository for full documentation, including a driver tutorial, theory of operations, and card catalog.

The release package can be downloaded from the Releases page.

If you find issues, please file them at the Issues page.

What's next? Ensuring this driver and utilities compile with all of our compilers. Expanding card size support toward the full 2 TB FAT32 limit, researching windowed FSCK validation for larger cards, and investigating the Silicon Power CMD18 compatibility issue. I also want to look into whether A2 command queuing features can/should be leveraged in SPI mode.

Enjoy!

Stephen

Comments

  • roglohrogloh Posts: 6,264

    Wow this is very extensive @"Stephen Moraco" . It looks very comprehensive from my initial browse on GitHub. I really like how you've collected and documented all the important design decisions here too, lots of stuff everyone can learn from. It will be great to try this out when I get a chance. I also like how it supports multi-COG operation, that opens up lots of interesting possibilities for P2 COG based apps/tools that could be run simultaneously and sharing the same filesystem. Very nice indeed!

  • ke4pjwke4pjw Posts: 1,283

    YES! Thank you @"Stephen Moraco" ! I love that it is handle based. This is the missing piece for me using tasks in spin to do a task switching webserver with multiple sockets. I will take it for a test drive this weekend using Spin Tools.

  • @"Stephen Moraco" , great work. I just started trying out the new driver.
    I started by running the SD_example_directory_walk program. The program seemed run correctly, but one thing I noticed is that the Volume Name that was displayed as "NO NAME", when the freshly formatted (using Windows 11 format) 8 GB SD card had a volume label of "P2DATA" defined.
    I'm not sure what is going on, is there an alternate location for where the volume label is stored?

    Cog0  INIT $0000_0000 $0000_0000 load
    Cog0  INIT $0000_0F64 $0000_6ACC jump
    Cog0  === SD Directory Walk Example ===
    Cog1  INIT $0000_0F64 $0000_1D2C jump
    Cog0  Volume: sd.volumeLabel() = "NO NAME    "
    Cog0  Free:   sd.freeSpace() >> 11 = 7_423 MB
    Cog0   
    Cog0  --- Root Directory ---
    Cog0    [DIR]  @name_copy = "EXDIR"
    Cog0   
    Cog0  --- Creating EXDIR with files ---
    Cog0   
    Cog0  --- EXDIR contents (via directory handle) ---
    Cog0    [DIR]  @name_copy = "."
    Cog0    [DIR]  @name_copy = ".."
    Cog0    [FILE] @name_copy = "FILE_A.TXT"  sd.fileSize() = 18 bytes
    Cog0    [FILE] @name_copy = "RENAMED.TXT"  sd.fileSize() = 18 bytes
    Cog0    [FILE] @name_copy = "FILE_B.TXT"  sd.fileSize() = 18 bytes
    Cog0    [FILE] @name_copy = "TEMP.TXT"  sd.fileSize() = 14 bytes
    Cog0   
    Cog0  --- File management ---
    Cog0  Deleted TEMP.TXT
    Cog0  Renamed FILE_B.TXT -> RENAMED.TXT
    Cog0   
    Cog0  --- EXDIR after changes ---
    Cog0    [DIR]  @name_copy = "."
    Cog0    [DIR]  @name_copy = ".."
    Cog0    [FILE] @name_copy = "FILE_A.TXT"  sd.fileSize() = 18 bytes
    Cog0    [FILE] @name_copy = "RENAMED.TXT"  sd.fileSize() = 18 bytes
    Cog0    [FILE] @name_copy = "FILE_B.TXT"  sd.fileSize() = 18 bytes
    Cog0   
    Cog0  === Done ===
    
  • evanhevanh Posts: 17,092
    edited 2026-02-26 09:08

    That is substantial. And filesystems are far from simple logic so I presume the bulk of it is ported. What is the original source code?

    I'd very much like to plug in my 4-bit SD mode low level driver. What you've got would need some reworking to suit having a low level interface though. There's way too many low level functions as it stands.

    Although it doesn't have to be this small, the basic interface is just cardinit(), readblocks() and writeblocks().

  • maccamacca Posts: 1,006

    Great job!

    @"Stephen Moraco" said:

    • Currently compiles with pnut/pnut-ts. Flexspin and Spin Tools IDE compile will be supported in next release.

    Just a note for Spin Tools:

    You may replace the #PRAGMA EXPORTDEF SD_INCLUDE_ALL that throw and error with #DEFINE SD_INCLUDE_ALL, the result is the same because in Spin Tools the #defines are propagated to child objects.

    I'll add support for EXPORTDEF in the next release anyway, until then you can also use the conditional compile to be compatible with both:

    #IFDEF __SPINTOOLS__
    #DEFINE SD_INCLUDE_ALL
    #ELSE
    #PRAGMA EXPORTDEF SD_INCLUDE_ALL
    #ENDIF
    

    I hope you can implement support for long file names in the future, that will be really great.

  • RaymanRayman Posts: 16,098
    edited 2026-02-26 09:54

    This looks really nice. Looking forward to FlexProp and Spin Tools support.
    How much memory does it need?

  • @evanh said:
    That is substantial. And filesystems are far from simple logic so I presume the bulk of it is ported. What is the original source code?

    This is a combination of starting with OBEX #4269 and the FAT32 specification. Then, studying the original for interchange robustness (carrying media to different OSes), and for power-fail robustness. After fixing the issues, the focus was entirely on how to adjust it for performance using the available P2 features, and then reshaping for multi-cog handling. We added regression tests (more to come) as we built the driver, using them to ensure that each change kept all other features working. When we finally had the performance sorted, we then had to rerun the performance analysis for our 15 selected cards and report on it all. Here's a brief summary from the github commit history (to provide a sense of scale).


    By the Numbers

    Metric Value
    Calendar days 41
    Regression test files 18
    Regression tests 345+
    SD cards characterized 25
    Driver architecture iterations 3 (bit-bang, V2 streamer, V3 handle API)

    Key Technical Milestones

    Date Milestone
    Jan 16 Project start — bit-bang driver, test framework
    Jan 20 Multi-cog worker architecture
    Jan 22 Streamer-based sector reads (XINIT/RDFAST)
    Jan 23 Multi-block CMD18/CMD25 operations
    Jan 29 V3 multi-file handle API
    Jan 31 CRC-16 via P2 GETCRC instruction
    Feb 13 Spin2 STRUCT types for register access
    Feb 16 TX streamer alignment fix (write path)
    Feb 18 Sector boundary bug fix (handle API)
    Feb 23 Deterministic SCK reset (read path)
    Feb 24 v0.9.3 — full regression suite green
    Feb 25 v1.0.0 released
  • Stephen MoracoStephen Moraco Posts: 426
    edited 2026-02-27 00:52

    @macca, thank you this is now in the upcoming release. Just wrapping the flexspin changes. Working on the 2TB fix as well (not that it is likely to be used. ;-)

    @"Francis Bauer", it looks like we found an issue with the driver vs. Windows. The theory is that Windows is not putting the volume label in both locations per spec. (Not all OSes do, so not unusual) The driver wasn't looking for the alternate location with the mount. I'm testing against Windows to verify my fix will work.

    @evanh let's talk offline about adaptation to 4-pin. The performance increase should be fun to see.

  • evanhevanh Posts: 17,092
    edited 2026-02-27 06:55

    @"Stephen Moraco" said:
    ... We added ...

    Who's we?

    EDIT: Ah, Chris Gadd by the looks. Does he not frequent the forums?

  • NEWS

    I just released v1.1.0

    Here's what's new/fixed:

    v1.1.0

    Driver

    • Breaking: V1 legacy API removed (readFile(), writeFile(), readDirectory(), etc.) — use handle-based API
    • Volume label scan follows full root directory cluster chain (was limited to first 16 entries)
    • FAT chain end-of-chain comparisons use unsigned operators for 2 TB addressing

    Utilities

    • FSCK full validation now works on cards of any size (windowed bitmap; cards >64 GB scanned in 2M-cluster passes)
    • Cross-compilation support added for Spin Tools IDE and flexspin

    Testing

    • Expanded to 389 tests across 20 suites (added CRC injection, recovery, and error handling suites)
    • FSCK windowed bitmap diagnostic test for 128 GB cards

    Visit the P2 microSD FAT32 Filesystem repository for full documentation, including a driver tutorial, theory of operations, and card catalog.

    The release package can be downloaded from the Releases page. Download the prepackaged .zip file.

    If you find issues, please file them at the Issues page.

    What's next? Investigating the Silicon Power CMD18 compatibility issue. I also want to look into whether A2 command queuing features can/should be leveraged in SPI mode.

    Enjoy!

    Stephen

  • @"Francis Bauer" this version should fix your volume label (Windows formatter) issue. Please let me know.

  • Stephen MoracoStephen Moraco Posts: 426
    edited 2026-02-28 21:39

    @Rayman said:
    This looks really nice. Looking forward to FlexProp and Spin Tools support.
    How much memory does it need?

    Thank you!

    Regarding tools, both tools should now be supported.

    Regarding memory use, I added a document to the repo. See the Memory Sizing Guide. It answers your question (albeit more long-winded than you might have expected ;-) but shows off a bit of how to use the -m (generate .map) option of pnut-ts.

  • RaymanRayman Posts: 16,098
    edited 2026-02-28 22:55

    @"Stephen Moraco" Looks like 25kB then? Not so bad for P2. Thanks for supporting FlexProp and Spin Tools! Imagine it's hard when you have your own tool...
    Or maybe it was easy because all the Spin2's are supposed to do the same thing?

  • Hi,
    It would be interesting to have a comparison table: What is the advantage or differences of this driver to the one, that is integrated into FlexProp?
    Cheers Christof

  • @"Christof Eb." said:
    Hi,
    It would be interesting to have a comparison table: What is the advantage or differences of this driver to the one, that is integrated into FlexProp?
    Cheers Christof

    I would enjoy having an interested party that knows the flexprop driver to report on this.

    Regarding your advantage question, if the flexprop driver works for you and is what you need/want, then you have the best one for you. This is a good answer; there need not be an advantage to using this one; you have what you need.

    My goal is to provide a suite of drivers that match key P2 Edge hardware that are all aggressively tested and "certified" if you will. In my case, with all of these tools, I regression-test; I'm very open about the test results and the tests themselves. So any of us can deeply understand the how, why, and the rigor of the testing. Yes, I'm kind of a nutbrain about this. But I enjoy crafting building blocks that I can walk away from their development and then employ in all of my projects. The regression testing ensures that if we find issues with one due to something missed or a new stretch of the use model, I can go back and adjust it, prove it's working again, and then walk away with a quick turn, which is just as solid as the original release.

    This is to enable us, as community members, to trust that the current release and future upgrade releases are stable and unlikely to cause problems when we build embedded systems for fun or for hire. We want to be able to field trusted code. This is consistent with how/why we regression-test the pnut-ts compiler. Trusted building blocks so we can get real work done and products delivered.

    The FLASH_FS driver was the first in this set. This driver is the second. There's a third coming in a day or two.

    Flexprop and Spin Tools IDE, to name a few, are developed in similar ways to provide us all with the best tools.

  • @Rayman said:
    @"Stephen Moraco" ..... Thanks for supporting FlexProp and Spin Tools! Imagine it's hard when you have your own tool...
    Or maybe it was easy because all the Spin2's are supposed to do the same thing?

    Actually, no, not hard, good for all of us when we are asked to provide this support, you saw @macca suggesting he was going to make a change. Eric also, when I discussed what I found while adapting for flexspin, talked to me about things we should consider for pnut-ts and noticed he wanted to make a change. This makes all of our tools better as we all respond. So, is it hard when I have my own tool? Not at all. I enjoy when we all work to support each other's tools. It's good for all of us as our tools get stronger, more capable.

    Oh, and one more thing: thank you all for your support when I said I would support these tools, but hadn't yet. Thank you for being patient.

  • Francis BauerFrancis Bauer Posts: 407
    edited 2026-03-01 08:09

    @"Stephen Moraco" said:
    @"Francis Bauer" this version should fix your volume label (Windows formatter) issue. Please let me know.

    Yes, I now see the correct Volume Label using version 1.1.0 of the driver.

    Thank you for the quick turnaround, @"Stephen Moraco"

    Cog0  INIT $0000_0000 $0000_0000 load
    Cog0  INIT $0000_0F64 $0000_669C jump
    Cog0  === SD Directory Walk Example ===
    Cog1  INIT $0000_0F64 $0000_1CFC jump
    Cog0  Volume: sd.volumeLabel() = "P2DATA     "
    Cog0  Free:   sd.freeSpace() >> 11 = 7_423 MB
    Cog0   
    Cog0  --- Root Directory ---
    Cog0   
    Cog0  --- Creating EXDIR with files ---
    Cog0   
    Cog0  --- EXDIR contents (via directory handle) ---
    Cog0    [DIR]  @name_copy = "."
    Cog0    [DIR]  @name_copy = ".."
    Cog0    [FILE] @name_copy = "FILE_A.TXT"  sd.fileSize() = 18 bytes
    Cog0    [FILE] @name_copy = "FILE_B.TXT"  sd.fileSize() = 18 bytes
    Cog0    [FILE] @name_copy = "TEMP.TXT"  sd.fileSize() = 14 bytes
    Cog0   
    Cog0  --- File management ---
    Cog0  Deleted TEMP.TXT
    Cog0  Renamed FILE_B.TXT -> RENAMED.TXT
    Cog0   
    Cog0  --- EXDIR after changes ---
    Cog0    [DIR]  @name_copy = "."
    Cog0    [DIR]  @name_copy = ".."
    Cog0    [FILE] @name_copy = "FILE_A.TXT"  sd.fileSize() = 18 bytes
    Cog0    [FILE] @name_copy = "RENAMED.TXT"  sd.fileSize() = 18 bytes
    
  • evanhevanh Posts: 17,092

    @"Christof Eb." said:
    Hi,
    It would be interesting to have a comparison table: What is the advantage or differences of this driver to the one, that is integrated into FlexProp?
    Cheers Christof

    The two performance tester programs I wrote in C originally I also ported to Spin2 but both use the libc type file handling API. ie: I used the libc.spin2 wrapper object that comes with Flexspin.

    I did port them to Catalina C as well. That needed some reworking of a few functions. A couple were in Pasm2. I should be able to do a matching job with Stephen's FAT32 as well ...

  • RossHRossH Posts: 5,709
    edited 2026-03-01 10:47

    @evanh

    I did port them to Catalina C as well. That needed some reworking of a few functions. A couple were in Pasm2. I should be able to do a matching job with Stephen's FAT32 as well ...

    If I can help, let me know. I had a quick look at the new Spin2 driver, but even though I am fairly proficient in both PASM and various high level languages, it is all just gibberish to me ... :)

  • Hi everyone, heads up, I'll be posting a v1.2.0 later today.

    In some of my work, I discovered that a couple of the routines are directly accessing SPI without using the backend cog. I don't know how my regression testing missed this, but it won't in the future ;-)

  • NEWS

    I just released v1.2.0

    Here's what's new/fixed:

    v1.2.0

    Driver

    • Breaking: 17 PUB methods now return SUCCESS (0) / negative error code instead of true/false: mount, unmount, sync, newDirectory, changeDirectory, deleteFile, rename, moveFile, setVolumeLabel, initCardOnly, readSectorRaw, writeSectorRaw, readVBRRaw, readCIDRaw, readCSDRaw, readSCRRaw, readSDStatusRaw
    • Code testing if sd.mount(...) (truthy = success) must change to if sd.mount(...) == sd.SUCCESS
    • mount() and initCardOnly() now detect missing cards using a P2 internal pull-up on MISO and return a specific error code E_NO_CARD instead of generic E_INIT_FAILED.
    • Wealth of code readability improvements across all code files.
    • Theory of Operations expanded: card presence detection, card identification, and adaptive timing

    If you have already written code for an earlier version of this driver, read the Migration Guide and make changes accordingly (to get you back on the air quickly with this new version).

    Visit the P2 microSD FAT32 Filesystem repository for full documentation, including a driver tutorial, theory of operations, and card catalog.

    The release package can be downloaded from the Releases page. Download the sd-card-driver-{version}.zip
    file.

    If you find issues, please file them at the Issues page.

    What's next? Investigating the Silicon Power CMD18 compatibility issue. I also want to look into whether A2 command queuing features can/should be leveraged in SPI mode.

    Enjoy!

    Stephen

  • evanhevanh Posts: 17,092
    edited 2026-03-03 05:53

    Table 7-2 of SD spec (Physical Layer Simplified Specification) shows the supported commands in SPI mode. None of the CQ commands are in it.

    PS: When I dabbled with command-queuing in SD mode it triggered the cards to put data on the DAT pins overlapping the timing of CMD responses. Perfectly allowed but I wasn't ready to handle it. And since I also wasn't intending to seriously use the capabilities of CQ, that ended my dabbling.

    PPS: Hmm, it looks like, technically, it may have needed the SD card's caching enabled too - https://forums.parallax.com/discussion/comment/1563158/#Comment_1563158
    I'd have to revisit it to be sure.
    PPPS: And, BTW, CQ was supported by only one SD card of mine.

  • evanhevanh Posts: 17,092
    edited 2026-03-03 10:23

    Stephen,
    The v1.2 release has chunks of the source code missing! Some sort of automation removing it?
    And what is this #PRAGMA stuff? Is it really part of Spin2?

    I'm not having much luck with mounting any of my cards either. Error -7.
    I'm not getting output from any debug()s in the FS object. How the frig does one enable debug() in an object? Printf(), even from Spin, just works.

  • Stephen MoracoStephen Moraco Posts: 426
    edited 2026-03-03 18:24

    I'm sorry to hear that this was frustrating. Let me try to explain. I don't believe the code is missing; the line count is higher in the latest release. The code was reorganized to make more logical sense as you scan the file from top to bottom. Is this maybe what you are seeing?

    The driver, as released, passes all regression tests. I even unpacked the prepackaged .zip file and ran the same tests; all passed. (What I did find when unpacking is that some of the documentation I wanted to be present was not. I've rebuilt this .zip file.)

    The preprocessor directives help adapt the code for multiple purposes. (1) allow auto detection of the compiler so each can compile this code (PNut, pnut-ts, flexspin, and spin tools IDE), and (2) allow by default the driver to be compiled in its smallest form (memory footprint). The utilities, via the pragma exportdef, override the driver's compilation to enable additional features (raw sector access, special uSD Controller register access, etc.). I've added a new document to the repository to explain all of this. See the Conditional Compilation Guide

    This guide also explains that DEBUG_DISABLE is being used in the driver file, which is likely what you were running into.

    Does this help?

Sign In or Register to comment.