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