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.
Diff: main.cpp
- 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