A re-written SDFileSystem library with improved compatibility, CRC support, and card removal/replacement support.

Dependencies:   FATFileSystem

Dependents:   demo_configfile

Fork of SDFileSystem by Neil Thiessen

Committer:
neilt6
Date:
Mon Aug 11 15:28:11 2014 +0000
Revision:
9:1906befe7f30
Parent:
8:7b6acbb6739b
Child:
10:395539a1481a
Readability improvements

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 7:61db99e52c0d 22 SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name, PinName cd, SwitchType cdtype, int hz) : FATFileSystem(name), m_Spi(mosi, miso, sclk), m_Cs(cs, 1), m_Cd(cd), m_CD_ASSERT((int)cdtype), m_FREQ(hz)
neilt6 0:2a6d8a096edc 23 {
neilt6 0:2a6d8a096edc 24 //Initialize the member variables
neilt6 6:55a26a56046a 25 m_CardType = CARD_NONE;
neilt6 7:61db99e52c0d 26 m_Crc = true;
neilt6 6:55a26a56046a 27 m_LargeFrames = false;
neilt6 0:2a6d8a096edc 28 m_Status = STA_NOINIT;
neilt6 0:2a6d8a096edc 29
neilt6 0:2a6d8a096edc 30 //Configure the SPI bus
neilt6 7:61db99e52c0d 31 m_Spi.format(8, 0);
neilt6 0:2a6d8a096edc 32
neilt6 0:2a6d8a096edc 33 //Configure the card detect pin
neilt6 7:61db99e52c0d 34 m_Cd.mode(PullUp);
neilt6 1:25f4ba436b81 35 if (cdtype == SWITCH_NO)
neilt6 7:61db99e52c0d 36 m_Cd.rise(this, &SDFileSystem::checkSocket);
neilt6 1:25f4ba436b81 37 else
neilt6 7:61db99e52c0d 38 m_Cd.fall(this, &SDFileSystem::checkSocket);
neilt6 0:2a6d8a096edc 39 }
neilt6 0:2a6d8a096edc 40
neilt6 0:2a6d8a096edc 41 SDFileSystem::CardType SDFileSystem::card_type()
neilt6 0:2a6d8a096edc 42 {
neilt6 0:2a6d8a096edc 43 //Check the card socket
neilt6 0:2a6d8a096edc 44 checkSocket();
neilt6 0:2a6d8a096edc 45
neilt6 0:2a6d8a096edc 46 //If a card is present but not initialized, initialize it
neilt6 0:2a6d8a096edc 47 if (!(m_Status & STA_NODISK) && (m_Status & STA_NOINIT))
neilt6 0:2a6d8a096edc 48 disk_initialize();
neilt6 0:2a6d8a096edc 49
neilt6 0:2a6d8a096edc 50 //Return the card type
neilt6 0:2a6d8a096edc 51 return m_CardType;
neilt6 0:2a6d8a096edc 52 }
neilt6 0:2a6d8a096edc 53
neilt6 7:61db99e52c0d 54 bool SDFileSystem::crc()
neilt6 6:55a26a56046a 55 {
neilt6 6:55a26a56046a 56 //Return whether or not CRC is enabled
neilt6 7:61db99e52c0d 57 return m_Crc;
neilt6 6:55a26a56046a 58 }
neilt6 6:55a26a56046a 59
neilt6 7:61db99e52c0d 60 void SDFileSystem::crc(bool enabled)
neilt6 6:55a26a56046a 61 {
neilt6 6:55a26a56046a 62 //Check the card socket
neilt6 6:55a26a56046a 63 checkSocket();
neilt6 6:55a26a56046a 64
neilt6 6:55a26a56046a 65 //Just update the member variable if the card isn't initialized
neilt6 6:55a26a56046a 66 if (m_Status & STA_NOINIT) {
neilt6 7:61db99e52c0d 67 m_Crc = enabled;
neilt6 6:55a26a56046a 68 return;
neilt6 6:55a26a56046a 69 }
neilt6 6:55a26a56046a 70
neilt6 6:55a26a56046a 71 //Enable or disable CRC
neilt6 7:61db99e52c0d 72 if (enabled && !m_Crc) {
neilt6 6:55a26a56046a 73 //Send CMD59(0x00000001) to enable CRC
neilt6 7:61db99e52c0d 74 m_Crc = true;
neilt6 6:55a26a56046a 75 writeCommand(CMD59, 0x00000001);
neilt6 7:61db99e52c0d 76 } else if (!enabled && m_Crc) {
neilt6 6:55a26a56046a 77 //Send CMD59(0x00000000) to disable CRC
neilt6 6:55a26a56046a 78 writeCommand(CMD59, 0x00000000);
neilt6 7:61db99e52c0d 79 m_Crc = false;
neilt6 6:55a26a56046a 80 }
neilt6 6:55a26a56046a 81 }
neilt6 6:55a26a56046a 82
neilt6 6:55a26a56046a 83 bool SDFileSystem::large_frames()
neilt6 6:55a26a56046a 84 {
neilt6 6:55a26a56046a 85 //Return whether or not 16-bit frames are enabled
neilt6 6:55a26a56046a 86 return m_LargeFrames;
neilt6 6:55a26a56046a 87 }
neilt6 6:55a26a56046a 88
neilt6 6:55a26a56046a 89 void SDFileSystem::large_frames(bool enabled)
neilt6 6:55a26a56046a 90 {
neilt6 6:55a26a56046a 91 //Set whether or not 16-bit frames are enabled
neilt6 6:55a26a56046a 92 m_LargeFrames = enabled;
neilt6 6:55a26a56046a 93 }
neilt6 6:55a26a56046a 94
neilt6 0:2a6d8a096edc 95 int SDFileSystem::disk_initialize()
neilt6 0:2a6d8a096edc 96 {
neilt6 0:2a6d8a096edc 97 char resp;
neilt6 0:2a6d8a096edc 98
neilt6 0:2a6d8a096edc 99 //Make sure there's a card in the socket before proceeding
neilt6 0:2a6d8a096edc 100 checkSocket();
neilt6 0:2a6d8a096edc 101 if (m_Status & STA_NODISK)
neilt6 0:2a6d8a096edc 102 return m_Status;
neilt6 0:2a6d8a096edc 103
neilt6 0:2a6d8a096edc 104 //Make sure we're not already initialized before proceeding
neilt6 0:2a6d8a096edc 105 if (!(m_Status & STA_NOINIT))
neilt6 0:2a6d8a096edc 106 return m_Status;
neilt6 0:2a6d8a096edc 107
neilt6 9:1906befe7f30 108 //Set the SPI frequency to 400kHz for initialization
neilt6 9:1906befe7f30 109 m_Spi.frequency(400000);
neilt6 0:2a6d8a096edc 110
neilt6 0:2a6d8a096edc 111 //Send 80 dummy clocks with /CS and DI held high
neilt6 7:61db99e52c0d 112 m_Cs = 1;
neilt6 0:2a6d8a096edc 113 for (int i = 0; i < 10; i++)
neilt6 7:61db99e52c0d 114 m_Spi.write(0xFF);
neilt6 0:2a6d8a096edc 115
neilt6 5:6befff2300d0 116 //Write CMD0(0x00000000) to reset the card
neilt6 5:6befff2300d0 117 resp = writeCommand(CMD0, 0x00000000);
neilt6 0:2a6d8a096edc 118 if (resp != 0x01) {
neilt6 0:2a6d8a096edc 119 //Initialization failed
neilt6 0:2a6d8a096edc 120 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 121 return m_Status;
neilt6 0:2a6d8a096edc 122 }
neilt6 0:2a6d8a096edc 123
neilt6 0:2a6d8a096edc 124 //Write CMD8(0x000001AA) to see if this is an SDCv2 card
neilt6 0:2a6d8a096edc 125 resp = writeCommand(CMD8, 0x000001AA);
neilt6 0:2a6d8a096edc 126 if (resp == 0x01) {
neilt6 0:2a6d8a096edc 127 //This is an SDCv2 card, get the 32-bit return value and verify the voltage range/check pattern
neilt6 0:2a6d8a096edc 128 if ((readReturn() & 0xFFF) != 0x1AA) {
neilt6 0:2a6d8a096edc 129 //Initialization failed
neilt6 0:2a6d8a096edc 130 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 131 return m_Status;
neilt6 0:2a6d8a096edc 132 }
neilt6 0:2a6d8a096edc 133
neilt6 5:6befff2300d0 134 //Send CMD58(0x00000000) to read the OCR, and verify that the card supports 3.2-3.3V
neilt6 5:6befff2300d0 135 resp = writeCommand(CMD58, 0x00000000);
neilt6 0:2a6d8a096edc 136 if (resp != 0x01 || !(readReturn() & (1 << 20))) {
neilt6 0:2a6d8a096edc 137 //Initialization failed
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 //Send ACMD41(0x40100000) repeatedly for up to 1 second to initialize the card
neilt6 0:2a6d8a096edc 143 for (int i = 0; i < 1000; i++) {
neilt6 0:2a6d8a096edc 144 resp = writeCommand(ACMD41, 0x40100000);
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 //Initialization failed
neilt6 0:2a6d8a096edc 153 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 154 return m_Status;
neilt6 0:2a6d8a096edc 155 }
neilt6 0:2a6d8a096edc 156
neilt6 5:6befff2300d0 157 //Send CMD58(0x00000000) to read the OCR
neilt6 5:6befff2300d0 158 resp = writeCommand(CMD58, 0x00000000);
neilt6 0:2a6d8a096edc 159 if (resp == 0x00) {
neilt6 0:2a6d8a096edc 160 //Check the CCS bit to determine if this is a high capacity card
neilt6 5:6befff2300d0 161 if (readReturn() & (1 << 30))
neilt6 0:2a6d8a096edc 162 m_CardType = CARD_SDHC;
neilt6 0:2a6d8a096edc 163 else
neilt6 0:2a6d8a096edc 164 m_CardType = CARD_SD;
neilt6 0:2a6d8a096edc 165 } else {
neilt6 0:2a6d8a096edc 166 //Initialization failed
neilt6 0:2a6d8a096edc 167 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 168 return m_Status;
neilt6 0:2a6d8a096edc 169 }
neilt6 0:2a6d8a096edc 170 } else {
neilt6 0:2a6d8a096edc 171 //Didn't respond or illegal command, this is either an SDCv1 or MMC card
neilt6 5:6befff2300d0 172 //Send CMD58(0x00000000) to read the OCR, and verify that the card supports 3.2-3.3V
neilt6 5:6befff2300d0 173 resp = writeCommand(CMD58, 0x00000000);
neilt6 0:2a6d8a096edc 174 if (resp != 0x01 || !(readReturn() & (1 << 20))) {
neilt6 0:2a6d8a096edc 175 //Initialization failed
neilt6 0:2a6d8a096edc 176 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 177 return m_Status;
neilt6 0:2a6d8a096edc 178 }
neilt6 0:2a6d8a096edc 179
neilt6 0:2a6d8a096edc 180 //Try to initialize the card using ACMD41(0x00100000) for 1 second
neilt6 0:2a6d8a096edc 181 for (int i = 0; i < 1000; i++) {
neilt6 0:2a6d8a096edc 182 resp = writeCommand(ACMD41, 0x00100000);
neilt6 0:2a6d8a096edc 183 if (resp != 0x01)
neilt6 0:2a6d8a096edc 184 break;
neilt6 0:2a6d8a096edc 185 wait_ms(1);
neilt6 0:2a6d8a096edc 186 }
neilt6 0:2a6d8a096edc 187
neilt6 0:2a6d8a096edc 188 //Check if the card initialized
neilt6 0:2a6d8a096edc 189 if (resp == 0x00) {
neilt6 0:2a6d8a096edc 190 //This is an SDCv1 standard capacity card
neilt6 0:2a6d8a096edc 191 m_CardType = CARD_SD;
neilt6 0:2a6d8a096edc 192 } else {
neilt6 0:2a6d8a096edc 193 //Try to initialize the card using CMD1(0x00100000) for 1 second
neilt6 0:2a6d8a096edc 194 for (int i = 0; i < 1000; i++) {
neilt6 0:2a6d8a096edc 195 resp = writeCommand(CMD1, 0x00100000);
neilt6 0:2a6d8a096edc 196 if (resp != 0x01)
neilt6 0:2a6d8a096edc 197 break;
neilt6 0:2a6d8a096edc 198 wait_ms(1);
neilt6 0:2a6d8a096edc 199 }
neilt6 0:2a6d8a096edc 200
neilt6 0:2a6d8a096edc 201 //Check if the card initialized
neilt6 0:2a6d8a096edc 202 if (resp == 0x00) {
neilt6 0:2a6d8a096edc 203 //This is an MMCv3 card
neilt6 0:2a6d8a096edc 204 m_CardType = CARD_MMC;
neilt6 0:2a6d8a096edc 205 } else {
neilt6 0:2a6d8a096edc 206 //Initialization failed
neilt6 0:2a6d8a096edc 207 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 208 return m_Status;
neilt6 0:2a6d8a096edc 209 }
neilt6 0:2a6d8a096edc 210 }
neilt6 0:2a6d8a096edc 211 }
neilt6 0:2a6d8a096edc 212
neilt6 6:55a26a56046a 213 //Send CMD59(0x00000001) to enable CRC if necessary
neilt6 7:61db99e52c0d 214 if (m_Crc) {
neilt6 6:55a26a56046a 215 resp = writeCommand(CMD59, 0x00000001);
neilt6 6:55a26a56046a 216 if (resp != 0x00) {
neilt6 6:55a26a56046a 217 //Initialization failed
neilt6 6:55a26a56046a 218 m_CardType = CARD_UNKNOWN;
neilt6 6:55a26a56046a 219 return m_Status;
neilt6 6:55a26a56046a 220 }
neilt6 0:2a6d8a096edc 221 }
neilt6 0:2a6d8a096edc 222
neilt6 0:2a6d8a096edc 223 //Send CMD16(0x00000200) to force the block size to 512B if necessary
neilt6 0:2a6d8a096edc 224 if (m_CardType != CARD_SDHC) {
neilt6 0:2a6d8a096edc 225 resp = writeCommand(CMD16, 0x00000200);
neilt6 0:2a6d8a096edc 226 if (resp != 0x00) {
neilt6 0:2a6d8a096edc 227 //Initialization failed
neilt6 0:2a6d8a096edc 228 m_CardType = CARD_UNKNOWN;
neilt6 0:2a6d8a096edc 229 return m_Status;
neilt6 0:2a6d8a096edc 230 }
neilt6 0:2a6d8a096edc 231 }
neilt6 0:2a6d8a096edc 232
neilt6 5:6befff2300d0 233 //Send ACMD42(0x00000000) to disconnect the internal pull-up resistor on /CS if necessary
neilt6 5:6befff2300d0 234 if (m_CardType != CARD_MMC) {
neilt6 5:6befff2300d0 235 resp = writeCommand(ACMD42, 0x00000000);
neilt6 5:6befff2300d0 236 if (resp != 0x00) {
neilt6 5:6befff2300d0 237 //Initialization failed
neilt6 5:6befff2300d0 238 m_CardType = CARD_UNKNOWN;
neilt6 5:6befff2300d0 239 return m_Status;
neilt6 5:6befff2300d0 240 }
neilt6 5:6befff2300d0 241 }
neilt6 5:6befff2300d0 242
neilt6 0:2a6d8a096edc 243 //The card is now initialized
neilt6 0:2a6d8a096edc 244 m_Status &= ~STA_NOINIT;
neilt6 0:2a6d8a096edc 245
neilt6 0:2a6d8a096edc 246 //Increase the SPI frequency to full speed (limited to 20MHz for MMC, or 25MHz for SDC)
neilt6 6:55a26a56046a 247 if (m_CardType == CARD_MMC && m_FREQ > 20000000)
neilt6 7:61db99e52c0d 248 m_Spi.frequency(20000000);
neilt6 6:55a26a56046a 249 else if (m_FREQ > 25000000)
neilt6 7:61db99e52c0d 250 m_Spi.frequency(25000000);
neilt6 0:2a6d8a096edc 251 else
neilt6 7:61db99e52c0d 252 m_Spi.frequency(m_FREQ);
neilt6 0:2a6d8a096edc 253
neilt6 9:1906befe7f30 254 //Return the disk status
neilt6 0:2a6d8a096edc 255 return m_Status;
neilt6 0:2a6d8a096edc 256 }
neilt6 0:2a6d8a096edc 257
neilt6 0:2a6d8a096edc 258 int SDFileSystem::disk_status()
neilt6 0:2a6d8a096edc 259 {
neilt6 0:2a6d8a096edc 260 //Check if there's a card in the socket
neilt6 0:2a6d8a096edc 261 checkSocket();
neilt6 0:2a6d8a096edc 262
neilt6 9:1906befe7f30 263 //Return the disk status
neilt6 0:2a6d8a096edc 264 return m_Status;
neilt6 0:2a6d8a096edc 265 }
neilt6 0:2a6d8a096edc 266
neilt6 0:2a6d8a096edc 267 int SDFileSystem::disk_read(uint8_t* buffer, uint64_t sector)
neilt6 0:2a6d8a096edc 268 {
neilt6 9:1906befe7f30 269 //Make sure the card is initialized before proceeding
neilt6 0:2a6d8a096edc 270 if (m_Status & STA_NOINIT)
neilt6 0:2a6d8a096edc 271 return RES_NOTRDY;
neilt6 0:2a6d8a096edc 272
neilt6 0:2a6d8a096edc 273 //Convert from LBA to a byte address for standard capacity cards
neilt6 0:2a6d8a096edc 274 if (m_CardType != CARD_SDHC)
neilt6 0:2a6d8a096edc 275 sector *= 512;
neilt6 0:2a6d8a096edc 276
neilt6 0:2a6d8a096edc 277 //Try to read the block up to 3 times
neilt6 0:2a6d8a096edc 278 for (int i = 0; i < 3; i++) {
neilt6 0:2a6d8a096edc 279 //Send CMD17(sector) to read a single block
neilt6 8:7b6acbb6739b 280 if (writeCommand(CMD17, sector) == 0x00) {
neilt6 0:2a6d8a096edc 281 //Try to read the sector, and return if successful
neilt6 0:2a6d8a096edc 282 if (readData((char*)buffer, 512))
neilt6 0:2a6d8a096edc 283 return RES_OK;
neilt6 0:2a6d8a096edc 284 } else {
neilt6 0:2a6d8a096edc 285 //The command failed
neilt6 0:2a6d8a096edc 286 return RES_ERROR;
neilt6 0:2a6d8a096edc 287 }
neilt6 0:2a6d8a096edc 288 }
neilt6 0:2a6d8a096edc 289
neilt6 9:1906befe7f30 290 //The read operation failed 3 times
neilt6 0:2a6d8a096edc 291 return RES_ERROR;
neilt6 0:2a6d8a096edc 292 }
neilt6 0:2a6d8a096edc 293
neilt6 0:2a6d8a096edc 294 int SDFileSystem::disk_write(const uint8_t* buffer, uint64_t sector)
neilt6 0:2a6d8a096edc 295 {
neilt6 9:1906befe7f30 296 //Make sure the card is initialized before proceeding
neilt6 0:2a6d8a096edc 297 if (m_Status & STA_NOINIT)
neilt6 0:2a6d8a096edc 298 return RES_NOTRDY;
neilt6 0:2a6d8a096edc 299
neilt6 9:1906befe7f30 300 //Make sure the card isn't write protected before proceeding
neilt6 0:2a6d8a096edc 301 if (m_Status & STA_PROTECT)
neilt6 0:2a6d8a096edc 302 return RES_WRPRT;
neilt6 0:2a6d8a096edc 303
neilt6 0:2a6d8a096edc 304 //Convert from LBA to a byte address for older cards
neilt6 0:2a6d8a096edc 305 if (m_CardType != CARD_SDHC)
neilt6 0:2a6d8a096edc 306 sector *= 512;
neilt6 0:2a6d8a096edc 307
neilt6 0:2a6d8a096edc 308 //Try to write the block up to 3 times
neilt6 0:2a6d8a096edc 309 for (int i = 0; i < 3; i++) {
neilt6 0:2a6d8a096edc 310 //Send CMD24(sector) to write a single block
neilt6 0:2a6d8a096edc 311 if (writeCommand(CMD24, sector) == 0x00) {
neilt6 9:1906befe7f30 312 //Try to write the sector, and return if successful
neilt6 9:1906befe7f30 313 if (writeData((char*)buffer))
neilt6 0:2a6d8a096edc 314 return RES_OK;
neilt6 0:2a6d8a096edc 315 } else {
neilt6 0:2a6d8a096edc 316 //The command failed
neilt6 0:2a6d8a096edc 317 return RES_ERROR;
neilt6 0:2a6d8a096edc 318 }
neilt6 0:2a6d8a096edc 319 }
neilt6 0:2a6d8a096edc 320
neilt6 9:1906befe7f30 321 //The write operation failed 3 times
neilt6 0:2a6d8a096edc 322 return RES_ERROR;
neilt6 0:2a6d8a096edc 323 }
neilt6 0:2a6d8a096edc 324
neilt6 0:2a6d8a096edc 325 int SDFileSystem::disk_sync()
neilt6 0:2a6d8a096edc 326 {
neilt6 0:2a6d8a096edc 327 //Select the card so we're forced to wait for the end of any internal write processes
neilt6 0:2a6d8a096edc 328 bool ret = select();
neilt6 0:2a6d8a096edc 329 deselect();
neilt6 0:2a6d8a096edc 330
neilt6 0:2a6d8a096edc 331 //Return success/failure
neilt6 0:2a6d8a096edc 332 return (ret) ? RES_OK : RES_ERROR;
neilt6 0:2a6d8a096edc 333 }
neilt6 0:2a6d8a096edc 334
neilt6 0:2a6d8a096edc 335 uint64_t SDFileSystem::disk_sectors()
neilt6 0:2a6d8a096edc 336 {
neilt6 9:1906befe7f30 337 //Make sure the card is initialized before proceeding
neilt6 0:2a6d8a096edc 338 if (m_Status & STA_NOINIT)
neilt6 0:2a6d8a096edc 339 return 0;
neilt6 0:2a6d8a096edc 340
neilt6 0:2a6d8a096edc 341 //Try to read the CSD register up to 3 times
neilt6 0:2a6d8a096edc 342 for (int i = 0; i < 3; i++) {
neilt6 5:6befff2300d0 343 //Send CMD9(0x00000000) to read the CSD register
neilt6 5:6befff2300d0 344 if (writeCommand(CMD9, 0x00000000) == 0x00) {
neilt6 0:2a6d8a096edc 345 //Receive the 16B CSD data
neilt6 0:2a6d8a096edc 346 char csd[16];
neilt6 0:2a6d8a096edc 347 if (readData(csd, 16)) {
neilt6 0:2a6d8a096edc 348 //Calculate the sector count based on the card type
neilt6 0:2a6d8a096edc 349 if ((csd[0] >> 6) == 0x01) {
neilt6 0:2a6d8a096edc 350 //Calculate the sector count a high capacity card
neilt6 0:2a6d8a096edc 351 uint64_t sectors = (((csd[7] & 0x3F) << 16) | (csd[8] << 8) | csd[9]) + 1;
neilt6 0:2a6d8a096edc 352 return sectors << 10;
neilt6 0:2a6d8a096edc 353 } else {
neilt6 0:2a6d8a096edc 354 //Calculate the sector count standard capacity card
neilt6 0:2a6d8a096edc 355 uint64_t sectors = (((csd[6] & 0x03) << 10) | (csd[7] << 2) | ((csd[8] & 0xC0) >> 6)) + 1;
neilt6 0:2a6d8a096edc 356 sectors <<= ((((csd[9] & 0x03) << 1) | ((csd[10] & 0x80) >> 7)) + 2);
neilt6 0:2a6d8a096edc 357 sectors <<= (csd[5] & 0x0F);
neilt6 0:2a6d8a096edc 358 return sectors >> 9;
neilt6 0:2a6d8a096edc 359 }
neilt6 0:2a6d8a096edc 360 }
neilt6 0:2a6d8a096edc 361 } else {
neilt6 0:2a6d8a096edc 362 //The command failed
neilt6 0:2a6d8a096edc 363 return 0;
neilt6 0:2a6d8a096edc 364 }
neilt6 0:2a6d8a096edc 365 }
neilt6 0:2a6d8a096edc 366
neilt6 9:1906befe7f30 367 //The read operation failed 3 times
neilt6 0:2a6d8a096edc 368 return 0;
neilt6 0:2a6d8a096edc 369 }
neilt6 0:2a6d8a096edc 370
neilt6 0:2a6d8a096edc 371 void SDFileSystem::checkSocket()
neilt6 0:2a6d8a096edc 372 {
neilt6 0:2a6d8a096edc 373 //Check if a card is in the socket
neilt6 7:61db99e52c0d 374 if (m_Cd == m_CD_ASSERT) {
neilt6 0:2a6d8a096edc 375 //The socket is occupied, clear the STA_NODISK flag
neilt6 0:2a6d8a096edc 376 m_Status &= ~STA_NODISK;
neilt6 0:2a6d8a096edc 377 } else {
neilt6 0:2a6d8a096edc 378 //The socket is empty
neilt6 0:2a6d8a096edc 379 m_Status |= (STA_NODISK | STA_NOINIT);
neilt6 0:2a6d8a096edc 380 m_CardType = CARD_NONE;
neilt6 0:2a6d8a096edc 381 }
neilt6 0:2a6d8a096edc 382 }
neilt6 0:2a6d8a096edc 383
neilt6 0:2a6d8a096edc 384 inline bool SDFileSystem::waitReady(int timeout)
neilt6 0:2a6d8a096edc 385 {
neilt6 0:2a6d8a096edc 386 //Wait for the specified timeout for the card to become ready
neilt6 0:2a6d8a096edc 387 for (int i = 0; i < timeout; i++) {
neilt6 7:61db99e52c0d 388 if (m_Spi.write(0xFF) == 0xFF)
neilt6 0:2a6d8a096edc 389 return true;
neilt6 0:2a6d8a096edc 390 wait_ms(1);
neilt6 0:2a6d8a096edc 391 }
neilt6 0:2a6d8a096edc 392
neilt6 0:2a6d8a096edc 393 //We timed out
neilt6 0:2a6d8a096edc 394 return false;
neilt6 0:2a6d8a096edc 395 }
neilt6 0:2a6d8a096edc 396
neilt6 0:2a6d8a096edc 397 inline bool SDFileSystem::select()
neilt6 0:2a6d8a096edc 398 {
neilt6 0:2a6d8a096edc 399 //Pull /CS low
neilt6 7:61db99e52c0d 400 m_Cs = 0;
neilt6 0:2a6d8a096edc 401
neilt6 9:1906befe7f30 402 //Send 8 dummy clocks with DI held high to enable DO
neilt6 7:61db99e52c0d 403 m_Spi.write(0xFF);
neilt6 0:2a6d8a096edc 404
neilt6 0:2a6d8a096edc 405 //Wait for up to 500ms for the card to become ready
neilt6 9:1906befe7f30 406 if (waitReady(500)) {
neilt6 0:2a6d8a096edc 407 return true;
neilt6 9:1906befe7f30 408 } else {
neilt6 9:1906befe7f30 409 //We timed out, deselect and return false
neilt6 9:1906befe7f30 410 deselect();
neilt6 9:1906befe7f30 411 return false;
neilt6 9:1906befe7f30 412 }
neilt6 0:2a6d8a096edc 413 }
neilt6 0:2a6d8a096edc 414
neilt6 0:2a6d8a096edc 415 inline void SDFileSystem::deselect()
neilt6 0:2a6d8a096edc 416 {
neilt6 0:2a6d8a096edc 417 //Pull /CS high
neilt6 7:61db99e52c0d 418 m_Cs = 1;
neilt6 0:2a6d8a096edc 419
neilt6 9:1906befe7f30 420 //Send 8 dummy clocks with DI held high to disable DO (will also initiate any internal write process)
neilt6 7:61db99e52c0d 421 m_Spi.write(0xFF);
neilt6 0:2a6d8a096edc 422 }
neilt6 0:2a6d8a096edc 423
neilt6 0:2a6d8a096edc 424 char SDFileSystem::writeCommand(char cmd, unsigned int arg)
neilt6 0:2a6d8a096edc 425 {
neilt6 0:2a6d8a096edc 426 char resp;
neilt6 0:2a6d8a096edc 427
neilt6 0:2a6d8a096edc 428 //Try to send the command up to 3 times
neilt6 0:2a6d8a096edc 429 for (int i = 0; i < 3; i++) {
neilt6 5:6befff2300d0 430 //Send CMD55(0x00000000) prior to an application specific command
neilt6 5:6befff2300d0 431 if (cmd == ACMD41 || cmd == ACMD42) {
neilt6 5:6befff2300d0 432 resp = writeCommand(CMD55, 0x00000000);
neilt6 0:2a6d8a096edc 433 if (resp > 0x01)
neilt6 0:2a6d8a096edc 434 return resp;
neilt6 0:2a6d8a096edc 435 }
neilt6 0:2a6d8a096edc 436
neilt6 2:eec1db773e7d 437 //Select the card, and wait for ready
neilt6 0:2a6d8a096edc 438 if (!select())
neilt6 0:2a6d8a096edc 439 return 0xFF;
neilt6 0:2a6d8a096edc 440
neilt6 0:2a6d8a096edc 441 //Prepare the command packet
neilt6 0:2a6d8a096edc 442 char cmdPacket[6];
neilt6 4:49b29888eca7 443 cmdPacket[0] = cmd;
neilt6 0:2a6d8a096edc 444 cmdPacket[1] = arg >> 24;
neilt6 0:2a6d8a096edc 445 cmdPacket[2] = arg >> 16;
neilt6 0:2a6d8a096edc 446 cmdPacket[3] = arg >> 8;
neilt6 0:2a6d8a096edc 447 cmdPacket[4] = arg;
neilt6 7:61db99e52c0d 448 if (m_Crc || cmd == CMD0 || cmd == CMD8)
neilt6 6:55a26a56046a 449 cmdPacket[5] = (CRC7(cmdPacket, 5) << 1) | 0x01;
neilt6 6:55a26a56046a 450 else
neilt6 6:55a26a56046a 451 cmdPacket[5] = 0x01;
neilt6 0:2a6d8a096edc 452
neilt6 0:2a6d8a096edc 453 //Send the command packet
neilt6 0:2a6d8a096edc 454 for (int b = 0; b < 6; b++)
neilt6 7:61db99e52c0d 455 m_Spi.write(cmdPacket[b]);
neilt6 0:2a6d8a096edc 456
neilt6 9:1906befe7f30 457 //Allow up to 8 bytes of delay for the command response
neilt6 9:1906befe7f30 458 for (int b = 0; b < 9; b++) {
neilt6 7:61db99e52c0d 459 resp = m_Spi.write(0xFF);
neilt6 0:2a6d8a096edc 460 if (!(resp & 0x80))
neilt6 0:2a6d8a096edc 461 break;
neilt6 0:2a6d8a096edc 462 }
neilt6 0:2a6d8a096edc 463
neilt6 2:eec1db773e7d 464 //Deselect the card on errors, or if the transaction is finished
neilt6 2:eec1db773e7d 465 if (resp > 0x01 || !(cmd == CMD8 || cmd == CMD9 || cmd == CMD17 || cmd == CMD24 || cmd == CMD55 || cmd == CMD58))
neilt6 0:2a6d8a096edc 466 deselect();
neilt6 0:2a6d8a096edc 467
neilt6 9:1906befe7f30 468 //Return the response unless there was a CRC error
neilt6 0:2a6d8a096edc 469 if (resp == 0xFF || !(resp & (1 << 3)))
neilt6 0:2a6d8a096edc 470 return resp;
neilt6 0:2a6d8a096edc 471 }
neilt6 0:2a6d8a096edc 472
neilt6 9:1906befe7f30 473 //The command failed 3 times
neilt6 0:2a6d8a096edc 474 return 0xFF;
neilt6 0:2a6d8a096edc 475 }
neilt6 0:2a6d8a096edc 476
neilt6 0:2a6d8a096edc 477 unsigned int SDFileSystem::readReturn()
neilt6 0:2a6d8a096edc 478 {
neilt6 0:2a6d8a096edc 479 unsigned int ret;
neilt6 0:2a6d8a096edc 480
neilt6 0:2a6d8a096edc 481 //Read the 32-bit response value
neilt6 7:61db99e52c0d 482 ret = (m_Spi.write(0xFF) << 24);
neilt6 7:61db99e52c0d 483 ret |= (m_Spi.write(0xFF) << 16);
neilt6 7:61db99e52c0d 484 ret |= (m_Spi.write(0xFF) << 8);
neilt6 7:61db99e52c0d 485 ret |= m_Spi.write(0xFF);
neilt6 0:2a6d8a096edc 486
neilt6 0:2a6d8a096edc 487 //Deselect the card
neilt6 0:2a6d8a096edc 488 deselect();
neilt6 0:2a6d8a096edc 489
neilt6 0:2a6d8a096edc 490 //Return the response value
neilt6 0:2a6d8a096edc 491 return ret;
neilt6 0:2a6d8a096edc 492 }
neilt6 0:2a6d8a096edc 493
neilt6 0:2a6d8a096edc 494 bool SDFileSystem::readData(char* buffer, int length)
neilt6 0:2a6d8a096edc 495 {
neilt6 0:2a6d8a096edc 496 char token;
neilt6 6:55a26a56046a 497 unsigned short crc;
neilt6 0:2a6d8a096edc 498
neilt6 9:1906befe7f30 499 //Wait for up to 200ms for the data token to arrive
neilt6 0:2a6d8a096edc 500 for (int i = 0; i < 200; i++) {
neilt6 7:61db99e52c0d 501 token = m_Spi.write(0xFF);
neilt6 0:2a6d8a096edc 502 if (token != 0xFF)
neilt6 0:2a6d8a096edc 503 break;
neilt6 0:2a6d8a096edc 504 wait_ms(1);
neilt6 0:2a6d8a096edc 505 }
neilt6 0:2a6d8a096edc 506
neilt6 0:2a6d8a096edc 507 //Make sure the token is valid
neilt6 6:55a26a56046a 508 if (token != 0xFE) {
neilt6 6:55a26a56046a 509 deselect();
neilt6 0:2a6d8a096edc 510 return false;
neilt6 6:55a26a56046a 511 }
neilt6 6:55a26a56046a 512
neilt6 6:55a26a56046a 513 //Check if large frames are enabled or not
neilt6 6:55a26a56046a 514 if (m_LargeFrames) {
neilt6 6:55a26a56046a 515 //Switch to 16-bit frames for better performance
neilt6 7:61db99e52c0d 516 m_Spi.format(16, 0);
neilt6 0:2a6d8a096edc 517
neilt6 9:1906befe7f30 518 //Read the data block into the buffer
neilt6 6:55a26a56046a 519 unsigned short dataWord;
neilt6 6:55a26a56046a 520 for (int i = 0; i < length; i += 2) {
neilt6 7:61db99e52c0d 521 dataWord = m_Spi.write(0xFFFF);
neilt6 6:55a26a56046a 522 buffer[i] = dataWord >> 8;
neilt6 6:55a26a56046a 523 buffer[i + 1] = dataWord;
neilt6 6:55a26a56046a 524 }
neilt6 6:55a26a56046a 525
neilt6 6:55a26a56046a 526 //Read the CRC16 checksum for the data block
neilt6 7:61db99e52c0d 527 crc = m_Spi.write(0xFFFF);
neilt6 0:2a6d8a096edc 528
neilt6 6:55a26a56046a 529 //Switch back to 8-bit frames
neilt6 7:61db99e52c0d 530 m_Spi.format(8, 0);
neilt6 6:55a26a56046a 531 } else {
neilt6 6:55a26a56046a 532 //Read the data into the buffer
neilt6 6:55a26a56046a 533 for (int i = 0; i < length; i++)
neilt6 7:61db99e52c0d 534 buffer[i] = m_Spi.write(0xFF);
neilt6 6:55a26a56046a 535
neilt6 6:55a26a56046a 536 //Read the CRC16 checksum for the data block
neilt6 7:61db99e52c0d 537 crc = (m_Spi.write(0xFF) << 8);
neilt6 7:61db99e52c0d 538 crc |= m_Spi.write(0xFF);
neilt6 6:55a26a56046a 539 }
neilt6 6:55a26a56046a 540
neilt6 6:55a26a56046a 541 //Deselect the card
neilt6 0:2a6d8a096edc 542 deselect();
neilt6 0:2a6d8a096edc 543
neilt6 9:1906befe7f30 544 //Return the validity of the CRC16 checksum (if enabled)
neilt6 7:61db99e52c0d 545 return (!m_Crc || crc == CRC16(buffer, length));
neilt6 0:2a6d8a096edc 546 }
neilt6 9:1906befe7f30 547
neilt6 9:1906befe7f30 548 bool SDFileSystem::writeData(char* buffer)
neilt6 9:1906befe7f30 549 {
neilt6 9:1906befe7f30 550 //Wait for up to 500ms for the card to become ready
neilt6 9:1906befe7f30 551 if (!waitReady(500)) {
neilt6 9:1906befe7f30 552 //We timed out, deselect and indicate failure
neilt6 9:1906befe7f30 553 deselect();
neilt6 9:1906befe7f30 554 return false;
neilt6 9:1906befe7f30 555 }
neilt6 9:1906befe7f30 556
neilt6 9:1906befe7f30 557 //Send the data token
neilt6 9:1906befe7f30 558 m_Spi.write(0xFE);
neilt6 9:1906befe7f30 559
neilt6 9:1906befe7f30 560 //Calculate the CRC16 checksum for the data block (if enabled)
neilt6 9:1906befe7f30 561 unsigned short crc = (m_Crc) ? CRC16(buffer, 512) : 0xFFFF;
neilt6 9:1906befe7f30 562
neilt6 9:1906befe7f30 563 //Check if large frames are enabled or not
neilt6 9:1906befe7f30 564 if (m_LargeFrames) {
neilt6 9:1906befe7f30 565 //Switch to 16-bit frames for better performance
neilt6 9:1906befe7f30 566 m_Spi.format(16, 0);
neilt6 9:1906befe7f30 567
neilt6 9:1906befe7f30 568 //Write the data block from the buffer
neilt6 9:1906befe7f30 569 for (int b = 0; b < 512; b += 2) {
neilt6 9:1906befe7f30 570 m_Spi.write((buffer[b] << 8) | buffer[b + 1]);
neilt6 9:1906befe7f30 571 }
neilt6 9:1906befe7f30 572
neilt6 9:1906befe7f30 573 //Send the CRC16 checksum for the data block
neilt6 9:1906befe7f30 574 m_Spi.write(crc);
neilt6 9:1906befe7f30 575
neilt6 9:1906befe7f30 576 //Switch back to 8-bit frames
neilt6 9:1906befe7f30 577 m_Spi.format(8, 0);
neilt6 9:1906befe7f30 578 } else {
neilt6 9:1906befe7f30 579 //Write the data block from the buffer
neilt6 9:1906befe7f30 580 for (int b = 0; b < 512; b++)
neilt6 9:1906befe7f30 581 m_Spi.write(buffer[b]);
neilt6 9:1906befe7f30 582
neilt6 9:1906befe7f30 583 //Send the CRC16 checksum for the data block
neilt6 9:1906befe7f30 584 m_Spi.write(crc >> 8);
neilt6 9:1906befe7f30 585 m_Spi.write(crc);
neilt6 9:1906befe7f30 586 }
neilt6 9:1906befe7f30 587
neilt6 9:1906befe7f30 588 //Receive the data response
neilt6 9:1906befe7f30 589 char resp = m_Spi.write(0xFF);
neilt6 9:1906befe7f30 590
neilt6 9:1906befe7f30 591 //Deselect the card (this will initiate the internal write process)
neilt6 9:1906befe7f30 592 deselect();
neilt6 9:1906befe7f30 593
neilt6 9:1906befe7f30 594 //Return success/failure
neilt6 9:1906befe7f30 595 return ((resp & 0x1F) == 0x05);
neilt6 9:1906befe7f30 596 }