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