Shop OBEX P1 Docs P2 Docs Learn Events
Strange problem with SD card program [solved] — Parallax Forums

Strange problem with SD card program [solved]

Patrick1abPatrick1ab Posts: 136
edited 2010-03-24 00:37 in Propeller 1
Hi everyone!

I'm experiencing some problems with the SD card interface of my newest project.
(a multi format music player with LCD, IR remote control, playback from SD card and Internet Radio Streams)

I even reduced my program to a minimum to locate the error, but I'm still not able to find it.

This is what happens:

The text message "Checking for SD card" is displayed and afterwards the program crashes.
In the original program it won't even listen for IR commands anymore, so I wondered whether there could be an infinite loop.
The strange thing about it is, that it doesn't matter whether I insert the SD card or not.

This is the configuration I use:

- Propeller running at 80 MHz
- I/O pin 13, 14 used for a modified version of "parallel_lcd"; because I connected my display to a PCF8574 port expander
- I/O pin 16, 17, 18, 19 used for my sd card interface (with pull up resistors; same values I already used with my webserver)
- newest version of fsrw (2.6)

This is the reduced program I used for testing purposes:

CON

  _clkmode = xtal1+pll16x
  _xinfreq = 5_000_000

VAR

  long filelist[noparse][[/noparse]255]

OBJ

  text    : "parallel_lcd_pexp_mod"
  'str     : "util_strings"
  sdfat   : "fsrw"
  
PUB start

  text.start
  text.str(string("Checking for SDcard"))
  text.pos(0,3)
  text.dec(checkforSD)
  text.pos(0,4)
  text.str(string("Done!"))

PRI checkforSD | NOofFiles, temp

  NOofFiles:=0
  temp:=0

  if sdfat.mount_explicit(16,17,18,19)==0
    sdfat.opendir
    repeat until sdfat.nextfile(@temp)==-1 OR NOofFiles>255
     filelist[noparse][[/noparse]NOofFiles]:=temp
     NOofFiles++
    return 0

  else
    return -1   




Please tell me if you can find the mistake I made.

Post Edited (Patrick1ab) : 3/24/2010 12:45:51 AM GMT

Comments

  • nicolad76nicolad76 Posts: 164
    edited 2010-03-22 20:11
    Hi,
    just a question....
    is
    filelist[noparse][[/noparse]NOofFiles]:=temp
    

    supposed to store the filename?
    I might be wrong but I do not think it does that.
    Have you tried to make the loop even simpler to check if this instruction is having any unexpected issue?
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-03-22 20:35
    Your temp should look like that:
    byte temp[noparse][[/noparse]sdfat#DIRSIZE]

    because it needs to be big enough for a complete directory-entry. The first characters are the filename. To print the filename you can do temp[noparse][[/noparse]11]:=0 to replace whatever comes next with the stringend and then print @temp.

    If you really want to copy all that strings, you need a bigger filelist too. Each filename needs 8+3 bytes (+stringend).
  • Patrick1abPatrick1ab Posts: 136
    edited 2010-03-22 22:19
    Thanks a lot guys!

    What you say sounds logical to me. I was a bit na
  • pullmollpullmoll Posts: 817
    edited 2010-03-23 08:44
    Patrick1ab said...

    Btw: Has anyone an idea how to create a dynamic structure in Spin like a list or a tree for example?
    This static array isn't a very nice solution: Limited to 255 files at the moment and if there are less lots of wasted memory space.

    You could create a linked list growing down from $8000 (assuming you can use this area of RAM, which I'm not sure about). If you don't know how to do this, I may try to write a few lines of Spin code to show how to do it.
    Okay, here's a try, but don't beat me if it's wrong. I haven't tried to compile it, just written from the top of my head. I hope you get the idea...

    VAR
        ...
        long    lsthead      ' start of the linked list
        long    lsttail         ' last entry in the linked list
        long    lstcurr        ' current entry in the linked list
        byte    filename[noparse][[/noparse]sdfat#DIRSIZE]
        long    name
    
    PUB main
        ....
        lsthead := lsttail := $7ffc
        long[noparse][[/noparse]lsthead] := 0
        ....
        repeat whatever
           add_list(filename)
    
        name := get_list_entry(3)
        if name
            print(name)
    
        lstcurr := listhead
        repeat while lstcurr
              name := get_list_name(lstcurr) 
              print(name)
              lstcurr := get_list_next(lstcurr)
    
    PUB add_list(filename) | ptr, len
        ptr := lsttail - (byte[noparse][[/noparse]lsttail+2] + 256 * byte[noparse][[/noparse]lsttail+3]) - 4
        if ptr <> lsttail
            byte[noparse][[/noparse]lsttail+0] := ptr           ' link to new entry
            byte[noparse][[/noparse]lsttail+1] := ptr >> 8
        byte[noparse][[/noparse]ptr+0] := 0          ' link to next is 0
        byte[noparse][[/noparse]ptr+1] := 0
        len := strsize(filename) + 1
        byte[noparse][[/noparse]ptr+2] := len
        byte[noparse][[/noparse]ptr+3] := len >> 8
        bytecopy(ptr - len, filename, len)
        lsttail := ptr
    
    PUB get_list_entry(index) | ptr
        ptr := lsthead
        repeat while index-- > 0
           ptr := byte[noparse][[/noparse]ptr+0] + 256 * byte[noparse][[/noparse]ptr+1]
           if ptr == 0
               return 0
        return (ptr - (byte[noparse][[/noparse]ptr+2] + 256 * byte[noparse][[/noparse]ptr+3]))
    
    PUB get_list_name(ptr)
        return (ptr - (byte[noparse][[/noparse]ptr+2] + 256 * byte[noparse][[/noparse]ptr+3]))
    
    PUB get_list_next(ptr)
           return (byte[noparse][[/noparse]ptr+0] + 256 * byte[noparse][[/noparse]ptr+1])
    
    PUB del_list_entry(index)
        ' TODO :)
    
    
    



    Hmm... the longer I think about it, you don't even need the pointers in byte 0+1, just the length. A length of 0 would indicate the end of the list.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    He died at the console of hunger and thirst.
    Next day he was buried. Face down, nine edge first.

    Post Edited (pullmoll) : 3/23/2010 10:53:06 AM GMT
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-03-23 12:03
    Why do you want to read the whole directory-list into the prop-memory? As the SD driver currently does support subdirectories you will have a lot of files in the root directory.

    The directory-entry always has a fixed size, no matter how long the filename is. The rest will be extended by $20 (space) as far as I remember. The extension is also on a fixed place and there is no ".".

    The problem with your code might be that you don't catch the abort properly. You need the \ in front of the mount to catch an abort condition. If you don't do it like that your main COG will be stopped.
  • Patrick1abPatrick1ab Posts: 136
    edited 2010-03-23 15:42
    MagIO2 said...
    The problem with your code might be that you don't catch the abort properly. You need the \ in front of the mount to catch an abort condition. If you don't do it like that your main COG will be stopped.

    Great! That's it. Thank you very much. Now the detection of the SD Card works and the program keeps running.

    MagIO2 said...
    Why do you want to read the whole directory-list into the prop-memory? As the SD driver currently does support subdirectories you will have a lot of files in the root directory.

    I'm doing this because I want to navigate through the files with the up and down buttons of the remote control.
    I could also navigate down by calling the nextfile procedure each time the down button is pressed, but a previousfile procedure is missing, so navigating up is not possible at the moment.
    Another thing is that navigating through the files should work without a big delay between press of the button and change of the display.
    In the next step I will add a file extension filter, so that only mp3, m4a, wav, ogg and mid files are allowed.

    MagIO2 said...
    The directory-entry always has a fixed size, no matter how long the filename is. The rest will be extended by $20 (space) as far as I remember. The extension is also on a fixed place and there is no ".".

    Okay, a fixed size will make it easy to store the filenames, but in the nextfile procedure the dot is definitely included.
    Have a look:

    pub nextfile(fbuf) | i, t, at, lns
    {{
    '   Find the next file in the root directory and extract its
    '   (8.3) name into fbuf.  Fbuf must be sized to hold at least
    '   13 characters (8 + 1 + 3 + 1).  If there is no next file,
    '   -1 will be returned.  If there is, 0 will be returned.
    }}
    
    
    



    Good thing is that the filenames are already zero terminated, so I don't have to worry about separators in my list.


    @pullmoll:

    Thank you very much for your help. The code looks great and I can't wait to try it out smile.gif
    The get_list_entry function is exactly what I need.

    Just one question: Why are you using different variables for filename and name? Is name another pointer?
  • pullmollpullmoll Posts: 817
    edited 2010-03-23 17:21
    Patrick1ab said...

    @pullmoll:

    Thank you very much for your help. The code looks great and I can't wait to try it out smile.gif
    The get_list_entry function is exactly what I need.

    Just one question: Why are you using different variables for filename and name? Is name another pointer?

    filename is an array of bytes used as a string buffer. name is just a pointer to somewhere, e.g. a string on the heap. Be careful, I don't know if you can use the memory from $8000 downwards or if it is used by Spin. In that case you would have to find out where the free memory begins by inspecting some system variable.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    He died at the console of hunger and thirst.
    Next day he was buried. Face down, nine edge first.
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-03-23 18:58
    I'd prefere to tweak the FSRW. Adding a prevfile should not be that difficult. But it saves you a lot of memory - and I can imagine that you'll need every byte in the end.

    Other solution .. start from the beginning and do nextfile until you reached the previous file. FSRW can read some at least hundred kilobytes per second which will be enough for a lot of directory entries.
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-03-23 19:15
    @Patrick1ab
    Oh ... reread your post ... ok ... here is some code I use to filter *.bmp-files:
      ' Scan the directory for .bmp files
      startT:=cnt
      sdfat.opendir
      bmpfound:=0
      repeat until sdfat.nextfile( @flname )
        y:=0
        repeat until flname[noparse][[/noparse]y++] == "." or y==13
        if flname[noparse][[/noparse]y]=="B" and flname[noparse][[/noparse]y+1]=="M" and flname[noparse][[/noparse]y+2]=="P"   
          sdfat.vwMemCmpCopy( BMP_BASE + bmpfound<<4, @flname, 13 )
          bmpfound++
      sdfat.vMemFlush
      endT:=cnt
    
    

    Maybe you want to use what I call "virtual memory" as well? It's an addition to FSRW and you can find a version in this thread:

    http://forums.parallax.com/showthread.php?p=856170

    The idea with virtual memory is that you have a file on the SD card which is accessed by addresses. So, if you have a list of filenames with a fixed length you can simply address entry x by calculating x*size of entry. This way the access will be very fast.

    In your case you can scan the directory on demand or when you detect changes and keep the filtered file-list in the virtual memory file.

    Post Edited (MagIO2) : 3/23/2010 7:25:57 PM GMT
  • Patrick1abPatrick1ab Posts: 136
    edited 2010-03-24 00:37
    MagIO2 said...
    Maybe you want to use what I call "virtual memory" as well? It's an addition to FSRW and you can find a version in this thread:

    http://forums.parallax.com/forums/default.aspx?f=25&m=401244&g=401357#m401357

    The idea with virtual memory is that you have a file on the SD card which is accessed by addresses. So, if you have a list of filenames with a fixed length you can simply address entry x by calculating x*size of entry. This way the access will be very fast.

    In your case you can scan the directory on demand or when you detect changes and keep the filtered file-list in the virtual memory file.

    Sounds interesting smile.gif Although I'm a bit scared of writing to an SD card with a microcontroller.
    Last time I tried, I killed the FAT system on it rolleyes.gif
    Luckily I made a backup of the files before, but I had to reformat the card afterwards.

    Maybe I'll try to extend the existing memory by connecting an SPI SRAM and then store a temporary copy of the file list there.
    I'll need a bigger memory anyway if I want to listen to streaming audio (for example: 48Kbyte for a three second buffer).
Sign In or Register to comment.