Shop OBEX P1 Docs P2 Docs Learn Events
Flash AND MicroSD in the same program - how to? / Flexprop — Parallax Forums

Flash AND MicroSD in the same program - how to? / Flexprop

pik33pik33 Posts: 2,388
edited 2022-11-26 17:47 in Propeller 2

There is jm_p2_flash.spin2. It works. But it reprograms pins, it has to... so after using this object to access the flash, the SD card no more works.

There is another problem. A 'read_block' procedure selects and deselects the flash via drvh and drvl #SF_CS. Call read_block several times and the SD is no more responding until power off (P2 soft reset doesn't help). I think the SD got clocks and started to do something/wait for something...

There is even worse problem: after one of experiments with reading/writing the flash I managed to overwrite the SD sector 0... :(

Now, work around:

(1) use the flash before mount "/sd", _vfs_open_sdcard()
(2) comment out drvh at the end of the read_block (I tested only reading) method, so it doesn't toggle the pin until all reads are done.

How to access both devices - when needed - in the same program?
How to protect the SD from being disabled/damaged when accessing the flash?
How to restore the pins after accessing the flash to enable SD again?

Edit: with commented out drvh there are errors reading from the flash. With not commented out drvh I have not responding SD card. I will try adding big gaps between reading blocks to check if it helps.

Edit 2: I gave up for now. This thing is too random. After several access to the flash SD became non-responsible until power off.

Edit 3: the boot process from flash doesn't harm the SD... so there is a way to read the flash in the way that SD still works after that...

Edit 4: the boot code doesn't use smart pins to access the flash....


The best solution seems to be adding flash_erase, flash_read and flash_write somewhere to the SD related flexprop driver. If these things are placed in one library, the library can keep the integrity of smart pins states between SD and SPI Flash access

Comments

  • evanhevanh Posts: 16,032
    edited 2022-11-26 23:49

    That can be improved for sure. I'll take the complete blame for not considering this scenario from the SD card side. Currently, the driver relies on exclusive smartpin use so it can leave them configured and come back on the assumption nothing else has changed that config.

    EDIT: Although if you're first unmounting the SD, then read/wrire EPPROM, then remounting the SD, then this smartpin reuse thing shouldn't be a problem.

  • evanhevanh Posts: 16,032
    edited 2022-11-26 23:45

    As for the EEPROM driver. It'll work best by also using SPI clock mode 3. Namely CPOL = 1. This prevents accidental mis-selecting of the SD card.

  • pik33pik33 Posts: 2,388
    edited 2022-11-27 20:45

    I ended up with a Basic/Spin procedure which simply bitbangs the SPI using pinhi and pinlo. This thing seems to work without disabling the SD if called before mount

    Edit: it works also when calling after mount, and then I still can read the file from SD after reading the flash so there is a hope...

    I used this "mode 3" with clock signal =1 at idle.

    The crude method looks like this:

    pub rd_block_2(fa,b,ha) |a,bb,i,j
    
    pinh(59)
    pinh(60)
    pinh(61)
    pinfloat(58)
    waitms(10)
    a:=$03000000+fa
    pinl(61) 'cs
    repeat i from 0 to 31
      org
      rol a,#1 wc
      if_c drvh #59
      if_nc drvl #59
      end 
      pinl(60)
      pinh(60)
    
    pinl(60)
    pinh(60)  
    repeat j from 0 to b-1
      bb:=0
      repeat i from 0 to 7
        pinl(60)
        pinh(60)
        bb:=(bb << 1) | pinread(58)
      byte[ha+j]:=bb
    pinh (61)
    

    Now... go to pure asm for some more speed :)

    Although if you're first unmounting the SD,

    How to unmount a SD?

  • evanhevanh Posts: 16,032
    edited 2022-11-27 23:11

    just umount( "/sd" );

    PS: I use it in my speed tester to induce a recalibration of the timings upon change of sysclock frequency. So not dissimilar situation in that the timings are calculated at init/mount time and reused per on-going read/write of the SD card.

    EDIT: Reading over the source again, the timings are embedded in the config of the smartpins themselves.

  • pik33pik33 Posts: 2,388

    It has to be_umount

    Then before accessing the flash, I had to do pinclear. And now it all seems to work.

    So the summary:

    • using smart pins as in jm_p2_flash.spin2 can hang up the SD even if the file system is not mounted and after that it needs power off to be usable again.
    • using bitbanging "mode 3" type timings so default clk is high works without hanging up the SD.
    • if the filesystem on SD is mounted, it needs to be unmounted by_umount before accessing the flash
    • after _umount the smart pins have to be cleared by pinclear before using flash, _umount doesn't clear pins
    • after accessing the flash the file system can be mounted again and it works.
  • evanhevanh Posts: 16,032
    edited 2022-11-28 11:58

    @pik33 said:
    It has to be_umount

    Odd, maybe that's changed at some point. My speed tester code doesn't use underscores.

    • using smart pins as in jm_p2_flash.spin2 can hang up the SD even if the file system is not mounted and after that it needs power off to be usable again.
    • using bitbanging "mode 3" type timings so default clk is high works without hanging up the SD.

    As expected. Most existing code uses mode 0, so is therefore prone to mis-selecting the SD card when attempting to access the EEPROM.

    It won't take much to alter Jon's EPPROM driver. Usually such code is agnostic to CPHA and will work as mode 3 simply by inverting the clock pin. Which can be done with a single WRPIN at the start.

    • after _umount the smart pins have to be cleared by pinclear before using flash, _umount doesn't clear pins

    Hmm, yeah, there isn't any existing callback in the sdmm.cc driver file for unmounting. Therefore there's no clearing of the smartpins during unmount.

    • after accessing the flash the file system can be mounted again and it works.

    Good.

  • pik33pik33 Posts: 2,388
    edited 2022-11-28 14:10

    Asm version of read block.

    I have several programs that needs only reading, so now I can remove the flash access full blown object and use this instead.

    pub rd_block_3(fa,b,ha) | bb,i      'fa - flash address, b - bytes to read, ha - hub address
    
           org
           drvh   #59                   ' prop->flash
           drvh   #60                   ' clock
           drvh   #61                   ' cs
           fltl   #58                   ' flash->prop
           add    fa,##$03000000        ' 03-read
           drvl   #61                   ' select the flash
           mov    i,#32                 ' send the command
    p1     rol    fa,#1 wc
           drvc   #59
           drvl   #60
           drvh   #60
           djnz   i,#p1
           drvl   #60
           drvh   #60
           nop                          ' without this nop the first bit is not correct
    p3     mov    i,#8                  ' read b bytes
    p2     drvl   #60
           drvh   #60
           testp  #58 wc
           rcl    bb,#1
           djnz   i,#p2       
           wrbyte bb,ha
           add    ha,#1
           djnz   b,#p3
           drvh   #61                   ' disable chip select
           end
    
  • evanhevanh Posts: 16,032
    edited 2022-11-29 04:31

    I've refined your code a little: Maximised the read lag compensation (14 sysclocks) for operating at highest sysclock frequencies, made the clock symmetrical, and optimised the inner loops to sysclock/8.

    pub  rd_block_3(fa,b,ha)      'fa - flash address, b - bytes to read, ha - hub address
        org
            drvh    #60                   ' clock
            drvh    #61                   ' cs
            drvh    #59                   ' prop->flash
            fltl    #58                   ' flash->prop
    
    ' tx command "read data"
            add     fa, ##$03000000       ' 03-read
            outl    #61                   ' select the flash
    
            rep     @p1, #32
            rol     fa, #1   wc
            outnot  #60
            outc    #59
            outnot  #60
    p1
    
    ' rx the data
            nop            ' clock spacer
            outnot  #60
            fltl    #59                   ' prop->flash
            outnot  #60
    p3
            rep     @p2, #8
            outnot  #60
            rcl     fa, #1
            outnot  #60
            testp   #58   wc
    p2
            rcl     fa, #1
            wrbyte  fa, ha
            add     ha, #1
            djnz    b, #p3
    
            drvh    #61                   ' disable chip select
        end
    
  • pik33pik33 Posts: 2,388
    edited 2022-11-29 08:34

    I forgot the rep instruction while writing this... 4 clocks and 2 local variables less in your version.


    Edit: it is possible to make the code faster using long write (if one doesn't need byte access). 833 instead of 970 microseconds for 4 kB read at 336 MHz

            org
            drvh    #60                   ' clock
            drvh    #61                   ' cs
            drvh    #59                   ' prop->flash
            fltl    #58                   ' flash->prop
    
    ' tx command "read data"
            add     fa, ##$03000000       ' 03-read
            outl    #61                   ' select the flash
    
            rep     @p1, #32
            rol     fa, #1   wc
            outnot  #60
            outc    #59
            outnot  #60
    p1
    
    ' rx the data
            shr b,#2           ' clock spacer
            outnot  #60
            fltl    #59                   ' prop->flash
            outnot  #60
    p3
            rep     @p2, #32
            outnot  #60
            rcl     fa, #1
            outnot  #60
            testp   #58   wc
    p2
            rcl     fa, #1
            movbyts fa,#%00011011
            wrlong  fa, ha
            add     ha, #4
            djnz    b, #p3
    
            drvh    #61                   ' disable chip select
            end
    
  • evanhevanh Posts: 16,032

    :)

  • You could also use WRFAST/WFBYTE to be even faster.

  • TonyB_TonyB_ Posts: 2,195
    edited 2022-11-29 16:25

    @Wuerfel_21 said:
    You could also use WRFAST/WFBYTE to be even faster.

    WFBYTE would be ~5% faster than WRBYTE but slower than WRLONG.
    WFLONG would be ~1% faster than WRLONG so hardly worth it.

    wrbyte fa, ha takes 6.25 cycles on average.
    wrlong fa, ha takes 5 cycles, whether or not ha long-aligned.

  • pik33pik33 Posts: 2,388
    edited 2022-12-08 13:30

    Update:

    DO not ever use jm_p2_flash.spin2 with an SD card residing in the slot.

    It can not only set the card in unusable state, it can unformat the card overwriting sector 0 on it.

    So remove the card before programming the flash or you can get an unformatted SD

    If this happens, the solution is to use a Linux machine with "testdisk" installed. Testdisk can find the partition and restore the partition table. After this, the card can be used again, it seems no other data was lost.

  • DO not ever use jm_p2_flash.spin2 with an SD card residing in the slot.

    Thank you for letting people know about this. I would have never thought to co-mingle the flash and uSD connections like this, hence I never put an a card into that socket.

  • pik33pik33 Posts: 2,388
    edited 2022-12-09 15:55

    The problem seems to be Mode 0 used. It causes the SD to receive random signals because flash clock is SD chipselect. If it is set low for too much time, the SD can think it is selected and starts to receiving commands.

    I don't know how it can be initialized and formatted this way, but this was the second time it has sector 0 erased by writing (too much) data to the flash.

    Now I use this bitbanged Mode 3 procedures. So far no side SD card effects. Maybe Mode 3 can be also done using smart pins. In theory reverting the clock should be sufficient. I didn't try this yet.

  • I did a very quick test with some demo code that uses the jm_p2_flash.spin2 driver. Per your suggestion, I inverted the clock output signal and get the same results as before. Hopefully, this will be helpful. What I'd really like is to see a unified driver that allows one to write to and read from either flash memory (above 1M) and the SD socket.

  • msrobotsmsrobots Posts: 3,709
    edited 2022-12-09 20:32

    Jon you are fast. :) - 9:07 - 9:09 - 2 min

    Mike

  • I'm able to compile the littlefs flash file system code with the latest flexspin, so it's at the point where we could add flash file system support. What's the final verdict on mixing SD and flash? Can they both be used together if mode 3 is used for the flash? Or should mounting one be possible only if the other is not mounted?

  • evanhevanh Posts: 16,032
    edited 2023-03-11 01:49

    @ersmith said:
    ... What's the final verdict on mixing SD and flash? Can they both be used together if mode 3 is used for the flash? Or should mounting one be possible only if the other is not mounted?

    As it stands, using SPI Clock Mode 3, they can cleanly share alternately (without corruption) but can't share concurrently. My SD smartpin code assumes exclusive control of those pins once mounted ... therefore has to be remounted after other software changes pin config.

  • pik33pik33 Posts: 2,388

    Unmount the SD before accessing the flash, remount after.

  • For me, once the SD has been mounted the flash is forever inaccessible, even if I unmount the SD. I guess something in the flash smartpin configuration is incompatible with the SPI object I'm using (the SimpleSpiFlash.spin2 object from the objex). Going the other way (mount flash, do stuff, unmount, then mount SD) seems to work though.

  • Oh, SimpleSpiFlash was one of the first pieces of code I wrote for the P2. I never claimed it is compatible with anything else. I was happy that it worked at all. o:)

    @JonnyMac said:
    What I'd really like is to see a unified driver that allows one to write to and read from either flash memory (above 1M) and the SD socket.

    Agreed, that is the best solution.

  • pik33pik33 Posts: 2,388
    edited 2023-03-14 14:51

    For me, once the SD has been mounted the flash is forever inaccessible, even if I unmount the SD.

    I tried a mixed flash/SD access in my test code that loads cog drivers from the flash instead of compiling them in the program and it works (at least it worked when I tried this), but to do this I used a bitbanged flash driver (without smart pins involved).

    This is the object:

    ' A simple bitbanged SPI Mode 3 flash driver
    ' v. 0.02 - 2022.12.08
    ' Piotr Kardasz pik33@o2.pl with a help from the P2 community
    
    ' read a block (256 bytes) from the flash
    ' fa - flash address, ha - hub address
    
    pub read_block(fa,ha) | bb,i     
    
            org
            drvh    #60                   ' clock
            drvh    #61                   ' cs
            drvh    #59                   ' prop->flash
            fltl    #58                   ' flash->prop
    
            add     fa, ##$03000000       ' 03-read
            outl    #61                   ' select the flash
    
            rep     @p1, #32              ' send command+address
            rol     fa, #1   wc
            outl    #60
            outc    #59
            outh    #60
    
    p1      mov     pr0,#64               ' read 64 longs 
            outl    #60
            fltl    #59                   
            outh    #60
    
    p3      rep     @p2, #32
            outl    #60
            rcl     fa, #1
            outh    #60
            testp   #58   wc
    
    p2      rcl     fa, #1
            movbyts fa,#%00011011
            wrlong  fa, ha
            add     ha, #4
            djnz    pr0, #p3
    
            drvh    #61                   ' disable chip select
            end
    
    ' erase a 4k block at fa
    
    pub erase_block(fa)
    
            org
            drvh    #60                   ' clock
            drvh    #61                   ' cs
            drvh    #59                   ' prop->flash
            fltl    #58                   ' flash->prop
    
            mov     pr0,##$06000000       ' write enable
            outl    #61
            rep     @p6,#8
            rol     pr0,#1 wc
            outl    #60
            outc    #59
            outh    #60
    p6  nop
        outh    #61
    
            waitx   ##$30_000        
    
            add     fa, ##$20000000      ' 20-erase 4k block
            and     fa, ##$FFFFF000      ' address has to be block aligned 
            outl    #61                  ' select the flash
    
            rep     @p1, #32
            rol     fa, #1   wc
            outl    #60
            outc    #59
            outh    #60
    p1      nop
            outh    #61
            waitx   ##$30_000_000        
    
            fltl    #59                   ' prop->flash
            end
    
    
    pub write_block(fa,ha)
    
            org
            drvh    #60                   ' clock
            drvh    #61                   ' cs
            drvh    #59                   ' prop->flash
            fltl    #58                   ' flash->prop
    
            mov     pr0,##$06000000
            outl    #61
            rep     @p6,#8
            rol     pr0,#1 wc
            outl    #60
            outc    #59
            outh    #60
    p6  nop
        outh    #61
    
            waitx   ##$30_000    
    
            add     fa, ##$02000000       ' 02 - write 256 bytes block
            outl    #61                   ' select the flash
    
            rep     @p1, #32
            rol     fa, #1   wc
            outl    #60
            outc    #59
            outh    #60
    p1      mov     pr1,#256
    
    p3      rdbyte  pr0,ha
            shl     pr0,#24
    
            rep     @p2,#8
    
            rol     pr0, #1   wc
            outl    #60
            outc    #59
            outh    #60
    p2      add     ha,#1
            djnz    pr1,#p3
            outh    #61
    
            waitx   ##3_000_000
    
            fltl    #59                   ' prop->flash
            drvh    #60
    
            end
    
  • D'oh, the answer was up-thread: the SD card pins have to have _pinclear applied at unmount. I've added a hook to sdmm.cc to allow this, and now switching between file systems works great.

    @ManAtWork : your SimpleSpiFlash works great, and is the only flash driver actually in the obex ( @JonnyMac did some flash drivers, I think, but they're in a QuickByte rather than the obex ).

  • AribaAriba Posts: 2,690
    edited 2023-03-14 15:25

    @ersmith said:
    For me, once the SD has been mounted the flash is forever inaccessible, even if I unmount the SD. I guess something in the flash smartpin configuration is incompatible with the SPI object I'm using (the SimpleSpiFlash.spin2 object from the objex). Going the other way (mount flash, do stuff, unmount, then mount SD) seems to work though.

    What board do you use to test this? Is there a series resistor between SD-DO and P58?
    The problem might be that the SD card is not released correctly at unmounting. Then the DO pin remains active high and disturbs communication with the Flash. This can be solved with such a resistor or with a good release procedure. Cluso99 claimed that his SD-boot code in ROM releases the card correctly.
    I think you need to set CS high and give the SDcard a bunch of clocks to release it fully.

    Here is another Flash access code from PIK33, that should work together with an SD card (first post):
    https://forums.parallax.com/discussion/175063/a-resource-burner-for-not-only-standalone-system#latest

    Andy

  • Thanks, Andy. I'm using a P2 Eval board, and the problem was that the FlexC SD code wasn't clearing the smart pins on unmount. That's fixed now.

  • hinvhinv Posts: 1,255

    @pik33 said:
    If this happens, the solution is to use a Linux machine with "testdisk" installed. Testdisk can find the partition and restore the partition table. After this, the card can be used again, it seems no other data was lost.

    Thanks for the tip. Here's the video I found to explain the process:

Sign In or Register to comment.