Issue Reading/Writing to SD card

Discussion in 'General Electronics Chat' started by newbieEm, Dec 9, 2011.

  1. newbieEm

    Thread Starter New Member

    Jun 8, 2010
    7
    0
    I have written code to read/write 512 bytes to SD/card. I can reset the card (send reset command), initialize but not write 512 bytes. I have a question, When I do sectorWrite(), do I start writing from sector 0? my mmc card is 2g, fat16 formatted. I am using PIC18F4550. here is my entire code. Can you guys see any problem. Thanks

    Code ( (Unknown Language)):
    1.  
    2. =======================================================
    3. #include "PicStar1000.h"          /* PicStar library header file            */
    4. #include "p18cxxx.h"
    5. #include <spi.h>
    6.  
    7. typedef unsigned long _ulong;
    8.  
    9. #define SIZE 32
    10.  
    11. #define SD_CS PORTBbits.RB2
    12. #define SD_CS_TRIS TRISBbits.TRISB2
    13. #define SD_CD PORTAbits.RA0
    14. #define SD_CD_TRIS TRISAbits.TRISA0
    15.  
    16. #define GO_IDLE_STATE 0 //CMD0
    17. #define SEND_OP_COND 1 //CMD1
    18. #define SETBLOCKLEN 16 //CMD16
    19. #define BLOCKLEN_512 512
    20. #define CRC_ON_OFF 59 //CMD59
    21. #define WRITE_SINGLE_BLOCK 24 //CMD24
    22. #define READ_SINGLE_BLOCK 17 //CMD17
    23. #define DATA_START_BYTE 0xFE
    24. #define DATA_ACCEPTED 0x05
    25.  
    26. //Globals
    27. long lDelay = 48000000;
    28. char data[SIZE];
    29. char buffer[SIZE];
    30.  
    31.  
    32. /*
    33.     TRISCbits.TRISC7 = 0;
    34.     //SCK (Master mode) must have TRISB<1>bit cleared
    35.     TRISBbits.TRISB1 = 0;
    36.     //SCK (SLave mode) must have TRISB<1>bit set (ignored)
    37.     //SS must have TRISA<5>bit set
    38.     TRISAbits.TRISA5 = 1;
    39.  
    40.     //0 = idle state for clock is a low level
    41.     SSPCON1bits.CKP = 1;
    42.     //bit 3 - 0 0010 = SPI Master mode, clock = F0sc/64
    43.     SSPCON1bits.SSPM0 = 0;
    44.     SSPCON1bits.SSPM1 = 0;
    45.     SSPCON1bits.SSPM2 = 1;
    46.     SSPCON1bits.SSPM3 = 0;
    47.  
    48.     //SSPCON1 bit 5 SSPEN set 1 - Enables serial port, configures SCK, SDO, SDI and SS as serial port pins
    49.     SSPCON1bits.SSPEN=1;        //SSPEN(5)=1 enable SPI
    50. */
    51.  
    52. void initSpi(void)
    53. {
    54.     SD_CS = 1; //Initialize SPI chip select line
    55.     //CS pin set it to output
    56.     SD_CS_TRIS = 0;
    57.  
    58.     OpenSPI(SPI_FOSC_64, MODE_11, SMPMID);
    59. }
    60.  
    61. unsigned char writeSPI(unsigned char buffer)
    62. {
    63.     SSPBUF = buffer;
    64.     while(!SSPSTATbits.BF);
    65.     return SSPBUF; 
    66. }
    67.  
    68. int sendCmd(unsigned char c, _ulong a )
    69. {
    70.     int i,r;
    71.     //All th SD Card commands are 6 bytes long and transmitted MSB first
    72.     //After programming operation is completed, host must check the results of the programming using SEND_STATUS (CMD13)
    73.  
    74.     //Commands
    75.     // CMD1 (SEND_OP_COND)
    76.     // ACMD41 (SD_SEND_OP_COND)
    77.     // CMD59 (CRC_ON_OFF)
    78.     // CMD58 (READ_OCR)
    79.  
    80.     SD_CS = 0; //Starting an operation by Chip select active low
    81.  
    82.     writeSPI(c|0x40);
    83.     writeSPI(a >> 24);
    84.     writeSPI(a >> 16);
    85.     writeSPI(a>>8);
    86.     writeSPI(a);
    87.  
    88.     writeSPI(0x95); //Send CRC
    89.  
    90.     //Response back from card
    91.     while((r = ReadSPI()) == 0xFF);
    92.    
    93.     /*
    94.     i = 9;
    95.     do
    96.     {
    97.         //r = ReadSPI();
    98.         r = writeSPI(0xFF);
    99.         if( r!= 0xFF) break;
    100.     } while(--i > 0 );
    101.     */
    102.     return r;
    103.  
    104. }
    105.  
    106. int initMedia(void)
    107. {
    108.     int i,r;
    109.  
    110.     SD_CS = 1; //It will enter SPI mode if the CS signal is asserted(negative)
    111.     writeSPI(0xFF);
    112.  
    113.     //Send 80 clock cycles to start up
    114.     for(i = 0; i < 10; i++)
    115.     {
    116.         writeSPI(0xFF);
    117.     }
    118.  
    119.     SD_CS  = 0;
    120.  
    121.    
    122.     //Reset command CMD0 40 00 00 00 00 95. All SD commands are 6 bytes long.
    123.     r = sendCmd( GO_IDLE_STATE, 0x0);
    124.  
    125.     //Disable SD it may be busy
    126.     SD_CS  = 1;
    127.     writeSPI(0xFF);
    128.  
    129.     /* 
    130.     if( r != 1 )
    131.     {
    132.    
    133.         return 0x84;
    134.     }
    135.     */
    136.     i = 10000;
    137.  
    138.     //Init command
    139.     SD_CS = 0;
    140.     do
    141.     {
    142.         r = sendCmd(SEND_OP_COND,0);
    143.        
    144.         //Disable SD
    145.         SD_CS  = 0;
    146.         writeSPI(0xFF);
    147.        
    148.         if( !r) break;
    149.     } while(--i > 0 );
    150.  
    151.     if( i == 0 )
    152.     {
    153.         return 0x85; //time out error
    154.     }
    155.  
    156.     OpenSPI(SPI_FOSC_4, MODE_11, SMPMID);//Increase clock speed
    157.     sendCmd(CRC_ON_OFF,0x0);  //Turn off CRC if possible
    158.     sendCmd(SETBLOCKLEN, BLOCKLEN_512);//Set block length 512
    159.  
    160.     return 0;
    161.  
    162. }
    163.  
    164. //Valid write command CMD24
    165. //Valid block length is 512
    166. // DataIn Command - Response - Start block token (1 byte)|Data block - Response/busy - Next Command
    167. int writeSector(_ulong a,char *p)
    168. {
    169.     unsigned r,i;
    170.     int index;
    171.  
    172.     r = sendCmd( WRITE_SINGLE_BLOCK ,(a<<9));
    173.    
    174.     if(r==0)
    175.     {
    176.  
    177.         writeSPI( DATA_START_BYTE );            //send Data Start byte
    178.         /*
    179.         for(i=0;i<SIZE;i++)     //first 256 bytes
    180.             writeSPI(*p1++);
    181.         for(i=0;i<SIZE;i++)     //second 256 bytes
    182.             writeSPI(*p2++);
    183.         */
    184.  
    185.         //Instead of 2 256 byes send 16 * 32 = 512 bytes
    186.         for( i = 0; i < 512; i++)
    187.         {
    188.             //writeSPI(*p);
    189.             writeSPI(1);
    190.         }      
    191.  
    192.         writeSPI(0xFF);         //send 2 bytes of dummy CRC
    193.         writeSPI(0xFF);
    194.  
    195.  
    196.         if((r = writeSPI(0xFF) & 0x0F) == DATA_ACCEPTED)
    197.         {  
    198.             index = 0;
    199.        
    200.             do
    201.             {
    202.                 r = writeSPI(0xFF);
    203.                 index++;
    204.             }while( (r == 0x00) && (index != 0));
    205.  
    206.             if(index == 0 )
    207.             {
    208.                 r = 0; //timeout
    209.             }
    210.  
    211.             writeSPI(0xFF);         //Clk cycles ...wait
    212.        
    213.         }
    214.         else
    215.         {
    216.             r=0;            //fail
    217.         }
    218.     }
    219.    
    220.     SD_CS = 1; //Chip select
    221.    
    222.     return(r);
    223. }
    224.  
    225. //Valid read command CMD17
    226. //DataIn (Host to card) --Command --- DataOut -- Response -- - DataBlock|CRC - Next Command
    227. int readSector(_ulong a, char *p)
    228. {
    229.     int r,i,j, index;
    230.     r = sendCmd( READ_SINGLE_BLOCK,(a<<9));
    231.    
    232.     if(r==0)
    233.     {              
    234.         i=10000;   
    235.         do{
    236.             r = writeSPI(0xFF);
    237.             if(r==0xFE)
    238.             {
    239.                 break;
    240.             }
    241.        
    242.         } while(--i > 0);
    243.        
    244.         if(i)
    245.         {   //if no timeout, read 512 byte sector
    246.             /*
    247.             for(i=0;i<SIZE;i++)
    248.                 *p1++ = writeSPI(0xff);
    249.             for(i=0;i<SIZE;i++)
    250.                 *p2++ = writeSPI(0xff);
    251.             */
    252.  
    253.             for( i = 0; i < 16; i++)
    254.             {
    255.                 for(j=0;j < 32;j++)    
    256.                 {
    257.                     *p = ReadSPI();//writeSPI(0xFF);
    258.                 }
    259.             }  
    260.            
    261.             writeSPI(0xFF);     //ignore CRC
    262.             writeSPI(0xFF);
    263.         }
    264.     }
    265.  
    266.     SD_CS = 1; //Chip select
    267.     writeSPI(0xFF);         //disable SD
    268.     return(r == 0xFE);
    269. }
    270.  
    271.  
    272. void main()
    273. {
    274.     int i,r;
    275.     _ulong addr;
    276.  
    277.     PsInitHw(0);
    278.  
    279.     initSpi();
    280.  
    281.     DelClks(lDelay/10);//Delay for 100 ms
    282.     r = initMedia();
    283.  
    284.     if( r )
    285.     {
    286.         //Error card init failed
    287.         return;
    288.     }
    289.  
    290.     //Fill send buffer and receive buffer
    291.     for(i=0;i<SIZE;i++)
    292.     {   //fill the send buffers
    293.         data[i]=i;
    294.         buffer[i]=0;       
    295.     }
    296.  
    297.     //Write card
    298.     i = 0;
    299.     addr = 10000;
    300.     //for(i=0;i<1000;i++)
    301.     //{
    302.         if(!writeSector(addr+i,data))
    303.         {
    304.             /*
    305.             while(1)
    306.             {   //write failed - 2 blinks
    307.                 DelClks(lDelay );  
    308.             }*/
    309.         }
    310.     //}
    311.  
    312.    
    313.     addr=10000;
    314.  
    315.     //Delay
    316.     DelClks(lDelay/5); //200 ms delay      
    317.  
    318.     //Read
    319.     //for(i=0;i<1000;i++)
    320.     //{
    321.         if(!readSector(addr+i,buffer))
    322.         {
    323.             /*
    324.             while(1)
    325.             {   //verify failed - 3 blinks
    326.                 DelClks(lDelay );
    327.             }*/
    328.         }
    329.     //}
    330.  
    331.     //Delay
    332.     DelClks(lDelay);       
    333.  
    334.    
    335.  
    336.     CloseSPI();
    337.  
    338.     KeyWait();
    339. }
    340.  
    341. [/i][/i]
     
    Last edited by a moderator: Dec 10, 2011
  2. Jotto

    Member

    Apr 1, 2011
    159
    17
    Are you using Ruby code? I also noticed you are checking CRC. This is such a big change from basic coding that I am used to. I mostly used fortran, C+ and C++. I have seen a lot of scripting with what I call Ruby, but I am not sure that is the correct name for it. Its a whole new ball game with this new coding. I like that quit a script an before you quit you can tell it to go to another script. So it just keeps going without a pause.
     
  3. kubeek

    AAC Fanatic!

    Sep 20, 2005
    4,670
    804
    How did you find that? It seems like pretty standard C to me..

    newbieEm: try looking up the SD protocol specification. That should clarify all your questions and you should be able to check if you issue the right commands in the right order.
     
  4. newbieEm

    Thread Starter New Member

    Jun 8, 2010
    7
    0
    Are you using Ruby code?

    Jotto, you are funny :)
     
  5. Jotto

    Member

    Apr 1, 2011
    159
    17
    We program controllers for progressives, they said it was C+, and others were C++, but we never programmed symbols like you use here, so I guess the unit took care of that after we entered the data required. We wouldn't see the finished product, so I thought this was a new type of program.

    The Ruby comes in because a lot of scripting that is done in another place I spend time, they call it Ruby and have the symbols that were being used here. I have never seen those symbols used. That is why I asked, the scripting that I have done uses "goto", "waitfor". Colan is used but not some of those other ones, {}. I can't make sense of it.
     
  6. newbieEm

    Thread Starter New Member

    Jun 8, 2010
    7
    0
    what sector address should i be using though? anyone?
     
  7. Wendy

    Moderator

    Mar 24, 2008
    20,765
    2,535
    Welcome to AAC!

    A thread belongs to the OP (original poster). Trying to take over someone elses thread is called hijacking, which is not allowed at All About Circuits. I have therefore given you a thread of your very own.

    This was split from http://forum.allaboutcircuits.com/showthread.php?t=61652
     
  8. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Is there any particular reason you are not using the free SD controller/file system library for this device that Microchip provides for free?

    And if there is a reason, then why don't you see how they do it and do the same?
     
  9. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    I think he's not sure about how a FAT system works?

    To newbieEM- writing to any sector on the card as a 512 byte sector is very easy and does not need a FAT formatted card. Some people use that system for its simplicity and just write data to the card that only the PIC can read. This can be common in dataloggers etc.

    If that is what you want, just a simple way for the PIC to read and write that card just put the data in whatever sector you choose.

    But if you want to write data to a file on the card (so that file can be read on your PIC in Windows etc), then you need to work with the FAT. The FAT tells what all the filenames are and where each file's data is stored, etc.

    Wiki has a very good page on FAT16. And like ErnieM said if you need FAT16 support you can get libraries from Microchip, or your compiler might even have FAT16 libraries built in or freely available (as MikroC compiler does).
     
  10. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,866
    988

    I have looked at that library. Unless I am missing something, it is very hard to setup unless you happen to have one of the chips to which it is targeted.
     
  11. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,866
    988
    This guy

    http://elm-chan.org/fsw_e.html

    has a FAT system that seems pretty simple to set up. I am still trying to work out the low level stuff myself.
     
  12. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Nah, it's pretty straightforward to set one of these up for any PIC you want to use. It's just not documented anywhere exactly HOW to do that.

    ELM has an excellent file system too, just that I have never used it. I have used the MC one and find it useful.

    One example of the file system for the PIC18 is at "...\Microchip Solutions v2011-10-18\MDD File System-SD Card"

    The Microchip libraries all typically depend on a file named "hardwareprofile.h" to be part of your project. This describes your specific PIC and how it is connected to the libraries. Figuring out what should go there is worth your effort; MC crams the definitions for so many PICs and platforms into these they are very hard to understand, but you can start simply. For a SD card I would just start with the clock, the SPI pins, and the other SD card pins.

    For the clock, you need something like this (adjusted to your real crystal frequency):
    Code ( (Unknown Language)):
    1.     #define GetSystemClock()        48000000                        // System clock frequency (Hz)
    2.     #define GetPeripheralClock()    GetSystemClock()                // Peripheral clock freq.
    3.     #define GetInstructionClock()   (GetSystemClock()/4)            // Instruction clock freq.
    4.  
    Next is the "hard part" but taken line by line you can adjust all the #defines to match your platform:
    Code ( (Unknown Language)):
    1.     #define USE_PIC18
    2.     #define USE_SD_INTERFACE_WITH_SPI
    3.    
    4.     #define INPUT_PIN           1
    5.     #define OUTPUT_PIN          0
    6.    
    7.     // Chip Select Signal
    8.     #define SD_CS               PORTBbits.RB3
    9.     #define SD_CS_TRIS          TRISBbits.TRISB3
    10.    
    11.     // Card detect signal
    12.     #define SD_CD               PORTBbits.RB4
    13.     #define SD_CD_TRIS          TRISBbits.TRISB4
    14.    
    15.     // Write protect signal
    16.     #define SD_WE               PORTAbits.RA4
    17.     #define SD_WE_TRIS          TRISAbits.TRISA4
    18.    
    19.     // Registers for the SPI module you want to use
    20.     #define SPICON1             SSP1CON1
    21.     #define SPISTAT             SSP1STAT
    22.     #define SPIBUF              SSP1BUF
    23.     #define SPISTAT_RBF         SSP1STATbits.BF
    24.     #define SPICON1bits         SSP1CON1bits
    25.     #define SPISTATbits         SSP1STATbits
    26.    
    27.     #define SPI_INTERRUPT_FLAG  PIR1bits.SSPIF  
    28.    
    29.     // Defines for the HPC Explorer board
    30.     #define SPICLOCK            TRISCbits.TRISC3
    31.     #define SPIIN               TRISCbits.TRISC4
    32.     #define SPIOUT              TRISCbits.TRISC5
    33.    
    34.     // Latch pins for SCK/SDI/SDO lines
    35.     #define SPICLOCKLAT         LATCbits.LATC3
    36.     #define SPIINLAT            LATCbits.LATC4
    37.     #define SPIOUTLAT           LATCbits.LATC5
    38.    
    39.     // Port pins for SCK/SDI/SDO lines
    40.     #define SPICLOCKPORT        PORTCbits.RC3
    41.     #define SPIINPORT           PORTCbits.RC4
    42.     #define SPIOUTPORT          PORTCbits.RC5
    43.    
    44.     #define SPIENABLE           SSPCON1bits.SSPEN
    45.    
    46.     // Will generate an error if the clock speed is too low to interface to the card
    47.     #if (GetSystemClock() < 400000)
    48.         #error System clock speed must exceed 400 kHz
    49.     #endif
    So those two areas should be the starting point of your customized hardwareprofile.h.

    There is also a file called FSconfig.h you need to look thru, it provides all the options your need to make concerning using the file system. You use it to add or remove features. Find a copy of it most anywhere and move it to your project folder, and edit that version.

    You add FSIO.c and SD-SPI as part of your project. Adjust your path (if need be) to see your hardwareprofile.h and FSconfig.h. And that's it. Try building it and then track down the errors starting top down.
     
  13. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,866
    988
    Thanks

    I will give it another look. Hope the OP follows your advice too.

    One thing that I remember is you have to play with memory blocks to get it to compile. You have to define your own block or something. Am I right?
     
  14. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,866
    988
    I am going to start my own thread on the Microchip SD library as to not hijack the OP's thread. I will post it in the embedded forum please look there.
     
  15. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    The MikroC compilers have built in FAT16 support, with functions for all the main stuff;
    * create a file
    * open a file
    * delete a file
    * write a byte to a file
    * read a byte from a file

    For the more complex directory management and FAT32 stuff MikroC have recently released a FAT32 library that loads straight into the compiler, it can be found on their library site;
    www.libstock.com
     
  16. Wendy

    Moderator

    Mar 24, 2008
    20,765
    2,535
    Whew, I thought I was going to have to split the post I just split for anothe hijack! :p
     
Loading...