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

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

12346»

Comments

  • RaymanRayman Posts: 16,370

    Don't know if it helps, but seem to recall a delay in FSRW that depends on clock speed...

  • evanhevanh Posts: 17,215
    edited 2026-05-04 23:09

    Macca,
    Just give that alternate code a whirl, it's in readSector() function. Adjusting align_delay to suit would be a good idea too. Earlier in readSector(), change to align_delay := spi_period + 3

    That'll hopefully fix the MBR reading and tell me I'm targetting the right part.

  • Stephen MoracoStephen Moraco Posts: 473
    edited 2026-05-04 23:30

    @evanh, careful, new driver coming with dynamic calculation of align_delay to improve our margin. Fixed a number of other things you pointed out as well... standby... we're an hour or two away from having broad fixes and fully regression-tested, with improved margins for older devices.

  • evanhevanh Posts: 17,215

    Stephen, I got another one for you. Since your minimum divider is 8, this gives plenty of timing leeway. align_delay isn't even needed for block writes:

        ' Streamer TX with deterministic clock alignment:
        ORG
                  RDFAST    #0, p_buf                       ' Setup RDFAST from hub buffer
                  SETXFRQ   xfrq                            ' Set streamer bit rate
                  FLTL      _sck                            ' Reset SCK: counter stops, output LOW, Y=0
                  XINIT     stream_mode, #0                 ' Start streamer; NCO ramps from zero
                  DIRH      _sck                            ' Re-enable: DIR=1 restarts base period counter fresh
                  WYPIN     clk_count, _sck                 ' Start clock - deterministic phase from dirh
                  WAITXFI                                   ' Wait for streamer to complete
        END
    
  • evanhevanh Posts: 17,215
    edited 2026-05-05 03:29

    Yeah, testing indicates the big write-up I had planned isn't needed. At least not for these larger dividers anyway.

  • maccamacca Posts: 1,040

    @evanh said:
    Macca,
    Just give that alternate code a whirl, it's in readSector() function. Adjusting align_delay to suit would be a good idea too. Earlier in readSector(), change to align_delay := spi_period + 3

    That'll hopefully fix the MBR reading and tell me I'm targetting the right part.

    Tried that, same result. As shown in the debug output, the problem is "[readSector] TIMEOUT waiting for start token" which, AFAIK, is outside the streamer block.

    If I comment the speed adjustment in initCard it can read the sector but then can't write, or better, the SD receives garbage because the card is apprently mounted but the MBR is wiped and can't be mounted anymore (error -22 = E_NOT_FAT32). Tried to move the RDFAST at the top of the instructions block without changes.

    Since I don't care about performances, I would be happy if it works with the default initial speed (whatever it is).
    I'll wait for Stephen's update.

  • @macca -- v1.5.1 should give your 1GB SDSC much better timing margin at low system clocks. Here is what we improved and the two tests we'd like you to run.

    What we improved

    Better SCK alignment in bulk-sector reads. We restructured the inline-PASM block in readSector so the first SCK pulse now lands on schedule for every system clock from 200 MHz up. The streamer's sampling now aligns precisely with the card's actual data output. This is the change most likely to fix your sector-0 reads at a sysclk of 250 MHz.

    Adaptive MISO sampling in byte-by-byte transfers. The driver now adapts its MISO sampling based on the system-clock-to-SCK ratio. At higher system clocks (≥255 MHz, 25 MHz SPI target), it samples on the edge as before. At lower system clocks, it samples slightly before the edge, giving slower cards more trailing-edge margin. For your card at sysclk=250 MHz, this shifts the sample point by roughly 30% of the bit cell, providing meaningful headroom. Fully internal, no API changes.

    Init-sequence pin-setup hygiene. Small reorder to reset the MISO pin before its mode is configured. Eliminates an edge case on re-mount paths.

    The write streamer block was not changed in v1.5.1; the analogous reorder is queued for v1.5.2

    Tests to run (build each with _CLKFREQ = 250_000_000)

    regression-tests/SD_RT_mount_tests.spin2 -- proves the read-path improvements work on your card. Exercises the mount command sequence, reads every sector, and remount cycles. Read-only.

    regression-tests/SD_RT_raw_sector_tests.spin2 -- proves the streamer write path works on your card. This test determines whether you need v1.5.2's write-side reorder or if v1.5.1 is sufficient.

    UTILS/SD_card_characterize.spin2 -- full register dump from your card. Send us the output, especially the raw CSD bytes and the [USED] TAAC / [USED] NSAC lines, so we can verify our timing model against your specific card.

    What the results tell us

    • Both tests pass → v1.5.1 is sufficient. Send us the register dump, and you're done.
    • Mount test passes, raw sector test fails → v1.5.2 will include the streamer-write reorder. Send us the failing output.
    • Mount test fails → reach out; we'll send a small diagnostic tool separately to find the right tuning for your card.
  • @evanh I'm testing this next. Good find. After passing regression tests, it should ship with v1.5.2

  • maccamacca Posts: 1,040

    @"Stephen Moraco" said:
    regression-tests/SD_RT_mount_tests.spin2 -- proves the read-path improvements work on your card. Exercises the mount command sequence, reads every sector, and remount cycles. Read-only.

    Cog0  INIT $0000_0000 $0000_0000 load
    Cog0  INIT $0000_0F64 $0000_7C58 jump
    Cog0   
    Cog0  ==============================================
    Cog0    SD Card Driver - Mount/Unmount Tests
    Cog0  ==============================================
    Cog0  * init VAR
    Cog0   
    Cog0   
    Cog0   ------------------------------------------------------------
    Cog0  * Test Group: Operations before mount should fail gracefully
    Cog0   
    Cog0  * Test #1: openFileRead() before mount
    Cog0    openFileRead(): 0
    Cog0     -> pass
    Cog0   
    Cog0  * Test #2: createFileNew() before mount
    Cog0    createFileNew(): 0
    Cog0     -> pass
    Cog0   
    Cog0  * Test #3: freeSpace() before mount
    Cog0    freeSpace(): 0
    Cog0     -> pass
    Cog0   
    Cog0   
    Cog0   ------------------------------------------------------------
    Cog0  * Test Group: Pre-Mount Error Validation
    Cog0   
    Cog0  * Test #4: openFileRead() before mount returns E_NOT_MOUNTED
    Cog0    openFileRead(): -20
    Cog0     -> pass
    Cog0   
    Cog0  * Test #5: createFileNew() before mount returns E_NOT_MOUNTED
    Cog0    createFileNew(): -20
    Cog0     -> pass
    Cog0   
    Cog0  * Test #6: readSectorRaw() before mount returns error
    Cog0    readSectorRaw(): -20
    Cog0     -> pass
    Cog0   
    Cog0  * Test #7: changeDirectory() before mount returns error
    Cog0    changeDirectory(): -20
    Cog0     -> pass
    Cog0   
    Cog0   
    Cog0   ------------------------------------------------------------
    Cog0  * Test Group: Pin offset validation (B-input ±3 limit)
    Cog0   
    Cog0  * Test #8: mount() with SCK too far from MOSI (offset=+5)
    Cog0    mount(bad pins): -9
    Cog0     -> pass
    Cog0   
    Cog0  * Test #9: mount() with SCK too far from MISO (offset=-4)
    Cog0    mount(bad pins): -9
    Cog0     -> pass
    Cog0   
    Cog0   
    Cog0   ------------------------------------------------------------
    Cog0  * Test Group: Mount SD card
    Cog0   
    Cog0  * Test #10: mount() with valid pins
    Cog1  INIT $0000_0F64 $0000_29F6 jump
    Cog0    mount(): -7 (expected 0)
    Cog0     -> FAIL
    Cog0   
    Cog0    DIAG: error()=-7
    Cog0    DIAG: lastCMD13=$$8 lastCMD13Error=$$8
    Cog0    DIAG: CRC match=0 mismatch=0 retry=0
    Cog0    DIAG: recvCRC=$$0 calcCRC=$$0
    Cog0    DIAG: readSectorRaw(0) FAILED
    Cog0   
    Cog0  * Test #11: Verify card is accessible - get volume label
    Cog0    volumeLabel() pointer: 13_323
    Cog0     -> pass
    Cog0   
    Cog0  * Test #12: Verify free space is reasonable
    Cog0    freeSpace(): 0 (expected 1 to 2_147_483_647)
    Cog0     -> FAIL
    Cog0   
    Cog0    Card Info:
    Cog0      Volume Label: 
    Cog0      Free Space: 0 sectors (0 MB)
    Cog0   
    Cog0   
    Cog0   ------------------------------------------------------------
    Cog0  * Test Group: Unmount SD card
    Cog0   
    Cog0  * Test #13: unmount() card
    Cog0    unmount(): 0
    Cog0     -> pass
    Cog0   
    Cog0  * Test #14: Operations after unmount should fail
    Cog0    freeSpace() after unmount: 0
    Cog0     -> pass
    Cog0   
    Cog0   
    Cog0   ------------------------------------------------------------
    Cog0  * Test Group: Remount SD card
    Cog0   
    Cog0  * Test #15: mount() again
    Cog0    mount() second time: -8 (expected 0)
    Cog0     -> FAIL
    Cog0    DIAG2: error()=-8
    Cog0    DIAG2: lastCMD13=$$0 lastCMD13Error=$$8
    Cog0    DIAG2: CRC match=0 mismatch=0 retry=0
    Cog0   
    Cog0  * Test #16: Card still accessible after remount
    Cog0    freeSpace() after remount: 0 (expected 1 to 2_147_483_647)
    Cog0     -> FAIL
    Cog0   
    Cog0   
    Cog0   ------------------------------------------------------------
    Cog0  * Test Group: Multiple mount/unmount cycles
    Cog0   
    Cog0  * Test #17: unmount()
    Cog0    unmount(): 0
    Cog0     -> pass
    Cog0   
    Cog0  * Test #18: mount() cycle 1
    Cog0    mount(): -8 (expected 0)
    Cog0     -> FAIL
    Cog0   
    Cog0  * Test #19: unmount()
    Cog0    unmount(): 0
    Cog0     -> pass
    Cog0   
    Cog0  * Test #20: mount() cycle 2
    Cog0    mount(): -8 (expected 0)
    Cog0     -> FAIL
    Cog0   
    Cog0  * Test #21: unmount()
    Cog0    unmount(): 0
    Cog0     -> pass
    Cog0   
    Cog0  * Test #22: mount() cycle 3
    Cog0    mount(): -8 (expected 0)
    Cog0     -> FAIL
    Cog0   
    Cog0  * Test #23: Card still works after 3 mount/unmount cycles
    Cog0    freeSpace(): 0 (expected 1 to 2_147_483_647)
    Cog0     -> FAIL
    Cog0   
    Cog0   
    Cog0   ------------------------------------------------------------
    Cog0  * Test Group: Post-Unmount State
    Cog0   
    Cog0  * Test #24: openFileRead() after unmount returns E_NOT_MOUNTED
    Cog0    openFileRead(): -20
    Cog0     -> pass
    Cog0   
    Cog0  * Test #25: createFileNew() after unmount returns E_NOT_MOUNTED
    Cog0    createFileNew(): -20
    Cog0     -> pass
    Cog0   
    Cog0  * Test #26: changeDirectory() after unmount returns E_NOT_MOUNTED
    Cog0    changeDirectory(): -20
    Cog0     -> pass
    Cog0   
    Cog0  * Test #27: Remount after unmount succeeds
    Cog0    mount() after unmount: -8 (expected 0)
    Cog0     -> FAIL
    Cog0   
    Cog0  * Test #28: freeSpace() works after remount
    Cog0    freeSpace() after remount: 0 (expected 1 to 2_147_483_647)
    Cog0     -> FAIL
    Cog0   
    Cog0   
    Cog0   ------------------------------------------------------------
    Cog0  * Test Group: Double-Mount Behavior
    Cog0   
    Cog0  * Test #29: Double mount returns SUCCESS
    Cog0    Sub-Test: mount() again
    Cog0    Value: -8 (expected 0)
    Cog0     -> Sub-FAIL
    Cog0    Sub-Test: freeSpace() valid
    Cog0    Value: 0 (expected 4_294_967_295)
    Cog0     -> Sub-FAIL
    Cog0    Sub-Test Results: count=1, Pass: 0, Fail: 1
    Cog0     -> FAIL
    Cog0   
    Cog0  * Test #30: Double mount preserves open file handle
    Cog0   
    Cog0  * Test #31: Double mount preserves working directory
    Cog0    Sub-Test: mount() in subdir
    Cog0    Value: -8 (expected 0)
    Cog0     -> Sub-FAIL
    Cog0    Sub-Test: file in subdir
    Cog0    Value: 0 (expected 4_294_967_295)
    Cog0     -> Sub-FAIL
    Cog0    Sub-Test Results: count=1, Pass: 0, Fail: 1
    Cog0     -> FAIL
    Cog0   
    Cog0  * Worker cog stack: 108 of 160 longs used
    Cog0   
    Cog0   ============================================================
    Cog0  * 31 Tests - Pass: 18, Fail: 12
    Cog0  *  BAD TEST COUNTS: 31 <> 30 (missing 1 tests)
    Cog0   ============================================================
    Cog0   
    Cog0  * Mount/Unmount Tests Complete
    Cog0  END_SESSION
    

    regression-tests/SD_RT_raw_sector_tests.spin2 -- proves the streamer write path works on your card. This test determines whether you need v1.5.2's write-side reorder or if v1.5.1 is sufficient.

    Cog0  INIT $0000_0000 $0000_0000 load
    Cog0  INIT $0000_0F64 $0000_7AE0 jump
    Cog0   
    Cog0  ============================================================
    Cog0    SD Raw Sector Round-Trip Test (V2 Driver)
    Cog0  ============================================================
    Cog0   
    Cog0  Initializing SD card (V2 driver with streamer)...
    Cog1  INIT $0000_0F64 $0000_206A jump
    Cog0  Card initialized successfully
    Cog0   
    Cog0  --- PHASE 1: Writing test patterns ---
    Cog0   
    Cog0  * Test: Write Pattern A (sequential) to sector 100_000
    Cog0    ERROR: Sector ID mismatch! Expected $$A0, got $$00
    Cog0    ERROR: Pattern ID mismatch! Expected $$A0, got $$00
    Cog0    ERROR: Head magic mismatch! Expected DEADBEEF, got $$00, $00, $00, $00
    Cog0    ERROR: Tail magic mismatch! Expected CAFEBABE
    Cog0    ERROR: Tail pattern mismatch!
    Cog0    ERROR: Tail sector ID mismatch!
    Cog0    -> FAIL (readback mismatch)
    Cog0  * Test: Write Pattern B (AA/55) to sector 100_001
    Cog0    WRITE FAILED!
    Cog0  * Test: Write Pattern C (all FF) to sector 100_002
    Cog0    WRITE FAILED!
    Cog0  * Test: Write Pattern D (all 00) to sector 100_003
    Cog0    WRITE FAILED!
    Cog0  * Test: Write Pattern E (offset) to sector 100_004
    Cog0    ERROR: Sector ID mismatch! Expected $$A4, got $$00
    Cog0    ERROR: Pattern ID mismatch! Expected $$E0, got $$00
    Cog0    ERROR: Head magic mismatch! Expected DEADBEEF, got $$00, $00, $00, $00
    Cog0    ERROR: Tail magic mismatch! Expected CAFEBABE
    Cog0    ERROR: Tail pattern mismatch!
    Cog0    ERROR: Tail sector ID mismatch!
    Cog0    -> FAIL (readback mismatch)
    Cog0   
    Cog0  --- PHASE 2: Verify by reading in REVERSE order ---
    Cog0  (Tests that correct sectors were written, not just cached)
    Cog0   
    Cog0  * Test: Read sector 100_004 (expect pattern E=$E0)
    Cog0    ERROR: Sector ID mismatch! Expected $$A4, got $$00
    Cog0    ERROR: Pattern ID mismatch! Expected $$E0, got $$00
    Cog0    ERROR: Head magic mismatch! Expected DEADBEEF, got $$00, $00, $00, $00
    Cog0    ERROR: Tail magic mismatch! Expected CAFEBABE
    Cog0    ERROR: Tail pattern mismatch!
    Cog0    ERROR: Tail sector ID mismatch!
    Cog0    -> FAIL
    Cog0  * Test: Read sector 100_003 (expect pattern D=$D0)
    Cog0    ERROR: Sector ID mismatch! Expected $$A3, got $$00
    Cog0    ERROR: Pattern ID mismatch! Expected $$D0, got $$00
    Cog0    ERROR: Head magic mismatch! Expected DEADBEEF, got $$00, $00, $00, $00
    Cog0    ERROR: Tail magic mismatch! Expected CAFEBABE
    Cog0    ERROR: Tail pattern mismatch!
    Cog0    ERROR: Tail sector ID mismatch!
    Cog0    -> FAIL
    Cog0  * Test: Read sector 100_002 (expect pattern C=$C0)
    Cog0    ERROR: Sector ID mismatch! Expected $$A2, got $$00
    Cog0    ERROR: Pattern ID mismatch! Expected $$C0, got $$00
    Cog0    ERROR: Head magic mismatch! Expected DEADBEEF, got $$00, $00, $00, $00
    Cog0    ERROR: Tail magic mismatch! Expected CAFEBABE
    Cog0    ERROR: Tail pattern mismatch!
    Cog0    ERROR: Tail sector ID mismatch!
    Cog0    -> FAIL
    Cog0  * Test: Read sector 100_001 (expect pattern B=$B0)
    Cog0    ERROR: Sector ID mismatch! Expected $$A1, got $$00
    Cog0    ERROR: Pattern ID mismatch! Expected $$B0, got $$00
    Cog0    ERROR: Head magic mismatch! Expected DEADBEEF, got $$00, $00, $00, $00
    Cog0    ERROR: Tail magic mismatch! Expected CAFEBABE
    Cog0    ERROR: Tail pattern mismatch!
    Cog0    ERROR: Tail sector ID mismatch!
    Cog0    -> FAIL
    Cog0  * Test: Read sector 100_000 (expect pattern A=$A0)
    Cog0    ERROR: Sector ID mismatch! Expected $$A0, got $$00
    Cog0    ERROR: Pattern ID mismatch! Expected $$A0, got $$00
    Cog0    ERROR: Head magic mismatch! Expected DEADBEEF, got $$00, $00, $00, $00
    Cog0    ERROR: Tail magic mismatch! Expected CAFEBABE
    Cog0    ERROR: Tail pattern mismatch!
    Cog0    ERROR: Tail sector ID mismatch!
    Cog0    -> FAIL
    Cog0   
    Cog0  --- PHASE 3: Full 512-byte data verification ---
    Cog0   
    Cog0  * Test: Full verify Pattern A (512 sequential bytes)
    Cog0    ERROR at byte 8: expected $$08, got $$00
    Cog0  * Test: Full verify Pattern B (alternating AA/55)
    Cog0    ERROR at byte 8: expected $$AA, got $$00
    Cog0   
    Cog0  --- PHASE 4: Sector Address Boundary Tests ---
    Cog0   
    Cog0  * Test: Read sector 0 (MBR) and verify signature $55 $AA
    Cog0    ERROR: Expected $55 $AA, got $$00 $$00
    Cog0    -> FAIL
    Cog0  * Test: Read high sector number 1,000,000 (large LBA)
    Cog0    High sector read returned: -7
    Cog0    -> pass (driver returned error for out-of-range sector)
    Cog0   
    Cog0  ============================================================
    Cog0    Raw Sector Tests - Pass: 1, Fail: 13
    Cog0  ============================================================
    Cog0   
    Cog0  END_SESSION
    

    UTILS/SD_card_characterize.spin2 -- full register dump from your card. Send us the output, especially the raw CSD bytes and the [USED] TAAC / [USED] NSAC lines, so we can verify our timing model against your specific card.

    Cog0  INIT $0000_0000 $0000_0000 load
    Cog0  INIT $0000_0F64 $0000_8860 jump
    Cog0  ##############################################
    Cog0  #  SD Card Characterization Report V3       #
    Cog0  #  All register fields - comprehensive      #
    Cog0  ##############################################
    Cog0   
    Cog0  Initializing SD card (no-mount mode)...
    Cog1  INIT $0000_0F64 $0000_321A jump
    Cog0  Card initialized successfully.
    Cog0   
    Cog0  --- Reading Card Registers ---
    Cog0    CID: OK (16 bytes)
    Cog0    CSD: OK (16 bytes)
    Cog0    SCR: OK (8 bytes)
    Cog0    OCR: OK (4 bytes)
    Cog0    SD Status: OK (64 bytes)
    Cog0   
    Cog0   
    Cog0  ======== CID REGISTER (Card Identification) ========
    Cog0  [USED] = Field used by V3 driver
    Cog0  [INFO] = Informational only
    Cog0   
    Cog0  [USED] MID (Manufacturer ID):     $$03 (SanDisk)
    Cog0  [INFO] OID (OEM/Application ID): $$53 $$44 (ASCII)
    Cog0  [INFO] PNM (Product Name):        [SU01G]
    Cog0  [INFO] PRV (Product Revision):    8.0
    Cog0  [INFO] PSN (Serial Number):       $$006C_D5B2
    Cog0  [INFO] MDT (Manufacturing Date): 2_007-06
    Cog0  [INFO] CRC7:                      $$6D
    Cog0   
    Cog0  ======== CSD REGISTER (Card Specific Data) ========
    Cog0   
    Cog0  [USED] CSD_STRUCTURE:        0 (CSD Version 1.0)
    Cog0         Card Type:            SDSC (Standard Capacity)
    Cog0   
    Cog0  --- Timing Parameters ---
    Cog0  [USED] TRAN_SPEED:           $$32 (25 MHz max)
    Cog0  [USED] TAAC:                 $$26 (read access time-1)
    Cog0  [USED] NSAC:                 0 (read access time-2, CLK cycles)
    Cog0  [USED] R2W_FACTOR:           4 (write time = read time x 16)
    Cog0         Read Timeout:         1_500 ms (calculated)
    Cog0         Write Timeout:        24_000 ms (calculated)
    Cog0   
    Cog0  --- Capacity ---
    Cog0  [USED] C_SIZE:               3_874 (SDSC device size)
    Cog0  [USED] C_SIZE_MULT:          7
    Cog0  [USED] READ_BL_LEN:          9 (max block = 512 bytes)
    Cog0         Capacity:             968 MB
    Cog0         Total Sectors:        1_982_464
    Cog0   
    Cog0  --- Command Classes (CCC) ---
    Cog0  [INFO] CCC:                  $$5F5
    Cog0         Class 0 (basic):      Yes
    Cog0         Class 2 (block read): Yes
    Cog0         Class 4 (block write):Yes
    Cog0         Class 5 (erase):      Yes
    Cog0         Class 6 (write prot): Yes
    Cog0         Class 7 (lock card):  Yes
    Cog0         Class 8 (app spec):   Yes
    Cog0         Class 10 (switch):    Yes
    Cog0   
    Cog0  --- Block Parameters ---
    Cog0  [INFO] READ_BL_LEN:          9 (512 bytes)
    Cog0  [INFO] WRITE_BL_LEN:         9 (512 bytes)
    Cog0  [INFO] READ_BL_PARTIAL:      1
    Cog0  [INFO] WRITE_BL_PARTIAL:     0
    Cog0  [INFO] READ_BLK_MISALIGN:    0
    Cog0  [INFO] WRITE_BLK_MISALIGN:   0
    Cog0   
    Cog0  --- Erase Parameters ---
    Cog0  [INFO] ERASE_BLK_EN:         1 (512-byte erase)
    Cog0  [INFO] SECTOR_SIZE:          31 (erase sector = 16_384 bytes)
    Cog0   
    Cog0  --- Write Protection ---
    Cog0  [INFO] WP_GRP_SIZE:          127
    Cog0  [INFO] WP_GRP_ENABLE:        1
    Cog0  [INFO] PERM_WRITE_PROTECT:   0
    Cog0  [INFO] TMP_WRITE_PROTECT:    0
    Cog0   
    Cog0  --- Other Fields ---
    Cog0  [INFO] DSR_IMP:              0 (Driver Stage Register not implemented)
    Cog0  [INFO] FILE_FORMAT_GRP:      0
    Cog0  [INFO] FILE_FORMAT:          0
    Cog0  [INFO] COPY:                 1
    Cog0  [INFO] CRC7:                 $$6B
    Cog0   
    Cog0  --- SDSC Current Requirements ---
    Cog0  [INFO] VDD_R_CURR_MIN:       7
    Cog0  [INFO] VDD_R_CURR_MAX:       6
    Cog0  [INFO] VDD_W_CURR_MIN:       7
    Cog0  [INFO] VDD_W_CURR_MAX:       6
    Cog0   
    Cog0  ======== OCR REGISTER (Operating Conditions) ========
    Cog0   
    Cog0         OCR Value:            $$80FF_8000
    Cog0   
    Cog0  [INFO] Bit 31 (Power Up):    1 (Ready)
    Cog0  [USED] Bit 30 (CCS):         0 (SDSC) ** CRITICAL: Determines addressing mode **
    Cog0  [INFO] Bit 29 (UHS-II):      0 (Not UHS-II)
    Cog0  [INFO] Bit 24 (S18A):        0 (3.3V only)
    Cog0   
    Cog0  --- Voltage Window ---
    Cog0  [INFO] 3.5-3.6V:             Supported
    Cog0  [INFO] 3.4-3.5V:             Supported
    Cog0  [INFO] 3.3-3.4V:             Supported
    Cog0  [INFO] 3.2-3.3V:             Supported
    Cog0  [INFO] 3.1-3.2V:             Supported
    Cog0  [INFO] 3.0-3.1V:             Supported
    Cog0  [INFO] 2.9-3.0V:             Supported
    Cog0  [INFO] 2.8-2.9V:             Supported
    Cog0  [INFO] 2.7-2.8V:             Supported
    Cog0   
    Cog0  ======== SCR REGISTER (SD Configuration) ========
    Cog0   
    Cog0  [INFO] SCR_STRUCTURE:        0 (SCR Version 1.0)
    Cog0  [USED] SD_SPEC:              2
    Cog0         SD Version:           2.00
    Cog0  [INFO] SD_SPEC3:             0 (SD 3.0 support: No)
    Cog0  [INFO] SD_SPEC4:             0 (SD 4.0 support: No)
    Cog0  [INFO] SD_SPECX:             0 (SD 5.x/6.x/7.x indicator)
    Cog0   
    Cog0  --- Bus Width Support ---
    Cog0  [INFO] SD_BUS_WIDTHS:        $$05
    Cog0         1-bit bus:            Supported (SPI mode uses this)
    Cog0         4-bit bus:            Supported
    Cog0   
    Cog0  --- Security ---
    Cog0  [INFO] SD_SECURITY:          2
    Cog0         Security:             SDSC Card (security v1.01)
    Cog0  [INFO] EX_SECURITY:          0
    Cog0   
    Cog0  --- Command Support ---
    Cog0  [INFO] CMD_SUPPORT:          $$00
    Cog0   
    Cog0  [INFO] DATA_STAT_AFTER_ERASE:0
    Cog0   
    Cog0  ======== RAW REGISTER DATA ========
    Cog0   
    Cog0  CID: $03 $53 $44 $53 $55 $30 $31 $47 $80 $00 $6C $D5 $B2 $00 $76 $DB
    Cog0  CSD: $00 $26 $00 $32 $5F $59 $83 $C8 $BE $FB $CF $FF $92 $40 $40 $D7
    Cog0  OCR: $$80FF_8000
    Cog0  SCR: $02 $25 $00 $00 $00 $00 $00 $00
    Cog0   
    Cog0  ======== FILESYSTEM INFORMATION ========
    Cog0   
    Cog0  MBR Partition Type:          $$00
    Cog0                               Unknown type
    Cog0  NOTE: Not FAT32 - VBR parsing skipped
    Cog0   
    Cog0  ##############################################
    Cog0    UNIQUE CARD ID: SanDisk_SU01G_8.0_006CD5B2_200706
    Cog0  ##############################################
    Cog0   
    Cog0  ##############################################
    Cog0    CARD DESIGNATOR
    Cog0  ##############################################
    Cog0  SanDisk SU01G SDSC 0GB [Empty] SD 2.0 rev8.0 SN:$006C_D5B2 2_007/06
    Cog0  Class 2, U0, V0, SPI 25 MHz
    Cog0  ##############################################
    Cog0   
    Cog0  ======== V3 DRIVER USAGE SUMMARY ========
    Cog0   
    Cog0  Fields marked [USED] are actively used by the driver:
    Cog0   
    Cog0  CID Register:
    Cog0    - MID: Determines PNY cards (20MHz limit) vs others (25MHz)
    Cog0   
    Cog0  CSD Register:
    Cog0    - CSD_STRUCTURE: Determines SDSC vs SDHC/SDXC formulas
    Cog0    - TRAN_SPEED: Calculates maximum SPI clock frequency
    Cog0    - TAAC/NSAC/R2W_FACTOR: Calculates timeouts (SDSC only)
    Cog0    - C_SIZE + multipliers: Calculates card capacity
    Cog0   
    Cog0  SCR Register:
    Cog0    - SD_SPEC: Determines CMD6 (High Speed) support
    Cog0   
    Cog0  OCR Register:
    Cog0    - CCS bit: CRITICAL - determines addressing mode
    Cog0      CCS=0: SDSC byte addressing (sector << 9)
    Cog0      CCS=1: SDHC/SDXC block addressing (sector)
    Cog0   
    Cog0  ##############################################
    Cog0  END_CHARACTERIZATION
    Cog0  ##############################################
    

    Doesn't look very good...

  • evanhevanh Posts: 17,215

    @macca said:
    Tried that, same result. As shown in the debug output, the problem is "[readSector] TIMEOUT waiting for start token" which, AFAIK, is outside the streamer block.

    Oh, good point. Hmm ...

  • evanhevanh Posts: 17,215
    edited 2026-05-05 07:57

    Macca,
    Have you tested that card using Flexspin's FAT filesystem and drivers? Do you have a 4-bit SD slot?

  • maccamacca Posts: 1,040

    @evanh said:
    Macca,
    Have you tested that card using Flexspin's FAT filesystem and drivers? Do you have a 4-bit SD slot?

    No and no (using the P2 Edge built-in slot).

    I have other implementations but I think all are using bitbanged SPI, like fsrw using sdspi_asm_mb2, no problems with that at any clock frequency, as far as I can tell.

    Just tested sd_dir.bas from flexprop and works (don't know what kind of spi implementation is using or the P2 clock setting, release is 7.6.2)

  • evanhevanh Posts: 17,215
    edited 2026-05-05 09:34

    @macca said:
    Just tested sd_dir.bas from flexprop and works (don't know what kind of spi implementation is using or the P2 clock setting, release is 7.6.2)

    The driver will be sdmm.cc. It uses smartpins on the Prop2, and pre-calculates the divider at init. There is no streamer ops in that driver. However, it obviously is handling the read block start bit without issue.

    Here's the relevant function:

    static
    int rcvr_datablock (    /* 1:OK, 0:Failed */
        BYTE *buff,         /* Data buffer to store received data */
        UINT btr            /* Byte count */
    )
    {
        BYTE *d = __builtin_alloca(2);
        UINT tmr, tmout;
    
        tmr = _cnt();
        tmout = _clockfreq() >> 3;  // 125 ms timeout
        for(;;) {
            rcvr_mmc( d, 1 );
            if( d[0] != 0xFF )  break;
            if( _cnt() - tmr >= tmout )  break;
        }
        if (d[0] != 0xFE) return 0;     /* If not valid data token, return with error */
    
        rcvr_mmc(buff, btr);            /* Receive the data block into buffer */
        rcvr_mmc(d, 2);             /* Discard CRC */
    
        return 1;               /* Return with success */
    }
    

    It looks functionally the same as Stephen's code.

    The only thing of significance prior to that is:

        cmd = count > 1 ? CMD18 : CMD17;            /*  READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */
        if (send_cmd(cmd, sect) == 0) {
    

    send_cmd() is a little complicated ...

  • evanhevanh Posts: 17,215
    edited 2026-05-05 10:23

    Ah, I just noticed your card is SDSC rather than SDHC. I've got one such card sitting in my digital camera ... and surprise, Stephen's code fails to read that MBR too, but not at the start bit.

    ...
    Cog1      [initCard] CMD8 echo unexpected: $(resp & CMD8_ECHO_MASK) = $0000_0FFF expected $1AA
    Cog1      [initCard] Treating as Ver 1.x card
    Cog1      [initCard] Step 6: ACMD41 init loop (arg=$acmd41_arg = $0000_0000)...
    Cog1      [initCard] ACMD41 complete - card ready!
    Cog1      [initCard] Step 7: CMD58 (READ_OCR)...
    Cog1      [initCard] OCR: $resp = $80FF_8000
    Cog1      [initCard]   Bit 31 (ready): ((Shr__(resp, 31)) & 0x1) = 1
    Cog1      [initCard]   Bit 30 (CCS):   ((Shr__(resp, OCR_CCS_SHIFT)) & 0x1) = 0
    Cog1      [initCard] Card type: SDSC (byte addressing)
    Cog1      [initCard] Step 8: Card identification and speed selection...
    Cog1      [applySPISpeed] Target=25_000 kHz, Actual=25_000 kHz
    Cog1      [applySPISpeed] Half-period=5 clocks
    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] CMD23 not advertised (CMD_SUPPORT=$$00)
    Cog1      [initCard] === INIT SUCCESS ===
    Cog1    [do_mount] Reading MBR sector 0...
    Cog1    [checkCardStatus] readSector: pre=[$FF $FF $FF $FF $FF $FF] NCR=2 R1=$$00 ST=$$00
    Cog1    [do_mount] MBR type code: $6
    Cog1    [do_mount] FAIL: Not FAT32 (type=$6)
    Cog1    [updateFSInfo] No valid FSInfo to update
    Cog0  Mount FAILED, error: -22
    

    EDIT: Oh, Doh! It's FAT16, not FAT32.

    EDIT2: Right, okay, works now I've reformatted to FAT32. :) But, boy, it's slow at writing one block at a time (CMD24). 14 kB/s :(

    EDIT3: It definitely goes a lot faster using long bursts of CMD25. The 4-bit driver gets 1200 kB/s writing to FAT32 and about 8000 kB/s writing to FAT16.

  • evanhevanh Posts: 17,215
    edited 2026-05-05 10:44

    @evanh said:
    send_cmd() is a little complicated ...

    Back to the issue - There is a notable difference between sdmm.cc's command handling and how Stephen's code works. Chip Select (CS) management is entirely done at the beginning of the routine in sdmm.cc. Namely it always deselects before reselecting the card, with one exception. If command is CMD12 then it skips the CS management. Whereas Stephen's code attempts to mange CS in a more start-to-finish approach.

    Just as a guess, there is a reasonable chance that CS has stayed selected (Low) when it should have toggled High then Low before the CMD17 block read. This would mean the SD card has not seen the command. I have no idea how this would occur for only one card though.

  • @macca evaluating your results... more soon

  • RaymanRayman Posts: 16,370

    @"Stephen Moraco" this is the problem of supporting a new uSD driver…

  • evanhevanh Posts: 17,215
    edited 2026-05-05 23:30

    I can't really fault the choice of divider values either. I used a wider range of values in sdmm.cc than in Stephen's but at the higher frequencies from sysclock 200 MHz and above, both are pretty similar. It's about as fast as Parallax's resistor limited boot slot can run at.

    The 4-bit driver isn't limited in that way.

  • @macca, thank you for the logs. These are very useful results. I'm seeing a number of things of interest. This is the first SDSC card we've seen; all the others I tested are SDHC/SDXC. Yours is failing at 25MHz SPI, which is stated as the max for your card, so derating for SDSC cards seems prudent. We don't have evidence yet, but I'm preparing quick tests for you to run, which will give us more insight across many areas, not just SPI speed. v1.5.2 is coming along with a new test for you to run. (Couple of hours yet...)

Sign In or Register to comment.