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:
Sun Jan 16 09:20:30 2011 +0000
Revision:
6:ddf09d859ed7
Parent:
5:d85e20b6b904
gave access to Initialization function to FAT module.
added disk formatting functionality.

Who changed what in which revision?

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