SD Card thought

Discussion in 'Microcontrollers' started by AtomSoft, Jun 10, 2009.

  1. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,596
    Likes:
    28
    Location:
    Brooklyn, NY US
    Ok i have a bunch of PIC micros and most with small amounts of memory and the large PICs are overkill so i was thinking of a way to use a SD Card without needing alot of memory.

    This will work well for reading ONLY! no write feature unless you are writing RAW data. But no FILE access tho since it requires to write 512 bytes. I got a theory on this too tho.

    Ok to READ with small amount of memory... well a custom amount even 1 byte!
    Code (text):

    int readCustom( LBA a, unsigned int start,unsigned int length, char *p)
    // a        LBA of sector requested
    // p        pointer to sector buffer
    // start    Start Byte
    // length   Length of bytes
    // returns  TRUE if successful
    {
        int r, i;
        int x;
        x = (512 - length) - start;
        READ_LED = 0;
           
        // 1. send READ command
        r = sendSDCmd( READ_SINGLE, ( a << 9));
        if ( r == 0)    // check if command was accepted
        {  
            // 2. wait for a response
            for( i=0; i<R_TIMEOUT; i++)
            {
                r = readSPI();    
                if ( r == DATA_START)
                    break;
            }

            // 3. if it did not timeout, read 512 byte of data
            if ( i != R_TIMEOUT)
            {
              for(i=0;i<start;i++)  //Skip the bytes until we hit our start byte
                readSPI();

                i = length;         //get our bytes using the length as a count
                do{
                    *p++ = readSPI();
                } while (--i>0);

                // 4. ignore CRC
                readSPI();
                readSPI();

              for(i=0;i<x;i++)      //skip the rest if any
                readSPI();
            } // data arrived
        } // command accepted
        // 5. remember to disable the card
        disableSD();

        READ_LED = 1;

        return ( r == DATA_START);    // return TRUE if successful
    } // readSECTOR

     
    EDIT:

    To write we would need 1 512 buffer since we can only write 512 block and the SD handles that so we can just ask it to skip... (not tha ti know of lol)
    Last edited: Jun 10, 2009
  2. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,596
    Likes:
    28
    Location:
    Brooklyn, NY US
    This can help alot because we dont waste space. Like if we need to verify:
    Code (text):

    Address   Desciption                   DEFAULT   SIZE
    1FEh        Boot Signature Code   55h AAh    2 bytes
     
    we just setup a small variable about 2 bytes aka a INT or a 2 Byte Array and :
    Code (text):

    //Get Boot Signature Code (sector 0x00000000)
    //0x01FE =our byte start
    //2 = our byte length
    //buff = our buffer (2 byte array or 1 int)

    //unsigned char buff[2];
    unsigned int buff;
    atmp  = 0x00000000
    result = readCustom(atmp, 0x01FE, 2, buff);

     
    Last edited: Jun 10, 2009
  3. Mr RB

    Mr RB New Member

    Joined:
    Jul 22, 2008
    Messages:
    4,720
    Likes:
    186
    Location:
    Out there
    Actually I developed a "kludge" for that. You don't need to write 512 bytes of DATA, you just need to write 512 bytes.

    The easiest way I found was to write 4 bytes for every real data byte, so you write a 512 byte block to the card but it only has 128 actual bytes (every 4th byte is real the other 3 are zeros).

    Then on the PC when you read the file from the card you can simply read it as 128 "words" which are a 4byte data type so it reads the data with no conversion needed.

    So the PIC only needs a 128 byte buffer, which just about all PICs can do.

    Of course this is a little wasteful of the memory card, but since you can buy a 4Gbyte memory card for about 6 peanuts these days that doesn't really matter. ;)
  4. rakeshkalwa

    rakeshkalwa New Member

    Joined:
    Jun 10, 2009
    Messages:
    2
    Likes:
    0
  5. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,596
    Likes:
    28
    Location:
    Brooklyn, NY US
    Mr RB so you would still have to read 512 bytes dude lol what if i want to edit data in on the 100th byte? how would i edit it without losing the other data?
    If its fine to waster space then i would do this..

    Setup a #define to set the max to write or what ever our pic can handle like

    #define SIZE 128

    So we know how much data the pic can buffer and just read from start of 512 byte and read those 128 bytes then you can skip the rest.

    Then you can alter the 128 bytes and write it back to start of sector you are on.

    .. this way you can have it set the max size your pic can handle.
  6. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,596
    Likes:
    28
    Location:
    Brooklyn, NY US
    The below code will only use the first 128 Bytes of each sector (512 byte).
    You define the max your pic can handle like:
    #define B_SIZE 512 //Full sector
    #define B_SIZE 384 //3/4 of a sector
    #define B_SIZE 256 //half a sector
    #define B_SIZE 128 //4th of a sector


    Code (text):

    #define B_SIZE              128

    int writeSECTOR( LBA a, char *p)
    // a        LBA of sector requested
    // p        pointer to sector buffer
    // returns  TRUE if successful
    {
        unsigned int r, i;
        char x;

        x = 512 - B_SIZE;
        // 0. check Write Protect
        //if ( getWP())
            //return FAIL;

        // 1. send WRITE command
        r = sendSDCmd( WRITE_SINGLE, ( a << 9));
        if ( r == 0)    // check if command was accepted
        {  
            // 2. send data
            writeSPI( DATA_START);
           
            // send B_SIZE bytes of data
            for( i=0; i<B_SIZE; i++)
                writeSPI( *p++);

            for(i=0;i<x;i++)      //skip the rest if any
                writeSPI(0x00);

            // 3. send dummy CRC
            clockSPI();
            clockSPI();
       
            // 4. check if data accepted
            r = readSPI();
            if ( (r & 0xf) == DATA_ACCEPT)
            {  
       
                WRITE_LED = 0;

                // 5. wait for write completion
                for( i=0; i<W_TIMEOUT; i++)
                {
                    r = readSPI();
                    if ( r != 0 )
                        break;
                }

                WRITE_LED = 1;


            } // accepted
            else
                r = FAIL;

        } // command accepted

        // 6. disable the card
        disableSD();

        return ( r);      // return TRUE if successful

    } // writeSECTOR

    int readCustom( LBA a, char *p)
    // a        LBA of sector requested
    // p        pointer to sector buffer
    // start    Start Byte
    // length   Length of bytes
    // returns  TRUE if successful
    {
        int r, i;
        int x;
        x = 512 - B_SIZE;
        READ_LED = 0;
           
        // 1. send READ command
        r = sendSDCmd( READ_SINGLE, ( a << 9));
        if ( r == 0)    // check if command was accepted
        {  
            // 2. wait for a response
            for( i=0; i<R_TIMEOUT; i++)
            {
                r = readSPI();    
                if ( r == DATA_START)
                    break;
            }

            // 3. if it did not timeout, read 512 byte of data
            if ( i != R_TIMEOUT)
            {
                i = B_SIZE;         //get our bytes using the length as a count
                do{
                    *p++ = readSPI();
                } while (--i>0);

                // 4. ignore CRC
                readSPI();
                readSPI();

              for(i=0;i<x;i++)      //skip the rest if any
                readSPI();
            } // data arrived
        } // command accepted
        // 5. remember to disable the card
        disableSD();

        READ_LED = 1;

        return ( r == DATA_START);    // return TRUE if successful
    } // readSECTOR
     
    Since:
    2 gigabytes = 2,147,483,648 bytes / 512 (sector length) = 4,194,304 So you can have about 4 million buffers on the card. Depending on B_SIZE:

    B_SIZE = 128 = 0.5GB (500MB)
    B_SIZE = 256 = 1.0GB
    B_SIZE = 384 = 1.5GB
    B_SIZE = 512 = 2.0GB

    2GB cards go for about $5 which is cheap anyway. Even if using only 500MB of space from it :D
    http://www.google.com/products/catalog?hl=en&q=2gb SD&cid=17626130196514867655&scoring=p#ps-sellers
    Last edited: Jun 11, 2009
  7. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,596
    Likes:
    28
    Location:
    Brooklyn, NY US
    Hey guys i just made a program using VB6 to read sectors on a HDD or SD card. You can select the sector and target and then view a 512 chunk of hex and charaters. Also have a next and prev. button.
    Nice simple fast nothing special.

    I made it because im making my own Filesystem on a SD card and needed RAW access so i though this might help alot of people tho..

    ENJOY!

    EDIT

    In all the hype i forgot to post it lol

    BTW this is the full source no EXE file ok! so you can know its safe lol its read only i havent added the option to write yet.

    Attached Files:

    Last edited: Jun 11, 2009
  8. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,596
    Likes:
    28
    Location:
    Brooklyn, NY US
    NOTICED a problem with MDD-FS demonstration code:

    Code (text):

        // Read one four-byte object
        if (FSfread (receiveBuffer, 4, 1, pointer) != 1)
            while(1);

     
    If you try the above with READ or WRITE it may fail if you dont use there exact stuff. This is because they used " != 1" . Which is BAD. If it fails it returns 0 or another number not always 1 so why did they do that? i got lost cuz of that ... here is a fix ...when ever you use something like the above try using "==0" or "!" like:

    Code (text):

        // Read one four-byte object
        if ([B]![/B]FSfread (receiveBuffer, 4, 1, pointer) )
            while(1);

    //or
        // Read one four-byte object
        if (FSfread (receiveBuffer, 4, 1, pointer) [B]== 0[/B] )
            while(1);

     
    Last edited: Jun 11, 2009
  9. Mr RB

    Mr RB New Member

    Joined:
    Jul 22, 2008
    Messages:
    4,720
    Likes:
    186
    Location:
    Out there
    OK, that is a very obvious solution and it works. :) But now when your PC reads the data file from the card you have 2 problems;
    1. It needs to know the chunk SIZE
    2. It needs special software to parse the file, ie read the chunks and ignore the padding.

    With my method the data in the file is contiguous, and can be read simply as a file by any PC. It just stores the data as "word" 32bit not as "char" 8bit. Since "word" is a default for most windows software that is all fine.

    The system I used for reading the data from a file was just to read a whole block of 512 (because you have to read a whole block) and just keep the data required by the PIC. In the example above the PIC reads a 512 byte block, keeps every 4th byte and stores in its 128 byte ram array. So you have seamless reading and writing of a whole memory card in blocks of 512 using just 128 bytes of PIC ram.

    Now if you need the PIC to read data written by the PC, you can get the PC to write 1byte data as "words" as explained above.

    If the PC has written 512 actual bytes, then you can read that 512 byte block and just keep the 128 (etc) bytes you need. But you cant write 512 actual data bytes unless you have 512 bytes of ram or buffer with the PIC eeprom memory (there are some examples of that on the net).

    In my first post I was not saying anything you did was wrong, you said you weren't using file access as you didnt have 512 bytes of ram and I suggested a nice kludge solution I developed that works, to allow proper file systems with only 128 bytes of ram needed. There's a lot of people think you just CAN'T do memory card file systems on the 16F PICs, but my system lets you do it quite elegantly, the only drawback is the 1:4 data size wasted in the memory card.
  10. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,596
    Likes:
    28
    Location:
    Brooklyn, NY US
    heh i never said yours was wrong either.

    A solution for telling the PC software the size it having my own boot sector type. Have it on a sector with no reserved data.

    So you can place information like buffer size and such on it and have that be like a custom MBR.

    Your solution also requires custom PC software regardless since it is also raw .
  11. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,596
    Likes:
    28
    Location:
    Brooklyn, NY US
    but its cool now i got the MDD-FS to work so im using it for now. Im going to try and make a few files using my bmp to hex and the glcd and see if i can read them from the sd card.
  12. mongerson

    mongerson New Member

    Joined:
    Apr 20, 2009
    Messages:
    31
    Likes:
    0
    Location:
    Hillsboro, OR
    Which PIC did you get the MDD-FS working with?

    Thanks,
    - Michael
  13. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,596
    Likes:
    28
    Location:
    Brooklyn, NY US
    You can make the Petite FS work with most 16F and 18F PICS but with no write support.
  14. mongerson

    mongerson New Member

    Joined:
    Apr 20, 2009
    Messages:
    31
    Likes:
    0
    Location:
    Hillsboro, OR
    I've never heard of the petite FS. I'm currently working on a project with a dsPIC33 and SD card using the MDD-FS. Have you done something similar? I'm having trouble getting past the initialization.

    Thanks for your help,
    - Michael
  15. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,596
    Likes:
    28
    Location:
    Brooklyn, NY US
    Last edited: Dec 3, 2009
  16. mongerson

    mongerson New Member

    Joined:
    Apr 20, 2009
    Messages:
    31
    Likes:
    0
    Location:
    Hillsboro, OR
    OK, so the petit file system is only for 8-bit controllers. I'm using a 16-bit controller. Thanks for the links, I'll see if they can help me understand the initialization sequence.

    - Michael
  17. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,596
    Likes:
    28
    Location:
    Brooklyn, NY US
    yeah be sure to look at the sample code links at the bottom
  18. Sceadwian

    Sceadwian Banned

    Joined:
    Oct 27, 2006
    Messages:
    14,047
    Likes:
    140
    Location:
    Rochester, US
    8 bit, 16 bit 3000 bit micro controller, won't change the interface.
  19. mongerson

    mongerson New Member

    Joined:
    Apr 20, 2009
    Messages:
    31
    Likes:
    0
    Location:
    Hillsboro, OR
    Yes, but it will change the file system.
  20. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,596
    Likes:
    28
    Location:
    Brooklyn, NY US
    not really the file system is FAT/FAT32 with all SD Cards really so your stuck on that.

    The difference is speed and buffer space really