updates

Dependencies:   FATFileSystem

Fork of SDFileSystem by Neil Thiessen

Committer:
neilt6
Date:
Wed Jul 30 15:36:56 2014 +0000
Revision:
1:25f4ba436b81
Parent:
0:2a6d8a096edc
Child:
2:eec1db773e7d
Added support for normally open card detect switches

Who changed what in which revision?

UserRevisionLine numberNew contents of line
neilt6 0:2a6d8a096edc 1 /* SD/MMC File System Library
neilt6 0:2a6d8a096edc 2 * Copyright (c) 2014 Neil Thiessen
neilt6 0:2a6d8a096edc 3 *
neilt6 0:2a6d8a096edc 4 * Licensed under the Apache License, Version 2.0 (the "License");
neilt6 0:2a6d8a096edc 5 * you may not use this file except in compliance with the License.
neilt6 0:2a6d8a096edc 6 * You may obtain a copy of the License at
neilt6 0:2a6d8a096edc 7 *
neilt6 0:2a6d8a096edc 8 * http://www.apache.org/licenses/LICENSE-2.0
neilt6 0:2a6d8a096edc 9 *
neilt6 0:2a6d8a096edc 10 * Unless required by applicable law or agreed to in writing, software
neilt6 0:2a6d8a096edc 11 * distributed under the License is distributed on an "AS IS" BASIS,
neilt6 0:2a6d8a096edc 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
neilt6 0:2a6d8a096edc 13 * See the License for the specific language governing permissions and
neilt6 0:2a6d8a096edc 14 * limitations under the License.
neilt6 0:2a6d8a096edc 15 */
neilt6 0:2a6d8a096edc 16
neilt6 0:2a6d8a096edc 17 #include "SDFileSystem.h"
neilt6 0:2a6d8a096edc 18 #include "diskio.h"
neilt6 0:2a6d8a096edc 19 #include "CRC7.h"
neilt6 0:2a6d8a096edc 20 #include "CRC16.h"
neilt6 0:2a6d8a096edc 21
neilt6 1:25f4ba436b81 22 SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName cd, const char* name, SwitchType cdtype, int hz) : FATFileSystem(name), m_SPI(mosi, miso, sclk), m_CS(cs, 1), m_CD(cd), m_CD_ASSERT((int)cdtype)
neilt6 0:2a6d8a096edc 23 {
neilt6 0:2a6d8a096edc 24 //Initialize the member variables
neilt6 0:2a6d8a096edc 25 m_SpiFreq = hz;
neilt6 0:2a6d8a096edc 26 m_Status = STA_NOINIT;
neilt6 0:2a6d8a096edc 27 m_CardType = CARD_NONE;
neilt6 0:2a6d8a096edc 28
neilt6 0:2a6d8a096edc 29 //Configure the SPI bus
neilt6 0:2a6d8a096edc 30 m_SPI.format(8, 0);
neilt6 0:2a6d8a096edc 31
neilt6 0:2a6d8a096edc 32 //Configure the card detect pin
neilt6 0:2a6d8a096edc 33 m_CD.mode(PullUp);
neilt6 1:25f4ba436b81 34 if (cdtype == SWITCH_NO)
neilt6 1:25f4ba436b81 35 m_CD.rise(this, &SDFileSystem::checkSocket);
neilt6 1:25f4ba436b81 36 else
neilt6 1:25f4ba436b81 37 m_CD.fall(this, &SDFileSystem::checkSocket);
neilt6 0:2a6d8a096edc 38 }
neilt6 0:2a6d8a096edc 39
neilt6 0:2a6d8a096edc 40 SDFileSystem::CardType SDFileSystem::card_type()
neilt6 0:2a6d8a096edc 41 {
neilt6 0:2a6d8a096edc 42 //Check the card socket
neilt6 0:2a6d8a096edc 43 checkSocket();
neilt6 0:2a6d8a096edc 44
neilt6 0:2a6d8a096edc 45 //If a card is present but not initialized, initialize it
neilt6 0:2a6d8a096edc 46 if (!(m_Status & STA_NODISK) && (m_Status & STA_NOINIT))
neilt6 0:2a6d8a096edc 47 disk_initialize();
neilt6 0:2a6d8a096edc 48
neilt6 0:2a6d8a096edc 49 //Return the card type
neilt6 0:2a6d8a096edc 50 return m_CardType;
neilt6 0:2a6d8a096edc 51 }
neilt6 0:2a6d8a096edc 52
neilt6 0:2a6d8a096edc 53 int SDFileSystem::disk_initialize()
neilt6 0:2a6d8a096edc 54 {
neilt6 0:2a6d8a096edc 55 char resp;
neilt6 0:2a6d8a096edc 56
neilt6 0:2a6d8a096edc 57 //Make sure there's a card in the socket before proceeding
neilt6 0:2a6d8a096edc 58 checkSocket();
neilt6 0:2a6d8a096edc 59 if (m_Status & STA_NODISK)
neilt6 0:2a6d8a096edc 60 return m_Status;
neilt6 0:2a6d8a096edc 61
neilt6 0:2a6d8a096edc 62 //Make sure we're not already initialized before proceeding
neilt6 0:2a6d8a096edc 63 if (!(m_Status & STA_NOINIT))
neilt6 0:2a6d8a096edc 64 return m_Status;
neilt6 0:2a6d8a096edc 65
neilt6 0:2a6d8a096edc 66 //Set the SPI frequency to 100kHz for initialization
neilt6 0:2a6d8a096edc 67 m_SPI.frequency(100000);
neilt6 0:2a6d8a096edc 68
neilt6 0:2a6d8a096edc 69 //Send 80 dummy clocks with /CS and DI held high
neilt6 0:2a6d8a096edc 70 m_CS = 1;
neilt6 0:2a6d8a096edc 71 for (int i = 0; i < 10; i++)
neilt6 0:2a6d8a096edc 72 m_SPI.write(0xFF);
neilt6 0:2a6d8a096edc 73
neilt6 0:2a6d8a096edc 74 //Write CMD0(0), and check for a valid response
neilt6 0:2a6d8a096edc 75 resp = writeCommand(CMD0, 0);
neilt6 0:2a6d8a096edc 76 if (resp != 0x01) {
neilt6 0:2a6d8a096edc 77 //Initialization failed
neilt6 0:2a6d8a096edc 78 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 79 return m_Status;
neilt6 0:2a6d8a096edc 80 }
neilt6 0:2a6d8a096edc 81
neilt6 0:2a6d8a096edc 82 //Write CMD8(0x000001AA) to see if this is an SDCv2 card
neilt6 0:2a6d8a096edc 83 resp = writeCommand(CMD8, 0x000001AA);
neilt6 0:2a6d8a096edc 84 if (resp == 0x01) {
neilt6 0:2a6d8a096edc 85 //This is an SDCv2 card, get the 32-bit return value and verify the voltage range/check pattern
neilt6 0:2a6d8a096edc 86 if ((readReturn() & 0xFFF) != 0x1AA) {
neilt6 0:2a6d8a096edc 87 //Initialization failed
neilt6 0:2a6d8a096edc 88 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 89 return m_Status;
neilt6 0:2a6d8a096edc 90 }
neilt6 0:2a6d8a096edc 91
neilt6 0:2a6d8a096edc 92 //Send CMD58(0) to read the OCR, and verify that the card supports 3.2-3.3V
neilt6 0:2a6d8a096edc 93 resp = writeCommand(CMD58, 0);
neilt6 0:2a6d8a096edc 94 if (resp != 0x01 || !(readReturn() & (1 << 20))) {
neilt6 0:2a6d8a096edc 95 //Initialization failed
neilt6 0:2a6d8a096edc 96 deselect();
neilt6 0:2a6d8a096edc 97 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 98 return m_Status;
neilt6 0:2a6d8a096edc 99 }
neilt6 0:2a6d8a096edc 100
neilt6 0:2a6d8a096edc 101 //Send ACMD41(0x40100000) repeatedly for up to 1 second to initialize the card
neilt6 0:2a6d8a096edc 102 for (int i = 0; i < 1000; i++) {
neilt6 0:2a6d8a096edc 103 resp = writeCommand(ACMD41, 0x40100000);
neilt6 0:2a6d8a096edc 104 if (resp != 0x01)
neilt6 0:2a6d8a096edc 105 break;
neilt6 0:2a6d8a096edc 106 wait_ms(1);
neilt6 0:2a6d8a096edc 107 }
neilt6 0:2a6d8a096edc 108
neilt6 0:2a6d8a096edc 109 //Check if the card initialized
neilt6 0:2a6d8a096edc 110 if (resp != 0x00) {
neilt6 0:2a6d8a096edc 111 //Initialization failed
neilt6 0:2a6d8a096edc 112 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 113 return m_Status;
neilt6 0:2a6d8a096edc 114 }
neilt6 0:2a6d8a096edc 115
neilt6 0:2a6d8a096edc 116 //Send CMD58(0) to read the OCR
neilt6 0:2a6d8a096edc 117 resp = writeCommand(CMD58, 0);
neilt6 0:2a6d8a096edc 118 if (resp == 0x00) {
neilt6 0:2a6d8a096edc 119 //Check the CCS bit to determine if this is a high capacity card
neilt6 0:2a6d8a096edc 120 if (readReturn() & 0x40000000)
neilt6 0:2a6d8a096edc 121 m_CardType = CARD_SDHC;
neilt6 0:2a6d8a096edc 122 else
neilt6 0:2a6d8a096edc 123 m_CardType = CARD_SD;
neilt6 0:2a6d8a096edc 124 } else {
neilt6 0:2a6d8a096edc 125 //Initialization failed
neilt6 0:2a6d8a096edc 126 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 127 return m_Status;
neilt6 0:2a6d8a096edc 128 }
neilt6 0:2a6d8a096edc 129 } else {
neilt6 0:2a6d8a096edc 130 //Didn't respond or illegal command, this is either an SDCv1 or MMC card
neilt6 0:2a6d8a096edc 131 deselect();
neilt6 0:2a6d8a096edc 132
neilt6 0:2a6d8a096edc 133 //Send CMD58(0) to read the OCR, and verify that the card supports 3.2-3.3V
neilt6 0:2a6d8a096edc 134 resp = writeCommand(CMD58, 0);
neilt6 0:2a6d8a096edc 135 if (resp != 0x01 || !(readReturn() & (1 << 20))) {
neilt6 0:2a6d8a096edc 136 //Initialization failed
neilt6 0:2a6d8a096edc 137 deselect();
neilt6 0:2a6d8a096edc 138 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 139 return m_Status;
neilt6 0:2a6d8a096edc 140 }
neilt6 0:2a6d8a096edc 141
neilt6 0:2a6d8a096edc 142 //Try to initialize the card using ACMD41(0x00100000) for 1 second
neilt6 0:2a6d8a096edc 143 for (int i = 0; i < 1000; i++) {
neilt6 0:2a6d8a096edc 144 resp = writeCommand(ACMD41, 0x00100000);
neilt6 0:2a6d8a096edc 145 if (resp != 0x01)
neilt6 0:2a6d8a096edc 146 break;
neilt6 0:2a6d8a096edc 147 wait_ms(1);
neilt6 0:2a6d8a096edc 148 }
neilt6 0:2a6d8a096edc 149
neilt6 0:2a6d8a096edc 150 //Check if the card initialized
neilt6 0:2a6d8a096edc 151 if (resp == 0x00) {
neilt6 0:2a6d8a096edc 152 //This is an SDCv1 standard capacity card
neilt6 0:2a6d8a096edc 153 m_CardType = CARD_SD;
neilt6 0:2a6d8a096edc 154 } else {
neilt6 0:2a6d8a096edc 155 //Try to initialize the card using CMD1(0x00100000) for 1 second
neilt6 0:2a6d8a096edc 156 for (int i = 0; i < 1000; i++) {
neilt6 0:2a6d8a096edc 157 resp = writeCommand(CMD1, 0x00100000);
neilt6 0:2a6d8a096edc 158 if (resp != 0x01)
neilt6 0:2a6d8a096edc 159 break;
neilt6 0:2a6d8a096edc 160 wait_ms(1);
neilt6 0:2a6d8a096edc 161 }
neilt6 0:2a6d8a096edc 162
neilt6 0:2a6d8a096edc 163 //Check if the card initialized
neilt6 0:2a6d8a096edc 164 if (resp == 0x00) {
neilt6 0:2a6d8a096edc 165 //This is an MMCv3 card
neilt6 0:2a6d8a096edc 166 m_CardType = CARD_MMC;
neilt6 0:2a6d8a096edc 167 } else {
neilt6 0:2a6d8a096edc 168 //Initialization failed
neilt6 0:2a6d8a096edc 169 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 170 return m_Status;
neilt6 0:2a6d8a096edc 171 }
neilt6 0:2a6d8a096edc 172 }
neilt6 0:2a6d8a096edc 173 }
neilt6 0:2a6d8a096edc 174
neilt6 0:2a6d8a096edc 175 //Send CMD59(0x00000001) to re-enable CRC
neilt6 0:2a6d8a096edc 176 resp = writeCommand(CMD59, 0x00000001);
neilt6 0:2a6d8a096edc 177 if (resp != 0x00) {
neilt6 0:2a6d8a096edc 178 //Initialization failed
neilt6 0:2a6d8a096edc 179 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 180 return m_Status;
neilt6 0:2a6d8a096edc 181 }
neilt6 0:2a6d8a096edc 182
neilt6 0:2a6d8a096edc 183 //Send CMD16(0x00000200) to force the block size to 512B if necessary
neilt6 0:2a6d8a096edc 184 if (m_CardType != CARD_SDHC) {
neilt6 0:2a6d8a096edc 185 resp = writeCommand(CMD16, 0x00000200);
neilt6 0:2a6d8a096edc 186 if (resp != 0x00) {
neilt6 0:2a6d8a096edc 187 //Initialization failed
neilt6 0:2a6d8a096edc 188 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 189 return m_Status;
neilt6 0:2a6d8a096edc 190 }
neilt6 0:2a6d8a096edc 191 }
neilt6 0:2a6d8a096edc 192
neilt6 0:2a6d8a096edc 193 //The card is now initialized
neilt6 0:2a6d8a096edc 194 m_Status &= ~STA_NOINIT;
neilt6 0:2a6d8a096edc 195
neilt6 0:2a6d8a096edc 196 //Increase the SPI frequency to full speed (limited to 20MHz for MMC, or 25MHz for SDC)
neilt6 0:2a6d8a096edc 197 if (m_CardType == CARD_MMC && m_SpiFreq > 20000000)
neilt6 0:2a6d8a096edc 198 m_SPI.frequency(20000000);
neilt6 0:2a6d8a096edc 199 else if (m_SpiFreq > 25000000)
neilt6 0:2a6d8a096edc 200 m_SPI.frequency(25000000);
neilt6 0:2a6d8a096edc 201 else
neilt6 0:2a6d8a096edc 202 m_SPI.frequency(m_SpiFreq);
neilt6 0:2a6d8a096edc 203
neilt6 0:2a6d8a096edc 204 //Return the device status
neilt6 0:2a6d8a096edc 205 return m_Status;
neilt6 0:2a6d8a096edc 206 }
neilt6 0:2a6d8a096edc 207
neilt6 0:2a6d8a096edc 208 int SDFileSystem::disk_status()
neilt6 0:2a6d8a096edc 209 {
neilt6 0:2a6d8a096edc 210 //Check if there's a card in the socket
neilt6 0:2a6d8a096edc 211 checkSocket();
neilt6 0:2a6d8a096edc 212
neilt6 0:2a6d8a096edc 213 //Return the device status
neilt6 0:2a6d8a096edc 214 return m_Status;
neilt6 0:2a6d8a096edc 215 }
neilt6 0:2a6d8a096edc 216
neilt6 0:2a6d8a096edc 217 int SDFileSystem::disk_read(uint8_t* buffer, uint64_t sector)
neilt6 0:2a6d8a096edc 218 {
neilt6 0:2a6d8a096edc 219 //Make sure the device is initialized before proceeding
neilt6 0:2a6d8a096edc 220 if (m_Status & STA_NOINIT)
neilt6 0:2a6d8a096edc 221 return RES_NOTRDY;
neilt6 0:2a6d8a096edc 222
neilt6 0:2a6d8a096edc 223 //Convert from LBA to a byte address for standard capacity cards
neilt6 0:2a6d8a096edc 224 if (m_CardType != CARD_SDHC)
neilt6 0:2a6d8a096edc 225 sector *= 512;
neilt6 0:2a6d8a096edc 226
neilt6 0:2a6d8a096edc 227 //Try to read the block up to 3 times
neilt6 0:2a6d8a096edc 228 for (int i = 0; i < 3; i++) {
neilt6 0:2a6d8a096edc 229 //Send CMD17(sector) to read a single block
neilt6 0:2a6d8a096edc 230 char resp = writeCommand(CMD17, sector);
neilt6 0:2a6d8a096edc 231 if (resp == 0x00) {
neilt6 0:2a6d8a096edc 232 //Try to read the sector, and return if successful
neilt6 0:2a6d8a096edc 233 if (readData((char*)buffer, 512))
neilt6 0:2a6d8a096edc 234 return RES_OK;
neilt6 0:2a6d8a096edc 235 } else {
neilt6 0:2a6d8a096edc 236 //The command failed
neilt6 0:2a6d8a096edc 237 deselect();
neilt6 0:2a6d8a096edc 238 return RES_ERROR;
neilt6 0:2a6d8a096edc 239 }
neilt6 0:2a6d8a096edc 240 }
neilt6 0:2a6d8a096edc 241
neilt6 0:2a6d8a096edc 242 //The read operation failed 3 times (CRC most likely)
neilt6 0:2a6d8a096edc 243 return RES_ERROR;
neilt6 0:2a6d8a096edc 244 }
neilt6 0:2a6d8a096edc 245
neilt6 0:2a6d8a096edc 246 int SDFileSystem::disk_write(const uint8_t* buffer, uint64_t sector)
neilt6 0:2a6d8a096edc 247 {
neilt6 0:2a6d8a096edc 248 //Make sure the device is initialized before proceeding
neilt6 0:2a6d8a096edc 249 if (m_Status & STA_NOINIT)
neilt6 0:2a6d8a096edc 250 return RES_NOTRDY;
neilt6 0:2a6d8a096edc 251
neilt6 0:2a6d8a096edc 252 //Make sure the device isn't write protected before proceeding
neilt6 0:2a6d8a096edc 253 if (m_Status & STA_PROTECT)
neilt6 0:2a6d8a096edc 254 return RES_WRPRT;
neilt6 0:2a6d8a096edc 255
neilt6 0:2a6d8a096edc 256 //Convert from LBA to a byte address for older cards
neilt6 0:2a6d8a096edc 257 if (m_CardType != CARD_SDHC)
neilt6 0:2a6d8a096edc 258 sector *= 512;
neilt6 0:2a6d8a096edc 259
neilt6 0:2a6d8a096edc 260 //Try to write the block up to 3 times
neilt6 0:2a6d8a096edc 261 for (int i = 0; i < 3; i++) {
neilt6 0:2a6d8a096edc 262 //Send CMD24(sector) to write a single block
neilt6 0:2a6d8a096edc 263 if (writeCommand(CMD24, sector) == 0x00) {
neilt6 0:2a6d8a096edc 264 //Wait for up to 500ms for the card to become ready
neilt6 0:2a6d8a096edc 265 if (!waitReady(500)) {
neilt6 0:2a6d8a096edc 266 //We timed out
neilt6 0:2a6d8a096edc 267 deselect();
neilt6 0:2a6d8a096edc 268 continue;
neilt6 0:2a6d8a096edc 269 }
neilt6 0:2a6d8a096edc 270
neilt6 0:2a6d8a096edc 271 //Send the write data token
neilt6 0:2a6d8a096edc 272 m_SPI.write(0xFE);
neilt6 0:2a6d8a096edc 273
neilt6 0:2a6d8a096edc 274 //Write the data block from the buffer
neilt6 0:2a6d8a096edc 275 for (int b = 0; b < 512; b++)
neilt6 0:2a6d8a096edc 276 m_SPI.write(buffer[b]);
neilt6 0:2a6d8a096edc 277
neilt6 0:2a6d8a096edc 278 //Calculate the CRC16 checksum for the data block and send it
neilt6 0:2a6d8a096edc 279 unsigned short crc = CRC16((char*)buffer, 512);
neilt6 0:2a6d8a096edc 280 m_SPI.write(crc >> 8);
neilt6 0:2a6d8a096edc 281 m_SPI.write(crc);
neilt6 0:2a6d8a096edc 282
neilt6 0:2a6d8a096edc 283 //Receive the data response, and deselect the card
neilt6 0:2a6d8a096edc 284 char resp = m_SPI.write(0xFF) & 0x1F;
neilt6 0:2a6d8a096edc 285 deselect();
neilt6 0:2a6d8a096edc 286
neilt6 0:2a6d8a096edc 287 //Check the response
neilt6 0:2a6d8a096edc 288 if (resp == 0x05)
neilt6 0:2a6d8a096edc 289 return RES_OK;
neilt6 0:2a6d8a096edc 290 else if (resp == 0x0D)
neilt6 0:2a6d8a096edc 291 return RES_ERROR;
neilt6 0:2a6d8a096edc 292 } else {
neilt6 0:2a6d8a096edc 293 //The command failed
neilt6 0:2a6d8a096edc 294 deselect();
neilt6 0:2a6d8a096edc 295 return RES_ERROR;
neilt6 0:2a6d8a096edc 296 }
neilt6 0:2a6d8a096edc 297 }
neilt6 0:2a6d8a096edc 298
neilt6 0:2a6d8a096edc 299 //The operation either timed out 3 times, failed the CRC check 3 times, or experienced a write error
neilt6 0:2a6d8a096edc 300 return RES_ERROR;
neilt6 0:2a6d8a096edc 301 }
neilt6 0:2a6d8a096edc 302
neilt6 0:2a6d8a096edc 303 int SDFileSystem::disk_sync()
neilt6 0:2a6d8a096edc 304 {
neilt6 0:2a6d8a096edc 305 //Select the card so we're forced to wait for the end of any internal write processes
neilt6 0:2a6d8a096edc 306 bool ret = select();
neilt6 0:2a6d8a096edc 307 deselect();
neilt6 0:2a6d8a096edc 308
neilt6 0:2a6d8a096edc 309 //Return success/failure
neilt6 0:2a6d8a096edc 310 return (ret) ? RES_OK : RES_ERROR;
neilt6 0:2a6d8a096edc 311 }
neilt6 0:2a6d8a096edc 312
neilt6 0:2a6d8a096edc 313 uint64_t SDFileSystem::disk_sectors()
neilt6 0:2a6d8a096edc 314 {
neilt6 0:2a6d8a096edc 315 //Make sure the device is initialized before proceeding
neilt6 0:2a6d8a096edc 316 if (m_Status & STA_NOINIT)
neilt6 0:2a6d8a096edc 317 return 0;
neilt6 0:2a6d8a096edc 318
neilt6 0:2a6d8a096edc 319 //Try to read the CSD register up to 3 times
neilt6 0:2a6d8a096edc 320 for (int i = 0; i < 3; i++) {
neilt6 0:2a6d8a096edc 321 //Send CMD9(0) to read the CSD register
neilt6 0:2a6d8a096edc 322 if (writeCommand(CMD9, 0) == 0x00) {
neilt6 0:2a6d8a096edc 323 //Receive the 16B CSD data
neilt6 0:2a6d8a096edc 324 char csd[16];
neilt6 0:2a6d8a096edc 325 if (readData(csd, 16)) {
neilt6 0:2a6d8a096edc 326 //Calculate the sector count based on the card type
neilt6 0:2a6d8a096edc 327 if ((csd[0] >> 6) == 0x01) {
neilt6 0:2a6d8a096edc 328 //Calculate the sector count a high capacity card
neilt6 0:2a6d8a096edc 329 uint64_t sectors = (((csd[7] & 0x3F) << 16) | (csd[8] << 8) | csd[9]) + 1;
neilt6 0:2a6d8a096edc 330 return sectors << 10;
neilt6 0:2a6d8a096edc 331 } else {
neilt6 0:2a6d8a096edc 332 //Calculate the sector count standard capacity card
neilt6 0:2a6d8a096edc 333 uint64_t sectors = (((csd[6] & 0x03) << 10) | (csd[7] << 2) | ((csd[8] & 0xC0) >> 6)) + 1;
neilt6 0:2a6d8a096edc 334 sectors <<= ((((csd[9] & 0x03) << 1) | ((csd[10] & 0x80) >> 7)) + 2);
neilt6 0:2a6d8a096edc 335 sectors <<= (csd[5] & 0x0F);
neilt6 0:2a6d8a096edc 336 return sectors >> 9;
neilt6 0:2a6d8a096edc 337 }
neilt6 0:2a6d8a096edc 338 }
neilt6 0:2a6d8a096edc 339 } else {
neilt6 0:2a6d8a096edc 340 //The command failed
neilt6 0:2a6d8a096edc 341 deselect();
neilt6 0:2a6d8a096edc 342 return 0;
neilt6 0:2a6d8a096edc 343 }
neilt6 0:2a6d8a096edc 344 }
neilt6 0:2a6d8a096edc 345
neilt6 0:2a6d8a096edc 346 //The read operation failed 3 times (CRC most likely)
neilt6 0:2a6d8a096edc 347 return 0;
neilt6 0:2a6d8a096edc 348 }
neilt6 0:2a6d8a096edc 349
neilt6 0:2a6d8a096edc 350 void SDFileSystem::checkSocket()
neilt6 0:2a6d8a096edc 351 {
neilt6 0:2a6d8a096edc 352 //Check if a card is in the socket
neilt6 1:25f4ba436b81 353 if (m_CD == m_CD_ASSERT) {
neilt6 0:2a6d8a096edc 354 //The socket is occupied, clear the STA_NODISK flag
neilt6 0:2a6d8a096edc 355 m_Status &= ~STA_NODISK;
neilt6 0:2a6d8a096edc 356 } else {
neilt6 0:2a6d8a096edc 357 //The socket is empty
neilt6 0:2a6d8a096edc 358 m_Status |= (STA_NODISK | STA_NOINIT);
neilt6 0:2a6d8a096edc 359 m_CardType = CARD_NONE;
neilt6 0:2a6d8a096edc 360 }
neilt6 0:2a6d8a096edc 361 }
neilt6 0:2a6d8a096edc 362
neilt6 0:2a6d8a096edc 363 inline bool SDFileSystem::waitReady(int timeout)
neilt6 0:2a6d8a096edc 364 {
neilt6 0:2a6d8a096edc 365 //Wait for the specified timeout for the card to become ready
neilt6 0:2a6d8a096edc 366 for (int i = 0; i < timeout; i++) {
neilt6 0:2a6d8a096edc 367 if (m_SPI.write(0xFF) == 0xFF)
neilt6 0:2a6d8a096edc 368 return true;
neilt6 0:2a6d8a096edc 369 wait_ms(1);
neilt6 0:2a6d8a096edc 370 }
neilt6 0:2a6d8a096edc 371
neilt6 0:2a6d8a096edc 372 //We timed out
neilt6 0:2a6d8a096edc 373 return false;
neilt6 0:2a6d8a096edc 374 }
neilt6 0:2a6d8a096edc 375
neilt6 0:2a6d8a096edc 376 inline bool SDFileSystem::select()
neilt6 0:2a6d8a096edc 377 {
neilt6 0:2a6d8a096edc 378 //Pull /CS low
neilt6 0:2a6d8a096edc 379 m_CS = 0;
neilt6 0:2a6d8a096edc 380
neilt6 0:2a6d8a096edc 381 //Send a dummy clock to enable DO
neilt6 0:2a6d8a096edc 382 m_SPI.write(0xFF);
neilt6 0:2a6d8a096edc 383
neilt6 0:2a6d8a096edc 384 //Wait for up to 500ms for the card to become ready
neilt6 0:2a6d8a096edc 385 if (waitReady(500))
neilt6 0:2a6d8a096edc 386 return true;
neilt6 0:2a6d8a096edc 387
neilt6 0:2a6d8a096edc 388 //We timed out, deselect and return false
neilt6 0:2a6d8a096edc 389 deselect();
neilt6 0:2a6d8a096edc 390 return false;
neilt6 0:2a6d8a096edc 391 }
neilt6 0:2a6d8a096edc 392
neilt6 0:2a6d8a096edc 393 inline void SDFileSystem::deselect()
neilt6 0:2a6d8a096edc 394 {
neilt6 0:2a6d8a096edc 395 //Pull /CS high
neilt6 0:2a6d8a096edc 396 m_CS = 1;
neilt6 0:2a6d8a096edc 397
neilt6 0:2a6d8a096edc 398 //Send a dummy byte to release DO
neilt6 0:2a6d8a096edc 399 m_SPI.write(0xFF);
neilt6 0:2a6d8a096edc 400 }
neilt6 0:2a6d8a096edc 401
neilt6 0:2a6d8a096edc 402 char SDFileSystem::writeCommand(char cmd, unsigned int arg)
neilt6 0:2a6d8a096edc 403 {
neilt6 0:2a6d8a096edc 404 char resp;
neilt6 0:2a6d8a096edc 405
neilt6 0:2a6d8a096edc 406 //Try to send the command up to 3 times
neilt6 0:2a6d8a096edc 407 for (int i = 0; i < 3; i++) {
neilt6 0:2a6d8a096edc 408 //Send a CMD55 prior to an ACMD
neilt6 0:2a6d8a096edc 409 if (cmd == ACMD41) {
neilt6 0:2a6d8a096edc 410 resp = writeCommand(CMD55, 0);
neilt6 0:2a6d8a096edc 411 if (resp > 0x01)
neilt6 0:2a6d8a096edc 412 return resp;
neilt6 0:2a6d8a096edc 413 }
neilt6 0:2a6d8a096edc 414
neilt6 0:2a6d8a096edc 415 //Select the card and wait for ready
neilt6 0:2a6d8a096edc 416 if (!select())
neilt6 0:2a6d8a096edc 417 return 0xFF;
neilt6 0:2a6d8a096edc 418
neilt6 0:2a6d8a096edc 419 //Prepare the command packet
neilt6 0:2a6d8a096edc 420 char cmdPacket[6];
neilt6 0:2a6d8a096edc 421 cmdPacket[0] = 0x40 | cmd;
neilt6 0:2a6d8a096edc 422 cmdPacket[1] = arg >> 24;
neilt6 0:2a6d8a096edc 423 cmdPacket[2] = arg >> 16;
neilt6 0:2a6d8a096edc 424 cmdPacket[3] = arg >> 8;
neilt6 0:2a6d8a096edc 425 cmdPacket[4] = arg;
neilt6 0:2a6d8a096edc 426 cmdPacket[5] = (CRC7(cmdPacket, 5) << 1) | 0x01;
neilt6 0:2a6d8a096edc 427
neilt6 0:2a6d8a096edc 428 //Send the command packet
neilt6 0:2a6d8a096edc 429 for (int b = 0; b < 6; b++)
neilt6 0:2a6d8a096edc 430 m_SPI.write(cmdPacket[b]);
neilt6 0:2a6d8a096edc 431
neilt6 0:2a6d8a096edc 432 //Allow up to 10 bytes of delay for the command response
neilt6 0:2a6d8a096edc 433 for (int b = 0; b < 10; b++) {
neilt6 0:2a6d8a096edc 434 resp = m_SPI.write(0xFF);
neilt6 0:2a6d8a096edc 435 if (!(resp & 0x80))
neilt6 0:2a6d8a096edc 436 break;
neilt6 0:2a6d8a096edc 437 }
neilt6 0:2a6d8a096edc 438
neilt6 0:2a6d8a096edc 439 //Deselect the card unless there's more data to read/write
neilt6 0:2a6d8a096edc 440 if (resp == 0xFF || (resp & (1 << 3)) || !(cmd == CMD8 || cmd == CMD9 || cmd == CMD17 || cmd == CMD24 || cmd == CMD55 || cmd == CMD58))
neilt6 0:2a6d8a096edc 441 deselect();
neilt6 0:2a6d8a096edc 442
neilt6 0:2a6d8a096edc 443 //Return the response if there were no CRC errors
neilt6 0:2a6d8a096edc 444 if (resp == 0xFF || !(resp & (1 << 3)))
neilt6 0:2a6d8a096edc 445 return resp;
neilt6 0:2a6d8a096edc 446 }
neilt6 0:2a6d8a096edc 447
neilt6 0:2a6d8a096edc 448 //The command failed 3 times due to CRC errors
neilt6 0:2a6d8a096edc 449 return 0xFF;
neilt6 0:2a6d8a096edc 450 }
neilt6 0:2a6d8a096edc 451
neilt6 0:2a6d8a096edc 452 unsigned int SDFileSystem::readReturn()
neilt6 0:2a6d8a096edc 453 {
neilt6 0:2a6d8a096edc 454 unsigned int ret;
neilt6 0:2a6d8a096edc 455
neilt6 0:2a6d8a096edc 456 //Read the 32-bit response value
neilt6 0:2a6d8a096edc 457 ret = (m_SPI.write(0xFF) << 24);
neilt6 0:2a6d8a096edc 458 ret |= (m_SPI.write(0xFF) << 16);
neilt6 0:2a6d8a096edc 459 ret |= (m_SPI.write(0xFF) << 8);
neilt6 0:2a6d8a096edc 460 ret |= m_SPI.write(0xFF);
neilt6 0:2a6d8a096edc 461
neilt6 0:2a6d8a096edc 462 //Deselect the card
neilt6 0:2a6d8a096edc 463 deselect();
neilt6 0:2a6d8a096edc 464
neilt6 0:2a6d8a096edc 465 //Return the response value
neilt6 0:2a6d8a096edc 466 return ret;
neilt6 0:2a6d8a096edc 467 }
neilt6 0:2a6d8a096edc 468
neilt6 0:2a6d8a096edc 469 bool SDFileSystem::readData(char* buffer, int length)
neilt6 0:2a6d8a096edc 470 {
neilt6 0:2a6d8a096edc 471 char token;
neilt6 0:2a6d8a096edc 472
neilt6 0:2a6d8a096edc 473 //Wait for up to 200ms for the DataStart token to arrive
neilt6 0:2a6d8a096edc 474 for (int i = 0; i < 200; i++) {
neilt6 0:2a6d8a096edc 475 token = m_SPI.write(0xFF);
neilt6 0:2a6d8a096edc 476 if (token != 0xFF)
neilt6 0:2a6d8a096edc 477 break;
neilt6 0:2a6d8a096edc 478 wait_ms(1);
neilt6 0:2a6d8a096edc 479 }
neilt6 0:2a6d8a096edc 480
neilt6 0:2a6d8a096edc 481 //Make sure the token is valid
neilt6 0:2a6d8a096edc 482 if (token != 0xFE)
neilt6 0:2a6d8a096edc 483 return false;
neilt6 0:2a6d8a096edc 484
neilt6 0:2a6d8a096edc 485 //Read the data into the buffer
neilt6 0:2a6d8a096edc 486 for (int i = 0; i < length; i++)
neilt6 0:2a6d8a096edc 487 buffer[i] = m_SPI.write(0xFF);
neilt6 0:2a6d8a096edc 488
neilt6 0:2a6d8a096edc 489 //Read the CRC16 checksum for the data block, and deselect the card
neilt6 0:2a6d8a096edc 490 unsigned short crc = (m_SPI.write(0xFF) << 8);
neilt6 0:2a6d8a096edc 491 crc |= m_SPI.write(0xFF);
neilt6 0:2a6d8a096edc 492 deselect();
neilt6 0:2a6d8a096edc 493
neilt6 0:2a6d8a096edc 494 //Indicate whether the CRC16 checksum was valid or not
neilt6 0:2a6d8a096edc 495 if (crc == CRC16(buffer, length))
neilt6 0:2a6d8a096edc 496 return true;
neilt6 0:2a6d8a096edc 497 else
neilt6 0:2a6d8a096edc 498 return false;
neilt6 0:2a6d8a096edc 499 }