Dependencies: PinDetect TextLCD mbed mRotaryEncoder
Diff: SDCard.cpp
- Revision:
- 0:afb2650fb49a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDCard.cpp Mon Feb 13 02:11:20 2012 +0000 @@ -0,0 +1,962 @@ +//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), + t(0), Timeout(1024), CRCMode(1), Capacity(0), Version(0), Status(0x00) + //card always starts uninitialized and in CRC mode; version 1 low-capacity + //card protocols are backwards-compatible with all other card protocols +{ + DataLines.frequency(100000); + //set universal speed + ChipSelect.write(1); + //deselect the chip + GenerateCRCTable(1, 137, CommandCRCTable); + //generate the CRC7 lookup table; polynomial x^7 + x^3 + 1 converts to + //decimal 137 + GenerateCRCTable(2, 69665, DataCRCTable); + //generate the crc16 lookup table; polynomial x^16 + x^12 + x^5 + 1 + //converts to decimal 69665 + Initialize(); + //run setup operations +} + +SDCard::~SDCard() + //delete all tables and card data registers +{ + delete[] CommandCRCTable; + delete[] DataCRCTable; + delete[] OCR; + delete[] CSD; + delete[] FSR; + delete this; +} + +unsigned char SDCard::disk_initialize() + //give the FAT module access to the card setup routine +{ + if (Status == 0x01) + { + return Initialize(); + } + else + { + return Status; + } +} +unsigned char SDCard::disk_status() + //return card initialization and availability status +{ return Status; } +unsigned char SDCard::disk_read( + unsigned char* buff, unsigned long sector, unsigned char count) + //give the FAT module access to the multiple-sector reading function +{ return Read((unsigned int)sector, count, buff); } +unsigned char SDCard::disk_write( + const unsigned char* buff, unsigned long sector, unsigned char count) + //give the FAT module access to the multiple-sector writing function +{ return Write((unsigned int)sector, count, (unsigned char*)buff); } +unsigned char SDCard::disk_sync() + //the disk is always synchronized, so return "disk ready" +{ return 0x00; } +unsigned long SDCard::disk_sector_count() + //calculate and return the number of sectors on the card from the CSD +{ + switch (CSD[0] & 0xC0) + { + case 0x00: + //calculate sector count as specified for version 1 cards + 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: + //calculate sector count as specified for version 2 cards + return ((((CSD[7] & 0x3F) << 16) + | (CSD[8] << 8) | CSD[9]) + 1) * 1024; + default: + return 0; + } +} +unsigned short SDCard::disk_sector_size() + //fix the sector size to 512 bytes for all cards versions +{ return 512; } +unsigned long SDCard::disk_block_size() + //calculate and return the number of sectors in an erase block from the CSD +{ + if (Version) + //the erase sector size is the allocation unit for version 2 cards + { + return 1; + } + else + //calculate the erase sector size for version 1 cards + { + return (CSD[10] << 1) | (CSD[11] >> 7) + 1; + } +} + +unsigned char SDCard::Format(unsigned int AllocationUnit) + //call the FAT module formatting function +{ + if (format(AllocationUnit)) + { + return 0x01; + } + else + { + return 0x00; + } +} + +unsigned char SDCard::Log(unsigned char Control, unsigned char Data) +{ + static unsigned char Workspace; + //work area for card commands and data transactions + static unsigned short Index = 0; + //store last written byte number of current memory block + static unsigned char Mode = 0x00; + //store previous operating mode to determine current behavior + + SelectCRCMode(0); + //CRC's are not used in raw data mode + + switch (Control) + { + case 0x00: + //control code 0x00 synchronizes the card + if (Mode) + //if the card is in read or write mode, synchronize the card + { + ChipSelect.write(0); + for (; Index < 512; Index++) + //get through the left over space, filling with 0xFF + { + DataLines.write(0xFF); + } + DataLines.write(0xFF); + DataLines.write(0xFF); + //get through the CRC + ChipSelect.write(1); + if (Mode == 0x01) + //if the card is in write mode, finish the current sector + //and finalize the writing operation + { + ChipSelect.write(0); + t = 0; + do + { + t++; + } while (((DataLines.write(0xFF) & 0x11) != 0x01) + && (t < Timeout)); + //get through the data response token + while (!DataLines.write(0xFF)); + //get through the busy signal + DataLines.write(0xFD); + DataLines.write(0xFF); + //send the stop transmission token + while (!DataLines.write(0xFF)); + //get through the busy signal + ChipSelect.write(1); + DataLines.write(0xFF); + } + else + //if the card is in read mode, finish the current sector + //and finalize the reading operation + { + Command(12, 0, &Workspace); + //send the stop transmission command + ChipSelect.write(0); + while (!DataLines.write(0xFF)); + //get through the busy signal + ChipSelect.write(1); + DataLines.write(0xFF); + } + Index = 0; + Mode = 0x00; + //reset the index to the start and switch the mode to + //synchronized mode + } + return 0xFF; + + case 0x01: + //control code 1 writes a byte + if (Mode != 0x01) + //if the previous call was not a write operation, synchronize + //the card, start a new write block, and set the function to + //write mode + { + Log(0, 0); + Command(25, 0, &Workspace); + Mode = 0x01; + } + if (Index == 0) + //if the index is at the start, send the start block token + //before the byte + { + ChipSelect.write(0); + DataLines.write(0xFC); + DataLines.write(Data); + ChipSelect.write(1); + Index++; + } + else if (Index < 511) + //if the index is between the boundaries, write the byte + { + ChipSelect.write(0); + DataLines.write(Data); + ChipSelect.write(1); + Index++; + } + else + //if the index is at the last address, get through the CRC, + //data response token, and busy signal and reset the index + { + 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: + //control code 2 reads a byte + if (Mode != 0x02) + //if the previous call was not a read operation, synchronise + //the card, start a new read block, and set the function to + //read mode + { + Log(0, 0); + Command(18, 0, &Workspace); + Mode = 0x02; + } + if (Index == 0) + //if the index is at the start, get the start block token + //and read the first byte + { + ChipSelect.write(0); + t = 0; + do + { + t++; + } while ((DataLines.write(0xFF) != 0xFE) + && (t < Timeout)); + Workspace = DataLines.write(0xFF); + ChipSelect.write(1); + Index++; + return Workspace; + } + else if (Index < 511) + //if the index is between the boundaries, read the byte + { + ChipSelect.write(0); + Workspace = DataLines.write(0xFF); + ChipSelect.write(1); + Index++; + return Workspace; + } + else + //if the index is at the last address, get through the CRC and + //reset the index + { + ChipSelect.write(0); + Workspace = DataLines.write(0xFF); + DataLines.write(0xFF); + DataLines.write(0xFF); + ChipSelect.write(1); + Index = 0; + return Workspace; + } + + default: + //undefined control codes will only return stuff bits + return 0xFF; + } +} + +unsigned char SDCard::Write(unsigned int Address, unsigned char* Data) +{ + unsigned char Workspace[2]; + //work area for card commands and data transactions + + if (Capacity) + //send the single-block write command addressed for high-capacity cards + { + Command(24, Address, Workspace); + } + else + //send the single-block write command addressed for low-capacity cards + { + Command(24, Address * 512, Workspace); + } + if (Workspace[0]) + //if a command error occurs, return "parameter error" + { return 0x04; } + DataCRC(512, Data, Workspace); + //calculate the CRC16 + ChipSelect.write(0); + DataLines.write(0xFE); + //write start block token + for (unsigned short i = 0; i < 512; i++) + //write the data to the addressed card sector + { + DataLines.write(Data[i]); + } + DataLines.write(Workspace[0]); + DataLines.write(Workspace[1]); + //write the data CRC16 + 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)) + //if the data response token indicates error, return write error + { return 0x01; } + else + { return 0x00; } +} +unsigned char SDCard::Write( + unsigned int Address, unsigned char SectorCount, unsigned char* Data) +{ + unsigned char Workspace[5]; + //work area for card commands and data transactions + static unsigned char CurrentSectorCount = 1; + //store the last write sector count + + if (SectorCount != CurrentSectorCount) + //set the expected number of write blocks if its different from + //previous multiple-block write operations + { + Command(55, 0, Workspace); + Command(23, SectorCount, Workspace); + if (Workspace[0]) + { return 0x04; } + CurrentSectorCount = SectorCount; + } + if (Capacity) + //send the multiple-block write command addressed for high-capacity + //cards + { + Command(25, Address, Workspace); + } + else + //send the multiple-block write command addressed for low-capacity + //cards + { + Command(25, Address * 512, Workspace); + } + if (Workspace[0]) + //if a command error occurs, return "parameter error" + { return 0x04; } + Workspace[4] = 0x00; + //initialize the error detection variable + for (unsigned char i = 0; i < SectorCount; i++) + //write each data sector + { + DataCRC(512, &Data[i * 512], Workspace); + //calculate the CRC16 + ChipSelect.write(0); + DataLines.write(0xFC); + //send multiple write block start token + for (unsigned int j = i * 512; j < (i + 1) * 512; j++) + //write each data block + { + DataLines.write(Data[j]); + } + DataLines.write(Workspace[0]); + DataLines.write(Workspace[1]); + //write the CRC16 + 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); + Workspace[4] |= Workspace[0]; + //record if any write errors that are detected in the data response + //tokens + if (t == Timeout) + //if a block write operation times out, stop operations + { break; } + } + ChipSelect.write(0); + DataLines.write(0xFD); + DataLines.write(0xFF); + //send the stop transmission token + while (!DataLines.write(0xFF)); + //get through the busy signal + ChipSelect.write(1); + DataLines.write(0xFF); + if (((Workspace[4] & 0x1F) != 0x05) || (t == Timeout)) + //if a data response token indicated an error, return "write error" + { return 0x01; } + else + { return 0x00; } +} + +unsigned char SDCard::Read(unsigned int Address, unsigned char* Data) +{ + unsigned char Workspace[4]; + //work area for card commands and data transactions + + if (Capacity) + //send the single-block read command addressed for high-capacity cards + { + Command(17, Address, Workspace); + } + else + //send the single-block read command addressed for low-capacity cards + { + Command(17, Address * 512, Workspace); + } + if (Workspace[0]) + //if a command error occurs, return "parameter error" + { return 0x04; } + ChipSelect.write(0); + t = 0; + do + { + t++; + } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout)); + //get to the start block token + if (t == Timeout) { + ChipSelect.write(1); DataLines.write(0xFF); return 0x01; } + 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 CRC16 + ChipSelect.write(1); + DataLines.write(0xFF); + DataCRC(512, Data, Workspace); + //calculate the CRC16 + if (CRCMode && ((Workspace[0] != Workspace[2]) + || (Workspace[1] != Workspace[3]))) + //if the CRC is invalid, return "read error" + { return 0x01; } + else + { return 0x00; } +} +unsigned char SDCard::Read( + unsigned int Address, unsigned char SectorCount, unsigned char* Data) +{ + unsigned char Workspace[5]; + //work area for card commands and data transactions + + if (Capacity) + //send the multiple-block read command addressed for high-capacity + //cards + { + Command(18, Address, Workspace); + } + else + //send the multiple-block read command addressed for low-capacity + //cards + { + Command(18, Address * 512, Workspace); + } + if (Workspace[0]) + //if a command error occurs, return "parameter error" + { return 0; } + Workspace[4] = 0x00; + //initialize error detection variable + for (unsigned char i = 0; i < SectorCount; i++) + //read each data sector + { + ChipSelect.write(0); + t = 0; + do + { + t++; + } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout)); + //get to the data block start token + if (t == Timeout) + { + break; + } + //if a block read operation times out, stop operations + for (unsigned int j = i * 512; j < (i + 1) * 512; j++) + { + Data[j] = DataLines.write(0xFF); + } + //read the data block + Workspace[2] = DataLines.write(0xFF); + Workspace[3] = DataLines.write(0xFF); + //read the data CRC from the card + ChipSelect.write(1); + DataCRC(512, &Data[i * 512], Workspace); + //calculate the CRC16 for each read data block + Workspace[4] |= (CRCMode && ((Workspace[0] != Workspace[2]) + || (Workspace[1] != Workspace[3]))); + //record if any invalid CRCs are detected during the + //transaction + } + Command(12, 0, Workspace); + //send the stop transmission command + ChipSelect.write(0); + while (!DataLines.write(0xFF)); + //get through the busy signal + ChipSelect.write(1); + DataLines.write(0xFF); + if ((Workspace[4]) || (t == Timeout)) + //if an invalid CRC was detected, return "read error" + { return 0x01; } + else + { return 0x00; } +} + +unsigned char SDCard::SelectCRCMode(bool Mode) +{ + unsigned char Response; + + if (CRCMode != Mode) + //only send command if CRCMode has been changed + { + t = 0; + do + { + Command(59, Mode, &Response); + //send the set CRC mode command + t++; + } while (Response && (t < Timeout)); + CRCMode = Mode; + } + if (t == Timeout) + //if the command times out, return "error" + { return 0x01; } + else + { return 0x00; } +} + +void SDCard::SetTimeout(unsigned int Retries) +{ + Timeout = Retries; + //Set the global number of times for operations to be retried +} + +unsigned char SDCard::Initialize() +{ + unsigned char Workspace[5]; + //work area for card commands and data transactions + + for (unsigned char i = 0; i < 16; i++) + //clock card at least 74 times to power up + { + DataLines.write(0xFF); + } + + t = 0; + do + { + Command(0, 0, Workspace); + //send the reset command to put the card into SPI mode + t++; + } while ((Workspace[0] != 0x01) && (t < Timeout)); + //check for command acceptance + if (t == Timeout) { Status = 0x01; return Status; } + + t = 0; + do + { + Command(59, 1, Workspace); + //turn on CRCs + t++; + } while ((Workspace[0] != 0x01) && (Workspace[0] != 0x05) + && (t < Timeout)); + //the set CRC mode command is not valid for all cards in idle state + if (t == Timeout) { Status = 0x01; return Status; } + + t = 0; + do + { + Command(8, 426, Workspace); + //the voltage bits are 0x01 for 2.7V - 3.6V, the check pattern is + //0xAA, 0x000001AA converts to decimal 426 + t++; + } while (((Workspace[0] != 0x01) || ((Workspace[3] & 0x0F) != 0x01) || + (Workspace[4] != 0xAA)) && (Workspace[0] != 0x05) && (t < Timeout)); + //check the version, voltage acceptance, and check pattern + if (t == Timeout) { Status = 0x01; return Status; } + Version = Workspace[0] != 0x05; + //store the card version + + if (!Version) + { + t = 0; + do + { + Command(16, 512, Workspace); + //set the data-block length to 512 bytes + t++; + } while (Workspace[0] && (t < Timeout)); + if (t == Timeout) { Status = 0x01; return Status; } + } + + t = 0; + do + { + Command(58, 0, Workspace); + //check the OCR + t++; + } while (((Workspace[0] != 0x01) || + !((Workspace[2] & 0x20) || (Workspace[2] & 0x10))) && (t < Timeout)); + //check for the correct operating voltage, 3.3V + if (t == Timeout) { Status = 0x01; return Status; } + + t = 0; + do + { + Command(55, 0, Workspace); + //initialize card command is application-specific + Command(41, 1073741824, Workspace); + //specify host supports high capacity cards, 0x40000000 converts to + //decimal 1073741824d + t++; + } while (Workspace[0] && (t < Timeout)); + //check if the card is ready + if (t == Timeout) { Status = 0x01; return Status; } + + if (SelectCRCMode(1)) + //turn on CRCs for all cards + { Status = 0x01; return Status; } + + t = 0; + do + { + Command(58, 0, Workspace); + //check the OCR again + t++; + } while ((Workspace[0] || !(Workspace[1] & 0x80)) && (t < Timeout)); + //check the power up status + if (t == Timeout) { Status = 0x01; return Status; } + for (unsigned char i = 0; i < 4; i++) + //record the OCR + { + OCR[i] = Workspace[i + 1]; + } + Capacity = (OCR[0] & 0x40) == 0x40; + //record the capacity + + t = 0; + do + { + do + { + Command(9, 0, Workspace); + //read the CSD + t++; + } while (Workspace[0] && (t < Timeout)); + if (t == Timeout) { Status = 0x01; return Status; } + 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); + Status = 0x01; return Status; } + for (unsigned char i = 0; i < 16; i++) + //record the CSD + { + CSD[i] = DataLines.write(0xFF); + } + Workspace[2] = DataLines.write(0xFF); + Workspace[3] = DataLines.write(0xFF); + //save the CSD CRC16 + ChipSelect.write(1); + DataLines.write(0xFF); + DataCRC(16, CSD, Workspace); + //calculate the CSD CRC16 + Workspace[4] = 0; + for (unsigned char i = 0; i < 15; i++) + { + Workspace[4] = CommandCRCTable[Workspace[4]] ^ CSD[i]; + } + Workspace[4] = CommandCRCTable[Workspace[4]] | 0x01; + //calculate the CSD CRC7 + t++; + } while (((Workspace[0] != Workspace[2]) || (Workspace[1] != Workspace[3]) + || (Workspace[4] != CSD[15])) && (t < Timeout)); + //perform all CSD CRCs + if (t == Timeout) { Status = 0x01; return Status; } + + if (((CSD[3] & 0x07) > 0x02) || + (((CSD[3] & 0x78) > 0x30) && ((CSD[3] & 0x07) > 0x01))) + //read the CSD card speed bits and speed up card operations + { + DataLines.frequency(25000000); + //maximum frequency is 25MHz + } + else + { + Workspace[0] = 1; + 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 + } + switch (CSD[3] & 0x78) + { + case 0x08: DataLines.frequency(Workspace[0] * 100000); break; + case 0x10: DataLines.frequency(Workspace[0] * 120000); break; + case 0x18: DataLines.frequency(Workspace[0] * 140000); break; + case 0x20: DataLines.frequency(Workspace[0] * 150000); break; + case 0x28: DataLines.frequency(Workspace[0] * 200000); break; + case 0x30: DataLines.frequency(Workspace[0] * 250000); break; + case 0x38: DataLines.frequency(Workspace[0] * 300000); break; + case 0x40: DataLines.frequency(Workspace[0] * 350000); break; + case 0x48: DataLines.frequency(Workspace[0] * 400000); break; + case 0x50: DataLines.frequency(Workspace[0] * 450000); break; + case 0x58: DataLines.frequency(Workspace[0] * 500000); break; + case 0x60: DataLines.frequency(Workspace[0] * 550000); break; + case 0x68: DataLines.frequency(Workspace[0] * 600000); break; + case 0x70: DataLines.frequency(Workspace[0] * 700000); break; + case 0x78: DataLines.frequency(Workspace[0] * 800000); break; + default: break; + } + } + + 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) { Status = 0x01; return Status; } + 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); Status = 0x01; return Status; } + for (unsigned char i = 0; i < 64; i++) + //gather the function status register + { + FSR[i] = DataLines.write(0xFF); + } + Workspace[2] = DataLines.write(0xFF); + Workspace[3] = DataLines.write(0xFF); + //record the CRC16 + ChipSelect.write(1); + DataLines.write(0xFF); + DataCRC(64, FSR, Workspace); + //calculate the CRC16 + t++; + } while (((Workspace[0] != Workspace[2]) + || (Workspace[1] != Workspace[3])) && (t < Timeout)); + //perform the CRC + if (t == Timeout) { Status = 0x01; return Status; } + if ((FSR[13] & 0x02) && ((FSR[16] & 0x0F) == 0x01)) + { + DataLines.frequency(50000000); + //increase the speed if the function switch was successful + } + } + } + + if (SelectCRCMode(0)) + { Status = 0x01; return Status; } + //turn off CRCs + + Status = 0x00; + return Status; +} + +void SDCard::Command( + unsigned char Index, unsigned int Argument, unsigned char* Response) +{ + CommandCRC(&Index, &Argument, Response); + //calculate the CRC7 + ChipSelect.write(0); + //assert chip select low to synchronize the command + DataLines.write(0x40 | Index); + //the index is assumed valid, commands start with bits 01 + DataLines.write(((char*)&Argument)[3]); + DataLines.write(((char*)&Argument)[2]); + DataLines.write(((char*)&Argument)[1]); + DataLines.write(((char*)&Argument)[0]); + //send the argument bytes in order from MSB to LSB + DataLines.write(*Response); + //send the CRC7 + 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 later + 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)) + //if the command returns a larger response, get the rest of it + { + for (unsigned char i = 1; i < 5; i++) + { + Response[i] = DataLines.write(0xFF); + } + } + ChipSelect.write(1); + //assert chip select high to synchronize command + DataLines.write(0xFF); + //clock the deselected card high to complete processing for some cards +} + +void SDCard::CommandCRC( + unsigned char* IndexPtr, unsigned int* ArgumentPtr, unsigned char* Result) +{ + if (CRCMode) + //only calculate if data-checks are desired + { + Result[0] = + CommandCRCTable[ + CommandCRCTable[ + CommandCRCTable[ + CommandCRCTable[ + CommandCRCTable[ + *IndexPtr | 0x40 + ] ^ ((char*)ArgumentPtr)[3] + ] ^ ((char*)ArgumentPtr)[2] + ] ^ ((char*)ArgumentPtr)[1] + ] ^ ((char*)ArgumentPtr)[0] + ] | 0x01; + //calculate the CRC7, SD protocol requires the last bit to be high + } + else + //if no data-checking is desired, the return bits are not used + { + Result[0] = 0xFF; + } +} + +void SDCard::DataCRC( + unsigned short Length, unsigned char* Data, unsigned char* Result) +{ + if (CRCMode) + //only calculate if data-checks are desired + { + unsigned char Reference; + //store the current CRC16 lookup value + Result[0] = 0x00; + Result[1] = 0x00; + //initialize the result carrier + for (unsigned short i = 0; i < Length; i++) + //step through each byte of the data to be checked + { + Reference = Result[0]; + //record the current CRC16 lookup for both bytes + Result[0] = DataCRCTable[2 * Reference] ^ Result[1]; + //the first byte result is XORed with the old second byte + Result[1] = DataCRCTable[(2 * Reference) + 1] ^ Data[i]; + //the second byte result is XORed with the 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]; + } + } + else + //if no data-checking is desired, the return bits are not used + { + 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 (unsigned char i = 0; i < 64; i++) + //shift generator left until the first bit is high + { + if (((char*)&Generator)[7] & 0x80) + { break; } + Generator = Generator << 1; + } + for (unsigned char i = 0; i < Size; i++) + //initialize table + { + Table[i] = 0x00; + } + 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, record its order and + //location and increment the counter + { + Index[Index[8]] = i; + Index[8]++; + } + for (unsigned char j = 0; j < (0x01 << i); j++) + //each bit doubles the number of XOR operations + { + for (unsigned char k = 0; k < Size; k++) + //we need to precalculate each byte in the CRC table + { + Table[(Size * ((0x01 << i) + j)) + k] + = Table[(Size * j) + k]; + //each power of two is equal to all previous entries with + //an added XOR with the generator on the leftmost bit and + //on each succeeding 1 in 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