Dependencies:   PinDetect TextLCD mbed mRotaryEncoder

Committer:
cicklaus
Date:
Mon Feb 13 02:11:20 2012 +0000
Revision:
0:afb2650fb49a

        

Who changed what in which revision?

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