1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

SD Card Project

Discussion in 'Microcontrollers' started by AtomSoft, Aug 11, 2008.

  1. futz

    futz Active Member

    Joined:
    Sep 15, 2007
    Messages:
    2,043
    Likes:
    24
    Location:
    Vancouver, B.C.
    Actually it is very good info, but stirred into it is some odd stuff that distracts from the info you actually need. It helped me a lot, but I still had some old memory knowledge from learning that stuff the hard way in the early 80's (no internet), so all I had to do was refresh my memory.

    You have one of Lucio Di Jasio's "Programming XX-bit Microcontrollers in C" books, right? In the 16-bit book, chapter 14 is all about FAT16. I know the 32-bit book follows the same format and has the same info. It isn't the easiest read unless you're using the same chip as him and just copying his code, but all the necessary info is there.

    Between both documents you should be able to puzzle it out. Ask here if you have specific questions.
     
  2. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    Thanks... i do have that book. Um on page 438 i believe you will see in the code:
    Code (text):

    #define FO_FIRST_TYPE 0 x 1C2 // offset of first partition type
     
    I checked my 0x1C2 and its a value of 0x72.
    Now i noticed this isnt a valid option for Fat16 Type:

    Code (text):

    i = buffer[ FO_FIRST_TYPE];

    switch ( i)
    {
        case 0 x 04:
        case 0 x 06:
        case 0 x 0E:
            // valid FAT16 options
            break;
        default:
            FError = FE_PARTITION_TYPE;
            free( D); free( buffer);
        return NULL;
    } // switch
     
    What am i reading wrong here? lol

    BTW im looking in buffer2 value 0xC2 since buffer1 is 256 bytes it ends at FF and resumes in buffer2 as 0x00 - 0xFF so 0xC2 in buffer2 is equal to 0X1C2

    Here is my dump... use a hex editor to view. Its a txt just so i can post without issue. You can rename to what ever.
     

    Attached Files:

    Last edited: Sep 16, 2008
  3. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    Also Futz i wanted to ask you. Why did you write and read to so many sectors?

    Code (text):

    for(i=0;i<1000;i++){
        if(!readSector(addr+i,buffer1,buffer2)){ //addr+i,buffer1,buffer2)){
            while(1){       //verify failed - 3 blinks
                LED=1;
                delay_ms(150);
                LED=0;
                delay_ms(150);
                LED=1;
                delay_ms(150);
                LED=0;
                delay_ms(150);
                LED=1;
                delay_ms(150);
                LED=0;
                delay_s(1);
            }
        }
    }
     
    i changed it to :
    Code (text):

    if(!readSector(0,buffer1,buffer2)){ //addr+i,buffer1,buffer2)){
        while(1){       //verify failed - 3 blinks
            LED=1;
            delay_ms(150);
            LED=0;
            delay_ms(150);
            LED=1;
            delay_ms(150);
            LED=0;
            delay_ms(150);
            LED=1;
            delay_ms(150);
            LED=0;
            delay_s(1);
        }
    }
     
    and it works flawlessly. I assume the write would also. Here is my code to read 512 bytes of sector 0.

    Code (text):

    #include <p18f4620.h>
    #include <stdio.h>
    #include <delays.h>

    #pragma config WDT = OFF, OSC = INTIO67, MCLRE = ON, XINST = OFF

    #define CSel    LATDbits.LATD2      //chip select line
    #define LED     LATDbits.LATD1

    typedef unsigned long LBA;

    void main(void);

    int writeSector(LBA,char *,char *);
    int readSector(LBA, char *,char *);
    int initMedia(void);
    int sendSDCmd(unsigned char,LBA);

    void delay_s(unsigned char);
    void delay_ms(unsigned char);
    void delay_us(unsigned char);

    unsigned char writeSPI(unsigned char);

    ///////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////

    #pragma udata data1
    char data1[256];
    #pragma udata data2
    char data2[256];
    #pragma udata buffer1
    char buffer1[256];
    #pragma udata buffer2
    char buffer2[256];

    void main(void){
        LBA addr;
        int i,r;

        TRISD = 0;
        TRISC = 0b00010000;

        CSel=1;             //init chip select (active low)
        LED=0;              //LED off

        OSCCON = 0x72;          //8MHz clock
        OSCTUNEbits.PLLEN = 0;          //disable PLL

        while(!OSCCONbits.IOFS);        //wait for osc stable

        SSPSTAT = 0b00000000;       //SMP(7)=0, CKE(6)=0 (clock edge idle to active)
        SSPCON1 = 0b00010010;       //CKP(4)=1 clock polarity (idle high)
                        //SSPM3:SSPM0(3:0)=010 spi clock FOSC/64 (<400kHz)
        SSPCON1bits.SSPEN=1;        //SSPEN(5)=1 enable SPI

        for(i=0;i<256;i++){     //fill the send buffers
            data1[i]=i;
            data2[i]=i;
            buffer1[i]=0;       //and clear the receive buffers
            buffer2[i]=0;
        }

        r=initMedia();

        if(r){              //card init failed - 1 blink
            while(1){
                LED=1;
                delay_ms(150);
                LED=0;
                delay_s(1);
            }
        }
        else
        {
            //card init passed all good now use it lol

                if(!readSector(0,buffer1,buffer2)){ //addr+i,buffer1,buffer2)){
                    while(1){       //verify failed - 3 blinks
                        LED=1;
                        delay_ms(150);
                        LED=0;
                        delay_ms(150);
                        LED=1;
                        delay_ms(150);
                        LED=0;
                        delay_ms(150);
                        LED=1;
                        delay_ms(150);
                        LED=0;
                        delay_s(1);
                    }
                }
        }
        while(1){                   //success!
            LED=1;
            delay_s(1);
            LED=0;
            delay_s(1);
        }
    }

    int writeSector(LBA a,char *p1,char *p2)
    {
        unsigned r,i;
        LED=1;                  //turn on write LED
        r=sendSDCmd(24,(a<<9));
        if(r==0){
            writeSPI(0xfe);         //send Data Start byte
            for(i=0;i<256;i++)      //first 256 bytes
                writeSPI(*p1++);
            for(i=0;i<256;i++)      //second 256 bytes
                writeSPI(*p2++);
            writeSPI(0xff);         //send dummy CRC
            writeSPI(0xff);
            if((r=writeSPI(0xff) & 0x0f) == 0x05){  //check if data accepted
                for(i=10000;i>0;i--){
                    if(r=writeSPI(0xff))
                        break;
                }
            }
            else
                r=0;            //fail
        }
        CSel=1;writeSPI(0xff);          //disable SD
        LED = 0;                //LED off
        return(r);
    }

    int readSector(LBA a, char *p1, char *p2)
    {
        int r,i;
        LED = 1;                //turn on read LED
        r = sendSDCmd(17,(a<<9));
        if(r==0){               //check if command was accepted
            i=10000;            //wait for a response
            do{
                r = writeSPI(0xff);
                if(r==0xfe)
                    break;
            }while(--i > 0);
            if(i){              //if no timeout, read 512 byte sector
                for(i=0;i<256;i++)
                    *p1++ = writeSPI(0xff);
                for(i=0;i<256;i++)
                    *p2++ = writeSPI(0xff);
                writeSPI(0xff);     //ignore CRC
                writeSPI(0xff);
            }
        }
        CSel=1;writeSPI(0xff);          //disable SD
        LED = 0;                //read LED off
        return(r == 0xfe);
    }

    int initMedia(void)
    {
        int i,r;

        CSel=1;writeSPI(0xff);          //while card is not selected

        for(i=0;i<16;i++)           //send 80 clock cycles to start up
            writeSPI(0xff);

        CSel=0;                 //then select the card
        r = sendSDCmd(0,0);         //send reset command to enter SPI mode
        CSel=1;writeSPI(0xff);          //disable SD

        if(r != 1)              //error check - need 1
            return 0x84;

        i = 10000;              //send init for up to 0.3s
        CSel=0;

        do{
            r = sendSDCmd(1,0);     //send init command
            CSel=1;writeSPI(0xff);      //disable SD
            if(!r) break;
        }while(--i > 0);

        if(i==0)                //time out error 0x85
            return 0x85;

        SSPCON1 = 0b00010000;       //speed up spi clock
        SSPCON1bits.SSPEN=1;

        return 0;
    }

    int sendSDCmd(unsigned char c,LBA a)
    {
        int i,r;
        CSel=0;                 //send command packet (6 bytes)
        writeSPI(c|0x40);           //send command & frame bit
        writeSPI(a>>24);            //send 32-bit address
        writeSPI(a>>16);
        writeSPI(a>>8);
        writeSPI(a);
        writeSPI(0x95);             //send CRC
        i=9;                    //wait for response
        do{
            r=writeSPI(0xff);       //check if ready
            if(r != 0xff)
                break;
        }while(--i > 0);
        return(r);
    }

    unsigned char writeSPI(unsigned char send)
    {
        SSPBUF=send;
        while(!SSPSTATbits.BF);
        return SSPBUF;
    }

    ////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////

    void delay_s(unsigned char x)
    {
        char var1;
        for(var1=0;var1<x;var1++)
        {
            Delay10KTCYx(200);    //2,000,000 cycles = 1 second
        }
    }

    void delay_ms(unsigned char x)
    {
        char var1;
        for(var1=0;var1<x;var1++)
        {
            Delay1KTCYx(2);    //2,000 cycles = 1 us
        }
    }

    void delay_us(unsigned char x)
    {
        char var1;
        for(var1=0;var1<x;var1++)
        {
            Delay1TCY();    //2 cycle = 1 us
            Delay1TCY();

        }
    }
     
    Even tho i am not writing to the card yet i left the 2 data variables in so when i do write (if i do) i can have it ready.

    I noticed 256 is the max size of a variable... why is that? If i can make 4 256 variables why cant i make 2 of 512?

    Can someone help on that also please... Thanks again
     
    Last edited: Sep 16, 2008
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US

    This has alot of info but im still lost.
    http://www.ntfs.com/#fat file system

    Why doesnt none match my SD card? Am i supposed to format it special?

    im in XP. So i format from a command prompt

    format x:\ /FS:FAT /A:512

    Any thoughts? MY HD is NTFS will that effect it? Is there a special Formater out there?
     
  6. futz

    futz Active Member

    Joined:
    Sep 15, 2007
    Messages:
    2,043
    Likes:
    24
    Location:
    Vancouver, B.C.
    Your problem is most likely that your SD card isn't formatted. I looked at the dump. The byte at offset $1c2 is the ascii value for the letter 'r' in the word 'other', which is in the sentence "Remove disks or other media". You either don't have a partition table there because the card isn't formatted, or you're not actually looking at sector zero.
     
  7. futz

    futz Active Member

    Joined:
    Sep 15, 2007
    Messages:
    2,043
    Likes:
    24
    Location:
    Vancouver, B.C.
    Why not? Lucio's code did it. I thought "Why not? That seems like a good test." :p

    My hex editor (read only at present) reads a single sector at a time.

    Because the PIC you're using has RAM paged in 256 byte banks. I guess the compiler writers decided they didn't want to deal with memory paging, and it only allows 256 byte arrays. Reading/writing in two 256 byte chunks is trivially easy anyway. Not a big deal at all.
     
  8. futz

    futz Active Member

    Joined:
    Sep 15, 2007
    Messages:
    2,043
    Likes:
    24
    Location:
    Vancouver, B.C.
    I just format it with the camera. Quick and easy.

    The NTFS filesystem on your HD has zero to do with the filesystem on the card. XP is perfectly capable of reading/writing any filesystem (need extra drivers for Linux filesystems), including old ones like FAT16.
     
  9. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    i think its my memory card :( I tried another 2gb i have and it shows a 0x06 @ 0x1C2
     

    Attached Files:

  10. Someone Electro

    Someone Electro New Member

    Joined:
    Sep 10, 2003
    Messages:
    2,579
    Likes:
    2
    Location:
    A boring village in Europe (slovene)
    Try using something called a low level format tool on it. All it dose is write all sectors to FF and so completely cleaning the card and then just use windowses built in tool to format to FAT16. This saved my thumb drive when the filesystem got corrupt and windows refused to even try formating it. after clearing it it worked agen.
     
  11. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    Someone Electro im testing that theory out right now . Hopefully it will work :)
     
  12. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    nope... nothing new. still formats with same info on it. it turns all to 0x00 and then i have to format it and now it has the same as before.
     
  13. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    Start OFFSET For Volume ID = in decimal it is 39 and in hex it is 0x27
    Code (text):


    dec      39 40 41 42
    hex      27 28 29 2A
    --------------------
          C2 E0 AA BC     now becomes    BC AA E0 C2

     
    Needs to be reversed to make my volume id which is "3165315266".
    I checked this with Disk Probe.
     
    Last edited: Sep 17, 2008
  14. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    Here is a snapshot of me getting the Bytes per sector using:

    Code (text):

    int BytesPerSec;

     //and in filling it i do :

            BytesPerSec = buffer1[0x0C];
            BytesPerSec = (BytesPerSec<<8) + buffer1[0x0B];
     
    I used "int" because its a word (2 byte) I decided to use variable to store the info because if i do another read i loose that info.

    But im stilling having issues with memory. How come i have to use:
    #pragma udata BytesPerSec
    int BytesPerSec;

    This is starting to bug me.
     

    Attached Files:

    Last edited: Sep 17, 2008
  15. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    Dude! I got to make a 512 Byte Variable. Its a matter of altering the linker and that pragma. Open up the hlpC18up.chm (the user guide)

    GOTO "Examples"
    GOTO "Application: Creating Large Data Objects and the USART"

    You will learn it there. It was so simple lol I call i simple because if i can do it anyone can lol

    Here is my project... so far...
     

    Attached Files:

    Last edited: Sep 17, 2008

Share This Page