Shop OBEX P1 Docs P2 Docs Learn Events
Better than sliced bread! SD3.01 FAT16/32 Driver Updated! - Page 6 — Parallax Forums

Better than sliced bread! SD3.01 FAT16/32 Driver Updated!

12346

Comments

  • KyeKye Posts: 2,200
    edited 2012-03-29 06:36
    Just make this function public:
    PRI readWriteBlock(address, command) ' 12 Stack Longs
      CIDPointer := @CIDRegisterCopy
      cardSectorAddress := (address + hiddenSectors)
      cardBlockAddress := @dataBlock
      cardCommandFlag := command
      repeat while(cardCommandFlag)
      if(cardErrorFlag~)
        abortError(Disk_IO_Error)
    

    Do you see the "hiddenSectors" offset? You'll need to somehow undo that offset when you want sector level access. You'll break the FAT file system if you just remove it however. The "hiddenSectors" value is the offset from the MBR to the file system partition. You'll also need to feed a different address to the "cardBlockAddress" value.
    PUB writeLowLevelSector(MMCAddress, RAMAddress)
    
    CIDPointer := @CIDRegisterCopy
    cardSectorAddress := (MMCaddress)
    cardBlockAddress := RAMAddress
    cardCommandFlag := "W"
    repeat while(cardCommandFlag)
    if(cardErrorFlag~)
      abortError(Disk_IO_Error)
    
    PUB readLowLevelSector(MMCAddress, RAMAddress)
    
    CIDPointer := @CIDRegisterCopy
    cardSectorAddress := (MMCaddress)
    cardBlockAddress := RAMAddress
    cardCommandFlag := "R"
    repeat while(cardCommandFlag)
    if(cardErrorFlag~)
      abortError(Disk_IO_Error)
    

    You'll want to take into account that you need to mount the file system first and all the other regular code I have running in the background is still going. So, don't do anything really weird. Also, the functions still abort...
  • MacTuxLinMacTuxLin Posts: 821
    edited 2012-03-29 09:13
    Hello Kye,

    Thank you. Always appreciates your support.

    I'll test this first thing tomorrow morning.
  • KyeKye Posts: 2,200
    edited 2012-03-29 14:31
    BTW: The MMC address value is in sectors... And try to make the RAM address long aligned.
  • MacTuxLinMacTuxLin Posts: 821
    edited 2012-03-29 22:43
    Kye wrote: »
    BTW: The MMC address value is in sectors... And try to make the RAM address long aligned.

    Thanks a lot Kye! It worked for me. See you guys @ Parallax Expo next month.
  • MacTuxLinMacTuxLin Posts: 821
    edited 2012-03-30 05:06
    Kye wrote: »
    You'll want to take into account that you need to mount the file system first and all the other regular code I have running in the background is still going. So, don't do anything really weird. Also, the functions still abort...

    Hello Kye,

    Sorry, its me again. In my test code, it worked beautifully (with only 1 uSD socket) but when I insert it into my main code & board (with 4 uSD sockets), it hang at readLowLevelSector. Is the problem due to launching more than 1 instances of SD-MMC_FATEngine.spin?

    Thanks a lot.
      '--- --- --- --- --- --- --- --- --- ---  
      '---          uSD (Master)
      '--- --- --- --- --- --- --- --- --- ---  
      _Mas_DO        = 0
      _Mas_Clk       = 1
      _Mas_DI        = 2
      _Mas_CS        = 3
      _Mas_CD        = -1
      _Mas_WP        = -1
    
    
      '--- --- --- --- --- --- --- --- --- ---  
      '---          uSD (Client 1)
      '--- --- --- --- --- --- --- --- --- ---  
      _So1_DO        = 4
      _So1_Clk       = 5
      _So1_DI        = 6
      _So1_CS        = 7
      _So1_CD        = -1
      _So1_WP        = -1
    
    
      '--- --- --- --- --- --- --- --- --- ---  
      '---          uSD (Client 2)
      '--- --- --- --- --- --- --- --- --- ---  
      _So2_DO        = 8
      _So2_Clk       = 9
      _So2_DI        = 10
      _So2_CS        = 11
      _So2_CD        = -1
      _So2_WP        = -1
    
    
      '--- --- --- --- --- --- --- --- --- ---  
      '---          uSD (Client 3)
      '--- --- --- --- --- --- --- --- --- ---  
      _So3_DO        = 12
      _So3_Clk       = 13
      _So3_DI        = 14
      _So3_CS        = 15
      _So3_CD        = -1
      _So3_WP        = -1
    
  • KyeKye Posts: 2,200
    edited 2012-03-30 08:42
    Um... if you have literally separate included versions of the SD card driver (i.e differently named files).... they shouldn't care about each other.

    If you made two instances with the same driver then you could have problems. So... how are you using two instances of the same driver file? You're by passing the locking mechanism with direct access.
  • MacTuxLinMacTuxLin Posts: 821
    edited 2012-03-31 03:00
    Kye wrote: »
    If you made two instances with the same driver then you could have problems. So... how are you using two instances of the same driver file?

    Thanks Kye. Let me detail out the project but if you think its better I start another thread so as not to hijack this one, let me know.

    I'm working on our small product called Portable MicroSD X4 Duplicator (<- embedded video link). Initially, I wrote:
    OBJ
      uSD[4]  : "SD-MMC_FATEngine.spin"
    

    and I only load those whose cards are inserted:
      '------------------
      '[OBJ] - Load Activated Drivers
      '------------------
      if(long[statusAddress] & _masCrdDet)
        'Master inserted, it should
        'Need to put Error capture in the future
        uSD[0].FATEngineStart(_Mas_DO, _Mas_Clk, _Mas_DI, _Mas_CS, _Mas_WP, _Mas_CD, -1, -1, -1)
        uSD[0].mountPartition(0)
        uSDCogChecker[0] := 1
        
      if(long[statusAddress] & _c1CrdDet)
        'Client 1
        uSD[1].FATEngineStart(_So1_DO, _So1_Clk, _So1_DI, _So1_CS, _So1_WP, _So1_CD, -1, -1, -1)
        uSD[1].mountPartition(0)
        uSDCogChecker[1] := 1
    
    
      if(long[statusAddress] & _c2CrdDet)
        'Client 2
        uSD[2].FATEngineStart(_So2_DO, _So2_Clk, _So2_DI, _So2_CS, _So2_WP, _So1_CD, -1, -1, -1)
        uSD[2].mountPartition(0)
        uSDCogChecker[2] := 1
    
    
      if(long[statusAddress] & _c3CrdDet)
        'Client 3
        uSD[3].FATEngineStart(_So3_DO, _So3_Clk, _So3_DI, _So3_CS, _So3_WP, _So3_CD, -1, -1, -1)
        uSD[3].mountPartition(0)
        uSDCogChecker[3] := 1
    

    but when I realise the problem with readLowLevelSector(), I changed to:
    OBJ
      uSD0  : "SD-MMC_FATEngine.spin"        
      uSD1  : "SD-MMC_FATEngine.spin"                
      uSD2  : "SD-MMC_FATEngine.spin"                 
      uSD3  : "SD-MMC_FATEngine.spin"              
    
      '------------------
      '[OBJ] - Load Activated Drivers
      '------------------
      if(long[statusAddress] & _masCrdDet)
        'Master inserted, it should
        'Need to put Error capture in the future
        uSD0.FATEngineStart(_Mas_DO, _Mas_Clk, _Mas_DI, _Mas_CS, _Mas_WP, _Mas_CD, -1, -1, -1)
        uSD0.mountPartition(0)
        uSDCogChecker[0] := 1
        
      if(long[statusAddress] & _c1CrdDet)
        'Client 1
        uSD1.FATEngineStart(_So1_DO, _So1_Clk, _So1_DI, _So1_CS, _So1_WP, _So1_CD, -1, -1, -1)
        uSD1.mountPartition(0)
        uSDCogChecker[1] := 1
    
    
      if(long[statusAddress] & _c2CrdDet)
        'Client 2
        uSD2.FATEngineStart(_So2_DO, _So2_Clk, _So2_DI, _So2_CS, _So2_WP, _So1_CD, -1, -1, -1)
        uSD2.mountPartition(0)
        uSDCogChecker[2] := 1
    
    
      if(long[statusAddress] & _c3CrdDet)
        'Client 3
        uSD3.FATEngineStart(_So3_DO, _So3_Clk, _So3_DI, _So3_CS, _So3_WP, _So3_CD, -1, -1, -1)
        uSD3.mountPartition(0)
        uSDCogChecker[3] := 1
    
    but I guess it makes no difference since the result was the same.

    Kye wrote: »
    ...You're by passing the locking mechanism with direct access.

    Since I would read from Master & write to Clientx, do I need to care about this one?

    Thanks a lot.
  • KyeKye Posts: 2,200
    edited 2012-03-31 09:10
    Hmm, um, lets see.

    So... you should have this...
    OBJ
    
      uSD0: "Master_SD-MMC_FATEngine.spin"
      uSD123[3]: "Slave_SD-MMC_FATEngine.spin" 
    
    

    Basically, this includes the driver 4 times. But, the master and slave versions are literally completely separate. THIS copies the entire code twice, be aware.

    Then you can use the trick you are trying to do by restarting the slave driver and moving it around on the pins.

    Try out this hacked version. I think it should work. I put in all the code for the function calls so that the locking is not bypassed.
  • MacTuxLinMacTuxLin Posts: 821
    edited 2012-03-31 09:16
    Kye wrote: »
    Hmm, um, lets see.

    So... you should have this...
    OBJ
    
      uSD0: "Master_SD-MMC_FATEngine.spin"
      uSD123[3]: "Slave_SD-MMC_FATEngine.spin" 
    
    

    Basically, this includes the driver 4 times. But, the master and slave versions are literally completely separate. THIS copies the entire code twice, be aware.

    Oh, I see. Got it. I'm going to test this right away... Thanks a lot, Kye!
  • KyeKye Posts: 2,200
    edited 2012-03-31 09:26
    I just attached a file to my last post. http://forums.parallax.com/attachment.php?attachmentid=91212&d=1333211103

    NOTE: You need to mount the file system like regular.
  • MacTuxLinMacTuxLin Posts: 821
    edited 2012-03-31 10:25
    Kye wrote: »
    I just attached a file to my last post. http://forums.parallax.com/attachment.php?attachmentid=91212&d=1333211103

    NOTE: You need to mount the file system like regular.

    Thanks Kye.

    I've tested & the result is the same. I've placed some debugging statements outputting to PST. It still hangs at readLowLevelSector() and I don't know why. I've tried increasing the stack all the way to 1_024 but that didn't help. I'm attaching the uSD controller object file.


    PST OUTPUT
    ======================================
    In LaunchX4uSDControllerCog Debug Mode
    ======================================
    
    
    
    
    uSD Socket [0] is : 1
    uSD Socket [1] is : 1
    uSD Socket [2] is : 0
    uSD Socket [3] is : 0
    Total Sectors for Card [0] is : 999920
    Total Sectors for Card [1] is : 3910976
    Total Sectors for Card [2] is : 0
    Total Sectors for Card [3] is : 0
    Inside Copying Loop ...
    Inside curSector =< totalSector ...
    Before readLowLevelSector from Master ...
    
    
    Master Drive
    ============
    Disk Signature : 0
    Volume ID : -153891637
    Parition Type: FAT16
    Volume Label : NO NAME
    Total Sectors : 999920
    
    
    Client Drive 1
    ==============
    Disk Signature : 0
    Volume ID : -1470471069
    Parition Type: FAT16
    Volume Label : NO NAME
    Total Sectors : 3910976
    
    
    curSector Value is : 0
    

    I can access both the Master & Client1 drive but it didn't display ""After readLowLevelSector of Master ..." after the readLowLevelSector().

    Thanks a lot.
  • KyeKye Posts: 2,200
    edited 2012-03-31 12:17
    Can you post a ZIP file? Also, I'm pretty short on time to help you out with this. I'll see what I can to today.
  • KyeKye Posts: 2,200
    edited 2012-03-31 12:28
    Also, if you have some time. Setup abort handling in your code to print any aborted errors. Its pretty much a requirement with my driver. If you aren't printing abort errors or handling them then it's very hard to debug.
  • MacTuxLinMacTuxLin Posts: 821
    edited 2012-03-31 19:30
    Kye wrote: »
    Can you post a ZIP file? Also, I'm pretty short on time to help you out with this. I'll see what I can to today.


    Sorry about that. (re-attaching). Yeah, no problem. You had been a great help already. I'll continue working on this. Thanks a lot.
  • MacTuxLinMacTuxLin Posts: 821
    edited 2012-03-31 19:38
    Kye wrote: »
    Also, if you have some time. Setup abort handling in your code to print any aborted errors. Its pretty much a requirement with my driver. If you aren't printing abort errors or handling them then it's very hard to debug.

    That's right.
    
    ======================================
    In LaunchX4uSDControllerCog Debug Mode
    ======================================
    
    
    
    
    uSD Socket [0] is : 1
    uSD Socket [1] is : 1
    uSD Socket [2] is : 0
    uSD Socket [3] is : 0
    Total Sectors for Card [0] is : 999920
    Total Sectors for Card [1] is : 3910976
    Total Sectors for Card [2] is : 0
    Total Sectors for Card [3] is : 0
    Inside Copying Loop ...
    Inside curSector =< totalSector ...
    Before readLowLevelSector from Master ...
    
    
    Master Drive
    ============
    Disk Signature : 0
    Volume ID : -153891637
    Parition Type: FAT16
    Volume Label : NO NAME
    Total Sectors : 999920
    
    
    Client Drive 1
    ==============
    Disk Signature : 0
    Volume ID : -1470471069
    Parition Type: FAT16
    Volume Label : NO NAME
    Total Sectors : 3910976
    
    
    curSector Value is : 0
    Debugging: Disk IO Error
    After readLowLevelSector of Master ... readSectorBlockBuffer:
    

    Hmm ... don't get it, I could access Master drive just before the function. I've tried swapping with other the cards but result still the same...
  • KyeKye Posts: 2,200
    edited 2012-04-01 05:34
    Hey, so... maybe this is the issue.

    It seems like you want to have 4 uSD cards at the same time. It that is the case then you need to have 4 separately named versions of the driver.

    ... Yeah, I know, not enough memory for that. Including the same named driver file more then once just allows you to have more than one file open. I.e. a file open per included version of the driver.

    ---

    So, do you even need the file system layer? You could just decapitate the file system part from the block driver.

    Also... I think you might have an easier time just using FSRW's block driver. It will allow you to do what you want more easily. I recommend that you use it. You'll get much faster transfer speeds also.
  • MacTuxLinMacTuxLin Posts: 821
    edited 2012-04-01 06:14
    You're right. I was holding that as an option for the sector-copy function. I seems to got a work around (including commenting out the lockFileSystem()) but, yeah, the speed does suffers a lot. I'll test a little more before switching to FSRW.

    Thanks a lot.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-11 21:26
    Hi Kye,

    Kyedos is doing great behind the scenes running the touchscreen GUI and all the fun demos like a touchscreen synthesizer.

    Is there an error code to tell if a fat.open has failed?

    I think at the moment it returns a pointer to a string and the string contains a message saying it worked or didn't work.

    Could you get the first 4 letters of that string and use them to determine "success" or "fail"? Or is there a better way?

    Many thanks - drac.
  • KyeKye Posts: 2,200
    edited 2012-05-12 07:35
    See the fat.partitionError function. It holds the last error encountered. See the defined constants at the top of the file for all the errors. This is also mentioned in the Parallax semiconductor an006 write up.

    Thanks,
  • Alex.StanfieldAlex.Stanfield Posts: 198
    edited 2012-05-12 11:29
    Hi Kye, can I suggest an addition to the FAT engine?

    I think that having an SD card is an excellent place to store logging data for any project and..

    This FAT driver already has all the needed stuff like getting date and time for a timestamp and of course handling the file writing.

    A function like
       fat.log(Severity, Message)
    

    With
    - "Severity" being a constant enumeration (Information/Warning/Error/Critical/etc)
    - "Message" a user defined text string

    This function would append in a user defined (or fixed) file a whole line of text that includes at least the following fields separated with a defined char like space/commas/tabs/etc
    - timestamp
    - cog number (optional, but would help))
    - Severity in clear text
    - message

    I can do it myself but surely You will do it faster and I think it would benefit everyone. What do you think?

    Thanks in advance
    Alex
  • Heater.Heater. Posts: 21,230
    edited 2012-05-12 11:43
    Such a logging feature does not belong in a file system API.
    For example it is possible a user may want to redirect log messages to a serial or network link for recording elsewhere. Or just stream them to a raw fash chip. Better to have a logging API at a higher level that may make use of a file system if wanted.
  • Alex.StanfieldAlex.Stanfield Posts: 198
    edited 2012-05-12 11:54
    Heater. wrote: »
    Such a logging feature does not belong in a file system API.
    For example it is possible a user may want to redirect log messages to a serial or network link for recording elsewhere. Or just stream them to a raw fash chip. Better to have a logging API at a higher level that may make use of a file system if wanted.

    Heater, I agree on a theoretical basis, however given the limited resources on a Propeller platform I still think a little deviation from a pure subsystem encapsulation is worth the price for the benefit.

    BTW, have you seen or have a logging API with the functions you described? For SPIN?

    Thanks
    Alex
  • KyeKye Posts: 2,200
    edited 2012-05-12 11:57
    I'd rather shrink the driver than grow it. Its already to big... way too big.
  • Heater.Heater. Posts: 21,230
    edited 2012-05-12 12:08
    No I have not seen such a logging API in Spin.

    I agree that when resources are constrained perhaps some architectural niceties have to go out the window.

    However making a logging system as you describe probably does not take much more space than mixing it into the file system where it will actually waste space for most users who don't use that feature.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-12 17:05
    Hi Kye,

    I think I am doing something wrong there.
        fat.openfile(stringptr,"R")
        hex(fat.partitionerror,8)
    

    returns zero if the file exists

    But if I try that with a file that does not exist, it hangs and never prints anything.

    Am I not using this function correctly?
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-13 00:45
    I found a solution. Replace every instance of fat.openfile(stringptr,"R") with a call to a different routine eg OpenFileRead which then displays both the error message and the filename (so you can debug it).
    PUB OpenFileRead(stringptr) ' open a file for reading and display a message if it fails
       result := \fat.openfile(stringptr,"R")
       if fat.partitionerror <> 0                           ' failed to find the file
         propfont_string(stringptr)                         ' print the filename
         propfont_string(result)                            ' print the error message
         repeat                                             ' stop the program
    

    Oh and I found the version that has no RTC and since I don't have a clock I've replaced the code with that version which saves some space.

    All working very nicely, Thanks!
  • Heater.Heater. Posts: 21,230
    edited 2012-05-13 03:09
    In your first case you have "fat.openfile(...)" in the second case you have "\fat.openfle(...)". Note the "\".
    If openfile fails it aborts. If the abort is not caught by adding that slash to the call then the program aborts totally and looks like a hang.
  • KyeKye Posts: 2,200
    edited 2012-05-13 06:27
    Good for you,
  • pik33pik33 Posts: 2,366
    edited 2012-05-13 09:05
    Is it possible to use this driver @ 100 MHz (first try failed...)
  • KyeKye Posts: 2,200
    edited 2012-05-13 09:42
    Yes, it should work at 100 MHz.

    Um, don't try 100 MHz with MMC cards. This doesn't work. For SD cards it does though. Try a different SD card.
Sign In or Register to comment.