Shop OBEX P1 Docs P2 Docs Learn Events
SD/fat32 implementations — Parallax Forums

SD/fat32 implementations

Has anyone developed a framework/object to access files on a fat32 filesystem of an SD card?

I know that TaqOz does this, but I didn't know if there was something outside of TaqOz.

Thanks,
Terry
«1

Comments

  • RaymanRayman Posts: 14,646
    Here is the spin only version of FSRW 2.6 that runs on P2. Compiles with FastSpin...
  • Cluso99Cluso99 Posts: 18,069
    The P2 ROM has callable routines to boot/access/load/run files from an SD Card formatted as FAT32. However, there are no write routines in the ROM, and only the root directory is supported directly.

    For an example, see the Fun with the P2 ROM thread.
  • Thanks guys!
  • I've been working on a version of FSRW2.6 using inline asm. I plan to convert the SDSPI to P2asm but it's very slow going for me. Here's my latest verson (still needs a ton of work)
  • @Rayman I changed the pin config to match the P2 Eval board, however I just get "Mounting"
    cs_pin=60
        clk_pin=61
        miso_pin=58
        mosi_pin=59
    

    Any thoughts about this?
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2019-03-07 02:57
    ke4pjw wrote: »
    @Rayman I changed the pin config to match the P2 Eval board, however I just get "Mounting"
    cs_pin=60
        clk_pin=61
        miso_pin=58
        mosi_pin=59
    

    Any thoughts about this?

    Use the built-in TAQOZ to do a sanity check for you. Just reset and type the three keys [>] [space] [esc] and from TAQOZ type MOUNT. From there you can do a DIR.
    If it doesn't work there then it won't work elsewhere.
      Cold start
    ----------------------------------------------------------------
      Parallax P2  .:.:--TAQOZ--:.:.  V1.0--142          180530-0135
    ----------------------------------------------------------------
    TAQOZ# MOUNT .SDSL08G 5E5F_7F14 TAQOZ      32k 7,576M ok
    TAQOZ# DIR 
    .SDSL08G 5E5F_7F14 TAQOZ      32k 7,576M
    TAQOZ        $0000_3F80   2018.05.21.10.33   0
    CODE         $0000_4080   2017.07.20.07.56   0
    HELP         $0000_42C0   2017.12.04.12.34   0
    MUSIC        $0000_4680   2016.06.25.02.37   0
    VIDEOS       $0004_06C0   2016.08.05.02.50   0
    3X5     .TXT $0007_A540   2017.11.23.15.06   3,968
    ASCIIART.TXT $0007_A580   2017.11.23.15.05   55,148
    CALCDEMO.FTH $0007_A600   2017.10.11.06.28   1,848
    EASYFILE.FTH $0007_A640   2017.10.24.13.53   46,173
    EASYNET .FTH $0007_A6C0   2017.10.24.01.57   42,985
    EXTEND  .FTH $0007_A740   2017.10.24.12.14   60,355
    FISH2   .VT  $0007_A7C0   2017.11.23.15.08   211,945
    HOME    .HTM $0007_A980   2014.06.15.15.45   68,513
    HTTP001 .HTM $0007_AA40   2013.12.02.16.25   388
    HTTP404 .HTM $0007_AA80   2013.12.02.23.58   564
    ILIAD   .TXT $0007_AAC0   2017.11.23.12.55   1,201,891
    KJV     .TXT $0007_B400   2017.08.28.12.28   5,504,282
    LEXICON .TXT $0007_DE00   2017.11.23.13.48   988,130
    LIFE    .FTH $0007_E5C0   2017.10.15.05.40   7,308
    LOGON   .HTM $0007_E600   2013.12.02.16.25   388
    LOVE    .WAV $0007_E640   2015.02.16.08.06   14,630,692
    MIDENG  .TXT $0008_5600   2017.11.23.14.11   1,248,077
    P8X32A  .PDF $0008_5FC0   2012.02.22.12.57   1,442,886
    PARALLAX.PNG $0008_6B00   2013.12.12.01.41   6,109
    POPCORN .WAV $0008_6B40   2012.11.07.13.26   3,242,394
    PRIDE   .TXT $0008_8400   2017.11.23.12.54   726,223
    ROUGES  .TXT $0008_89C0   2017.11.23.13.51   219,885
    SEE     .FTH $0008_8B80   2017.07.06.01.30   2,187
    SPLAT-V4.FTH $0008_8BC0   2017.03.09.12.30   18,944
    VULGAR  .TXT $0008_8C00   2017.11.23.13.56   511,916
    WARPEACE.TXT $0008_9000   2015.08.30.07.27   3,226,652
    WARWORLD.TXT $0008_A8C0   2017.11.23.13.42   365,413
    WEBSTERS.TXT $0008_ABC0   2017.11.23.12.59   28,956,348
    _BOOT_P2.BIN $0009_8940   2018.12.27.06.48   131,072
    BEACH   .BMP $0009_8C40   2018.12.03.06.50   308,314
    P2      .ROM $0009_BF40   2019.02.18.07.09   65,536
    _BOOT_P2.BIB $0009_8B40   2018.12.27.06.48   131,072
     BOOT_P2.BIX $0009_C0C0   2019.02.15.08.21   65,536
    BEACH2  .BMP $0009_8EC0   2018.12.06.14.20   308,274
    BIRD    .BMP $0009_9140   2018.12.03.06.54   308,346
    BUZZ    .BMP $0009_93C0   2018.11.11.01.53   308,346
    DRAGON  .BMP $0009_9640   2018.10.23.01.21   308,346
    EYEGOD  .BMP $0009_98C0   2018.10.28.04.17   308,346
    FACE    .BMP $0009_9B40   2018.10.28.04.03   308,346
    FIRE    .BMP $0009_9DC0   2018.11.02.23.51   308,346
    LMMS    .BMP $0009_A040   2018.10.23.01.01   308,280
    MARIO   .BMP $0009_A2C0   2018.12.03.06.55   308,266
    MARIO   .PNG $0009_A540   2018.10.19.14.37   16,813
    MCQUEEN .BMP $0009_A580   2018.10.28.04.19   308,346
    P2D2    .BMP $0009_A800   2018.12.06.14.26   308,346
    SPIDEY  .BMP $0009_AA80   2018.10.28.04.24   308,346
    SPIDEY  .GIF $0009_AD00   2018.10.29.01.28   145,609
    SPIDEY  .PNG $0009_AE40   2018.10.29.13.16   124,697
    SUNSET  .BMP $0009_AF40   2018.10.28.04.13   308,346
    TIGER   .BMP $0009_B1C0   2018.12.06.14.23   308,346
    TIGER   .GIF $0009_B440   2018.10.25.01.16   248,692
    TIGER   .JPG $0009_B640   2018.10.25.01.10   133,590
    TIGER   .PNG $0009_B780   2018.10.25.01.07   693,848
    TIGER1  .BMP $0009_BD00   2018.12.03.06.58   77,946
    TAQOZ1V1.FTH $0009_BDC0   2018.12.30.14.06   25,371
    W5500A  .FTH $0009_BE00   2018.12.30.00.56   12,367
    C2PROG  .FTH $0009_BE40   2018.12.12.13.58   12,180
    _BOOT_P2.BY  $0009_BE80   2019.01.28.06.53   84,736
    _BOOT_P2.BIZ $0009_8A40   2018.12.27.06.48   131,072
    _BOOT_P2.BAD $0009_C0C0   2019.02.15.08.21   65,536
    A_ _ B O. O  $0C80_3F80   1980.02.02.00.01   5,767,241
    __BOOT~1.BIX $0009_C140   2019.02.19.12.40   32
     ok
    TAQOZ#
    
  • It's because you're using PortB pins using the old OUTs and DIRs method. If you change the pin instructions to ones that span 64 pins OR sub 32 from pin numbers it should work.
  • Good thinking Peter! I can mount the card and view its directory.

    Looking in sdspi.spin2, I think this may be the problem.
       do := basepin++
       clk := basepin++ 
       di := basepin++
       cs := basepin
    

    I don't think the pins are laid out the same.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2019-03-07 04:36
    @ke4pjw - yes, that looks like you should skip that ++ method and assign them using basepin as an offset.
    You can also test your pin arrangement other than the default with TAQOZ by changing the sdpin constant with this expression:
    &60.58.59.61 ' sdpins 2+ !
    
    It's a bit more awkward than it usually is with the cramped ROM space because we are writing directly to the sdpins constant whereas normally we have a word to take care of it easily.
    But the syntax is & for a decimal bytes notation (as in IP notation where every group of decimal digits represent a byte) in the sequence CS.MISO,MOSI.CLK and then the tick ' then a space and the name of the constant (sdpins) then 2+ to modify that address to point to the parameter field and then ! to store the new value into the sdpins constant. Just in case you want to double check your original setup.

    BTW, the extended TAQOZ implementation of FAT32 includes all the FOPEN type commands, handling a file as virtual memory etc as well as the disk utilities and FORMAT.
  • I'm not sure if you've gone through my thread, but I wasn't able to get Ray's to work either. I think with the portB replacement macro you'd need to subtract 32 from the pin number to span 0-31.
    pri read | r
    '
    '   Read eight bits from the card.
    '
       r := 0
       repeat 8
          outa[clk] := 0
          outa[clk] := 1
          r += r + ina[do]
       return r
    

    becomes
    pri read | r
    '
    '   Read eight bits from the card.
    '
       r := 0
       repeat 8
          outB[clk] := 0
          outB[clk] := 1
          r += r + inB[do]
       return r
    
    Which won't work with pin numbers >31!!

    Pretty sure he already fixed the Start_Explicit… at least I have it in mine if you need.

    The thread I've got for what I was working on is here;

    https://forums.parallax.com/discussion/169786/working-on-fsrw/p1


    Right now I'm trying to learn how to start a cog the right way and pass everything, basic asm engine stuff. Once I have a handle on that I plan on using the smart pins. This is my SDSPI using inline asm. It should just replace fsrw2.6 sdspi, although I made some small tweaks to the fsrw file to make things return gracefully. When all the abort code was changed to return there were some edge cases that didn't seem quite right.
    {{
        SDSPI driver for P2-ES FastSpin/InlineASM RC2
        Cheezus Slice (Joe Heinz)  -    Feb - 2019
        Thanks to cluso, ersmith, David Betz, Rayman, Dave Hein 
        and all the other greats out there in fourm land!
        Original spin version by Radical Eye Software Copyright 2008
    }}
    con
       sectorsize = 512
       sectorshift = 9
       
    var
       long di, do, clk, cs, starttime, sdhc, di_mask, do_mask, clk_mask, do_pin
      
    pri send(outv) | c, i       '   Send eight bits, then raise di.
    
            i := di
            c := clk
        asm
                rol     outv,       #24        
                rep     #.end_send, #8
                rol     outv,       #1      wc
                drvl    c
                drvc    i
                drvh    c 
    .end_send     
                drvh    i    
    endasm
    
    
    pri read : r  | c, o        '   Read eight bits from the card.
    
            c := clk
            o := do
        asm
            mov     r,          #0
            rep     #.end_read, #8
            drvl    c
            waitx   #14    '' !! 13 safe for up to 160 mhz, 14 for 320mhz
            testp   o               wc  
            drvh    c   
            rcl     r,          #1
    .end_read
        endasm
    
    
    pri readresp | r
    '' made return timeout to caller CHZ 2-2019
    '   Read eight bits, and loop until we
    '   get something other than $ff.
    '
       repeat
          if (r := read) <> $ff
             return r
          if checktime == -41
            return -41
     
         
    pri busy | r        '   Wait until card stops returning busy
    '' made return timeout to caller CHZ 2-2019
    
    '
       repeat
          if (r := read)
             return r
          if checktime == -41
            return -41
    
    
    pri checktime       '   Did we go over our time limit yet?
    
    
    {
       if cnt - starttime > clkfreq
          return -41'abort -41 ' Timeout during read
    }
    pri cmd(op, parm) 
    '
    '   Send a full command sequence, and get and
    '   return the response.  We make sure cs is low,
    '   send the required eight clocks, then the
    '   command and parameter, and then the CRC for
    '   the only command that needs one (the first one).
    '   Finally we spin until we get a result.
    
        DRVL_(cs)
    
        read
        send($40+op)
        send(parm >> 24)
        send(parm >> 16)
        send(parm >> 8)
        send(parm << 0)
        if (op == 0)
            send($95)
        else
            send($87)   
        return readresp
       
    pri endcmd      ' Deselect the card to terminate a command.
            drvh_(cs)           ' Deselect the card to terminate a command.
    
    PUB stop                    ' RJA adding in some things
    
    PUB release   
    
    pub start_explicit(iDO, iCLK, iDI, iCS)| t  'RJA adding in some things to make work
        do := iDO
        clk := iCLK
        di := iDI
        cs := iCS
    
        t := clk
            outh_(cs)
            outh_(clk)
            outh_(di)
            dirh_(cs)
            dirh_(clk)
            dirh_(di)
    
        asm
            rep #.initclksout,   #4800
                drvnot t
    .initclksout       
            getct   t             
       endasm
    
        starttime := t
         
        cmd(0, 0)
        drvh_(cs)               ' Deselect the card to terminate a command.
    
        cmd(8, $1aa)
        read
        read
        read
        read
        drvh_(cs)               ' Deselect the card to terminate a command.  
    
        repeat
                cmd(55, 0)
                t := cmd(41, $4000_0000)
                drvh_(cs)           ' Deselect the card to terminate a command.
                if t <> 1
                    quit
        if t
                return -40'abort -40 ' could not initialize card
    
        cmd(58, 0)
        sdhc := (read >> 6) & 1
        read
        read
        read
        drvh_(cs)               ' Deselect the card to terminate a command.
    
        return sdhc +1              ' return card type
           
    pub start(basepin)
    
      result := start_explicit(basepin, basepin+1, basepin+2, basepin+3)
      
    PUB doSDHC(n)
        if sdhc == 0  
            return n  <<= 9
        else 
            return n
           
    pub readblock(n, b)
    '
    '   Read a single block.  The "n" passed in is the
    '   block number (blocks are 512 bytes); the b passed
    '   in is the address of 512 blocks to fill with the
    '   data.
    '
       starttime := cnt
       cmd(17, doSDHC(n))
       readresp
       repeat sectorsize
          byte[b++] := read
       read
       read
       return endcmd
    {
    pub getCSD(b)
    '
    '   Read the CSD register.  Passed in is a 16-byte
    '   buffer.
    '
       starttime := cnt
       cmd(9, 0)
       readresp
       repeat 16
          byte[b++] := read
       read
       read
       return endcmd
    }
    pub writeblock(n, b)
    '
    '   Write a single block.  Mirrors the read above.
    '
       starttime := cnt
       cmd(24, doSDHC(n))
       send($fe)
       repeat sectorsize
          send(byte[b++])
       read
       read
       if ((readresp & $1f) <> 5)
          return -42'abort -42
       busy
       return endcmd
    
    {{
    '  Permission is hereby granted, free of charge, to any person obtaining
    '  a copy of this software and associated documentation files
    '  (the "Software"), to deal in the Software without restriction,
    '  including without limitation the rights to use, copy, modify, merge,
    '  publish, distribute, sublicense, and/or sell copies of the Software,
    '  and to permit persons to whom the Software is furnished to do so,
    '  subject to the following conditions:
    '
    '  The above copyright notice and this permission notice shall be included
    '  in all copies or substantial portions of the Software.
    '
    '  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    '  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    '  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    '  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    '  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    '  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    '  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    }}
    
    
    
    

  • Thanks for the direction @cheezus ! (Pardon the pun.)

    So, I replaced dira and outa with DIR and OUT. I am going to look through simple serial and see how that works. I have pin 62 assigned.


  • That did the trick!
    Mounting.
    Mounted.
    Dir:
    That's the dir
    Wrote file.urned -
    That's, all, folks! 3
    Returned from start
    
  • Well, maybe not, but it appears to be doing something different. I will keep poking at it.
  • No problem! I worked on my version for a while but it's far from perfect. I've looked at the output asm from fastspin and there's tons of room for improvement. The block read / write have not even been touched, other than to add sd / sdhc compatibility. I've tried to understand the best way to use the resources of the p2 and using the smartpins should be a huge boost, since the required turnaround from cog ->pin -> pin -> cog should disappear.

    I think the idea is to set smartpin mode %00101 = transition output for the clock. Then use Sync serial tx and rx to push data around. It should end up with some really optimized code, as well as nice mhz.

    Now that you have the dir and out macro, you'll still need to change the pin numbers by 32 right? ;)
  • RaymanRayman Posts: 14,646
    edited 2019-03-07 15:49
    You do probably need to use "Mount Explicit" …

    I didn't try this on Eval board's uSD, used one on my own board...

    I imagine those switches have to be in the right position for uSD access...
  • RaymanRayman Posts: 14,646
    edited 2019-03-07 15:59
    Ok, I see the issue is probably being on pins >31, right?

    I'll look into this and see about fixing it.
    I thought this stuff at the beginning would make it work, but maybe not
    #ifdef __P2__
    #define OUT OUTB
    #define DIR DIRB
    #else
    #define OUT OUTA
    #define DIR DIRA
    #endif
    

    Maybe changing OUTA to OUTB and DIRA to DIRB in sdspi.spin2 would fix it?
  • The Pins.spin2 class is a nice idea, but it can be made much more efficient by using some fastspin builtins:
    PUB High(pin)
      drvh_(pin)
    PUB Low(pin)
      drvl_(pin)
    PUB Toggle(pin)
      drvnot_(pin)
    PUB In(pin) : state
    #ifdef __P2__
      asm
        testp pin wc
        muxc state, #1
      endasm
    #else
      dira[pin] := 0
      waitx_(clkfreq / 10000)
      state := ina[pin]
    #endif
    

    fastspin provides P1 definitions for drvh_, drvl_, drvnot_, and waitx_. I should create a testp_ builtin as well, I think.
  • Rayman wrote: »
    Ok, I see the issue is probably being on pins >31, right?

    I'll look into this and see about fixing it.
    I thought this stuff at the beginning would make it work, but maybe not
    #ifdef __P2__
    #define OUT OUTB
    #define DIR DIRB
    #else
    #define OUT OUTA
    #define DIR DIRA
    #endif
    

    Maybe changing OUTA to OUTB and DIRA to DIRB in sdspi.spin2 would fix it?

    The RIGHT way to do it would be to use the DRVx instructions (and TESTP), since they can span all 64 pins. The one place to watch seems to be the READ mov ina. I have a rather large delay to make sure things work at 320mhz and that's using the TESTP instruction...
    pri read : r  | c, o        '   Read eight bits from the card.
    
            c := clk
            o := do
        asm
            mov     r,          #0
            rep     #.end_read, #8
            drvl    c
            waitx   #14    '' !! 13 safe for up to 160 mhz, 14 for 320mhz
            testp   o               wc  
            drvh    c   
            rcl     r,          #1
    .end_read
        endasm
    
    

    I'm pretty sure using the smart pins will make that delay go away. Cluso's way is to toggle the clock early and end up with an extra clock. I was going for the more brute force method, at least until I understand the chip better.
  • RaymanRayman Posts: 14,646
    Just changing dira to dirb, outa to outb seems to be enough to make this work for the uSD on the eval board. Code attached.
  • Rayman et al, I think I am doing something wrong. I can't get it to work. I updated fsrw.spin2 to point to sdspi2.spin2 for sdspi.

    @Rayman, could you share your working version with all three .spin2 files in a zip? The one above only has sdspi2.spin2, but not the other spin2 files. I am sure I am doing something wrong and would like to compare with one that works.
  • RaymanRayman Posts: 14,646
    Here they are... Good luck.
  • No dice. I can mount the thing from TAQOZ and perform a DIR. I reformatted just to make sure something weird was hanging it up. All four LEDs light up solid when "Mounting" is sent through serial. P58-P61

    Weird. Not sure what to do next. Maybe I should do a logic capture and compare with TAQOZ.
  • I see the problem now. CLK is idle high instead of low. This is a similar problem to what I had with the smartpin code I was doing for the 5-wire interface for the OLED display.

    I think the pins just need to be initialized properly.

    non-working mount with fsrw
    sdproblem.png

    Working mount in TAQOZ.

    taqozsdmount.png
    1463 x 725 - 111K
    1465 x 737 - 104K
  • RaymanRayman Posts: 14,646
    What kind of card is this? I wonder if clock polarity is different for different card types...
  • The card works just fine. This fsrw can't mount any card, for me. I have found that under some circumstances the pins will default "high" or "low" in an inconstant way. I think this may have something to do with the difference between how the pin is accessed by the COG vs smartpin or how it works when "floating".
  • RaymanRayman Posts: 14,646
    edited 2019-03-20 17:48
    Did you compile this with FastSpin? Or, PNut?
    It might only work with FastSpin...

    Ok, never mind PNut doesn't do Spin, dumb question...

    I'm puzzled as to why it works for me and not you on the same hardware...
  • Does not work for me either. I started looking at adapting safe_spi.spin from the fsrw26 version (using the slow_reaf/write functions). But it fails at the 1st command send (reset), same as with Rayman's code .

    I lack a logic analyzer/scope, so I'm a bit stuck. Maybe start loking into ozpropdev's or cluso's prop2 based LA working.
  • Rayman wrote: »
    Did you compile this with FastSpin? Or, PNut?
    It might only work with FastSpin...

    Ok, never mind PNut doesn't do Spin, dumb question...

    I'm puzzled as to why it works for me and not you on the same hardware...

    I was unable to get your version of FSRW working as well. I'm wondering how much of this has to do with PortB. I'm thinking once I attach a card to PortA pins things should work but I'll let you know when I figure it out.

    BTW, I've been idling the clock high without an issue.
  • RaymanRayman Posts: 14,646
    edited 2019-03-20 18:55
    Can we load a "binary" file? Maybe Spin2Gui can do this?

    If so, I'll upload my working binary. Can't imagine what's going on here...

    You are running this as the top level file, right?:
    sdrw_test_eval.spin2
Sign In or Register to comment.