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:
Mon Aug 23 07:12:13 2010 +0000
Revision:
3:210eb67b260c
Parent:
1:94c648931f84
Child:
4:9a5878d316d5

        

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