Writing into a SD card over SPI with PIC18F25K80

Thread Starter

Sangam Singh

Joined Jun 23, 2015
9
I have, in the code below, initialized the SD card and have found the address of the Root section. I now want to write data into the SD card. I am stuck at this point as to how should i use this info to write. I am refering to this site for information on SD card operation. I am attaching my code below.


Code:
#include <xc.h>
#include <p18cxxx.h>
#include <stdio.h>
#include <stdlib.h>
#include <plib/pconfig.h>
#include <spi.h>

void init_Device(void) //Initializes the device, setting the    scialltor    speed, pin direction, and pull-ups
{
      OSCCON=0b01110111; //Oscillator 8 Mhz
      TRISA=0; // all Port A output
      TRISB=0; // all Port B output
      TRISB5=1; // make serial port reception pin input
      TRISB4=1; //make SDI reception pin input
      TRISC=0; // all Port C output
      TRISC3=1; // Make RC3 input
      PEIE=1; //enable interrupts for RCIF
      SBOREN=0; //disable brown out reset
}

void init_SPI(void)
{
    CKP=0; //0=idle clock state is low
    CKE=1; //0=Data transmitted on falling edge of SCK
    SMP=1; //1=SPI mode-Input data sampled at end of data output time
    SSPM3=0; //FOSC/64
    SSPM2=0; //FOSC/64
    SSPM1=0; //FOSC/4 - "1" for /64
    SSPM0=0; //FOSC/64
}

void Delay(long x)
{
    while (x>0){x--;}
}

     void InitializeSPIMode(void)
     {
        char x; //used for "while" loops
        unsigned long Address=0;
        unsigned short BytesPerSector=0;
        char ReservedSectors=0;
        char FATCount=0;
        unsigned short SectorsPerFat=0;
        unsigned long FatSpace=0;

       char AddressL=0; //Low byte of address
      char AddressM=0; //Mid byte of address
      char AddressH=0; //High byte of address

      Delay(25000); //Wait one millisecond

      //////////////// Slow Oscillator/SPI down for initialization ///////////////

     OSCCON=0b01000111; //Oscillator 8 Mhz 0b01110111 for 8mhz
     SSPM1=1; //SPI - FOSC/64

       //////////////////// Initialize SPI Mode ///////////////////
     Delay(1);
     WriteSPI(0xFF);
     WriteSPI(0xFF);
     WriteSPI(0xFF);
     WriteSPI(0xFF);
     WriteSPI(0xFF);
     WriteSPI(0xFF);
     WriteSPI(0xFF);
     WriteSPI(0xFF);
     WriteSPI(0xFF);
     WriteSPI(0xFF); //Wake up the card (80 clock pulses)

     RA5=0; Delay(5);//Assert CS

     WriteSPI(0x40);
     WriteSPI(0x00);
     WriteSPI(0x00);
     WriteSPI(0x00);
     WriteSPI(0x00);
     WriteSPI(0x95); //CMD0
     WriteSPI(0);
     WriteSPI(0);

         WriteSPI(0x48);
         WriteSPI(0x00);
         WriteSPI(0x00);
         WriteSPI(0x01);
         WriteSPI(0b10101010);
         WriteSPI(0x87); //CMD8
         WriteSPI(0);
         WriteSPI(0);

         while(SSPBUF!=0) //ACMD 41 to initialize SD Card - keep doing until you get 0 meaning it's not busy
        {
          RA5=1; //deassert CS
          Delay(5);
          RA5=0; //assert CS

       WriteSPI(0xFF);

       WriteSPI(0b0111011);
        WriteSPI(0x00);
        WriteSPI(0x00);
        WriteSPI(0x00);
       WriteSPI(0x00);
       WriteSPI(0xFF); //CMD55
       WriteSPI(0xFF);
       WriteSPI(0xFF);

       RA5=1; //deassert CS
       RA5=0; //assert CS

       WriteSPI(0xFF);
       WriteSPI(0b01101001);
       WriteSPI(0b00000000);
       WriteSPI(0b00000000);
       WriteSPI(0x00);
       WriteSPI(0x00);
       WriteSPI(0xFF); //ACMD41
       WriteSPI(0xFF);
       WriteSPI(0xFF);
    }

      /////////// Speed Oscillator and SPI back up after initialization  ///////////

     OSCCON=0b01110111; //Oscillator 8 Mhz 0b01110111 for 8mhz
     SSPM1=0;

    ///////////// Find Address of FAT16 Partition Entry ////////

     RA5=1; //deassert CS
     RA5=0; //assert CS

     WriteSPI(0xFF);

     WriteSPI(0b01010000);
     WriteSPI(0);
     WriteSPI(0);
     WriteSPI(0);
     WriteSPI(4);
     WriteSPI(0xFF); //CMD16 4 byte block - want a return of "0"
     WriteSPI(0xFF);
     WriteSPI(0xFF);
     WriteSPI(0xFF);

     WriteSPI(0b01010001);
     WriteSPI(0x00);
     WriteSPI(0x00);
     WriteSPI(0x01);
     WriteSPI(0xC6);
      WriteSPI(0xFF); //CMD17 (Read Single Block) - want a response of XFE  signaling that data is coming

      while(SSPBUF!=0xFE) //Keep clocking until we get valid info (Follows 0xFE)
     {
        WriteSPI(0xFF);
     }

     WriteSPI(0xFF);
     Address=SSPBUF; //Loads LSB of address
     WriteSPI(0xFF);
     Address=Address+SSPBUF*256; //loads second bytes into address
     WriteSPI(0xFF);
     AddressH=Address+SSPBUF*65536; //loads third bytes into address
     WriteSPI(0xFF);
     WriteSPI(0xFF); //two dummy blocks at end to get through check sums
     WriteSPI(0xFF);

      ////////////// Find Address of Root //////////////

      RA5=1; //deassert CS
      Delay(5);
      RA5=0; //assert CS

     Address=Address*2; //Since address is in sectors, multiply by 2 then shift a byte over
     Address=Address<<8;
     AddressL=Address;
     AddressM=Address>>8;
     AddressH=Address>>16;

     WriteSPI(0b01010000);
     WriteSPI(0);
     WriteSPI(0);
     WriteSPI(0);
     WriteSPI(13);
     WriteSPI(0xFF); //CMD16 13 byte block - want a return of "0"
     WriteSPI(0xFF);
     WriteSPI(0xFF);
     WriteSPI(0xFF);

     WriteSPI(0b01010001);
     WriteSPI(0);
     WriteSPI(AddressH);
     WriteSPI(AddressM);
     WriteSPI(11);
     WriteSPI(0xFF); //CMD17 (Read single Block) - want a response of XFE    signaling that data is coming

    while(SSPBUF!=0xFE) //Keep clocking until we get valid info (Follows 0xFE)
    {
      WriteSPI(0xFF);
    }

    WriteSPI(0xFF);
    BytesPerSector=SSPBUF; //LSB of Bytes per Sector
    WriteSPI(0xFF);
    BytesPerSector=BytesPerSector+SSPBUF*256; //MSB of Bytes per sector
    WriteSPI(0xFF); //sectors per cluster, unused
    WriteSPI(0xFF);
    ReservedSectors=SSPBUF; //LSB of reserved sectors
    WriteSPI(0xFF); //MSB of reserved sectors (ignore)
    WriteSPI(0xFF);
    FATCount=SSPBUF; //number of FATs
    WriteSPI(0xFF); //number of root entries, unused
    WriteSPI(0xFF); //number of root entries, unused
    WriteSPI(0xFF); //small sectors, unused
    WriteSPI(0xFF); //small sectors, unused
    WriteSPI(0xFF); //Media Type, unused
    WriteSPI(0xFF);
    SectorsPerFat=SSPBUF; //LSB of sectors per FAT
    WriteSPI(0xFF);
    SectorsPerFat=SectorsPerFat+SSPBUF*256; //MSB of sectors per FAT
    WriteSPI(0xFF); //Two dummy bytes to clear the CRC
    WriteSPI(0xFF);

    Address=Address+BytesPerSector*ReservedSectors; //Adds the number of    reserved sectors to the starting address
    FatSpace=FATCount;
    FatSpace=FatSpace*BytesPerSector;
    FatSpace=FatSpace*SectorsPerFat;

    Address=Address+FatSpace; //add FAT data space to the address to get to the    root directory



      /****Writing into the disk*****/

      WriteSPI(0xFE);
      int i;
      for(i=0;i<400;i++)
       WriteSPI(0xDE);

     }

     void main(void){

     init_Device(); //initialize device
     init_SPI(); //initialize SPO module
     PORTA=0;
     PORTB=0;
     PORTC=0;

     RB6=0; //Set clock to low
     RA5=1; //set CS to high

     InitializeSPIMode();

     for(;;)
     {
     }
}
 

ErnieM

Joined Apr 24, 2011
8,415
Do yourself a favor and dig thru Microchip's application libraries and find their code for doing this. You will get a FAT compliant file system, meaning you can take the SD card out of your PIC and plug it into your PC and read and write to it there.

I've done this a dozen times so far and only had trouble on the very first one where I naively connected the OUT to OUT and In to IN on the SPI lines.

Unfortunately, since Microchip "improved" their libraries I can no longer find the awesome code I once used so easily. Perhaps going back to the archives would help.
 

Thread Starter

Sangam Singh

Joined Jun 23, 2015
9
Do yourself a favor and dig thru Microchip's application libraries and find their code for doing this. You will get a FAT compliant file system, meaning you can take the SD card out of your PIC and plug it into your PC and read and write to it there.

I've done this a dozen times so far and only had trouble on the very first one where I naively connected the OUT to OUT and In to IN on the SPI lines.

Unfortunately, since Microchip "improved" their libraries I can no longer find the awesome code I once used so easily. Perhaps going back to the archives would help.
I did check the archived libraries but the problem with them i am having is that when i compile the code i am getting the makefle error. On referring i got that it is getting confused between XC8 and C18 compiler. Presently I am using XC8 compiler but the libraries are for C18 compilers.
 

Thread Starter

Sangam Singh

Joined Jun 23, 2015
9
The C18 compiler is still available. Ive been using that for years now with no issues.
I have my entire code in XC8, making the entire code C18 compatible will be a big trouble now. Is there a way I can write into the card using XC8 compiler.
 

ErnieM

Joined Apr 24, 2011
8,415
The Microchip MPLAB Harmony Integrated Software Framework has this code. You will just have to dig thru it and find it for yourself.

They do have some sample apps you can study to see how to use it.
 

Thread Starter

Sangam Singh

Joined Jun 23, 2015
9
The Microchip MPLAB Harmony Integrated Software Framework has this code. You will just have to dig thru it and find it for yourself.

They do have some sample apps you can study to see how to use it.
he Microchip MPLAB Harmony Integrated Software Framework works with XC32 and not with XC8 or C18. I shifted my project to C18 so that I can use the MDD libraries but the I am getting a weird problem. It is not able to include the header file even though it exists in the directory.

Code:
C:\Program Files (x86)\Microchip\mplabc18\v3.47\h\FSconfig.h:38:Error [1027] unable to locate 'Compiler.h'
C:\Program Files (x86)\Microchip\mplabc18\v3.47\h\FSconfig.h:39:Error [1027] unable to locate 'HardwareProfile.h'
C:\Program Files (x86)\Microchip\mplabc18\v3.47\h\FSconfig.h:40:Error [1027] unable to locate 'MDD File System/SD-SPI.h'
C:\Program Files (x86)\Microchip\mplabc18\v3.47\h\FSconfig.h:41:Error [1027] unable to locate 'MDD File System/CF-PMP.h'
C:\Program Files (x86)\Microchip\mplabc18\v3.47\h\FSDefs.h:38:Error [1027] unable to locate 'GenericTypeDefs.h'
C:\Program Files (x86)\Microchip\mplabc18\v3.47\h\FSconfig.h:38:Error [1027] unable to locate 'Compiler.h'
C:\Program Files (x86)\Microchip\mplabc18\v3.47\h\FSconfig.h:39:Error [1027] unable to locate 'HardwareProfile.h'
C:\Program Files (x86)\Microchip\mplabc18\v3.47\h\FSconfig.h:40:Error [1027] unable to locate 'MDD File System/SD-SPI.h'
C:\Program Files (x86)\Microchip\mplabc18\v3.47\h\FSconfig.h:41:Error [1027] unable to locate 'MDD File System/CF-PMP.h'
That is the error.
 

ErnieM

Joined Apr 24, 2011
8,415
When using C18 inside MPLAB you need to add the oddball paths by hitting Project in the menu and choose Build Options | Project, and on the directories tab "Show directories for:" select "Include Search Path" and add the folder where each of those resides. If multiple files reside in the same area you need to include it just once.

MPLAB-X must have something similar but I am not as familiar with that IDE as of yet.

If you simply do not have these files they are all available for downloading from the legacy Microchip Applications Library (MAL)

http://www.microchip.com/pagehandler/en-us/devtools/mla/legacy-mla.html

(MPLAB and C18 are by BFF.)
 
Last edited:

Thread Starter

Sangam Singh

Joined Jun 23, 2015
9
I swtiched to MPLAB and C18. I downloaded the Legacy MLA library.
I moved all the required header files(.h) and .c file to the separate folder and set the build path to it. I am still having issues with the code. I am putting forth how I exactly did it all. If you maylet me know the if I am doing something wrong

This is how I am placing the files in a folder.
Screenshot 2015-06-25 14.40.42.png
Screenshot 2015-06-25 14.40.52.png

This is how i included the search paths.
Capture.PNG

And this is my code. (I have excluded the Configuration bits.)

Code:
// Header Files
#include <p18F25K80.h>
#include <stdio.h>
#include <stdlib.h>
#include <spi.h>
#include <FSIO.h>

#define bfrSize 5

void main(void)
    {
    FSFILE *pOldFile;
    FSFILE *pNewFile;
    char myData[20];
    char bfr [6];
    int bytesRead, bytesWritten;
    char newFile[] = "newfile.txt";
    char writeArg = 'w';
    // Must initialize the FAT16 library. It also initializes SPI and other related pins.
    while( !FSInit() )
    // Failed to initialize FAT16 – do something…
    //return 1; // Card not present or wrong format
    // Create a new file
    pNewFile = FSfopen (newFile, 'w');
    // Open an existing file to read
    pOldFile = FSfopenpgm ("myfile.txt", 'r');
 
    // Read 10 bytes of data from the file.
    bytesRead = FSfread((void*)myData, 10, 1, pOldFile);
    // read bfrSize (5) items (of size 1 byte). returns items count
    bytesRead = FSfread( (void *)bfr, 1, bfrSize, pOldFile );
    // Write those fifteen bytes to the new file
    bytesWritten = FSfwrite ((void *) myData, 10, 1, pNewFile);
    bytesWritten = FSfwrite ((void *) bfr, 1, bfrSize, pNewFile);
    // After processing, close the file.
    FSfclose( pOldFile );
    FSfclose (pNewFile);
}

- Thanks.
 

ErnieM

Joined Apr 24, 2011
8,415
I've never had to move these files around, I reference them from where they live in the MAL folders. That is especially true as the relative paths are sometimes hard coded into Microchip's code.

The sole exception to this is I believe the fs configuration file, which is custom to your project. I don't remember offhand which files have to be customized (and thus should live in your main project folder)

Sorry to say I don't have this setup where I am and I am leaving the country for a vacation tomorrow, and I doubt I will have time to look for you befoer I go. But you should be able to find some reference projects inside the MLA that can be used as a guide.
 
Top