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.
SDCard.cpp@6:ddf09d859ed7, 2011-01-16 (annotated)
- Committer:
- Blaze513
- Date:
- Sun Jan 16 09:20:30 2011 +0000
- Revision:
- 6:ddf09d859ed7
- Parent:
- 5:d85e20b6b904
gave access to Initialization function to FAT module.
added disk formatting functionality.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Blaze513 | 3:210eb67b260c | 1 | //mbed Microcontroller Library |
Blaze513 | 3:210eb67b260c | 2 | //SDCard Interface |
Blaze513 | 3:210eb67b260c | 3 | //Copyright 2010 |
Blaze513 | 3:210eb67b260c | 4 | //Thomas Hamilton |
Blaze513 | 3:210eb67b260c | 5 | |
Blaze513 | 0:f3870f76a890 | 6 | #include "SDCard.h" |
Blaze513 | 0:f3870f76a890 | 7 | |
Blaze513 | 5:d85e20b6b904 | 8 | SDCard::SDCard(PinName mosi, PinName miso, PinName sck, PinName cs, |
Blaze513 | 6:ddf09d859ed7 | 9 | const char* DiskName) : |
Blaze513 | 6:ddf09d859ed7 | 10 | FATFileSystem(DiskName), DataLines(mosi, miso, sck), ChipSelect(cs), |
Blaze513 | 6:ddf09d859ed7 | 11 | t(0), Timeout(1024), CRCMode(1), Capacity(0), Version(0), Status(0x00) |
Blaze513 | 6:ddf09d859ed7 | 12 | //card always starts uninitialized and in CRC mode; version 1 low-capacity |
Blaze513 | 6:ddf09d859ed7 | 13 | //card protocols are backwards-compatible with all other card protocols |
Blaze513 | 0:f3870f76a890 | 14 | { |
Blaze513 | 0:f3870f76a890 | 15 | DataLines.frequency(100000); |
Blaze513 | 0:f3870f76a890 | 16 | //set universal speed |
Blaze513 | 0:f3870f76a890 | 17 | ChipSelect.write(1); |
Blaze513 | 6:ddf09d859ed7 | 18 | //deselect the chip |
Blaze513 | 0:f3870f76a890 | 19 | GenerateCRCTable(1, 137, CommandCRCTable); |
Blaze513 | 6:ddf09d859ed7 | 20 | //generate the CRC7 lookup table; polynomial x^7 + x^3 + 1 converts to |
Blaze513 | 6:ddf09d859ed7 | 21 | //decimal 137 |
Blaze513 | 0:f3870f76a890 | 22 | GenerateCRCTable(2, 69665, DataCRCTable); |
Blaze513 | 6:ddf09d859ed7 | 23 | //generate the crc16 lookup table; polynomial x^16 + x^12 + x^5 + 1 |
Blaze513 | 6:ddf09d859ed7 | 24 | //converts to decimal 69665 |
Blaze513 | 0:f3870f76a890 | 25 | Initialize(); |
Blaze513 | 6:ddf09d859ed7 | 26 | //run setup operations |
Blaze513 | 3:210eb67b260c | 27 | } |
Blaze513 | 3:210eb67b260c | 28 | |
Blaze513 | 3:210eb67b260c | 29 | SDCard::~SDCard() |
Blaze513 | 6:ddf09d859ed7 | 30 | //delete all tables and card data registers |
Blaze513 | 3:210eb67b260c | 31 | { |
Blaze513 | 3:210eb67b260c | 32 | delete[] CommandCRCTable; |
Blaze513 | 3:210eb67b260c | 33 | delete[] DataCRCTable; |
Blaze513 | 3:210eb67b260c | 34 | delete[] OCR; |
Blaze513 | 3:210eb67b260c | 35 | delete[] CSD; |
Blaze513 | 3:210eb67b260c | 36 | delete[] FSR; |
Blaze513 | 3:210eb67b260c | 37 | delete this; |
Blaze513 | 1:94c648931f84 | 38 | } |
Blaze513 | 1:94c648931f84 | 39 | |
Blaze513 | 1:94c648931f84 | 40 | unsigned char SDCard::disk_initialize() |
Blaze513 | 6:ddf09d859ed7 | 41 | //give the FAT module access to the card setup routine |
Blaze513 | 6:ddf09d859ed7 | 42 | { |
Blaze513 | 6:ddf09d859ed7 | 43 | if (Status == 0x01) |
Blaze513 | 6:ddf09d859ed7 | 44 | { |
Blaze513 | 6:ddf09d859ed7 | 45 | return Initialize(); |
Blaze513 | 6:ddf09d859ed7 | 46 | } |
Blaze513 | 6:ddf09d859ed7 | 47 | else |
Blaze513 | 6:ddf09d859ed7 | 48 | { |
Blaze513 | 6:ddf09d859ed7 | 49 | return Status; |
Blaze513 | 6:ddf09d859ed7 | 50 | } |
Blaze513 | 6:ddf09d859ed7 | 51 | } |
Blaze513 | 1:94c648931f84 | 52 | unsigned char SDCard::disk_status() |
Blaze513 | 6:ddf09d859ed7 | 53 | //return card initialization and availability status |
Blaze513 | 6:ddf09d859ed7 | 54 | { return Status; } |
Blaze513 | 3:210eb67b260c | 55 | unsigned char SDCard::disk_read( |
Blaze513 | 3:210eb67b260c | 56 | unsigned char* buff, unsigned long sector, unsigned char count) |
Blaze513 | 6:ddf09d859ed7 | 57 | //give the FAT module access to the multiple-sector reading function |
Blaze513 | 1:94c648931f84 | 58 | { return Read((unsigned int)sector, count, buff); } |
Blaze513 | 3:210eb67b260c | 59 | unsigned char SDCard::disk_write( |
Blaze513 | 3:210eb67b260c | 60 | const unsigned char* buff, unsigned long sector, unsigned char count) |
Blaze513 | 6:ddf09d859ed7 | 61 | //give the FAT module access to the multiple-sector writing function |
Blaze513 | 1:94c648931f84 | 62 | { return Write((unsigned int)sector, count, (unsigned char*)buff); } |
Blaze513 | 1:94c648931f84 | 63 | unsigned char SDCard::disk_sync() |
Blaze513 | 6:ddf09d859ed7 | 64 | //the disk is always synchronized, so return "disk ready" |
Blaze513 | 1:94c648931f84 | 65 | { return 0x00; } |
Blaze513 | 1:94c648931f84 | 66 | unsigned long SDCard::disk_sector_count() |
Blaze513 | 6:ddf09d859ed7 | 67 | //calculate and return the number of sectors on the card from the CSD |
Blaze513 | 1:94c648931f84 | 68 | { |
Blaze513 | 1:94c648931f84 | 69 | switch (CSD[0] & 0xC0) |
Blaze513 | 1:94c648931f84 | 70 | { |
Blaze513 | 1:94c648931f84 | 71 | case 0x00: |
Blaze513 | 6:ddf09d859ed7 | 72 | //calculate sector count as specified for version 1 cards |
Blaze513 | 5:d85e20b6b904 | 73 | return ((((CSD[6] & 0x03) << 10) | (CSD[7] << 2) |
Blaze513 | 5:d85e20b6b904 | 74 | | ((CSD[8] & 0xC0) >> 6)) + 1) |
Blaze513 | 5:d85e20b6b904 | 75 | * (1 << ((((CSD[9] & 0x03) << 1) |
Blaze513 | 5:d85e20b6b904 | 76 | | ((CSD[10] & 0x80) >> 7)) + 2)); |
Blaze513 | 1:94c648931f84 | 77 | case 0x40: |
Blaze513 | 6:ddf09d859ed7 | 78 | //calculate sector count as specified for version 2 cards |
Blaze513 | 5:d85e20b6b904 | 79 | return ((((CSD[7] & 0x3F) << 16) |
Blaze513 | 5:d85e20b6b904 | 80 | | (CSD[8] << 8) | CSD[9]) + 1) * 1024; |
Blaze513 | 1:94c648931f84 | 81 | default: |
Blaze513 | 1:94c648931f84 | 82 | return 0; |
Blaze513 | 1:94c648931f84 | 83 | } |
Blaze513 | 1:94c648931f84 | 84 | } |
Blaze513 | 1:94c648931f84 | 85 | unsigned short SDCard::disk_sector_size() |
Blaze513 | 6:ddf09d859ed7 | 86 | //fix the sector size to 512 bytes for all cards versions |
Blaze513 | 1:94c648931f84 | 87 | { return 512; } |
Blaze513 | 1:94c648931f84 | 88 | unsigned long SDCard::disk_block_size() |
Blaze513 | 6:ddf09d859ed7 | 89 | //calculate and return the number of sectors in an erase block from the CSD |
Blaze513 | 1:94c648931f84 | 90 | { |
Blaze513 | 6:ddf09d859ed7 | 91 | if (Version) |
Blaze513 | 6:ddf09d859ed7 | 92 | //the erase sector size is the allocation unit for version 2 cards |
Blaze513 | 1:94c648931f84 | 93 | { |
Blaze513 | 6:ddf09d859ed7 | 94 | return 1; |
Blaze513 | 6:ddf09d859ed7 | 95 | } |
Blaze513 | 6:ddf09d859ed7 | 96 | else |
Blaze513 | 6:ddf09d859ed7 | 97 | //calculate the erase sector size for version 1 cards |
Blaze513 | 6:ddf09d859ed7 | 98 | { |
Blaze513 | 6:ddf09d859ed7 | 99 | return (CSD[10] << 1) | (CSD[11] >> 7) + 1; |
Blaze513 | 1:94c648931f84 | 100 | } |
Blaze513 | 0:f3870f76a890 | 101 | } |
Blaze513 | 6:ddf09d859ed7 | 102 | |
Blaze513 | 6:ddf09d859ed7 | 103 | unsigned char SDCard::Format(unsigned int AllocationUnit) |
Blaze513 | 6:ddf09d859ed7 | 104 | //call the FAT module formatting function |
Blaze513 | 6:ddf09d859ed7 | 105 | { |
Blaze513 | 6:ddf09d859ed7 | 106 | if (format(AllocationUnit)) |
Blaze513 | 6:ddf09d859ed7 | 107 | { |
Blaze513 | 6:ddf09d859ed7 | 108 | return 0x01; |
Blaze513 | 6:ddf09d859ed7 | 109 | } |
Blaze513 | 6:ddf09d859ed7 | 110 | else |
Blaze513 | 6:ddf09d859ed7 | 111 | { |
Blaze513 | 6:ddf09d859ed7 | 112 | return 0x00; |
Blaze513 | 6:ddf09d859ed7 | 113 | } |
Blaze513 | 6:ddf09d859ed7 | 114 | } |
Blaze513 | 0:f3870f76a890 | 115 | |
Blaze513 | 1:94c648931f84 | 116 | unsigned char SDCard::Log(unsigned char Control, unsigned char Data) |
Blaze513 | 0:f3870f76a890 | 117 | { |
Blaze513 | 6:ddf09d859ed7 | 118 | static unsigned char Workspace; |
Blaze513 | 6:ddf09d859ed7 | 119 | //work area for card commands and data transactions |
Blaze513 | 1:94c648931f84 | 120 | static unsigned short Index = 0; |
Blaze513 | 3:210eb67b260c | 121 | //store last written byte number of current memory block |
Blaze513 | 6:ddf09d859ed7 | 122 | static unsigned char Mode = 0x00; |
Blaze513 | 6:ddf09d859ed7 | 123 | //store previous operating mode to determine current behavior |
Blaze513 | 1:94c648931f84 | 124 | |
Blaze513 | 6:ddf09d859ed7 | 125 | SelectCRCMode(0); |
Blaze513 | 5:d85e20b6b904 | 126 | //CRC's are not used in raw data mode |
Blaze513 | 3:210eb67b260c | 127 | |
Blaze513 | 1:94c648931f84 | 128 | switch (Control) |
Blaze513 | 0:f3870f76a890 | 129 | { |
Blaze513 | 1:94c648931f84 | 130 | case 0x00: |
Blaze513 | 6:ddf09d859ed7 | 131 | //control code 0x00 synchronizes the card |
Blaze513 | 1:94c648931f84 | 132 | if (Mode) |
Blaze513 | 6:ddf09d859ed7 | 133 | //if the card is in read or write mode, synchronize the card |
Blaze513 | 1:94c648931f84 | 134 | { |
Blaze513 | 1:94c648931f84 | 135 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 136 | for (; Index < 512; Index++) |
Blaze513 | 6:ddf09d859ed7 | 137 | //get through the left over space, filling with 0xFF |
Blaze513 | 1:94c648931f84 | 138 | { |
Blaze513 | 1:94c648931f84 | 139 | DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 140 | } |
Blaze513 | 1:94c648931f84 | 141 | DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 142 | DataLines.write(0xFF); |
Blaze513 | 6:ddf09d859ed7 | 143 | //get through the CRC |
Blaze513 | 1:94c648931f84 | 144 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 145 | if (Mode == 0x01) |
Blaze513 | 6:ddf09d859ed7 | 146 | //if the card is in write mode, finish the current sector |
Blaze513 | 6:ddf09d859ed7 | 147 | //and finalize the writing operation |
Blaze513 | 1:94c648931f84 | 148 | { |
Blaze513 | 1:94c648931f84 | 149 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 150 | t = 0; |
Blaze513 | 1:94c648931f84 | 151 | do |
Blaze513 | 1:94c648931f84 | 152 | { |
Blaze513 | 1:94c648931f84 | 153 | t++; |
Blaze513 | 5:d85e20b6b904 | 154 | } while (((DataLines.write(0xFF) & 0x11) != 0x01) |
Blaze513 | 5:d85e20b6b904 | 155 | && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 156 | //get through the data response token |
Blaze513 | 1:94c648931f84 | 157 | while (!DataLines.write(0xFF)); |
Blaze513 | 6:ddf09d859ed7 | 158 | //get through the busy signal |
Blaze513 | 1:94c648931f84 | 159 | DataLines.write(0xFD); |
Blaze513 | 1:94c648931f84 | 160 | DataLines.write(0xFF); |
Blaze513 | 6:ddf09d859ed7 | 161 | //send the stop transmission token |
Blaze513 | 1:94c648931f84 | 162 | while (!DataLines.write(0xFF)); |
Blaze513 | 6:ddf09d859ed7 | 163 | //get through the busy signal |
Blaze513 | 1:94c648931f84 | 164 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 165 | DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 166 | } |
Blaze513 | 1:94c648931f84 | 167 | else |
Blaze513 | 6:ddf09d859ed7 | 168 | //if the card is in read mode, finish the current sector |
Blaze513 | 6:ddf09d859ed7 | 169 | //and finalize the reading operation |
Blaze513 | 1:94c648931f84 | 170 | { |
Blaze513 | 6:ddf09d859ed7 | 171 | Command(12, 0, &Workspace); |
Blaze513 | 6:ddf09d859ed7 | 172 | //send the stop transmission command |
Blaze513 | 1:94c648931f84 | 173 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 174 | while (!DataLines.write(0xFF)); |
Blaze513 | 6:ddf09d859ed7 | 175 | //get through the busy signal |
Blaze513 | 1:94c648931f84 | 176 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 177 | DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 178 | } |
Blaze513 | 1:94c648931f84 | 179 | Index = 0; |
Blaze513 | 1:94c648931f84 | 180 | Mode = 0x00; |
Blaze513 | 6:ddf09d859ed7 | 181 | //reset the index to the start and switch the mode to |
Blaze513 | 6:ddf09d859ed7 | 182 | //synchronized mode |
Blaze513 | 1:94c648931f84 | 183 | } |
Blaze513 | 1:94c648931f84 | 184 | return 0xFF; |
Blaze513 | 3:210eb67b260c | 185 | |
Blaze513 | 1:94c648931f84 | 186 | case 0x01: |
Blaze513 | 5:d85e20b6b904 | 187 | //control code 1 writes a byte |
Blaze513 | 1:94c648931f84 | 188 | if (Mode != 0x01) |
Blaze513 | 6:ddf09d859ed7 | 189 | //if the previous call was not a write operation, synchronize |
Blaze513 | 6:ddf09d859ed7 | 190 | //the card, start a new write block, and set the function to |
Blaze513 | 5:d85e20b6b904 | 191 | //write mode |
Blaze513 | 1:94c648931f84 | 192 | { |
Blaze513 | 1:94c648931f84 | 193 | Log(0, 0); |
Blaze513 | 6:ddf09d859ed7 | 194 | Command(25, 0, &Workspace); |
Blaze513 | 1:94c648931f84 | 195 | Mode = 0x01; |
Blaze513 | 1:94c648931f84 | 196 | } |
Blaze513 | 1:94c648931f84 | 197 | if (Index == 0) |
Blaze513 | 5:d85e20b6b904 | 198 | //if the index is at the start, send the start block token |
Blaze513 | 5:d85e20b6b904 | 199 | //before the byte |
Blaze513 | 1:94c648931f84 | 200 | { |
Blaze513 | 1:94c648931f84 | 201 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 202 | DataLines.write(0xFC); |
Blaze513 | 1:94c648931f84 | 203 | DataLines.write(Data); |
Blaze513 | 1:94c648931f84 | 204 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 205 | Index++; |
Blaze513 | 1:94c648931f84 | 206 | } |
Blaze513 | 1:94c648931f84 | 207 | else if (Index < 511) |
Blaze513 | 5:d85e20b6b904 | 208 | //if the index is between the boundaries, write the byte |
Blaze513 | 1:94c648931f84 | 209 | { |
Blaze513 | 1:94c648931f84 | 210 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 211 | DataLines.write(Data); |
Blaze513 | 1:94c648931f84 | 212 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 213 | Index++; |
Blaze513 | 1:94c648931f84 | 214 | } |
Blaze513 | 1:94c648931f84 | 215 | else |
Blaze513 | 6:ddf09d859ed7 | 216 | //if the index is at the last address, get through the CRC, |
Blaze513 | 6:ddf09d859ed7 | 217 | //data response token, and busy signal and reset the index |
Blaze513 | 1:94c648931f84 | 218 | { |
Blaze513 | 1:94c648931f84 | 219 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 220 | DataLines.write(Data); |
Blaze513 | 1:94c648931f84 | 221 | DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 222 | DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 223 | t = 0; |
Blaze513 | 1:94c648931f84 | 224 | do |
Blaze513 | 1:94c648931f84 | 225 | { |
Blaze513 | 1:94c648931f84 | 226 | t++; |
Blaze513 | 5:d85e20b6b904 | 227 | } while (((DataLines.write(0xFF) & 0x11) != 0x01) |
Blaze513 | 5:d85e20b6b904 | 228 | && (t < Timeout)); |
Blaze513 | 1:94c648931f84 | 229 | while (!DataLines.write(0xFF)); |
Blaze513 | 1:94c648931f84 | 230 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 231 | Index = 0; |
Blaze513 | 1:94c648931f84 | 232 | } |
Blaze513 | 1:94c648931f84 | 233 | return 0xFF; |
Blaze513 | 3:210eb67b260c | 234 | |
Blaze513 | 1:94c648931f84 | 235 | case 0x02: |
Blaze513 | 5:d85e20b6b904 | 236 | //control code 2 reads a byte |
Blaze513 | 1:94c648931f84 | 237 | if (Mode != 0x02) |
Blaze513 | 6:ddf09d859ed7 | 238 | //if the previous call was not a read operation, synchronise |
Blaze513 | 6:ddf09d859ed7 | 239 | //the card, start a new read block, and set the function to |
Blaze513 | 5:d85e20b6b904 | 240 | //read mode |
Blaze513 | 1:94c648931f84 | 241 | { |
Blaze513 | 1:94c648931f84 | 242 | Log(0, 0); |
Blaze513 | 6:ddf09d859ed7 | 243 | Command(18, 0, &Workspace); |
Blaze513 | 1:94c648931f84 | 244 | Mode = 0x02; |
Blaze513 | 1:94c648931f84 | 245 | } |
Blaze513 | 1:94c648931f84 | 246 | if (Index == 0) |
Blaze513 | 5:d85e20b6b904 | 247 | //if the index is at the start, get the start block token |
Blaze513 | 5:d85e20b6b904 | 248 | //and read the first byte |
Blaze513 | 1:94c648931f84 | 249 | { |
Blaze513 | 1:94c648931f84 | 250 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 251 | t = 0; |
Blaze513 | 1:94c648931f84 | 252 | do |
Blaze513 | 1:94c648931f84 | 253 | { |
Blaze513 | 1:94c648931f84 | 254 | t++; |
Blaze513 | 5:d85e20b6b904 | 255 | } while ((DataLines.write(0xFF) != 0xFE) |
Blaze513 | 5:d85e20b6b904 | 256 | && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 257 | Workspace = DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 258 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 259 | Index++; |
Blaze513 | 6:ddf09d859ed7 | 260 | return Workspace; |
Blaze513 | 1:94c648931f84 | 261 | } |
Blaze513 | 1:94c648931f84 | 262 | else if (Index < 511) |
Blaze513 | 5:d85e20b6b904 | 263 | //if the index is between the boundaries, read the byte |
Blaze513 | 1:94c648931f84 | 264 | { |
Blaze513 | 1:94c648931f84 | 265 | ChipSelect.write(0); |
Blaze513 | 6:ddf09d859ed7 | 266 | Workspace = DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 267 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 268 | Index++; |
Blaze513 | 6:ddf09d859ed7 | 269 | return Workspace; |
Blaze513 | 1:94c648931f84 | 270 | } |
Blaze513 | 1:94c648931f84 | 271 | else |
Blaze513 | 6:ddf09d859ed7 | 272 | //if the index is at the last address, get through the CRC and |
Blaze513 | 6:ddf09d859ed7 | 273 | //reset the index |
Blaze513 | 1:94c648931f84 | 274 | { |
Blaze513 | 1:94c648931f84 | 275 | ChipSelect.write(0); |
Blaze513 | 6:ddf09d859ed7 | 276 | Workspace = DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 277 | DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 278 | DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 279 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 280 | Index = 0; |
Blaze513 | 6:ddf09d859ed7 | 281 | return Workspace; |
Blaze513 | 1:94c648931f84 | 282 | } |
Blaze513 | 3:210eb67b260c | 283 | |
Blaze513 | 1:94c648931f84 | 284 | default: |
Blaze513 | 6:ddf09d859ed7 | 285 | //undefined control codes will only return stuff bits |
Blaze513 | 1:94c648931f84 | 286 | return 0xFF; |
Blaze513 | 0:f3870f76a890 | 287 | } |
Blaze513 | 0:f3870f76a890 | 288 | } |
Blaze513 | 0:f3870f76a890 | 289 | |
Blaze513 | 1:94c648931f84 | 290 | unsigned char SDCard::Write(unsigned int Address, unsigned char* Data) |
Blaze513 | 0:f3870f76a890 | 291 | { |
Blaze513 | 6:ddf09d859ed7 | 292 | unsigned char Workspace[2]; |
Blaze513 | 6:ddf09d859ed7 | 293 | //work area for card commands and data transactions |
Blaze513 | 6:ddf09d859ed7 | 294 | |
Blaze513 | 6:ddf09d859ed7 | 295 | if (Capacity) |
Blaze513 | 6:ddf09d859ed7 | 296 | //send the single-block write command addressed for high-capacity cards |
Blaze513 | 6:ddf09d859ed7 | 297 | { |
Blaze513 | 6:ddf09d859ed7 | 298 | Command(24, Address, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 299 | } |
Blaze513 | 6:ddf09d859ed7 | 300 | else |
Blaze513 | 6:ddf09d859ed7 | 301 | //send the single-block write command addressed for low-capacity cards |
Blaze513 | 0:f3870f76a890 | 302 | { |
Blaze513 | 1:94c648931f84 | 303 | Command(24, Address * 512, Workspace); |
Blaze513 | 0:f3870f76a890 | 304 | } |
Blaze513 | 3:210eb67b260c | 305 | if (Workspace[0]) |
Blaze513 | 6:ddf09d859ed7 | 306 | //if a command error occurs, return "parameter error" |
Blaze513 | 3:210eb67b260c | 307 | { return 0x04; } |
Blaze513 | 1:94c648931f84 | 308 | DataCRC(512, Data, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 309 | //calculate the CRC16 |
Blaze513 | 1:94c648931f84 | 310 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 311 | DataLines.write(0xFE); |
Blaze513 | 3:210eb67b260c | 312 | //write start block token |
Blaze513 | 1:94c648931f84 | 313 | for (unsigned short i = 0; i < 512; i++) |
Blaze513 | 5:d85e20b6b904 | 314 | //write the data to the addressed card sector |
Blaze513 | 1:94c648931f84 | 315 | { |
Blaze513 | 1:94c648931f84 | 316 | DataLines.write(Data[i]); |
Blaze513 | 1:94c648931f84 | 317 | } |
Blaze513 | 1:94c648931f84 | 318 | DataLines.write(Workspace[0]); |
Blaze513 | 1:94c648931f84 | 319 | DataLines.write(Workspace[1]); |
Blaze513 | 6:ddf09d859ed7 | 320 | //write the data CRC16 |
Blaze513 | 1:94c648931f84 | 321 | t = 0; |
Blaze513 | 1:94c648931f84 | 322 | do |
Blaze513 | 1:94c648931f84 | 323 | { |
Blaze513 | 1:94c648931f84 | 324 | Workspace[0] = DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 325 | t++; |
Blaze513 | 1:94c648931f84 | 326 | } while (((Workspace[0] & 0x11) != 0x01) && (t < Timeout)); |
Blaze513 | 3:210eb67b260c | 327 | //gather the data block response token |
Blaze513 | 1:94c648931f84 | 328 | while (!DataLines.write(0xFF)); |
Blaze513 | 3:210eb67b260c | 329 | //get through the busy signal |
Blaze513 | 1:94c648931f84 | 330 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 331 | DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 332 | if (((Workspace[0] & 0x1F) != 0x05) || (t == Timeout)) |
Blaze513 | 6:ddf09d859ed7 | 333 | //if the data response token indicates error, return write error |
Blaze513 | 1:94c648931f84 | 334 | { return 0x01; } |
Blaze513 | 1:94c648931f84 | 335 | else |
Blaze513 | 1:94c648931f84 | 336 | { return 0x00; } |
Blaze513 | 1:94c648931f84 | 337 | } |
Blaze513 | 5:d85e20b6b904 | 338 | unsigned char SDCard::Write( |
Blaze513 | 5:d85e20b6b904 | 339 | unsigned int Address, unsigned char SectorCount, unsigned char* Data) |
Blaze513 | 1:94c648931f84 | 340 | { |
Blaze513 | 6:ddf09d859ed7 | 341 | unsigned char Workspace[5]; |
Blaze513 | 6:ddf09d859ed7 | 342 | //work area for card commands and data transactions |
Blaze513 | 1:94c648931f84 | 343 | static unsigned char CurrentSectorCount = 1; |
Blaze513 | 3:210eb67b260c | 344 | //store the last write sector count |
Blaze513 | 6:ddf09d859ed7 | 345 | |
Blaze513 | 1:94c648931f84 | 346 | if (SectorCount != CurrentSectorCount) |
Blaze513 | 6:ddf09d859ed7 | 347 | //set the expected number of write blocks if its different from |
Blaze513 | 6:ddf09d859ed7 | 348 | //previous multiple-block write operations |
Blaze513 | 1:94c648931f84 | 349 | { |
Blaze513 | 1:94c648931f84 | 350 | Command(55, 0, Workspace); |
Blaze513 | 1:94c648931f84 | 351 | Command(23, SectorCount, Workspace); |
Blaze513 | 1:94c648931f84 | 352 | if (Workspace[0]) |
Blaze513 | 1:94c648931f84 | 353 | { return 0x04; } |
Blaze513 | 1:94c648931f84 | 354 | CurrentSectorCount = SectorCount; |
Blaze513 | 1:94c648931f84 | 355 | } |
Blaze513 | 6:ddf09d859ed7 | 356 | if (Capacity) |
Blaze513 | 6:ddf09d859ed7 | 357 | //send the multiple-block write command addressed for high-capacity |
Blaze513 | 6:ddf09d859ed7 | 358 | //cards |
Blaze513 | 6:ddf09d859ed7 | 359 | { |
Blaze513 | 6:ddf09d859ed7 | 360 | Command(25, Address, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 361 | } |
Blaze513 | 6:ddf09d859ed7 | 362 | else |
Blaze513 | 6:ddf09d859ed7 | 363 | //send the multiple-block write command addressed for low-capacity |
Blaze513 | 6:ddf09d859ed7 | 364 | //cards |
Blaze513 | 1:94c648931f84 | 365 | { |
Blaze513 | 1:94c648931f84 | 366 | Command(25, Address * 512, Workspace); |
Blaze513 | 1:94c648931f84 | 367 | } |
Blaze513 | 3:210eb67b260c | 368 | if (Workspace[0]) |
Blaze513 | 6:ddf09d859ed7 | 369 | //if a command error occurs, return "parameter error" |
Blaze513 | 3:210eb67b260c | 370 | { return 0x04; } |
Blaze513 | 1:94c648931f84 | 371 | Workspace[4] = 0x00; |
Blaze513 | 6:ddf09d859ed7 | 372 | //initialize the error detection variable |
Blaze513 | 1:94c648931f84 | 373 | for (unsigned char i = 0; i < SectorCount; i++) |
Blaze513 | 5:d85e20b6b904 | 374 | //write each data sector |
Blaze513 | 1:94c648931f84 | 375 | { |
Blaze513 | 1:94c648931f84 | 376 | DataCRC(512, &Data[i * 512], Workspace); |
Blaze513 | 6:ddf09d859ed7 | 377 | //calculate the CRC16 |
Blaze513 | 1:94c648931f84 | 378 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 379 | DataLines.write(0xFC); |
Blaze513 | 3:210eb67b260c | 380 | //send multiple write block start token |
Blaze513 | 1:94c648931f84 | 381 | for (unsigned int j = i * 512; j < (i + 1) * 512; j++) |
Blaze513 | 5:d85e20b6b904 | 382 | //write each data block |
Blaze513 | 0:f3870f76a890 | 383 | { |
Blaze513 | 1:94c648931f84 | 384 | DataLines.write(Data[j]); |
Blaze513 | 1:94c648931f84 | 385 | } |
Blaze513 | 1:94c648931f84 | 386 | DataLines.write(Workspace[0]); |
Blaze513 | 1:94c648931f84 | 387 | DataLines.write(Workspace[1]); |
Blaze513 | 6:ddf09d859ed7 | 388 | //write the CRC16 |
Blaze513 | 1:94c648931f84 | 389 | t = 0; |
Blaze513 | 1:94c648931f84 | 390 | do |
Blaze513 | 1:94c648931f84 | 391 | { |
Blaze513 | 1:94c648931f84 | 392 | Workspace[0] = DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 393 | t++; |
Blaze513 | 1:94c648931f84 | 394 | } while (((Workspace[0] & 0x11) != 0x01) && (t < Timeout)); |
Blaze513 | 5:d85e20b6b904 | 395 | //gather the data block response token |
Blaze513 | 1:94c648931f84 | 396 | while (!DataLines.write(0xFF)); |
Blaze513 | 5:d85e20b6b904 | 397 | //get through the busy signal |
Blaze513 | 1:94c648931f84 | 398 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 399 | Workspace[4] |= Workspace[0]; |
Blaze513 | 6:ddf09d859ed7 | 400 | //record if any write errors that are detected in the data response |
Blaze513 | 5:d85e20b6b904 | 401 | //tokens |
Blaze513 | 1:94c648931f84 | 402 | if (t == Timeout) |
Blaze513 | 6:ddf09d859ed7 | 403 | //if a block write operation times out, stop operations |
Blaze513 | 5:d85e20b6b904 | 404 | { break; } |
Blaze513 | 0:f3870f76a890 | 405 | } |
Blaze513 | 0:f3870f76a890 | 406 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 407 | DataLines.write(0xFD); |
Blaze513 | 1:94c648931f84 | 408 | DataLines.write(0xFF); |
Blaze513 | 6:ddf09d859ed7 | 409 | //send the stop transmission token |
Blaze513 | 1:94c648931f84 | 410 | while (!DataLines.write(0xFF)); |
Blaze513 | 6:ddf09d859ed7 | 411 | //get through the busy signal |
Blaze513 | 1:94c648931f84 | 412 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 413 | DataLines.write(0xFF); |
Blaze513 | 5:d85e20b6b904 | 414 | if (((Workspace[4] & 0x1F) != 0x05) || (t == Timeout)) |
Blaze513 | 6:ddf09d859ed7 | 415 | //if a data response token indicated an error, return "write error" |
Blaze513 | 1:94c648931f84 | 416 | { return 0x01; } |
Blaze513 | 1:94c648931f84 | 417 | else |
Blaze513 | 1:94c648931f84 | 418 | { return 0x00; } |
Blaze513 | 1:94c648931f84 | 419 | } |
Blaze513 | 1:94c648931f84 | 420 | |
Blaze513 | 1:94c648931f84 | 421 | unsigned char SDCard::Read(unsigned int Address, unsigned char* Data) |
Blaze513 | 1:94c648931f84 | 422 | { |
Blaze513 | 6:ddf09d859ed7 | 423 | unsigned char Workspace[4]; |
Blaze513 | 6:ddf09d859ed7 | 424 | //work area for card commands and data transactions |
Blaze513 | 6:ddf09d859ed7 | 425 | |
Blaze513 | 6:ddf09d859ed7 | 426 | if (Capacity) |
Blaze513 | 6:ddf09d859ed7 | 427 | //send the single-block read command addressed for high-capacity cards |
Blaze513 | 6:ddf09d859ed7 | 428 | { |
Blaze513 | 6:ddf09d859ed7 | 429 | Command(17, Address, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 430 | } |
Blaze513 | 6:ddf09d859ed7 | 431 | else |
Blaze513 | 6:ddf09d859ed7 | 432 | //send the single-block read command addressed for low-capacity cards |
Blaze513 | 0:f3870f76a890 | 433 | { |
Blaze513 | 1:94c648931f84 | 434 | Command(17, Address * 512, Workspace); |
Blaze513 | 0:f3870f76a890 | 435 | } |
Blaze513 | 3:210eb67b260c | 436 | if (Workspace[0]) |
Blaze513 | 6:ddf09d859ed7 | 437 | //if a command error occurs, return "parameter error" |
Blaze513 | 3:210eb67b260c | 438 | { return 0x04; } |
Blaze513 | 1:94c648931f84 | 439 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 440 | t = 0; |
Blaze513 | 1:94c648931f84 | 441 | do |
Blaze513 | 0:f3870f76a890 | 442 | { |
Blaze513 | 1:94c648931f84 | 443 | t++; |
Blaze513 | 1:94c648931f84 | 444 | } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 445 | //get to the start block token |
Blaze513 | 5:d85e20b6b904 | 446 | if (t == Timeout) { |
Blaze513 | 5:d85e20b6b904 | 447 | ChipSelect.write(1); DataLines.write(0xFF); return 0x01; } |
Blaze513 | 1:94c648931f84 | 448 | for (unsigned short i = 0; i < 512; i++) |
Blaze513 | 1:94c648931f84 | 449 | { |
Blaze513 | 1:94c648931f84 | 450 | Data[i] = DataLines.write(0xFF); |
Blaze513 | 0:f3870f76a890 | 451 | } |
Blaze513 | 3:210eb67b260c | 452 | //read the data from the addressed card sector |
Blaze513 | 1:94c648931f84 | 453 | Workspace[2] = DataLines.write(0xFF); |
Blaze513 | 0:f3870f76a890 | 454 | Workspace[3] = DataLines.write(0xFF); |
Blaze513 | 6:ddf09d859ed7 | 455 | //read the CRC16 |
Blaze513 | 0:f3870f76a890 | 456 | ChipSelect.write(1); |
Blaze513 | 0:f3870f76a890 | 457 | DataLines.write(0xFF); |
Blaze513 | 0:f3870f76a890 | 458 | DataCRC(512, Data, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 459 | //calculate the CRC16 |
Blaze513 | 5:d85e20b6b904 | 460 | if (CRCMode && ((Workspace[0] != Workspace[2]) |
Blaze513 | 5:d85e20b6b904 | 461 | || (Workspace[1] != Workspace[3]))) |
Blaze513 | 6:ddf09d859ed7 | 462 | //if the CRC is invalid, return "read error" |
Blaze513 | 1:94c648931f84 | 463 | { return 0x01; } |
Blaze513 | 1:94c648931f84 | 464 | else |
Blaze513 | 1:94c648931f84 | 465 | { return 0x00; } |
Blaze513 | 1:94c648931f84 | 466 | } |
Blaze513 | 5:d85e20b6b904 | 467 | unsigned char SDCard::Read( |
Blaze513 | 5:d85e20b6b904 | 468 | unsigned int Address, unsigned char SectorCount, unsigned char* Data) |
Blaze513 | 1:94c648931f84 | 469 | { |
Blaze513 | 6:ddf09d859ed7 | 470 | unsigned char Workspace[5]; |
Blaze513 | 6:ddf09d859ed7 | 471 | //work area for card commands and data transactions |
Blaze513 | 6:ddf09d859ed7 | 472 | |
Blaze513 | 6:ddf09d859ed7 | 473 | if (Capacity) |
Blaze513 | 6:ddf09d859ed7 | 474 | //send the multiple-block read command addressed for high-capacity |
Blaze513 | 6:ddf09d859ed7 | 475 | //cards |
Blaze513 | 6:ddf09d859ed7 | 476 | { |
Blaze513 | 6:ddf09d859ed7 | 477 | Command(18, Address, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 478 | } |
Blaze513 | 6:ddf09d859ed7 | 479 | else |
Blaze513 | 6:ddf09d859ed7 | 480 | //send the multiple-block read command addressed for low-capacity |
Blaze513 | 6:ddf09d859ed7 | 481 | //cards |
Blaze513 | 1:94c648931f84 | 482 | { |
Blaze513 | 1:94c648931f84 | 483 | Command(18, Address * 512, Workspace); |
Blaze513 | 1:94c648931f84 | 484 | } |
Blaze513 | 3:210eb67b260c | 485 | if (Workspace[0]) |
Blaze513 | 6:ddf09d859ed7 | 486 | //if a command error occurs, return "parameter error" |
Blaze513 | 3:210eb67b260c | 487 | { return 0; } |
Blaze513 | 1:94c648931f84 | 488 | Workspace[4] = 0x00; |
Blaze513 | 5:d85e20b6b904 | 489 | //initialize error detection variable |
Blaze513 | 1:94c648931f84 | 490 | for (unsigned char i = 0; i < SectorCount; i++) |
Blaze513 | 5:d85e20b6b904 | 491 | //read each data sector |
Blaze513 | 1:94c648931f84 | 492 | { |
Blaze513 | 1:94c648931f84 | 493 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 494 | t = 0; |
Blaze513 | 1:94c648931f84 | 495 | do |
Blaze513 | 1:94c648931f84 | 496 | { |
Blaze513 | 1:94c648931f84 | 497 | t++; |
Blaze513 | 1:94c648931f84 | 498 | } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 499 | //get to the data block start token |
Blaze513 | 1:94c648931f84 | 500 | if (t == Timeout) |
Blaze513 | 1:94c648931f84 | 501 | { |
Blaze513 | 5:d85e20b6b904 | 502 | break; |
Blaze513 | 1:94c648931f84 | 503 | } |
Blaze513 | 6:ddf09d859ed7 | 504 | //if a block read operation times out, stop operations |
Blaze513 | 1:94c648931f84 | 505 | for (unsigned int j = i * 512; j < (i + 1) * 512; j++) |
Blaze513 | 1:94c648931f84 | 506 | { |
Blaze513 | 1:94c648931f84 | 507 | Data[j] = DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 508 | } |
Blaze513 | 6:ddf09d859ed7 | 509 | //read the data block |
Blaze513 | 1:94c648931f84 | 510 | Workspace[2] = DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 511 | Workspace[3] = DataLines.write(0xFF); |
Blaze513 | 5:d85e20b6b904 | 512 | //read the data CRC from the card |
Blaze513 | 6:ddf09d859ed7 | 513 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 514 | DataCRC(512, &Data[i * 512], Workspace); |
Blaze513 | 6:ddf09d859ed7 | 515 | //calculate the CRC16 for each read data block |
Blaze513 | 5:d85e20b6b904 | 516 | Workspace[4] |= (CRCMode && ((Workspace[0] != Workspace[2]) |
Blaze513 | 5:d85e20b6b904 | 517 | || (Workspace[1] != Workspace[3]))); |
Blaze513 | 5:d85e20b6b904 | 518 | //record if any invalid CRCs are detected during the |
Blaze513 | 5:d85e20b6b904 | 519 | //transaction |
Blaze513 | 1:94c648931f84 | 520 | } |
Blaze513 | 1:94c648931f84 | 521 | Command(12, 0, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 522 | //send the stop transmission command |
Blaze513 | 1:94c648931f84 | 523 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 524 | while (!DataLines.write(0xFF)); |
Blaze513 | 6:ddf09d859ed7 | 525 | //get through the busy signal |
Blaze513 | 1:94c648931f84 | 526 | ChipSelect.write(1); |
Blaze513 | 5:d85e20b6b904 | 527 | DataLines.write(0xFF); |
Blaze513 | 5:d85e20b6b904 | 528 | if ((Workspace[4]) || (t == Timeout)) |
Blaze513 | 6:ddf09d859ed7 | 529 | //if an invalid CRC was detected, return "read error" |
Blaze513 | 1:94c648931f84 | 530 | { return 0x01; } |
Blaze513 | 1:94c648931f84 | 531 | else |
Blaze513 | 1:94c648931f84 | 532 | { return 0x00; } |
Blaze513 | 0:f3870f76a890 | 533 | } |
Blaze513 | 0:f3870f76a890 | 534 | |
Blaze513 | 1:94c648931f84 | 535 | unsigned char SDCard::SelectCRCMode(bool Mode) |
Blaze513 | 0:f3870f76a890 | 536 | { |
Blaze513 | 5:d85e20b6b904 | 537 | unsigned char Response; |
Blaze513 | 6:ddf09d859ed7 | 538 | |
Blaze513 | 5:d85e20b6b904 | 539 | if (CRCMode != Mode) |
Blaze513 | 5:d85e20b6b904 | 540 | //only send command if CRCMode has been changed |
Blaze513 | 1:94c648931f84 | 541 | { |
Blaze513 | 5:d85e20b6b904 | 542 | t = 0; |
Blaze513 | 5:d85e20b6b904 | 543 | do |
Blaze513 | 5:d85e20b6b904 | 544 | { |
Blaze513 | 5:d85e20b6b904 | 545 | Command(59, Mode, &Response); |
Blaze513 | 6:ddf09d859ed7 | 546 | //send the set CRC mode command |
Blaze513 | 5:d85e20b6b904 | 547 | t++; |
Blaze513 | 5:d85e20b6b904 | 548 | } while (Response && (t < Timeout)); |
Blaze513 | 5:d85e20b6b904 | 549 | CRCMode = Mode; |
Blaze513 | 5:d85e20b6b904 | 550 | } |
Blaze513 | 1:94c648931f84 | 551 | if (t == Timeout) |
Blaze513 | 6:ddf09d859ed7 | 552 | //if the command times out, return "error" |
Blaze513 | 1:94c648931f84 | 553 | { return 0x01; } |
Blaze513 | 1:94c648931f84 | 554 | else |
Blaze513 | 1:94c648931f84 | 555 | { return 0x00; } |
Blaze513 | 1:94c648931f84 | 556 | } |
Blaze513 | 1:94c648931f84 | 557 | |
Blaze513 | 3:210eb67b260c | 558 | void SDCard::SetTimeout(unsigned int Retries) |
Blaze513 | 3:210eb67b260c | 559 | { |
Blaze513 | 3:210eb67b260c | 560 | Timeout = Retries; |
Blaze513 | 6:ddf09d859ed7 | 561 | //Set the global number of times for operations to be retried |
Blaze513 | 3:210eb67b260c | 562 | } |
Blaze513 | 3:210eb67b260c | 563 | |
Blaze513 | 1:94c648931f84 | 564 | unsigned char SDCard::Initialize() |
Blaze513 | 1:94c648931f84 | 565 | { |
Blaze513 | 5:d85e20b6b904 | 566 | unsigned char Workspace[5]; |
Blaze513 | 6:ddf09d859ed7 | 567 | //work area for card commands and data transactions |
Blaze513 | 6:ddf09d859ed7 | 568 | |
Blaze513 | 1:94c648931f84 | 569 | for (unsigned char i = 0; i < 16; i++) |
Blaze513 | 5:d85e20b6b904 | 570 | //clock card at least 74 times to power up |
Blaze513 | 0:f3870f76a890 | 571 | { |
Blaze513 | 0:f3870f76a890 | 572 | DataLines.write(0xFF); |
Blaze513 | 0:f3870f76a890 | 573 | } |
Blaze513 | 1:94c648931f84 | 574 | |
Blaze513 | 1:94c648931f84 | 575 | t = 0; |
Blaze513 | 1:94c648931f84 | 576 | do |
Blaze513 | 0:f3870f76a890 | 577 | { |
Blaze513 | 0:f3870f76a890 | 578 | Command(0, 0, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 579 | //send the reset command to put the card into SPI mode |
Blaze513 | 1:94c648931f84 | 580 | t++; |
Blaze513 | 1:94c648931f84 | 581 | } while ((Workspace[0] != 0x01) && (t < Timeout)); |
Blaze513 | 5:d85e20b6b904 | 582 | //check for command acceptance |
Blaze513 | 6:ddf09d859ed7 | 583 | if (t == Timeout) { Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 584 | |
Blaze513 | 1:94c648931f84 | 585 | t = 0; |
Blaze513 | 1:94c648931f84 | 586 | do |
Blaze513 | 0:f3870f76a890 | 587 | { |
Blaze513 | 0:f3870f76a890 | 588 | Command(59, 1, Workspace); |
Blaze513 | 1:94c648931f84 | 589 | //turn on CRCs |
Blaze513 | 1:94c648931f84 | 590 | t++; |
Blaze513 | 5:d85e20b6b904 | 591 | } while ((Workspace[0] != 0x01) && (Workspace[0] != 0x05) |
Blaze513 | 5:d85e20b6b904 | 592 | && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 593 | //the set CRC mode command is not valid for all cards in idle state |
Blaze513 | 6:ddf09d859ed7 | 594 | if (t == Timeout) { Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 595 | |
Blaze513 | 1:94c648931f84 | 596 | t = 0; |
Blaze513 | 1:94c648931f84 | 597 | do |
Blaze513 | 0:f3870f76a890 | 598 | { |
Blaze513 | 0:f3870f76a890 | 599 | Command(8, 426, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 600 | //the voltage bits are 0x01 for 2.7V - 3.6V, the check pattern is |
Blaze513 | 6:ddf09d859ed7 | 601 | //0xAA, 0x000001AA converts to decimal 426 |
Blaze513 | 1:94c648931f84 | 602 | t++; |
Blaze513 | 1:94c648931f84 | 603 | } while (((Workspace[0] != 0x01) || ((Workspace[3] & 0x0F) != 0x01) || |
Blaze513 | 6:ddf09d859ed7 | 604 | (Workspace[4] != 0xAA)) && (Workspace[0] != 0x05) && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 605 | //check the version, voltage acceptance, and check pattern |
Blaze513 | 6:ddf09d859ed7 | 606 | if (t == Timeout) { Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 607 | Version = Workspace[0] != 0x05; |
Blaze513 | 6:ddf09d859ed7 | 608 | //store the card version |
Blaze513 | 1:94c648931f84 | 609 | |
Blaze513 | 5:d85e20b6b904 | 610 | if (!Version) |
Blaze513 | 5:d85e20b6b904 | 611 | { |
Blaze513 | 5:d85e20b6b904 | 612 | t = 0; |
Blaze513 | 5:d85e20b6b904 | 613 | do |
Blaze513 | 5:d85e20b6b904 | 614 | { |
Blaze513 | 5:d85e20b6b904 | 615 | Command(16, 512, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 616 | //set the data-block length to 512 bytes |
Blaze513 | 5:d85e20b6b904 | 617 | t++; |
Blaze513 | 5:d85e20b6b904 | 618 | } while (Workspace[0] && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 619 | if (t == Timeout) { Status = 0x01; return Status; } |
Blaze513 | 5:d85e20b6b904 | 620 | } |
Blaze513 | 5:d85e20b6b904 | 621 | |
Blaze513 | 1:94c648931f84 | 622 | t = 0; |
Blaze513 | 1:94c648931f84 | 623 | do |
Blaze513 | 0:f3870f76a890 | 624 | { |
Blaze513 | 0:f3870f76a890 | 625 | Command(58, 0, Workspace); |
Blaze513 | 0:f3870f76a890 | 626 | //check the OCR |
Blaze513 | 1:94c648931f84 | 627 | t++; |
Blaze513 | 1:94c648931f84 | 628 | } while (((Workspace[0] != 0x01) || |
Blaze513 | 6:ddf09d859ed7 | 629 | !((Workspace[2] & 0x20) || (Workspace[2] & 0x10))) && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 630 | //check for the correct operating voltage, 3.3V |
Blaze513 | 6:ddf09d859ed7 | 631 | if (t == Timeout) { Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 632 | |
Blaze513 | 1:94c648931f84 | 633 | t = 0; |
Blaze513 | 1:94c648931f84 | 634 | do |
Blaze513 | 0:f3870f76a890 | 635 | { |
Blaze513 | 0:f3870f76a890 | 636 | Command(55, 0, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 637 | //initialize card command is application-specific |
Blaze513 | 0:f3870f76a890 | 638 | Command(41, 1073741824, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 639 | //specify host supports high capacity cards, 0x40000000 converts to |
Blaze513 | 6:ddf09d859ed7 | 640 | //decimal 1073741824d |
Blaze513 | 1:94c648931f84 | 641 | t++; |
Blaze513 | 1:94c648931f84 | 642 | } while (Workspace[0] && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 643 | //check if the card is ready |
Blaze513 | 6:ddf09d859ed7 | 644 | if (t == Timeout) { Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 645 | |
Blaze513 | 1:94c648931f84 | 646 | if (SelectCRCMode(1)) |
Blaze513 | 5:d85e20b6b904 | 647 | //turn on CRCs for all cards |
Blaze513 | 6:ddf09d859ed7 | 648 | { Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 649 | |
Blaze513 | 1:94c648931f84 | 650 | t = 0; |
Blaze513 | 1:94c648931f84 | 651 | do |
Blaze513 | 0:f3870f76a890 | 652 | { |
Blaze513 | 0:f3870f76a890 | 653 | Command(58, 0, Workspace); |
Blaze513 | 0:f3870f76a890 | 654 | //check the OCR again |
Blaze513 | 1:94c648931f84 | 655 | t++; |
Blaze513 | 1:94c648931f84 | 656 | } while ((Workspace[0] || !(Workspace[1] & 0x80)) && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 657 | //check the power up status |
Blaze513 | 6:ddf09d859ed7 | 658 | if (t == Timeout) { Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 659 | for (unsigned char i = 0; i < 4; i++) |
Blaze513 | 6:ddf09d859ed7 | 660 | //record the OCR |
Blaze513 | 1:94c648931f84 | 661 | { |
Blaze513 | 1:94c648931f84 | 662 | OCR[i] = Workspace[i + 1]; |
Blaze513 | 0:f3870f76a890 | 663 | } |
Blaze513 | 0:f3870f76a890 | 664 | Capacity = (OCR[0] & 0x40) == 0x40; |
Blaze513 | 6:ddf09d859ed7 | 665 | //record the capacity |
Blaze513 | 1:94c648931f84 | 666 | |
Blaze513 | 1:94c648931f84 | 667 | t = 0; |
Blaze513 | 1:94c648931f84 | 668 | do |
Blaze513 | 0:f3870f76a890 | 669 | { |
Blaze513 | 1:94c648931f84 | 670 | do |
Blaze513 | 0:f3870f76a890 | 671 | { |
Blaze513 | 1:94c648931f84 | 672 | Command(9, 0, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 673 | //read the CSD |
Blaze513 | 1:94c648931f84 | 674 | t++; |
Blaze513 | 1:94c648931f84 | 675 | } while (Workspace[0] && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 676 | if (t == Timeout) { Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 677 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 678 | do |
Blaze513 | 1:94c648931f84 | 679 | { |
Blaze513 | 1:94c648931f84 | 680 | t++; |
Blaze513 | 1:94c648931f84 | 681 | } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 682 | //get to the start data block token |
Blaze513 | 6:ddf09d859ed7 | 683 | if (t == Timeout) { ChipSelect.write(1); DataLines.write(0xFF); |
Blaze513 | 6:ddf09d859ed7 | 684 | Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 685 | for (unsigned char i = 0; i < 16; i++) |
Blaze513 | 6:ddf09d859ed7 | 686 | //record the CSD |
Blaze513 | 0:f3870f76a890 | 687 | { |
Blaze513 | 1:94c648931f84 | 688 | CSD[i] = DataLines.write(0xFF); |
Blaze513 | 0:f3870f76a890 | 689 | } |
Blaze513 | 1:94c648931f84 | 690 | Workspace[2] = DataLines.write(0xFF); |
Blaze513 | 0:f3870f76a890 | 691 | Workspace[3] = DataLines.write(0xFF); |
Blaze513 | 6:ddf09d859ed7 | 692 | //save the CSD CRC16 |
Blaze513 | 0:f3870f76a890 | 693 | ChipSelect.write(1); |
Blaze513 | 0:f3870f76a890 | 694 | DataLines.write(0xFF); |
Blaze513 | 0:f3870f76a890 | 695 | DataCRC(16, CSD, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 696 | //calculate the CSD CRC16 |
Blaze513 | 1:94c648931f84 | 697 | Workspace[4] = 0; |
Blaze513 | 1:94c648931f84 | 698 | for (unsigned char i = 0; i < 15; i++) |
Blaze513 | 0:f3870f76a890 | 699 | { |
Blaze513 | 1:94c648931f84 | 700 | Workspace[4] = CommandCRCTable[Workspace[4]] ^ CSD[i]; |
Blaze513 | 0:f3870f76a890 | 701 | } |
Blaze513 | 1:94c648931f84 | 702 | Workspace[4] = CommandCRCTable[Workspace[4]] | 0x01; |
Blaze513 | 6:ddf09d859ed7 | 703 | //calculate the CSD CRC7 |
Blaze513 | 1:94c648931f84 | 704 | t++; |
Blaze513 | 6:ddf09d859ed7 | 705 | } while (((Workspace[0] != Workspace[2]) || (Workspace[1] != Workspace[3]) |
Blaze513 | 6:ddf09d859ed7 | 706 | || (Workspace[4] != CSD[15])) && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 707 | //perform all CSD CRCs |
Blaze513 | 6:ddf09d859ed7 | 708 | if (t == Timeout) { Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 709 | |
Blaze513 | 1:94c648931f84 | 710 | if (((CSD[3] & 0x07) > 0x02) || |
Blaze513 | 1:94c648931f84 | 711 | (((CSD[3] & 0x78) > 0x30) && ((CSD[3] & 0x07) > 0x01))) |
Blaze513 | 5:d85e20b6b904 | 712 | //read the CSD card speed bits and speed up card operations |
Blaze513 | 0:f3870f76a890 | 713 | { |
Blaze513 | 0:f3870f76a890 | 714 | DataLines.frequency(25000000); |
Blaze513 | 5:d85e20b6b904 | 715 | //maximum frequency is 25MHz |
Blaze513 | 0:f3870f76a890 | 716 | } |
Blaze513 | 0:f3870f76a890 | 717 | else |
Blaze513 | 0:f3870f76a890 | 718 | { |
Blaze513 | 5:d85e20b6b904 | 719 | Workspace[0] = 1; |
Blaze513 | 1:94c648931f84 | 720 | for (unsigned char i = 0; i < (CSD[3] & 0x07); i++) |
Blaze513 | 0:f3870f76a890 | 721 | { |
Blaze513 | 0:f3870f76a890 | 722 | Workspace[0] *= 10; |
Blaze513 | 6:ddf09d859ed7 | 723 | //the first three bits are a power of ten multiplier for speed |
Blaze513 | 0:f3870f76a890 | 724 | } |
Blaze513 | 0:f3870f76a890 | 725 | switch (CSD[3] & 0x78) |
Blaze513 | 0:f3870f76a890 | 726 | { |
Blaze513 | 0:f3870f76a890 | 727 | case 0x08: DataLines.frequency(Workspace[0] * 100000); break; |
Blaze513 | 0:f3870f76a890 | 728 | case 0x10: DataLines.frequency(Workspace[0] * 120000); break; |
Blaze513 | 0:f3870f76a890 | 729 | case 0x18: DataLines.frequency(Workspace[0] * 140000); break; |
Blaze513 | 0:f3870f76a890 | 730 | case 0x20: DataLines.frequency(Workspace[0] * 150000); break; |
Blaze513 | 0:f3870f76a890 | 731 | case 0x28: DataLines.frequency(Workspace[0] * 200000); break; |
Blaze513 | 0:f3870f76a890 | 732 | case 0x30: DataLines.frequency(Workspace[0] * 250000); break; |
Blaze513 | 0:f3870f76a890 | 733 | case 0x38: DataLines.frequency(Workspace[0] * 300000); break; |
Blaze513 | 0:f3870f76a890 | 734 | case 0x40: DataLines.frequency(Workspace[0] * 350000); break; |
Blaze513 | 0:f3870f76a890 | 735 | case 0x48: DataLines.frequency(Workspace[0] * 400000); break; |
Blaze513 | 0:f3870f76a890 | 736 | case 0x50: DataLines.frequency(Workspace[0] * 450000); break; |
Blaze513 | 0:f3870f76a890 | 737 | case 0x58: DataLines.frequency(Workspace[0] * 500000); break; |
Blaze513 | 0:f3870f76a890 | 738 | case 0x60: DataLines.frequency(Workspace[0] * 550000); break; |
Blaze513 | 0:f3870f76a890 | 739 | case 0x68: DataLines.frequency(Workspace[0] * 600000); break; |
Blaze513 | 0:f3870f76a890 | 740 | case 0x70: DataLines.frequency(Workspace[0] * 700000); break; |
Blaze513 | 0:f3870f76a890 | 741 | case 0x78: DataLines.frequency(Workspace[0] * 800000); break; |
Blaze513 | 0:f3870f76a890 | 742 | default: break; |
Blaze513 | 0:f3870f76a890 | 743 | } |
Blaze513 | 0:f3870f76a890 | 744 | } |
Blaze513 | 1:94c648931f84 | 745 | |
Blaze513 | 1:94c648931f84 | 746 | if (CSD[4] & 0x40) |
Blaze513 | 1:94c648931f84 | 747 | //check for switch command class support |
Blaze513 | 1:94c648931f84 | 748 | { |
Blaze513 | 1:94c648931f84 | 749 | t = 0; |
Blaze513 | 1:94c648931f84 | 750 | do |
Blaze513 | 1:94c648931f84 | 751 | { |
Blaze513 | 1:94c648931f84 | 752 | Command(6, 2147483649, Workspace); |
Blaze513 | 1:94c648931f84 | 753 | //switch to high-speed mode (SDR25, 50MHz) |
Blaze513 | 1:94c648931f84 | 754 | t++; |
Blaze513 | 1:94c648931f84 | 755 | } while (Workspace[0] && (Workspace[0] != 0x04) && (t < Timeout)); |
Blaze513 | 5:d85e20b6b904 | 756 | //some cards that support switch class commands respond with |
Blaze513 | 6:ddf09d859ed7 | 757 | //"illegal command" |
Blaze513 | 6:ddf09d859ed7 | 758 | if (t == Timeout) { Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 759 | if (!Workspace[0]) |
Blaze513 | 1:94c648931f84 | 760 | { |
Blaze513 | 1:94c648931f84 | 761 | do |
Blaze513 | 1:94c648931f84 | 762 | { |
Blaze513 | 1:94c648931f84 | 763 | ChipSelect.write(0); |
Blaze513 | 1:94c648931f84 | 764 | do |
Blaze513 | 1:94c648931f84 | 765 | { |
Blaze513 | 1:94c648931f84 | 766 | t++; |
Blaze513 | 1:94c648931f84 | 767 | } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 768 | //get to the start data block token |
Blaze513 | 5:d85e20b6b904 | 769 | if (t == Timeout) { ChipSelect.write(1); |
Blaze513 | 6:ddf09d859ed7 | 770 | DataLines.write(0xFF); Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 771 | for (unsigned char i = 0; i < 64; i++) |
Blaze513 | 6:ddf09d859ed7 | 772 | //gather the function status register |
Blaze513 | 1:94c648931f84 | 773 | { |
Blaze513 | 1:94c648931f84 | 774 | FSR[i] = DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 775 | } |
Blaze513 | 1:94c648931f84 | 776 | Workspace[2] = DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 777 | Workspace[3] = DataLines.write(0xFF); |
Blaze513 | 6:ddf09d859ed7 | 778 | //record the CRC16 |
Blaze513 | 1:94c648931f84 | 779 | ChipSelect.write(1); |
Blaze513 | 1:94c648931f84 | 780 | DataLines.write(0xFF); |
Blaze513 | 1:94c648931f84 | 781 | DataCRC(64, FSR, Workspace); |
Blaze513 | 6:ddf09d859ed7 | 782 | //calculate the CRC16 |
Blaze513 | 1:94c648931f84 | 783 | t++; |
Blaze513 | 5:d85e20b6b904 | 784 | } while (((Workspace[0] != Workspace[2]) |
Blaze513 | 5:d85e20b6b904 | 785 | || (Workspace[1] != Workspace[3])) && (t < Timeout)); |
Blaze513 | 6:ddf09d859ed7 | 786 | //perform the CRC |
Blaze513 | 6:ddf09d859ed7 | 787 | if (t == Timeout) { Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 788 | if ((FSR[13] & 0x02) && ((FSR[16] & 0x0F) == 0x01)) |
Blaze513 | 1:94c648931f84 | 789 | { |
Blaze513 | 1:94c648931f84 | 790 | DataLines.frequency(50000000); |
Blaze513 | 6:ddf09d859ed7 | 791 | //increase the speed if the function switch was successful |
Blaze513 | 1:94c648931f84 | 792 | } |
Blaze513 | 1:94c648931f84 | 793 | } |
Blaze513 | 1:94c648931f84 | 794 | } |
Blaze513 | 1:94c648931f84 | 795 | |
Blaze513 | 1:94c648931f84 | 796 | if (SelectCRCMode(0)) |
Blaze513 | 6:ddf09d859ed7 | 797 | { Status = 0x01; return Status; } |
Blaze513 | 1:94c648931f84 | 798 | //turn off CRCs |
Blaze513 | 1:94c648931f84 | 799 | |
Blaze513 | 6:ddf09d859ed7 | 800 | Status = 0x00; |
Blaze513 | 6:ddf09d859ed7 | 801 | return Status; |
Blaze513 | 0:f3870f76a890 | 802 | } |
Blaze513 | 0:f3870f76a890 | 803 | |
Blaze513 | 6:ddf09d859ed7 | 804 | void SDCard::Command( |
Blaze513 | 6:ddf09d859ed7 | 805 | unsigned char Index, unsigned int Argument, unsigned char* Response) |
Blaze513 | 0:f3870f76a890 | 806 | { |
Blaze513 | 5:d85e20b6b904 | 807 | CommandCRC(&Index, &Argument, Response); |
Blaze513 | 6:ddf09d859ed7 | 808 | //calculate the CRC7 |
Blaze513 | 0:f3870f76a890 | 809 | ChipSelect.write(0); |
Blaze513 | 6:ddf09d859ed7 | 810 | //assert chip select low to synchronize the command |
Blaze513 | 0:f3870f76a890 | 811 | DataLines.write(0x40 | Index); |
Blaze513 | 6:ddf09d859ed7 | 812 | //the index is assumed valid, commands start with bits 01 |
Blaze513 | 0:f3870f76a890 | 813 | DataLines.write(((char*)&Argument)[3]); |
Blaze513 | 0:f3870f76a890 | 814 | DataLines.write(((char*)&Argument)[2]); |
Blaze513 | 0:f3870f76a890 | 815 | DataLines.write(((char*)&Argument)[1]); |
Blaze513 | 0:f3870f76a890 | 816 | DataLines.write(((char*)&Argument)[0]); |
Blaze513 | 5:d85e20b6b904 | 817 | //send the argument bytes in order from MSB to LSB |
Blaze513 | 5:d85e20b6b904 | 818 | DataLines.write(*Response); |
Blaze513 | 6:ddf09d859ed7 | 819 | //send the CRC7 |
Blaze513 | 1:94c648931f84 | 820 | t = 0; |
Blaze513 | 1:94c648931f84 | 821 | do |
Blaze513 | 0:f3870f76a890 | 822 | { |
Blaze513 | 0:f3870f76a890 | 823 | Response[0] = DataLines.write(0xFF); |
Blaze513 | 5:d85e20b6b904 | 824 | //clock the card high to let it run operations, the first byte |
Blaze513 | 5:d85e20b6b904 | 825 | //will be busy (all high), the response will be sent later |
Blaze513 | 1:94c648931f84 | 826 | t++; |
Blaze513 | 1:94c648931f84 | 827 | } while ((Response[0] & 0x80) && (t < Timeout)); |
Blaze513 | 1:94c648931f84 | 828 | //check for a response by testing if the first bit is low |
Blaze513 | 0:f3870f76a890 | 829 | if ((Index == 8) || (Index == 13) || (Index == 58)) |
Blaze513 | 5:d85e20b6b904 | 830 | //if the command returns a larger response, get the rest of it |
Blaze513 | 0:f3870f76a890 | 831 | { |
Blaze513 | 1:94c648931f84 | 832 | for (unsigned char i = 1; i < 5; i++) |
Blaze513 | 0:f3870f76a890 | 833 | { |
Blaze513 | 1:94c648931f84 | 834 | Response[i] = DataLines.write(0xFF); |
Blaze513 | 0:f3870f76a890 | 835 | } |
Blaze513 | 0:f3870f76a890 | 836 | } |
Blaze513 | 0:f3870f76a890 | 837 | ChipSelect.write(1); |
Blaze513 | 0:f3870f76a890 | 838 | //assert chip select high to synchronize command |
Blaze513 | 0:f3870f76a890 | 839 | DataLines.write(0xFF); |
Blaze513 | 0:f3870f76a890 | 840 | //clock the deselected card high to complete processing for some cards |
Blaze513 | 0:f3870f76a890 | 841 | } |
Blaze513 | 0:f3870f76a890 | 842 | |
Blaze513 | 6:ddf09d859ed7 | 843 | void SDCard::CommandCRC( |
Blaze513 | 6:ddf09d859ed7 | 844 | unsigned char* IndexPtr, unsigned int* ArgumentPtr, unsigned char* Result) |
Blaze513 | 0:f3870f76a890 | 845 | { |
Blaze513 | 1:94c648931f84 | 846 | if (CRCMode) |
Blaze513 | 5:d85e20b6b904 | 847 | //only calculate if data-checks are desired |
Blaze513 | 1:94c648931f84 | 848 | { |
Blaze513 | 1:94c648931f84 | 849 | Result[0] = |
Blaze513 | 0:f3870f76a890 | 850 | CommandCRCTable[ |
Blaze513 | 0:f3870f76a890 | 851 | CommandCRCTable[ |
Blaze513 | 0:f3870f76a890 | 852 | CommandCRCTable[ |
Blaze513 | 0:f3870f76a890 | 853 | CommandCRCTable[ |
Blaze513 | 1:94c648931f84 | 854 | CommandCRCTable[ |
Blaze513 | 1:94c648931f84 | 855 | *IndexPtr | 0x40 |
Blaze513 | 1:94c648931f84 | 856 | ] ^ ((char*)ArgumentPtr)[3] |
Blaze513 | 1:94c648931f84 | 857 | ] ^ ((char*)ArgumentPtr)[2] |
Blaze513 | 1:94c648931f84 | 858 | ] ^ ((char*)ArgumentPtr)[1] |
Blaze513 | 1:94c648931f84 | 859 | ] ^ ((char*)ArgumentPtr)[0] |
Blaze513 | 1:94c648931f84 | 860 | ] | 0x01; |
Blaze513 | 6:ddf09d859ed7 | 861 | //calculate the CRC7, SD protocol requires the last bit to be high |
Blaze513 | 1:94c648931f84 | 862 | } |
Blaze513 | 1:94c648931f84 | 863 | else |
Blaze513 | 6:ddf09d859ed7 | 864 | //if no data-checking is desired, the return bits are not used |
Blaze513 | 1:94c648931f84 | 865 | { |
Blaze513 | 1:94c648931f84 | 866 | Result[0] = 0xFF; |
Blaze513 | 1:94c648931f84 | 867 | } |
Blaze513 | 0:f3870f76a890 | 868 | } |
Blaze513 | 0:f3870f76a890 | 869 | |
Blaze513 | 5:d85e20b6b904 | 870 | void SDCard::DataCRC( |
Blaze513 | 5:d85e20b6b904 | 871 | unsigned short Length, unsigned char* Data, unsigned char* Result) |
Blaze513 | 0:f3870f76a890 | 872 | { |
Blaze513 | 1:94c648931f84 | 873 | if (CRCMode) |
Blaze513 | 5:d85e20b6b904 | 874 | //only calculate if data-checks are desired |
Blaze513 | 0:f3870f76a890 | 875 | { |
Blaze513 | 1:94c648931f84 | 876 | unsigned char Reference; |
Blaze513 | 6:ddf09d859ed7 | 877 | //store the current CRC16 lookup value |
Blaze513 | 1:94c648931f84 | 878 | Result[0] = 0x00; |
Blaze513 | 1:94c648931f84 | 879 | Result[1] = 0x00; |
Blaze513 | 6:ddf09d859ed7 | 880 | //initialize the result carrier |
Blaze513 | 1:94c648931f84 | 881 | for (unsigned short i = 0; i < Length; i++) |
Blaze513 | 1:94c648931f84 | 882 | //step through each byte of the data to be checked |
Blaze513 | 1:94c648931f84 | 883 | { |
Blaze513 | 1:94c648931f84 | 884 | Reference = Result[0]; |
Blaze513 | 6:ddf09d859ed7 | 885 | //record the current CRC16 lookup for both bytes |
Blaze513 | 1:94c648931f84 | 886 | Result[0] = DataCRCTable[2 * Reference] ^ Result[1]; |
Blaze513 | 6:ddf09d859ed7 | 887 | //the first byte result is XORed with the old second byte |
Blaze513 | 1:94c648931f84 | 888 | Result[1] = DataCRCTable[(2 * Reference) + 1] ^ Data[i]; |
Blaze513 | 6:ddf09d859ed7 | 889 | //the second byte result is XORed with the new data byte |
Blaze513 | 1:94c648931f84 | 890 | } |
Blaze513 | 1:94c648931f84 | 891 | for (unsigned char i = 0; i < 2; i++) |
Blaze513 | 6:ddf09d859ed7 | 892 | //the final result must be XORed with two 0x00 bytes |
Blaze513 | 1:94c648931f84 | 893 | { |
Blaze513 | 1:94c648931f84 | 894 | Reference = Result[0]; |
Blaze513 | 1:94c648931f84 | 895 | Result[0] = DataCRCTable[2 * Reference] ^ Result[1]; |
Blaze513 | 1:94c648931f84 | 896 | Result[1] = DataCRCTable[(2 * Reference) + 1]; |
Blaze513 | 1:94c648931f84 | 897 | } |
Blaze513 | 0:f3870f76a890 | 898 | } |
Blaze513 | 1:94c648931f84 | 899 | else |
Blaze513 | 6:ddf09d859ed7 | 900 | //if no data-checking is desired, the return bits are not used |
Blaze513 | 0:f3870f76a890 | 901 | { |
Blaze513 | 1:94c648931f84 | 902 | Result[0] = 0xFF; |
Blaze513 | 1:94c648931f84 | 903 | Result[1] = 0xFF; |
Blaze513 | 0:f3870f76a890 | 904 | } |
Blaze513 | 0:f3870f76a890 | 905 | } |
Blaze513 | 0:f3870f76a890 | 906 | |
Blaze513 | 5:d85e20b6b904 | 907 | void SDCard::GenerateCRCTable(unsigned char Size, |
Blaze513 | 5:d85e20b6b904 | 908 | unsigned long long Generator, unsigned char* Table) |
Blaze513 | 0:f3870f76a890 | 909 | { |
Blaze513 | 0:f3870f76a890 | 910 | unsigned char Index[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; |
Blaze513 | 6:ddf09d859ed7 | 911 | //this will hold information from the generator; the position indicates |
Blaze513 | 6:ddf09d859ed7 | 912 | //the order of the encountered 1, the value indicates its position in |
Blaze513 | 6:ddf09d859ed7 | 913 | //the generator, the 9th entry indicates the number of 1's encountered |
Blaze513 | 6:ddf09d859ed7 | 914 | |
Blaze513 | 1:94c648931f84 | 915 | for (unsigned char i = 0; i < 64; i++) |
Blaze513 | 5:d85e20b6b904 | 916 | //shift generator left until the first bit is high |
Blaze513 | 0:f3870f76a890 | 917 | { |
Blaze513 | 0:f3870f76a890 | 918 | if (((char*)&Generator)[7] & 0x80) |
Blaze513 | 0:f3870f76a890 | 919 | { break; } |
Blaze513 | 0:f3870f76a890 | 920 | Generator = Generator << 1; |
Blaze513 | 0:f3870f76a890 | 921 | } |
Blaze513 | 1:94c648931f84 | 922 | for (unsigned char i = 0; i < Size; i++) |
Blaze513 | 5:d85e20b6b904 | 923 | //initialize table |
Blaze513 | 0:f3870f76a890 | 924 | { |
Blaze513 | 1:94c648931f84 | 925 | Table[i] = 0x00; |
Blaze513 | 0:f3870f76a890 | 926 | } |
Blaze513 | 0:f3870f76a890 | 927 | for (unsigned char i = 0; i < 8; i++) |
Blaze513 | 0:f3870f76a890 | 928 | //increment through each generator bit |
Blaze513 | 0:f3870f76a890 | 929 | { |
Blaze513 | 0:f3870f76a890 | 930 | if ((0x80 >> i) & ((unsigned char*)&Generator)[7]) |
Blaze513 | 6:ddf09d859ed7 | 931 | //if a 1 is encountered in the generator, record its order and |
Blaze513 | 6:ddf09d859ed7 | 932 | //location and increment the counter |
Blaze513 | 0:f3870f76a890 | 933 | { |
Blaze513 | 0:f3870f76a890 | 934 | Index[Index[8]] = i; |
Blaze513 | 0:f3870f76a890 | 935 | Index[8]++; |
Blaze513 | 0:f3870f76a890 | 936 | } |
Blaze513 | 0:f3870f76a890 | 937 | for (unsigned char j = 0; j < (0x01 << i); j++) |
Blaze513 | 6:ddf09d859ed7 | 938 | //each bit doubles the number of XOR operations |
Blaze513 | 0:f3870f76a890 | 939 | { |
Blaze513 | 0:f3870f76a890 | 940 | for (unsigned char k = 0; k < Size; k++) |
Blaze513 | 5:d85e20b6b904 | 941 | //we need to precalculate each byte in the CRC table |
Blaze513 | 0:f3870f76a890 | 942 | { |
Blaze513 | 5:d85e20b6b904 | 943 | Table[(Size * ((0x01 << i) + j)) + k] |
Blaze513 | 5:d85e20b6b904 | 944 | = Table[(Size * j) + k]; |
Blaze513 | 6:ddf09d859ed7 | 945 | //each power of two is equal to all previous entries with |
Blaze513 | 6:ddf09d859ed7 | 946 | //an added XOR with the generator on the leftmost bit and |
Blaze513 | 5:d85e20b6b904 | 947 | //on each succeeding 1 in the generator |
Blaze513 | 0:f3870f76a890 | 948 | for (unsigned char l = 0; l < Index[8]; l++) |
Blaze513 | 0:f3870f76a890 | 949 | //increment through the encountered generator 1s |
Blaze513 | 0:f3870f76a890 | 950 | { |
Blaze513 | 4:9a5878d316d5 | 951 | Table[(Size * ((0x01 << i) + j)) + k] ^= |
Blaze513 | 5:d85e20b6b904 | 952 | (((unsigned char*)&Generator)[7-k] |
Blaze513 | 5:d85e20b6b904 | 953 | << (i + 1 - Index[l])); |
Blaze513 | 4:9a5878d316d5 | 954 | Table[(Size * ((0x01 << i) + j)) + k] ^= |
Blaze513 | 5:d85e20b6b904 | 955 | (((unsigned char*)&Generator)[6-k] |
Blaze513 | 5:d85e20b6b904 | 956 | >> (7 - i + Index[l])); |
Blaze513 | 6:ddf09d859ed7 | 957 | //XOR the new bit and the new generator 1s |
Blaze513 | 0:f3870f76a890 | 958 | } |
Blaze513 | 0:f3870f76a890 | 959 | } |
Blaze513 | 0:f3870f76a890 | 960 | } |
Blaze513 | 0:f3870f76a890 | 961 | } |
Blaze513 | 0:f3870f76a890 | 962 | } |