SD Card Interface class. Log raw data bytes to memory addresses of your choice, or format the card and use the FAT file system to write files.

Dependencies:   mbed

Revision:
3:210eb67b260c
Parent:
1:94c648931f84
Child:
4:9a5878d316d5
--- a/SDCard.cpp	Mon Aug 23 01:31:50 2010 +0000
+++ b/SDCard.cpp	Mon Aug 23 07:12:13 2010 +0000
@@ -1,7 +1,12 @@
+//mbed Microcontroller Library
+//SDCard Interface
+//Copyright 2010
+//Thomas Hamilton
+
 #include "SDCard.h"
 
 SDCard::SDCard(PinName mosi, PinName miso, PinName sck, PinName cs, const char* DiskName) :
-    FATFileSystem(DiskName), DataLines(mosi, miso, sck), ChipSelect(cs), CRCMode(1), Timeout(8192)
+    FATFileSystem(DiskName), DataLines(mosi, miso, sck), ChipSelect(cs), CRCMode(1), Timeout(1024)
 {
     DataLines.frequency(100000);
         //set universal speed
@@ -14,18 +19,38 @@
         //generate the command crc lookup table
         //(generator polynomial x^16 + x^12 + x^5 + 1 converts to decimal 69665)
     Initialize();
+        //run card setup operations
+}
+
+SDCard::~SDCard()
+{
+    delete[] CommandCRCTable;
+    delete[] DataCRCTable;
+    delete[] OCR;
+    delete[] CSD;
+    delete[] FSR;
+    delete[] Workspace;
+        //delete all card data register copies and workspaces
+    delete this;
 }
 
 unsigned char SDCard::disk_initialize()
 { return 0x00; }
+    //disc is initialized during construction
 unsigned char SDCard::disk_status()
 { return 0x00; }
-unsigned char SDCard::disk_read(unsigned char* buff, unsigned long sector, unsigned char count)
+    //card is always initialized
+unsigned char SDCard::disk_read(
+    unsigned char* buff, unsigned long sector, unsigned char count)
 { return Read((unsigned int)sector, count, buff); }
-unsigned char SDCard::disk_write(const unsigned char* buff, unsigned long sector, unsigned char count)
+    //read operations must efficiently complete multiple sector transactions
+unsigned char SDCard::disk_write(
+    const unsigned char* buff, unsigned long sector, unsigned char count)
 { return Write((unsigned int)sector, count, (unsigned char*)buff); }
+    //write operations must efficiently complete multiple sector transactions
 unsigned char SDCard::disk_sync()
 { return 0x00; }
+    //all disc functions are synchronous
 unsigned long SDCard::disk_sector_count()
 {
     switch (CSD[0] & 0xC0)
@@ -33,37 +58,47 @@
         case 0x00:
             return ((((CSD[6] & 0x03) << 10) | (CSD[7] << 2) | ((CSD[8] & 0xC0) >> 6)) + 1)
                 * (1 << ((((CSD[9] & 0x03) << 1) | ((CSD[10] & 0x80) >> 7)) + 2));
+                //calculate sector count as specified for version 1 cards
         case 0x40:
             return ((((CSD[7] & 0x3F) << 16) | (CSD[8] << 8) | CSD[9]) + 1) * 1024;
+                //calculate sector count as specified for version 2 cards
         default:
             return 0;
     }
 }
+    //return number of sectors on card
 unsigned short SDCard::disk_sector_size()
 { return 512; }
+    //fix SD card sector size to 512 for all cards
 unsigned long SDCard::disk_block_size()
 {
     switch (CSD[0] & 0xC0)
     {
         case 0x00:
             return (CSD[10] << 1) | (CSD[11] >> 7) + 1;
+                //calculate erase sector size for version 1 cards
         case 0x40:
             return 1;
+                //erase sector size is given by allocation unit for version 2 cards
         default:
             return 0;
     }
 }
+    //return the number of sectors in an erase sector
 
 unsigned char SDCard::Log(unsigned char Control, unsigned char Data)
 {
     static unsigned char Mode = 0x00;
+        //store previous operating mode to determine current behavior
     static unsigned short Index = 0;
+        //store last written byte number of current memory block
 
     if (CRCMode)
     {
         SelectCRCMode(0);
     }
-    
+        //CRC's are not used in raw data mode
+
     switch (Control)
     {
         case 0x00:
@@ -74,8 +109,10 @@
                 {
                     DataLines.write(0xFF);
                 }
+                    //get through left over space, filling with 0xFF for write blocks
                 DataLines.write(0xFF);
                 DataLines.write(0xFF);
+                    //get through CRC
                 ChipSelect.write(1);
                 if (Mode == 0x01)
                 {
@@ -85,26 +122,36 @@
                     {
                         t++;
                     } while (((DataLines.write(0xFF) & 0x11) != 0x01) && (t < Timeout));
+                        //get through data response token
                     while (!DataLines.write(0xFF));
+                        //get through busy signal
                     DataLines.write(0xFD);
                     DataLines.write(0xFF);
+                        //send stop transmission token
                     while (!DataLines.write(0xFF));
+                        //get through busy signal
                     ChipSelect.write(1);
                     DataLines.write(0xFF);
                 }
+                    //finish write block
                 else
                 {
                     Command(12, 0, Workspace);
+                        //send stop transmission command
                     ChipSelect.write(0);
                     while (!DataLines.write(0xFF));
+                        //get through busy signal
                     ChipSelect.write(1);
                     DataLines.write(0xFF);
                 }
+                    //finish read block
                 Index = 0;
                 Mode = 0x00;
+                    //reset index to start and mode to synced
             }
             return 0xFF;
-            
+                //control code 0 synchronizes the card
+
         case 0x01:
             if (Mode != 0x01)
             {
@@ -112,6 +159,8 @@
                 Command(25, 0, Workspace);
                 Mode = 0x01;
             }
+                //if previous call was not a write operation, sync the card, start a new write
+                //block, and set function to write mode
             if (Index == 0)
             {
                 ChipSelect.write(0);
@@ -120,6 +169,7 @@
                 ChipSelect.write(1);
                 Index++;
             }
+                //if the index is at the start, send the start block token before the byte
             else if (Index < 511)
             {
                 ChipSelect.write(0);
@@ -127,6 +177,7 @@
                 ChipSelect.write(1);
                 Index++;
             }
+                //if the index is between the boundaries, simply write the byte
             else
             {
                 ChipSelect.write(0);
@@ -142,8 +193,11 @@
                 ChipSelect.write(1);
                 Index = 0;
             }
+                //if the index is at the last address, get through CRC, Data response token, and
+                //busy signal and reset the index
             return 0xFF;
-            
+                //return stuff bits; control code 1 writes a byte
+
         case 0x02:
             if (Mode != 0x02)
             {
@@ -151,6 +205,8 @@
                 Command(18, 0, Workspace);
                 Mode = 0x02;
             }
+                //if previous call was not a read operation, sync the card, start a new read block,
+                //and set function to read mode
             if (Index == 0)
             {
                 ChipSelect.write(0);
@@ -164,6 +220,7 @@
                 Index++;
                 return Workspace[0];
             }
+                //if the index is at the start, get the start block token and read the first byte
             else if (Index < 511)
             {
                 ChipSelect.write(0);
@@ -172,6 +229,7 @@
                 Index++;
                 return Workspace[0];
             }
+                //if the index is between the boundaries, simply read the byte
             else
             {
                 ChipSelect.write(0);
@@ -182,9 +240,12 @@
                 Index = 0;
                 return Workspace[0];
             }
-            
+                //if the index is at the last address, get through CRC and reset the index;
+                //control code 2 reads a byte
+
         default:
             return 0xFF;
+                //return stuff bits
     }
 }
 
@@ -193,41 +254,49 @@
     if (!Capacity)
     {
         Command(24, Address * 512, Workspace);
-        if (Workspace[0])
-        { return 0x04; }
     }
     else
     {
         Command(24, Address, Workspace);
-        if (Workspace[0])
-        { return 0x04; }
     }
+        //send single block write command; addressing depends on the card version
+    if (Workspace[0])
+    { return 0x04; }
+        //if a command error occurs, return parameter error
     DataCRC(512, Data, Workspace);
+        //calculate the data CRC
     ChipSelect.write(0);
     DataLines.write(0xFE);
+        //write start block token
     for (unsigned short i = 0; i < 512; i++)
     {
         DataLines.write(Data[i]);
     }
+        //write the data to the addressed card sector
     DataLines.write(Workspace[0]);
     DataLines.write(Workspace[1]);
+        //write the data CRC to the card
     t = 0;
     do
     {
         Workspace[0] = DataLines.write(0xFF);
         t++;
     } while (((Workspace[0] & 0x11) != 0x01) && (t < Timeout));
+        //gather the data block response token
     while (!DataLines.write(0xFF));
+        //get through the busy signal
     ChipSelect.write(1);
     DataLines.write(0xFF);
     if (((Workspace[0] & 0x1F) != 0x05) || (t == Timeout))
     { return 0x01; }
     else
     { return 0x00; }
+        //if data response token indicates error, return R/W error
 }
 unsigned char SDCard::Write(unsigned int Address, unsigned char SectorCount, unsigned char* Data)
 {
     static unsigned char CurrentSectorCount = 1;
+        //store the last write sector count
     if (SectorCount != CurrentSectorCount)
     {
         Command(55, 0, Workspace);
@@ -236,28 +305,30 @@
         { return 0x04; }
         CurrentSectorCount = SectorCount;
     }
+        //set the expected number of write blocks if different from previous operations
     if (!Capacity)
     {
         Command(25, Address * 512, Workspace);
-        if (Workspace[0])
-        { return 0x04; }
     }
     else
     {
         Command(25, Address, Workspace);
-        if (Workspace[0])
-        { return 0x04; }
     }
+    if (Workspace[0])
+    { return 0x04; }
     Workspace[4] = 0x00;
     for (unsigned char i = 0; i < SectorCount; i++)
     {
         DataCRC(512, &Data[i * 512], Workspace);
+            //calculate data crc for each passed write block
         ChipSelect.write(0);
         DataLines.write(0xFC);
+            //send multiple write block start token
         for (unsigned int j = i * 512; j < (i + 1) * 512; j++)
         {
             DataLines.write(Data[j]);
         }
+            //write each data block
         DataLines.write(Workspace[0]);
         DataLines.write(Workspace[1]);
         t = 0;
@@ -269,6 +340,7 @@
         while (!DataLines.write(0xFF));
         ChipSelect.write(1);
         Workspace[4] |= Workspace[0];
+            //record if any write errors are detected in the data response tokens
         if (t == Timeout)
         {
             ChipSelect.write(0);
@@ -278,6 +350,7 @@
             DataLines.write(0xFF);
             return 0x01;
         }
+            //if a block write operation gets timed out, make sure the card is synced and exit
     }
     ChipSelect.write(0);
     DataLines.write(0xFD);
@@ -296,15 +369,15 @@
     if (!Capacity)
     {
         Command(17, Address * 512, Workspace);
-        if (Workspace[0])
-        { return 0x04; }
     }
     else
     {
         Command(17, Address, Workspace);
-        if (Workspace[0])
-        { return 0x04; }
     }
+        //send single block read command; addressing depends on the card version
+    if (Workspace[0])
+    { return 0x04; }
+        //if a command error occurs, return parameter error
     ChipSelect.write(0);
     t = 0;
     do
@@ -312,34 +385,37 @@
         t++;
     } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout));
     if (t == Timeout) { ChipSelect.write(1); DataLines.write(0xFF); return 0x01; }
+        //get to start block token
     for (unsigned short i = 0; i < 512; i++)
     {
         Data[i] = DataLines.write(0xFF);
     }
+        //read the data from the addressed card sector
     Workspace[2] = DataLines.write(0xFF);
     Workspace[3] = DataLines.write(0xFF);
+        //read the data CRC to the card
     ChipSelect.write(1);
     DataLines.write(0xFF);
     DataCRC(512, Data, Workspace);
+        //calculate the data CRC
     if (CRCMode && ((Workspace[0] != Workspace[2]) || (Workspace[1] != Workspace[3])))
     { return 0x01; }
     else
     { return 0x00; }
+        //if CRC is invalid, return R/W error
 }
 unsigned char SDCard::Read(unsigned int Address, unsigned char SectorCount, unsigned char* Data)
 {
     if (!Capacity)
     {
         Command(18, Address * 512, Workspace);
-        if (Workspace[0])
-        { return 0; }
     }
     else
     {
         Command(18, Address, Workspace);
-        if (Workspace[0])
-        { return 0; }
     }
+    if (Workspace[0])
+    { return 0; }
     Workspace[4] = 0x00;
     for (unsigned char i = 0; i < SectorCount; i++)
     {
@@ -349,6 +425,7 @@
         {
             t++;
         } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout));
+            //get to each data block start token
         if (t == Timeout)
         {
             ChipSelect.write(1);
@@ -359,15 +436,19 @@
             DataLines.write(0xFF);
             return 0x01;
         }
+            //if a block read operation gets timed out, make sure the card is synced and exit
         for (unsigned int j = i * 512; j < (i + 1) * 512; j++)
         {
             Data[j] = DataLines.write(0xFF);
         }
+            //read each data block
         Workspace[2] = DataLines.write(0xFF);
         Workspace[3] = DataLines.write(0xFF);
         ChipSelect.write(1);
         DataCRC(512, &Data[i * 512], Workspace);
+            //calculate data crc for each read data block
         Workspace[4] |= ((Workspace[0] != Workspace[2]) || (Workspace[1] != Workspace[3]));
+            //record if any invalid CRCs are detected during the transaction
     }
     Command(12, 0, Workspace);
     ChipSelect.write(0);
@@ -385,6 +466,7 @@
     do
     {
         Command(59, Mode, Workspace);
+            //command 59 sets card CRC mode
         t++;
     } while (Workspace[0] && (t < Timeout));
     CRCMode = Mode;
@@ -392,8 +474,15 @@
     { return 0x01; }
     else
     { return 0x00; }
+        //if command times out, return error
 }
 
+void SDCard::SetTimeout(unsigned int Retries)
+{
+    Timeout = Retries;
+}
+    //set c=number of retries for card operations
+
 unsigned char SDCard::Initialize()
 {
     for (unsigned char i = 0; i < 16; i++)