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:
1:94c648931f84
Parent:
0:f3870f76a890
Child:
3:210eb67b260c
--- a/SDCard.cpp	Sun Jul 18 21:26:24 2010 +0000
+++ b/SDCard.cpp	Sat Aug 07 18:32:30 2010 +0000
@@ -1,7 +1,7 @@
 #include "SDCard.h"
 
-SDCard::SDCard(PinName mosi, PinName miso, PinName sck, PinName cs)
-    : DataLines(mosi, miso, sck), ChipSelect(cs), CRCMode(1)
+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)
 {
     DataLines.frequency(100000);
         //set universal speed
@@ -14,240 +14,523 @@
         //generate the command crc lookup table
         //(generator polynomial x^16 + x^12 + x^5 + 1 converts to decimal 69665)
     Initialize();
-        //send card initialization sequence
+}
+
+unsigned char SDCard::disk_initialize()
+{ return 0x00; }
+unsigned char SDCard::disk_status()
+{ return 0x00; }
+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)
+{ return Write((unsigned int)sector, count, (unsigned char*)buff); }
+unsigned char SDCard::disk_sync()
+{ return 0x00; }
+unsigned long SDCard::disk_sector_count()
+{
+    switch (CSD[0] & 0xC0)
+    {
+        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));
+        case 0x40:
+            return ((((CSD[7] & 0x3F) << 16) | (CSD[8] << 8) | CSD[9]) + 1) * 1024;
+        default:
+            return 0;
+    }
+}
+unsigned short SDCard::disk_sector_size()
+{ return 512; }
+unsigned long SDCard::disk_block_size()
+{
+    switch (CSD[0] & 0xC0)
+    {
+        case 0x00:
+            return (CSD[10] << 1) | (CSD[11] >> 7) + 1;
+        case 0x40:
+            return 1;
+        default:
+            return 0;
+    }
 }
 
-bool SDCard::Write(unsigned int Address, unsigned char* Data)
+unsigned char SDCard::Log(unsigned char Control, unsigned char Data)
 {
-    if (Capacity)
+    static unsigned char Mode = 0x00;
+    static unsigned short Index = 0;
+
+    if (CRCMode)
     {
-        for (unsigned int j = 0; j < 8192; j++)
-        {
-            Command(24, Address, Workspace);
-            if (Workspace[0] == 0x00)
-            { break; }
-            if (j == 8191)
-            { return 0; }
-        }
-    }
-    else
-    {
-        for (unsigned int j = 0; j < 8192; j++)
-        {
-            Command(24, Address * 512, Workspace);///////////implement block length
-            if (Workspace[0] == 0x00)
-            { break; }
-            if (j == 8191)
-            { return 0; }
-        }
+        SelectCRCMode(0);
     }
-    ChipSelect.write(0);
-    DataLines.write(0xFE);
-        //start data block token
-    for (unsigned short j = 0; j < 512; j++)
-    {
-        DataLines.write(Data[j]);
-            //write the data
-    }
-    DataCRC(512, Data, Workspace);
-    DataLines.write(Workspace[1]);
-    DataLines.write(Workspace[2]);
-    for (unsigned int j = 0; j < 8192; j++)
+    
+    switch (Control)
     {
-        Workspace[0] = DataLines.write(0xFF);
-        if ((Workspace[0] & 0x1F) == 0x05)
-        { break; }
-    }
-    while (!DataLines.write(0xFF));
-    ChipSelect.write(1);
-    DataLines.write(0xFF);
-    if ((Workspace[0] & 0x1F) == 0x05)
-    { return 1; }
-    else
-    {
-        for (unsigned int j = 0; j < 8192; j++)
-        {
-            Command(13, 0, Workspace);
-            if (Workspace[0] == 0x00)
-            { break; }
-        }
-        return 0;
+        case 0x00:
+            if (Mode)
+            {
+                ChipSelect.write(0);
+                for (; Index < 512; Index++)
+                {
+                    DataLines.write(0xFF);
+                }
+                DataLines.write(0xFF);
+                DataLines.write(0xFF);
+                ChipSelect.write(1);
+                if (Mode == 0x01)
+                {
+                    ChipSelect.write(0);
+                    t = 0;
+                    do
+                    {
+                        t++;
+                    } while (((DataLines.write(0xFF) & 0x11) != 0x01) && (t < Timeout));
+                    while (!DataLines.write(0xFF));
+                    DataLines.write(0xFD);
+                    DataLines.write(0xFF);
+                    while (!DataLines.write(0xFF));
+                    ChipSelect.write(1);
+                    DataLines.write(0xFF);
+                }
+                else
+                {
+                    Command(12, 0, Workspace);
+                    ChipSelect.write(0);
+                    while (!DataLines.write(0xFF));
+                    ChipSelect.write(1);
+                    DataLines.write(0xFF);
+                }
+                Index = 0;
+                Mode = 0x00;
+            }
+            return 0xFF;
+            
+        case 0x01:
+            if (Mode != 0x01)
+            {
+                Log(0, 0);
+                Command(25, 0, Workspace);
+                Mode = 0x01;
+            }
+            if (Index == 0)
+            {
+                ChipSelect.write(0);
+                DataLines.write(0xFC);
+                DataLines.write(Data);
+                ChipSelect.write(1);
+                Index++;
+            }
+            else if (Index < 511)
+            {
+                ChipSelect.write(0);
+                DataLines.write(Data);
+                ChipSelect.write(1);
+                Index++;
+            }
+            else
+            {
+                ChipSelect.write(0);
+                DataLines.write(Data);
+                DataLines.write(0xFF);
+                DataLines.write(0xFF);
+                t = 0;
+                do
+                {
+                    t++;
+                } while (((DataLines.write(0xFF) & 0x11) != 0x01) && (t < Timeout));
+                while (!DataLines.write(0xFF));
+                ChipSelect.write(1);
+                Index = 0;
+            }
+            return 0xFF;
+            
+        case 0x02:
+            if (Mode != 0x02)
+            {
+                Log(0, 0);
+                Command(18, 0, Workspace);
+                Mode = 0x02;
+            }
+            if (Index == 0)
+            {
+                ChipSelect.write(0);
+                t = 0;
+                do
+                {
+                    t++;
+                } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout));
+                Workspace[0] = DataLines.write(0xFF);
+                ChipSelect.write(1);
+                Index++;
+                return Workspace[0];
+            }
+            else if (Index < 511)
+            {
+                ChipSelect.write(0);
+                Workspace[0] = DataLines.write(0xFF);
+                ChipSelect.write(1);
+                Index++;
+                return Workspace[0];
+            }
+            else
+            {
+                ChipSelect.write(0);
+                Workspace[0] = DataLines.write(0xFF);
+                DataLines.write(0xFF);
+                DataLines.write(0xFF);
+                ChipSelect.write(1);
+                Index = 0;
+                return Workspace[0];
+            }
+            
+        default:
+            return 0xFF;
     }
 }
 
-bool SDCard::Read(unsigned int Address, unsigned char* Data)
+unsigned char SDCard::Write(unsigned int Address, unsigned char* Data)
 {
-    if (Capacity)
+    if (!Capacity)
     {
-        for (unsigned int j = 0; j < 8192; j++)
-        {
-            Command(17, Address, Workspace);
-            if (Workspace[0] == 0x00)
-            { break; }
-            if (j == 8191)
-            { return 0; }
-        }
+        Command(24, Address * 512, Workspace);
+        if (Workspace[0])
+        { return 0x04; }
     }
     else
     {
-        for (unsigned int j = 0; j < 8192; j++)
+        Command(24, Address, Workspace);
+        if (Workspace[0])
+        { return 0x04; }
+    }
+    DataCRC(512, Data, Workspace);
+    ChipSelect.write(0);
+    DataLines.write(0xFE);
+    for (unsigned short i = 0; i < 512; i++)
+    {
+        DataLines.write(Data[i]);
+    }
+    DataLines.write(Workspace[0]);
+    DataLines.write(Workspace[1]);
+    t = 0;
+    do
+    {
+        Workspace[0] = DataLines.write(0xFF);
+        t++;
+    } while (((Workspace[0] & 0x11) != 0x01) && (t < Timeout));
+    while (!DataLines.write(0xFF));
+    ChipSelect.write(1);
+    DataLines.write(0xFF);
+    if (((Workspace[0] & 0x1F) != 0x05) || (t == Timeout))
+    { return 0x01; }
+    else
+    { return 0x00; }
+}
+unsigned char SDCard::Write(unsigned int Address, unsigned char SectorCount, unsigned char* Data)
+{
+    static unsigned char CurrentSectorCount = 1;
+    if (SectorCount != CurrentSectorCount)
+    {
+        Command(55, 0, Workspace);
+        Command(23, SectorCount, Workspace);
+        if (Workspace[0])
+        { return 0x04; }
+        CurrentSectorCount = SectorCount;
+    }
+    if (!Capacity)
+    {
+        Command(25, Address * 512, Workspace);
+        if (Workspace[0])
+        { return 0x04; }
+    }
+    else
+    {
+        Command(25, Address, Workspace);
+        if (Workspace[0])
+        { return 0x04; }
+    }
+    Workspace[4] = 0x00;
+    for (unsigned char i = 0; i < SectorCount; i++)
+    {
+        DataCRC(512, &Data[i * 512], Workspace);
+        ChipSelect.write(0);
+        DataLines.write(0xFC);
+        for (unsigned int j = i * 512; j < (i + 1) * 512; j++)
         {
-            Command(17, Address * 512, Workspace);///////////implement block length
-            if (Workspace[0] == 0x00)
-            { break; }
-            if (j == 8191)
-            { return 0; }
+            DataLines.write(Data[j]);
+        }
+        DataLines.write(Workspace[0]);
+        DataLines.write(Workspace[1]);
+        t = 0;
+        do
+        {
+            Workspace[0] = DataLines.write(0xFF);
+            t++;
+        } while (((Workspace[0] & 0x11) != 0x01) && (t < Timeout));
+        while (!DataLines.write(0xFF));
+        ChipSelect.write(1);
+        Workspace[4] |= Workspace[0];
+        if (t == Timeout)
+        {
+            ChipSelect.write(0);
+            DataLines.write(0xFD);
+            while (!DataLines.write(0xFF));
+            ChipSelect.write(1);
+            DataLines.write(0xFF);
+            return 0x01;
         }
     }
     ChipSelect.write(0);
-    for (unsigned int j = 0; j < 8192; j++)
+    DataLines.write(0xFD);
+    DataLines.write(0xFF);
+    while (!DataLines.write(0xFF));
+    ChipSelect.write(1);
+    DataLines.write(0xFF);
+    if ((Workspace[4] & 0x1F) != 0x05)
+    { return 0x01; }
+    else
+    { return 0x00; }
+}
+
+unsigned char SDCard::Read(unsigned int Address, unsigned char* Data)
+{
+    if (!Capacity)
     {
-        if (DataLines.write(0xFF) == 0xFE)
-        { break; }
+        Command(17, Address * 512, Workspace);
+        if (Workspace[0])
+        { return 0x04; }
     }
-    for (unsigned short j = 0; j < 512; j++)
+    else
+    {
+        Command(17, Address, Workspace);
+        if (Workspace[0])
+        { return 0x04; }
+    }
+    ChipSelect.write(0);
+    t = 0;
+    do
     {
-        Data[j] = DataLines.write(0xFF);
+        t++;
+    } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout));
+    if (t == Timeout) { ChipSelect.write(1); DataLines.write(0xFF); return 0x01; }
+    for (unsigned short i = 0; i < 512; i++)
+    {
+        Data[i] = DataLines.write(0xFF);
     }
+    Workspace[2] = DataLines.write(0xFF);
     Workspace[3] = DataLines.write(0xFF);
-    Workspace[4] = DataLines.write(0xFF);
     ChipSelect.write(1);
     DataLines.write(0xFF);
     DataCRC(512, Data, Workspace);
-    if ((Workspace[1] == Workspace[3]) && (Workspace[2] == Workspace[4]))
-    { return 1; }
+    if (CRCMode && ((Workspace[0] != Workspace[2]) || (Workspace[1] != Workspace[3])))
+    { return 0x01; }
+    else
+    { return 0x00; }
+}
+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
-    { return 0; }
+    {
+        Command(18, Address, Workspace);
+        if (Workspace[0])
+        { return 0; }
+    }
+    Workspace[4] = 0x00;
+    for (unsigned char i = 0; i < SectorCount; i++)
+    {
+        ChipSelect.write(0);
+        t = 0;
+        do
+        {
+            t++;
+        } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout));
+        if (t == Timeout)
+        {
+            ChipSelect.write(1);
+            Command(12, 0, Workspace);
+            ChipSelect.write(0);
+            while (!DataLines.write(0xFF));
+            ChipSelect.write(1);
+            DataLines.write(0xFF);
+            return 0x01;
+        }
+        for (unsigned int j = i * 512; j < (i + 1) * 512; j++)
+        {
+            Data[j] = DataLines.write(0xFF);
+        }
+        Workspace[2] = DataLines.write(0xFF);
+        Workspace[3] = DataLines.write(0xFF);
+        ChipSelect.write(1);
+        DataCRC(512, &Data[i * 512], Workspace);
+        Workspace[4] |= ((Workspace[0] != Workspace[2]) || (Workspace[1] != Workspace[3]));
+    }
+    Command(12, 0, Workspace);
+    ChipSelect.write(0);
+    while (!DataLines.write(0xFF));
+    ChipSelect.write(1);
+    if (Workspace[4])
+    { return 0x01; }
+    else
+    { return 0x00; }
 }
 
-bool SDCard::Initialize()
+unsigned char SDCard::SelectCRCMode(bool Mode)
 {
-    for (unsigned char j = 0; j < 16; j++)
+    t = 0;
+    do
+    {
+        Command(59, Mode, Workspace);
+        t++;
+    } while (Workspace[0] && (t < Timeout));
+    CRCMode = Mode;
+    if (t == Timeout)
+    { return 0x01; }
+    else
+    { return 0x00; }
+}
+
+unsigned char SDCard::Initialize()
+{
+    for (unsigned char i = 0; i < 16; i++)
     {
         DataLines.write(0xFF);
+            //clock card at least 74 times to power up
     }
-        //perform specified power up sequence
-    
-    for (unsigned int j = 0; j < 8192; j++)
+
+    t = 0;
+    do
     {
         Command(0, 0, Workspace);
             //send command 0 to put the card into SPI mode
-        if (Workspace[0] == 0x01)
-            //check for idle mode
-        { break; }
-        if (j == 8191)
-        { return 0; }
-    }
-    
-    for (unsigned int j = 0; j < 8192; j++)
+        t++;
+    } while ((Workspace[0] != 0x01) && (t < Timeout));
+    if (t == Timeout) { return 0x01; }
+
+    t = 0;
+    do
     {
         Command(59, 1, Workspace);
-            //send command 59 to turn on CRCs
-        if (Workspace[0] == 0x01)
-        { break; }
-        if (j == 8191)
-        { return 0; }
-    }
-    
-    for (unsigned int j = 0; j < 8192; j++)
+            //turn on CRCs
+        t++;
+    } while ((Workspace[0] != 0x01) && (Workspace[0] != 0x05) && (t < Timeout));
+        //command 59 is not valid for all cards in idle state
+    if (t == Timeout) { return 0x01; }
+
+    t = 0;
+    do
     {
         Command(8, 426, Workspace);
             //voltage bits are 0x01 for 2.7V - 3.6V,
             //check pattern 0xAA, [00,00,01,AA] = 426
-        if ((Workspace[0] == 0x05) || ((Workspace[0] == 0x01) &&
-            ((Workspace[3] & 0x0F) == 0x01) && (Workspace[4] == 0xAA)))
-            //check version, voltage acceptance, and check pattern
-        { break; }
-        if (j == 8191)
-        { return 0; }
-    }
-    Version = Workspace[0] == 0x01;
+        t++;
+    } while (((Workspace[0] != 0x01) || ((Workspace[3] & 0x0F) != 0x01) ||
+        (Workspace[4] != 0xAA)) && (Workspace[0] != 0x05) && (t < Timeout));
+        //check version, voltage acceptance, and check pattern
+    if (t == Timeout) { return 0x01; }
+    Version = Workspace[0] != 0x05;
         //store card version
-    
-    for (unsigned int j = 0; j < 8192; j++)
+
+    t = 0;
+    do
     {
         Command(58, 0, Workspace);
             //check the OCR
-        if ((Workspace[0] == 0x01) && ((Workspace[2] & 0x20) || (Workspace[2] & 0x10)))
-            //check for correct operating voltage 3.3V
-        { break; }
-        if (j == 8191)
-        { return 0; }
-    }
-    
-    for (unsigned int j = 0; j < 8192; j++)
+        t++;
+    } while (((Workspace[0] != 0x01) ||
+        !((Workspace[2] & 0x20) || (Workspace[2] & 0x10))) && (t < Timeout));
+        //check for correct operating voltage 3.3V
+    if (t == Timeout) { return 0x01; }
+
+    t = 0;
+    do
     {
         Command(55, 0, Workspace);
-            //specify application-specific command
         Command(41, 1073741824, Workspace);
-            //specify host supports high capacity cards
-            //[40,00,00,00] = 1073741824
-        if (Workspace[0] == 0x00)
-            //check if card is ready
-        { break; }
-        if (j == 8191)
-        { return 0; }
-    }
-    
-    for (unsigned int j = 0; j < 8192; j++)
+            //specify host supports high capacity
+            //cards, [40,00,00,00] = 1073741824
+        t++;
+    } while (Workspace[0] && (t < Timeout));
+        //check if card is ready
+    if (t == Timeout) { return 0x01; }
+
+    if (SelectCRCMode(1))
+    { return 0x01; }
+        //turn on CRCs for all cards
+
+    t = 0;
+    do
     {
         Command(58, 0, Workspace);
             //check the OCR again
-        if ((Workspace[0] == 0x00) && (Workspace[1] & 0x80))
-        { break; }
-        if (j == 8191)
-        { return 0; }
+        t++;
+    } while ((Workspace[0] || !(Workspace[1] & 0x80)) && (t < Timeout));
+        //check power up status
+    if (t == Timeout) { return 0x01; }
+    for (unsigned char i = 0; i < 4; i++)
+    {
+        OCR[i] = Workspace[i + 1];
+            //record OCR
     }
-    for (unsigned char j = 0; j < 4; j++)
-    {
-        OCR[j] = Workspace[j + 1];
-    }
-        //record OCR
     Capacity = (OCR[0] & 0x40) == 0x40;
         //record capacity
-    
-    for (unsigned int j = 0; j < 8192; j++)
+
+    t = 0;
+    do
     {
-        Command(9, 0, Workspace);
-            //read the card-specific data register
-        ChipSelect.write(0);
-        for (unsigned int k = 0; k < 8192; k++)
+        do
         {
-            if (DataLines.write(0xFF) == 0xFE)
-            { break; }
-        }
+            Command(9, 0, Workspace);
+                //read the card-specific-data register
+            t++;
+        } while (Workspace[0] && (t < Timeout));
+        if (t == Timeout) { return 0x01; }
+        ChipSelect.write(0);
+        do
+        {
+            t++;
+        } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout));
             //get to the start-data-block token
-        for (unsigned char k = 0; k < 16; k++)
+        if (t == Timeout) { ChipSelect.write(1); DataLines.write(0xFF); return 0x01; }
+        for (unsigned char i = 0; i < 16; i++)
         {
-            CSD[k] = DataLines.write(0xFF);
+            CSD[i] = DataLines.write(0xFF);
+                //gather CSD
         }
+        Workspace[2] = DataLines.write(0xFF);
         Workspace[3] = DataLines.write(0xFF);
-        Workspace[4] = DataLines.write(0xFF);
+            //save CSD CRC
         ChipSelect.write(1);
         DataLines.write(0xFF);
         DataCRC(16, CSD, Workspace);
             //calculate the CSD data CRC
-        Workspace[0] = 0;
-        for (unsigned char k = 0; k < 15; k++)
+        Workspace[4] = 0;
+        for (unsigned char i = 0; i < 15; i++)
         {
-            Workspace[0] = CommandCRCTable[Workspace[0]] ^ CSD[k];
+            Workspace[4] = CommandCRCTable[Workspace[4]] ^ CSD[i];
         }
-        Workspace[0] = CommandCRCTable[Workspace[0]] | 0x01;
-        if ((Workspace[0] == CSD[15]) && (Workspace[1] == Workspace[3]) && (Workspace[2] == Workspace[4]))
-        { break; }
-        if (j == 8191)
-        { return 0; }
-    }
-    
-    if (((CSD[3] & 0x07) > 2) || ((CSD[3] & 0x7F) > 0x32))
+        Workspace[4] = CommandCRCTable[Workspace[4]] | 0x01;
+            //calculate the CSD table CRC
+        t++;
+    } while (((Workspace[0] != Workspace[2]) || (Workspace[1] != Workspace[3]) ||
+        (Workspace[4] != CSD[15])) && (t < Timeout));
+        //check all CSD CRCs
+    if (t == Timeout) { return 0x01; }
+
+    if (((CSD[3] & 0x07) > 0x02) ||
+        (((CSD[3] & 0x78) > 0x30) && ((CSD[3] & 0x07) > 0x01)))
     {
         DataLines.frequency(25000000);
-            //maximum speed is given at 25MHz
+            //maximum speed is 25MHz
     }
     else
     {
        Workspace[0] = 1;
-        for (unsigned char j = 0; j < (CSD[3] & 0x07); j++)
+        for (unsigned char i = 0; i < (CSD[3] & 0x07); i++)
         {
             Workspace[0] *= 10;
                 //the first three bits are a power of ten multiplier for speed
@@ -273,25 +556,78 @@
                 //read the CSD card speed bits and speed up card operations
         }
     }
-    
+
+    if (CSD[4] & 0x40)
+        //check for switch command class support
+    {
+        t = 0;
+        do
+        {
+            Command(6, 2147483649, Workspace);
+                //switch to high-speed mode (SDR25, 50MHz)
+            t++;
+        } while (Workspace[0] && (Workspace[0] != 0x04) && (t < Timeout));
+            //some cards that support switch class commands respond with illegal command
+        if (t == Timeout) { return 0x01; }
+        if (!Workspace[0])
+        {
+            do
+            {
+                ChipSelect.write(0);
+                do
+                {
+                    t++;
+                } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout));
+                    //get to the start-data-block token
+                if (t == Timeout) { ChipSelect.write(1); DataLines.write(0xFF); return 0x01; }
+                for (unsigned char i = 0; i < 64; i++)
+                {
+                    FSR[i] = DataLines.write(0xFF);
+                        //gather function-status register
+                }
+                Workspace[2] = DataLines.write(0xFF);
+                Workspace[3] = DataLines.write(0xFF);
+                    //record data CRC
+                ChipSelect.write(1);
+                DataLines.write(0xFF);
+                DataCRC(64, FSR, Workspace);
+                    //calculate CRC
+                t++;
+            } while (((Workspace[0] != Workspace[2]) || (Workspace[1] != Workspace[3])) &&
+                (t < Timeout));
+                //complete CRC
+            if (t == Timeout) { return 0x01; }
+            if ((FSR[13] & 0x02) && ((FSR[16] & 0x0F) == 0x01))
+            {
+                DataLines.frequency(50000000);
+                    //increase speed if function switch was successful
+            }
+        }
+    }
+
     if (!Version)
     {
-        for (unsigned int j = 0; j < 8192; j++)
+        t = 0;
+        do
         {
             Command(16, 512, Workspace);
                 //set data-block length to 512 bytes
-            if (Workspace[0] == 0x00)
-            { break; }
-            if (j == 8191)
-            { return 0; }
-        }
+            t++;
+        } while (Workspace[0] && (t < Timeout));
+        if (t == Timeout) { return 0x01; }
     }
-        ////////////////////////////////////////////implement data block sizing later
-    return 1;
+
+    if (SelectCRCMode(0))
+    { return 0x01; }
+        //turn off CRCs
+
+    return 0x00;
 }
 
 void SDCard::Command(unsigned char Index, unsigned int Argument, unsigned char* Response)
 {
+    CommandCRC(&Index, &Argument, Workspace);
+        //calculate command CRC
     ChipSelect.write(0);
         //assert chip select low to synchronize command
     DataLines.write(0x40 | Index);
@@ -301,25 +637,22 @@
     DataLines.write(((char*)&Argument)[1]);
     DataLines.write(((char*)&Argument)[0]);
         //send the argument bytes in order from MSB to LSB (mbed is little endian)
-    if (CRCMode)
-    { DataLines.write(CommandCRC(&Index, &Argument)); }
-    else
-    { DataLines.write(0x00); }
+    DataLines.write(Workspace[0]);
         //send the command CRC
-    for (unsigned int j = 0; j < 8192; j++)
+    t = 0;
+    do
     {
         Response[0] = DataLines.write(0xFF);
             //clock the card high to let it run operations, the first byte will be
             //busy (all high), the response will be sent some time later
-        if (!(Response[0] & 0x80))
-            //check for a response by testing if the first bit is low
-        { break; }
-    }
+        t++;
+    } while ((Response[0] & 0x80) && (t < Timeout));
+        //check for a response by testing if the first bit is low
     if ((Index == 8) || (Index == 13) || (Index == 58))
     {
-        for (unsigned char j = 1; j < 5; j++)
+        for (unsigned char i = 1; i < 5; i++)
         {
-            Response[j] = DataLines.write(0xFF);
+            Response[i] = DataLines.write(0xFF);
         }
             //get the rest of the response
     }
@@ -329,66 +662,83 @@
         //clock the deselected card high to complete processing for some cards
 }
 
-char SDCard::CommandCRC(unsigned char* IndexPtr, unsigned int* ArgumentPtr)
+void SDCard::CommandCRC(unsigned char* IndexPtr, unsigned int* ArgumentPtr, unsigned char* Result)
 {
-    return
-        CommandCRCTable[
+    if (CRCMode)
+    {
+        Result[0] =
             CommandCRCTable[
                 CommandCRCTable[
                     CommandCRCTable[
                         CommandCRCTable[
-                            *IndexPtr | 0x40
-                        ] ^ ((char*)ArgumentPtr)[3]
-                    ] ^ ((char*)ArgumentPtr)[2]
-                ] ^ ((char*)ArgumentPtr)[1]
-            ] ^ ((char*)ArgumentPtr)[0]
-        ] | 0x01;
-        //using a CRC table, the CRC result of a byte is equal to the byte in the table at the
-        //address equal to the input byte, a message CRC is obtained by successively XORing these
-        //with the message bytes
+                            CommandCRCTable[
+                                *IndexPtr | 0x40
+                            ] ^ ((char*)ArgumentPtr)[3]
+                        ] ^ ((char*)ArgumentPtr)[2]
+                    ] ^ ((char*)ArgumentPtr)[1]
+                ] ^ ((char*)ArgumentPtr)[0]
+            ] | 0x01;
+    }
+    else
+    {
+        Result[0] = 0xFF;
+    }
+        //using a CRC table, the CRC result of a byte is equal to the byte
+        //in the table at the address equal to the input byte, a message CRC
+        //is obtained by successively XORing these with the message bytes
 }
 
 void SDCard::DataCRC(unsigned short Length, unsigned char* Data, unsigned char* Result)
 {
-    Result[1] = 0x00;
-    Result[2] = 0x00;
-        //initialize result carrier
-    for (int i = 0; i < Length; i++)
-        //step through each byte of the data to be checked
+    if (CRCMode)
     {
-        Result[0] = Result[1];
-            //record current crc lookup for both bytes
-        Result[1] = DataCRCTable[2 * Result[0]] ^ Result[2];
-            //new fist byte result is XORed with old second byte result
-        Result[2] = DataCRCTable[(2 * Result[0]) + 1] ^ Data[i];
-            //new second byte result is XORed with new data byte
+        unsigned char Reference;
+            //store the current CRC lookup value
+        Result[0] = 0x00;
+        Result[1] = 0x00;
+            //initialize result carrier
+        for (unsigned short i = 0; i < Length; i++)
+            //step through each byte of the data to be checked
+        {
+            Reference = Result[0];
+                //record current crc lookup for both bytes
+            Result[0] = DataCRCTable[2 * Reference] ^ Result[1];
+                //new fist byte result is XORed with old second byte result
+            Result[1] = DataCRCTable[(2 * Reference) + 1] ^ Data[i];
+                //new second byte result is XORed with new data byte
+        }
+        for (unsigned char i = 0; i < 2; i++)
+            //the final result must be XORed with two 0x00 bytes.
+        {
+            Reference = Result[0];
+            Result[0] = DataCRCTable[2 * Reference] ^ Result[1];
+            Result[1] = DataCRCTable[(2 * Reference) + 1];
+        }
     }
-    for (int i = 0; i < 2; i++)
-        //the final result must be XORed with two 0x00 bytes.
+    else
     {
-        Result[0] = Result[1];
-        Result[1] = DataCRCTable[2 * Result[0]] ^ Result[2];
-        Result[2] = DataCRCTable[(2 * Result[0]) + 1];
+        Result[0] = 0xFF;
+        Result[1] = 0xFF;
     }
 }
 
 void SDCard::GenerateCRCTable(unsigned char Size, unsigned long long Generator, unsigned char* Table)
 {
     unsigned char Index[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
-        //this will hold information from the generator; the position indicates the
-        //order of the encountered 1, the value indicates its position in the
-        //generator, the 9th entry indicates the number of 1's encountered
-    for (int i = 0; i < 64; i++)
+        //this will hold information from the generator; the position indicates
+        //the order of the encountered 1, the value indicates its position in
+        //the generator, the 9th entry indicates the number of 1's encountered
+    for (unsigned char i = 0; i < 64; i++)
     {
         if (((char*)&Generator)[7] & 0x80)
         { break; }
         Generator = Generator << 1;
             //shift generator so that the first bit is high
     }
-    for (unsigned char k = 0; k < Size; k++)
+    for (unsigned char i = 0; i < Size; i++)
     {
-        Table[k] = 0x00;
-            //initialize the first CRC bytes
+        Table[i] = 0x00;
+            //initialize table
     }
     for (unsigned char i = 0; i < 8; i++)
         //increment through each generator bit
@@ -407,8 +757,8 @@
                 //we need to perform operations for each byte in the CRC result
             {
                 Table[(Size * ((0x01 << i) + j)) + k] = Table[(Size * j) + k];
-                    //each new power is equal to all previous entries with an added xor
-                    //on the leftmost bit and each succeeding 1 on the generator
+                    //each new power is equal to all previous entries with an added
+                    //xor on the leftmost bit and each succeeding 1 on the generator
                 for (unsigned char l = 0; l < Index[8]; l++)
                     //increment through the encountered generator 1s
                 {