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:
0:f3870f76a890
Child:
1:94c648931f84
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Jul 18 21:26:24 2010 +0000
@@ -0,0 +1,547 @@
+#include "mbed.h"
+#include "stdint.h"
+
+SPI Card(p5, p6, p7);
+    //mosi, miso, sck
+DigitalOut cs(p8);
+    //chip select
+
+unsigned char OCR[4];
+    //operating condition register
+unsigned char CSD[16];
+    //card-specific data register
+bool Version;
+    //card version, low for 1, high for 2
+bool Capacity;
+    //low for low-capacity, high for high-capacity
+bool CRCMode;
+    //low to disable CRCs, high to enable CRCs
+unsigned char CommandCRCTable[256];
+    //CRC7 lookup table
+unsigned char DataCRCTable[512];
+    //CRC CCITT lookup table
+unsigned char Workspace[5];
+    //generic information holder
+
+//////////////////////////////
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+Serial Computer(USBTX, USBRX);
+    //for testing
+//////////////////////////////
+
+bool Initialize();
+bool Write(unsigned int Address, unsigned char* Data);
+bool Read(unsigned int Address, unsigned char* Data);
+void Command(unsigned char Index, unsigned int Argument, unsigned char* Response);
+char CommandCRC(unsigned char* IndexPtr, unsigned int* ArgumentPtr);
+void DataCRC(unsigned short Length, unsigned char* Data, unsigned char* Result);
+void GenerateCRCTable(unsigned char Size, unsigned long long Generator, unsigned char* Table);
+
+int main()
+{
+/////////////////////
+    led1 = 0;
+    led2 = 0;
+    led3 = 0;
+    led4 = 0;
+    Computer.baud(9600);
+        //for testing
+    unsigned char wdata[512];
+    unsigned char rdata[512];
+    int testaddress = 9;
+/////////////////////
+    
+    //Initialize();
+    
+    /*for(unsigned short j = 0; j < 512; j++)
+    {
+        wdata[j] = 0x00;
+    }
+    Write(testaddress, wdata);
+    Read(testaddress, rdata);
+    for(unsigned short j = 0; j < 512; j++)
+    {
+        Computer.putc(rdata[j]);
+    }
+    for(unsigned short j = 0; j < 512; j++)
+    {
+        wdata[j] = 0x00 + j;
+    }
+    Write(testaddress, wdata);
+    Read(testaddress, rdata);
+    for(unsigned short j = 0; j < 512; j++)
+    {
+        Computer.putc(rdata[j]);
+    }*/
+
+/////////////////////
+    if (Initialize())
+    {
+        while(1)
+        {
+            led1 = !led1;
+            wait_ms(250);
+            led2 = !led2;
+            wait_ms(250);
+            led3 = !led3;
+            wait_ms(250);
+            led4 = !led4;
+            wait_ms(250);
+        }
+    }//victory dance
+    else
+    {
+        while(1)
+        {
+            
+            led1 = !led1;
+            led2 = !led2;
+            led3 = !led3;
+            led4 = !led4;
+            wait_ms(250);
+        }
+    }//failure
+        //for testing
+/////////////////////
+}
+
+bool Initialize()
+{
+    Card.frequency(100000);
+        //set universal speed
+    cs = 1;
+        //chip select is active low
+    CRCMode = 1;
+        //turn cyclic redundancy checks on
+
+    GenerateCRCTable(1, 137, CommandCRCTable);
+        //generate the command crc lookup table
+        //(generator polynomial x^7 + x^3 + 1 converts to decimal 137)
+    GenerateCRCTable(2, 69665, DataCRCTable);
+        //generate the command crc lookup table
+        //(generator polynomial x^16 + x^12 + x^5 + 1 converts to decimal 69665)
+            
+    for (unsigned char j = 0; j < 16; j++)
+    {
+        Card.write(0xFF);
+    }
+        //perform specified power up sequence
+    
+    for (unsigned int j = 0; j < 8192; j++)
+    {
+        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; }
+    }
+    Computer.putc(0x1F);
+    Computer.putc(Workspace[0]);
+    
+    for (unsigned int j = 0; j < 8192; j++)
+    {
+        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;
+        //store card version
+    Computer.putc(0x3F);
+    Computer.putc(Workspace[0]);
+    Computer.putc(Version);
+    
+    for (unsigned int j = 0; j < 8192; j++)
+    {
+        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; }
+    }
+    Computer.putc(0x4F);
+    Computer.putc(Workspace[0]);
+    
+    for (unsigned int j = 0; j < 8192; j++)
+    {
+        Command(59, 1, Workspace);
+            //send command 59 to turn on CRCs
+    Computer.putc(Workspace[0]);
+        if (Workspace[0] == 0x01)
+        { break; }
+        if (j == 8191)
+        { return 0; }
+    }
+    Computer.putc(0x2F);
+    Computer.putc(Workspace[0]);
+    
+    for (unsigned int j = 0; j < 8192; j++)
+    {
+        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; }
+    }
+    Computer.putc(0x5F);
+    Computer.putc(Workspace[0]);
+    
+    for (unsigned int j = 0; j < 8192; j++)
+    {
+        Command(58, 0, Workspace);
+            //check the OCR again
+        if ((Workspace[0] == 0x00) && (Workspace[1] & 0x80))
+        { break; }
+        if (j == 8191)
+        { return 0; }
+    }
+    for (unsigned char j = 0; j < 4; j++)
+    {
+        OCR[j] = Workspace[j + 1];
+    }
+        //record OCR
+    Capacity = (OCR[0] & 0x40) == 0x40;
+        //record capacity
+    Computer.putc(0x6F);
+    Computer.putc(Workspace[0]);
+    Computer.putc(Capacity);
+    
+    for (unsigned int j = 0; j < 8192; j++)
+    {
+        Command(9, 0, Workspace);
+            //read the card-specific data register
+        cs = 0;
+        for (unsigned int k = 0; k < 8192; k++)
+        {
+            if (Card.write(0xFF) == 0xFE)
+            { break; }
+        }
+            //get to the start-data-block token
+        for (unsigned char k = 0; k < 16; k++)
+        {
+            CSD[k] = Card.write(0xFF);
+        }
+        Workspace[3] = Card.write(0xFF);
+        Workspace[4] = Card.write(0xFF);
+        cs = 1;
+        Card.write(0xFF);
+        DataCRC(16, CSD, Workspace);
+            //calculate the CSD data CRC
+        Workspace[0] = 0;
+        for (unsigned char k = 0; k < 15; k++)
+        {
+            Workspace[0] = CommandCRCTable[Workspace[0]] ^ CSD[k];
+        }
+        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; }
+    }
+    Computer.putc(0x7F);
+    Computer.putc(Workspace[0]);
+    Computer.putc(CSD[3] & 0x7F);
+    
+    if (((CSD[3] & 0x07) > 2) || ((CSD[3] & 0x7F) > 0x32))
+    {
+        Card.frequency(25000000);
+            //maximum speed is given at 25MHz
+    }
+    else
+    {
+       Workspace[0] = 1;
+        for (unsigned char j = 0; j < (CSD[3] & 0x07); j++)
+        {
+            Workspace[0] *= 10;
+                //the first three bits are a power of ten multiplier for speed
+        }
+        switch (CSD[3] & 0x78)
+        {
+            case 0x08: Card.frequency(Workspace[0] * 100000); break;
+            case 0x10: Card.frequency(Workspace[0] * 120000); break;
+            case 0x18: Card.frequency(Workspace[0] * 140000); break;
+            case 0x20: Card.frequency(Workspace[0] * 150000); break;
+            case 0x28: Card.frequency(Workspace[0] * 200000); break;
+            case 0x30: Card.frequency(Workspace[0] * 250000); break;
+            case 0x38: Card.frequency(Workspace[0] * 300000); break;
+            case 0x40: Card.frequency(Workspace[0] * 350000); break;
+            case 0x48: Card.frequency(Workspace[0] * 400000); break;
+            case 0x50: Card.frequency(Workspace[0] * 450000); break;
+            case 0x58: Card.frequency(Workspace[0] * 500000); break;
+            case 0x60: Card.frequency(Workspace[0] * 550000); break;
+            case 0x68: Card.frequency(Workspace[0] * 600000); break;
+            case 0x70: Card.frequency(Workspace[0] * 700000); break;
+            case 0x78: Card.frequency(Workspace[0] * 800000); break;
+            default: break;
+                //read the csd card speed bits and speed up card operations
+        }
+    }
+    
+    if (!Version)
+    {
+        for (unsigned int j = 0; j < 8192; j++)
+        {
+            Command(16, 512, Workspace);
+                //set data-block length to 512 bytes
+            if (Workspace[0] == 0x00)
+            { break; }
+            if (j == 8191)
+            { return 0; }
+        }
+    }
+    Computer.putc(0x8F);
+    Computer.putc(Workspace[0]);
+        ////////////////////////////////////////////implement data block sizing later
+    return 1;
+}
+
+bool Write(unsigned int Address, unsigned char* Data)
+{
+    if (Capacity)
+    {
+        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; }
+        }
+    }
+    cs = 0;
+    Card.write(0xFE);
+        //start data block token
+    for (unsigned short j = 0; j < 512; j++)
+    {
+        Card.write(Data[j]);
+            //write the data
+    }
+    DataCRC(512, Data, Workspace);
+    Card.write(Workspace[1]);
+    Card.write(Workspace[2]);
+    for (unsigned int j = 0; j < 8192; j++)
+    {
+        Workspace[0] = Card.write(0xFF);
+        if ((Workspace[0] & 0x1F) == 0x05)
+        { break; }
+    }
+    while (!Card.write(0xFF));
+    cs = 1;
+    Card.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;
+    }
+}
+
+bool Read(unsigned int Address, unsigned char* Data)
+{
+    if (Capacity)
+    {
+        for (unsigned int j = 0; j < 8192; j++)
+        {
+            Command(17, Address, Workspace);
+            if (Workspace[0] == 0x00)
+            { break; }
+            if (j == 8191)
+            { return 0; }
+        }
+    }
+    else
+    {
+        for (unsigned int j = 0; j < 8192; j++)
+        {
+            Command(17, Address * 512, Workspace);///////////implement block length
+            if (Workspace[0] == 0x00)
+            { break; }
+            if (j == 8191)
+            { return 0; }
+        }
+    }
+    cs = 0;
+    for (unsigned int j = 0; j < 8192; j++)
+    {
+        if (Card.write(0xFF) == 0xFE)
+        { break; }
+    }
+    for (unsigned short j = 0; j < 512; j++)
+    {
+        Data[j] = Card.write(0xFF);
+    }
+    Workspace[3] = Card.write(0xFF);
+    Workspace[4] = Card.write(0xFF);
+    cs = 1;
+    Card.write(0xFF);
+    DataCRC(512, Data, Workspace);
+    if ((Workspace[1] == Workspace[3]) && (Workspace[2] == Workspace[4]))
+    { return 1; }
+    else
+    { return 0; }
+}
+
+void Command(unsigned char Index, unsigned int Argument, unsigned char* Response)
+{
+    cs = 0;
+        //assert chip select low to synchronize command
+    Card.write(0x40 | Index);
+        //the index is assumed valid, commands start with "01b"
+    Card.write(((char*)&Argument)[3]);
+    Card.write(((char*)&Argument)[2]);
+    Card.write(((char*)&Argument)[1]);
+    Card.write(((char*)&Argument)[0]);
+        //send the argument bytes in order from MSB to LSB (mbed is little endian)
+    if (CRCMode)
+    { Card.write(CommandCRC(&Index, &Argument)); }
+    else
+    { Card.write(0x00); }
+        //send the command CRC
+    for (unsigned int j = 0; j < 8192; j++)
+    {
+        Response[0] = Card.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; }
+    }
+    if ((Index == 8) || (Index == 13) || (Index == 58))
+    {
+        for (unsigned char j = 1; j < 5; j++)
+        {
+            Response[j] = Card.write(0xFF);
+        }
+            //get the rest of the response
+    }
+    cs = 1;
+        //assert chip select high to synchronize command
+    Card.write(0xFF);
+        //clock the deselected card high to complete processing for some cards
+}
+    
+char CommandCRC(unsigned char* IndexPtr, unsigned int* ArgumentPtr)
+{
+    return
+        CommandCRCTable[
+            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
+}
+
+void 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
+    {
+        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
+    }
+    for (int i = 0; i < 2; i++)
+        //the final result must be XORed with two 0x00 bytes.
+    {
+        Result[0] = Result[1];
+        Result[1] = DataCRCTable[2 * Result[0]] ^ Result[2];
+        Result[2] = DataCRCTable[(2 * Result[0]) + 1];
+    }
+}
+
+void 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++)
+    {
+        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++)
+    {
+        Table[k] = 0x00;
+            //initialize the first CRC bytes
+    }
+    for (unsigned char i = 0; i < 8; i++)
+        //increment through each generator bit
+    {
+        if ((0x80 >> i) & ((unsigned char*)&Generator)[7])
+            //if a 1 is encountered in the generator
+        {
+            Index[Index[8]] = i;
+            Index[8]++;
+                //record its order and location and increment the counter
+        }
+        for (unsigned char j = 0; j < (0x01 << i); j++)
+            //each bit increases the number of xor operations by a power of 2
+        {
+            for (unsigned char k = 0; k < Size; k++)
+                //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
+                for (unsigned char l = 0; l < Index[8]; l++)
+                    //increment through the encountered generator 1s
+                {
+                    Table[(Size * ((0x01 << i) + j)) + k] ^= (((unsigned char*)&Generator)[7-k] << (i + 1 - Index[l]));
+                    Table[(Size * ((0x01 << i) + j)) + k] ^= (((unsigned char*)&Generator)[6-k] >> (7 - i + Index[l]));
+                        //xor the new bit and the new generator 1s
+                }
+            }
+        }
+    }
+}
\ No newline at end of file