SD Card Interface class. Log raw data bytes to memory addresses of your choice, or format the card and use the FAT file system to write files.

Dependencies:   mbed

Committer:
Blaze513
Date:
Sat Jan 15 05:58:22 2011 +0000
Revision:
5:d85e20b6b904
Parent:
4:9a5878d316d5
Child:
6:ddf09d859ed7
Fixed CRC bug, can now run without CRCs

Who changed what in which revision?

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