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

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

13»

Comments

  • evanhevanh Posts: 17,127

    @"Stephen Moraco" said:
    @evanh, what is the current state with v1.3.0 vs. your older card? Is the logic working?

    I've done more reading of the spec and found the answer. Turns out there is a minimum of 1 byte gap and these cards are following the spec correctly. The timing diagram I posted above should have but doesn't specify the timing of relevance, Nrc. It is listed in the table but has it's own separate diagram:

    Sorry for not just uploading the PDF itself. It's one I found in a Web search that is not the free edition.

  • evanhevanh Posts: 17,127

    So adding a padding $FF byte at the end of the prior sequence, before rasing CS instead of after lowering CS, should also do the job.

  • evanhevanh Posts: 17,127
    edited 2026-03-08 12:50

    I suppose, to be fair, it's not clear, from the diagram at least, if Nrc holds true after CS rises. CS high could be considered a reset so then my previous interpretation would hold. It's a little fuzzy so not surprising different manufacturers might have interpreted different ways.

    Either way, it's clear the driver has to make the allowance for Nrc holding true irrespective of CS. And the best solution is to, like Flexspin's sdmm.c driver, combine it with the busy check.

  • evanhevanh Posts: 17,127
    edited 2026-03-10 04:32

    @"Stephen Moraco" said:
    @evanh, what is the current state with v1.3.0 vs. your older card? Is the logic working?

    Every time you post an update at the moment I have to redo a huge number of debug deletes so that the important parts can report anything. Otherwise I just get compile errors of too big debug.

    Here's the relevant Adata 16GB card:

    Cog0  INIT $0000_0000 $0000_0000 load
    Cog0  INIT $0000_0404 $0000_0000 load
    Cog0  clkfreq = 200_000_000, clkmode = $100_09FB
    Cog0    [start] Worker cog 1 started, lock 0
    Cog1  INIT $0000_0404 $0001_8DF2 load
    Cog1    [fs_worker] Starting on cog 1
    Cog1    [fs_worker] Pins initialized: CS=P39 MOSI=P34 MISO=P36 SCK=P35
    Cog1    [do_mount] Calling initCard()...
    Cog1      [initCard] Starting card init...
    Cog1      [initCard] Reference: SPI_SD_Implementation_Reference.md
    Cog1      [initCard] Step 1: Power-on delay (100ms)...
    Cog1      [initCard] Step 2: SPI config, bit_delay=bit_delay = 2_000 (~50kHz)
    Cog1      [initCard] Pins: CS=1 MOSI=1 MISO=1 SCK=0
    Cog1      [initCard] Step 3: Recovery flush (4096 clocks to clear stuck transfer)...
    Cog1      [initCard] MISO after recovery flush: 1 (should be 1)
    Cog1      [initCard] Step 3.5: Initializing smart pins (ManAtWork pattern)...
    Cog1      [initSPIPins] Setting up smart pins (ManAtWork pattern)...
    Cog1      [initSPIPins] Mode values:
    Cog1      [initSPIPins]   spi_clk_mode=$spi_clk_mode = $0000_004A (P_TRANSITION | P_OE, idle LOW)
    Cog1      [initSPIPins]   spi_tx_mode=$spi_tx_mode = $0100_0078 (P_SYNC_TX | P_OE | smartB)
    Cog1      [initSPIPins]   spi_rx_mode=$spi_rx_mode = $0700_003A (P_SYNC_RX | smartB)
    Cog1      [initSPIPins]   SCK=P35 MOSI=P34 MISO=P36
    Cog1      [initSPIPins]   SCK configured: P_TRANSITION | P_OE (awaiting applySPISpeed)
    Cog1      [initSPIPins]   MOSI configured: P_SYNC_TX | smartB (enabled)
    Cog1      [initSPIPins]   MISO configured: P_SYNC_RX | smartB (enabled)
    Cog1      [initSPIPins]   Event SE1 configured for SCK pin 35
    Cog1      [initSPIPins] Smart pins configured and enabled
    Cog1      [applySPISpeed] Target=400 kHz, Actual=400 kHz
    Cog1      [applySPISpeed] Half-period=250 clocks
    Cog1      [sp_transfer_8] pins: miso=36 sck=35 raw=$FF00_0000 final=$FF
    Cog1      [sp_transfer_8] pins: miso=36 sck=35 raw=$FFFF_0000 final=$FF
    Cog1      [sp_transfer_8] pins: miso=36 sck=35 raw=$FFFF_FF00 final=$FF
    Cog1      [sp_transfer_8] pins: miso=36 sck=35 raw=$FFFF_FFFF final=$FF
    Cog1      [sp_transfer_8] pins: miso=36 sck=35 raw=$FFFF_FFFF final=$FF
    Cog1      [initCard] Dummy clocks sent via smart pins
    Cog1      [initCard] Step 4: CMD0 (GO_IDLE_STATE)...
    Cog1        [cmd] CS before assert: 1
    Cog1        [cmd] CS after pinl: 0 MISO=0
    Cog1        [cmd] After CMD0 sent, MISO=0
    Cog1      [initCard] CMD0 response: $$1
    Cog1      [initCard] CMD0 OK - card in idle state
    Cog1      [initCard] Step 5: CMD8 (SEND_IF_COND, VHS=1, pattern=$AA)...
    Cog1      [initCard] CMD8 response (32-bit): $resp = $0000_01AA
    Cog1      [initCard] CMD8 echo valid ($1AA) -> Ver 2.0+ SD card
    Cog1      [initCard] Step 6: ACMD41 init loop (arg=$acmd41_arg = $4000_0000)...
    Cog1      [initCard] ACMD41 complete - card ready!
    Cog1      [initCard] Step 7: CMD58 (READ_OCR)...
    Cog1      [initCard] OCR: $resp = $C0FF_8000
    Cog1      [initCard]   Bit 31 (ready): ((Shr__(resp, 31)) & 0x1) = 1
    Cog1      [initCard]   Bit 30 (CCS):   ((Shr__(resp, OCR_CCS_SHIFT)) & 0x1) = 1
    Cog1      [initCard] Card type: SDHC/SDXC (block addressing)
    Cog1      [initCard] Step 8: Card identification and speed selection...
    Cog1    [identifyCard] Reading card registers...
    Cog1    [parseMfrId] Manufacturer ID=$$1D
    Cog1    [identifyCard] Detected PNY/AData card - using conservative timing
    Cog1    [parseTransSpeed] TRAN_SPEED=$$32 -> (speed_hz / 1000000) = 25 MHz
    Cog1    [parseTimeouts] SDHC/SDXC: read=100ms, write=500ms
    Cog1      [applySPISpeed] Target=20_000 kHz, Actual=20_000 kHz
    Cog1      [applySPISpeed] Half-period=5 clocks
    Cog1    [setOptimalSpeed] Limited to 20 MHz for slow card
    Cog1      [initCard] Dummy clocks sent, CS HIGH
    Cog1      [probeCmd13] pre=[$FF $FF $FF $FF $FF $FF]
    Cog1      [probeCmd13] cap=[$FF $00 $00 $FF $FF $FF $FF $FF] NCR=2
    Cog1      [probeCmd13] R1=$$00 STATUS=$$00
    Cog1      [probeCmd13] CMD13 OK (R1=$$00 STATUS=$$00)
    Cog1      [probeCmd23] SCR advertises CMD23 (CMD_SUPPORT=$$03) - verifying...
    Cog1      [probeCmd23] CMD23 REJECTED R1=$$04 - not supported in SPI mode
    Cog1      [initCard] === INIT SUCCESS ===
    Cog1    [do_mount] Reading MBR sector 0...
    Cog1    [do_mount] MBR type code: $B
    Cog1    [do_mount] FAT32 detected, VBR at sector vbr_sec = 2_048
    Cog1    [do_mount] Bytes/sector: vbrBytesPerSec(pVBR) = 512
    Cog1    [do_mount] Sectors/cluster: sec_per_clus = 64
    Cog1    [do_mount] Reserved sectors: reserved = 64
    Cog1    [do_mount] Number of FATs: vbrNumFats(pVBR) = 2
    Cog1    [do_mount] VBR volume label: (&vol_label) = "ADATA64    "
    Cog1    [do_mount] Root dir volume label: (&vol_label) = "ADATA64    "
    Cog1    [do_mount] FSInfo: free_count=fsi_free_count = 1_902_460 nxt_free=fsi_nxt_free = 210
    Cog1    [do_mount] SUCCESS
    Cog1    [do_mount] SUCCESS, mode=FILESYSTEM
    Cog0    [mount] Mount successful, mode=FILESYSTEM
    Cog0  Card mounted, volume: ADATA64    
    

    So the probeCmd13() is succeeding now. However, such a check is also defunct now that we know the why.

  • evanhevanh Posts: 17,127
    edited 2026-03-10 04:38

    @evanh said:
    Every time you post an update at the moment I have to redo a huge number of debug deletes so that the important parts can report anything. Otherwise I just get compile errors of too big debug.

    It kind of begs the question of how have you been getting any reporting yourself, Stephen?

  • RaymanRayman Posts: 16,124

    I am very supportive of this effort and appears off to great start.
    Keep it up @"Stephen Moraco"

    8.3 filenames is a serious limitation. But directory support helps a lot with that. Should be fine. FatFs can do long filenames but like triples the memory usage :(

    I’m crazy backed up in projects but will prioritize testing this…

    One minor thing to examine is support for RTC for file dating.

  • @evanh said:

    @evanh said:
    Every time you post an update at the moment I have to redo a huge number of debug deletes so that the important parts can report anything. Otherwise I just get compile errors of too big debug.

    It kind of begs the question of how have you been getting any reporting yourself, Stephen?

    Augh! That is painful. The latest release, v1.3.2, now has DEBUG_MASK and "CHANNEL"s for debug output. Set the mask to a new value, recompile, and only the new selected debug channels are compiled into your code. Should be much easier. This is all documented.

    I started with driver debug only, then eventually it became stable enough that I moved to disabling debug in the driver and pushing some critical state through the caller <-> backend COG interface and just reporting it via debug in the calling program. All the regression tests do this.

  • Stephen MoracoStephen Moraco Posts: 445
    edited 2026-03-10 07:05

    @Rayman said:
    One minor thing to examine is support for RTC for file dating.

    Useful idea. We need to brainstorm a bit about how to support this. Pretty complicated trying to support RTC devices. Pass a creation time through the file create/write method; maybe have a set date/time call for the driver to keep it updated, and use this for file creation/modification? Maybe let the app maintain the current date/time and pass a reference to the driver for use in file creation/modification? Any other ideas?

    FYI- (if my understanding is correct) our FAT32 directory entries can contain (all local date time, not utc):

    • Creation date/time (plus 1‑byte sub‑second field).
    • Last write/modify date/time.
    • Last access date (no time of day, date only).
  • evanhevanh Posts: 17,127

    Stephen,
    I just noticed you've made an incorrect note in the source comments about ManAtWork's clock polarity reference material. Clock mode 0 is not a necessity at all. SPI slave devices that accept clock mode 0 (CPOL=0 and CPHA=0) are also happy to accept clock mode 3 (CPOL=1 and CPHA=1). In fact bit-bashed master implementations on microcontrollers are rarely precisely mode 0 or mode 3 but somewhere in between. I regularly write routines that explicitly take advantage of this flexibility to allow higher clock rates to be used.

    Now, when it comes to the Prop2 boot pins, P58/P59/P60/P61, there is a good reason to always use CPOL=1, and therefore cmode 3. The same four pins are used for both the SD card slot and the soldered Flash EEPROM chip. The difference being SCLK and CS are swapped. But that means that a clock low on one is a chip-select on the other. Things are much less likely to get into a confused state between them if the clock idles high instead of low. Hence why ManAtWork did it the way he did.

  • evanhevanh Posts: 17,127

    @"Stephen Moraco" said:

    @evanh said:
    Every time you post an update at the moment I have to redo a huge number of debug deletes so that the important parts can report anything. Otherwise I just get compile errors of too big debug.

    Augh! That is painful. The latest release, v1.3.2, now has DEBUG_MASK and "CHANNEL"s for debug output. Set the mask to a new value, recompile, and only the new selected debug channels are compiled into your code. Should be much easier. This is all documented.

    DEBUG_MASK is working. Thank you!

Sign In or Register to comment.