Code for Technion Formula car sensors reader

Dependencies:   mbed Buffer FATFileSystem

Fork of SX1272PingPong by Semtech

This is code is part of a Technion course project in advanced IoT, implementing a device to read and transmit sensors data from a Formula racing car built by students at Technion - Israel Institute of Technology.

How to install

  • Create an account on Mbed: https://os.mbed.com/account/signup/
  • Import project into Compiler
  • In the Program Workspace select "Formula_Nucleo_Reader"
  • Select a Platform like so:
  1. Click button at top-left
  2. Add Board
  3. Search "NUCLEO F103RB" and then "Add to your Mbed Compiler"
  • Finally click "Compile", if the build was successful, the binary would download automatically
  • To install it on device simply plug it in to a PC, open device drive and drag then drop binary file in it
Committer:
wardm
Date:
Thu May 17 20:37:41 2018 +0000
Revision:
15:2e0d977dbb31
V1.0.0

Who changed what in which revision?

UserRevisionLine numberNew contents of line
wardm 15:2e0d977dbb31 1 /* SD/MMC File System Library
wardm 15:2e0d977dbb31 2 * Copyright (c) 2016 Neil Thiessen
wardm 15:2e0d977dbb31 3 *
wardm 15:2e0d977dbb31 4 * Licensed under the Apache License, Version 2.0 (the "License");
wardm 15:2e0d977dbb31 5 * you may not use this file except in compliance with the License.
wardm 15:2e0d977dbb31 6 * You may obtain a copy of the License at
wardm 15:2e0d977dbb31 7 *
wardm 15:2e0d977dbb31 8 * http://www.apache.org/licenses/LICENSE-2.0
wardm 15:2e0d977dbb31 9 *
wardm 15:2e0d977dbb31 10 * Unless required by applicable law or agreed to in writing, software
wardm 15:2e0d977dbb31 11 * distributed under the License is distributed on an "AS IS" BASIS,
wardm 15:2e0d977dbb31 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
wardm 15:2e0d977dbb31 13 * See the License for the specific language governing permissions and
wardm 15:2e0d977dbb31 14 * limitations under the License.
wardm 15:2e0d977dbb31 15 */
wardm 15:2e0d977dbb31 16
wardm 15:2e0d977dbb31 17 #include "SDFileSystem.h"
wardm 15:2e0d977dbb31 18 #include "diskio.h"
wardm 15:2e0d977dbb31 19 #include "pinmap.h"
wardm 15:2e0d977dbb31 20 #include "SDCRC.h"
wardm 15:2e0d977dbb31 21
wardm 15:2e0d977dbb31 22 SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name, PinName cd, SwitchType cdtype, int hz)
wardm 15:2e0d977dbb31 23 : FATFileSystem(name),
wardm 15:2e0d977dbb31 24 m_Spi(mosi, miso, sclk),
wardm 15:2e0d977dbb31 25 m_Cs(cs, 1),
wardm 15:2e0d977dbb31 26 m_Cd(cd),
wardm 15:2e0d977dbb31 27 m_FREQ(hz)
wardm 15:2e0d977dbb31 28 {
wardm 15:2e0d977dbb31 29 //Initialize the member variables
wardm 15:2e0d977dbb31 30 m_CardType = CARD_NONE;
wardm 15:2e0d977dbb31 31 m_Crc = true;
wardm 15:2e0d977dbb31 32 m_LargeFrames = false;
wardm 15:2e0d977dbb31 33 m_WriteValidation = true;
wardm 15:2e0d977dbb31 34 m_Status = STA_NOINIT;
wardm 15:2e0d977dbb31 35
wardm 15:2e0d977dbb31 36 //Enable the internal pull-up resistor on MISO
wardm 15:2e0d977dbb31 37 pin_mode(miso, PullUp);
wardm 15:2e0d977dbb31 38
wardm 15:2e0d977dbb31 39 //Configure the SPI bus
wardm 15:2e0d977dbb31 40 m_Spi.format(8, 0);
wardm 15:2e0d977dbb31 41
wardm 15:2e0d977dbb31 42 //Configure the card detect pin
wardm 15:2e0d977dbb31 43 if (cdtype == SWITCH_POS_NO) {
wardm 15:2e0d977dbb31 44 m_Cd.mode(PullDown);
wardm 15:2e0d977dbb31 45 m_CdAssert = 1;
wardm 15:2e0d977dbb31 46 m_Cd.fall(this, &SDFileSystem::onCardRemoval);
wardm 15:2e0d977dbb31 47 } else if (cdtype == SWITCH_POS_NC) {
wardm 15:2e0d977dbb31 48 m_Cd.mode(PullDown);
wardm 15:2e0d977dbb31 49 m_CdAssert = 0;
wardm 15:2e0d977dbb31 50 m_Cd.rise(this, &SDFileSystem::onCardRemoval);
wardm 15:2e0d977dbb31 51 } else if (cdtype == SWITCH_NEG_NO) {
wardm 15:2e0d977dbb31 52 m_Cd.mode(PullUp);
wardm 15:2e0d977dbb31 53 m_CdAssert = 0;
wardm 15:2e0d977dbb31 54 m_Cd.rise(this, &SDFileSystem::onCardRemoval);
wardm 15:2e0d977dbb31 55 } else if (cdtype == SWITCH_NEG_NC) {
wardm 15:2e0d977dbb31 56 m_Cd.mode(PullUp);
wardm 15:2e0d977dbb31 57 m_CdAssert = 1;
wardm 15:2e0d977dbb31 58 m_Cd.fall(this, &SDFileSystem::onCardRemoval);
wardm 15:2e0d977dbb31 59 } else {
wardm 15:2e0d977dbb31 60 m_CdAssert = -1;
wardm 15:2e0d977dbb31 61 }
wardm 15:2e0d977dbb31 62 }
wardm 15:2e0d977dbb31 63
wardm 15:2e0d977dbb31 64 bool SDFileSystem::card_present()
wardm 15:2e0d977dbb31 65 {
wardm 15:2e0d977dbb31 66 //Check the card socket
wardm 15:2e0d977dbb31 67 checkSocket();
wardm 15:2e0d977dbb31 68
wardm 15:2e0d977dbb31 69 //Return whether or not a card is present
wardm 15:2e0d977dbb31 70 return !(m_Status & STA_NODISK);
wardm 15:2e0d977dbb31 71 }
wardm 15:2e0d977dbb31 72
wardm 15:2e0d977dbb31 73 SDFileSystem::CardType SDFileSystem::card_type()
wardm 15:2e0d977dbb31 74 {
wardm 15:2e0d977dbb31 75 //Check the card socket
wardm 15:2e0d977dbb31 76 checkSocket();
wardm 15:2e0d977dbb31 77
wardm 15:2e0d977dbb31 78 //Return the card type
wardm 15:2e0d977dbb31 79 return m_CardType;
wardm 15:2e0d977dbb31 80 }
wardm 15:2e0d977dbb31 81
wardm 15:2e0d977dbb31 82 bool SDFileSystem::crc()
wardm 15:2e0d977dbb31 83 {
wardm 15:2e0d977dbb31 84 //Return whether or not CRC is enabled
wardm 15:2e0d977dbb31 85 return m_Crc;
wardm 15:2e0d977dbb31 86 }
wardm 15:2e0d977dbb31 87
wardm 15:2e0d977dbb31 88 void SDFileSystem::crc(bool enabled)
wardm 15:2e0d977dbb31 89 {
wardm 15:2e0d977dbb31 90 //Check the card socket
wardm 15:2e0d977dbb31 91 checkSocket();
wardm 15:2e0d977dbb31 92
wardm 15:2e0d977dbb31 93 //Just update the member variable if the card isn't initialized
wardm 15:2e0d977dbb31 94 if (m_Status & STA_NOINIT) {
wardm 15:2e0d977dbb31 95 m_Crc = enabled;
wardm 15:2e0d977dbb31 96 return;
wardm 15:2e0d977dbb31 97 }
wardm 15:2e0d977dbb31 98
wardm 15:2e0d977dbb31 99 //Enable or disable CRC
wardm 15:2e0d977dbb31 100 if (enabled && !m_Crc) {
wardm 15:2e0d977dbb31 101 //Send CMD59(0x00000001) to enable CRC
wardm 15:2e0d977dbb31 102 m_Crc = true;
wardm 15:2e0d977dbb31 103 commandTransaction(CMD59, 0x00000001);
wardm 15:2e0d977dbb31 104 } else if (!enabled && m_Crc) {
wardm 15:2e0d977dbb31 105 //Send CMD59(0x00000000) to disable CRC
wardm 15:2e0d977dbb31 106 commandTransaction(CMD59, 0x00000000);
wardm 15:2e0d977dbb31 107 m_Crc = false;
wardm 15:2e0d977dbb31 108 }
wardm 15:2e0d977dbb31 109 }
wardm 15:2e0d977dbb31 110
wardm 15:2e0d977dbb31 111 bool SDFileSystem::large_frames()
wardm 15:2e0d977dbb31 112 {
wardm 15:2e0d977dbb31 113 //Return whether or not 16-bit frames are enabled
wardm 15:2e0d977dbb31 114 return m_LargeFrames;
wardm 15:2e0d977dbb31 115 }
wardm 15:2e0d977dbb31 116
wardm 15:2e0d977dbb31 117 void SDFileSystem::large_frames(bool enabled)
wardm 15:2e0d977dbb31 118 {
wardm 15:2e0d977dbb31 119 //Set whether or not 16-bit frames are enabled
wardm 15:2e0d977dbb31 120 m_LargeFrames = enabled;
wardm 15:2e0d977dbb31 121 }
wardm 15:2e0d977dbb31 122
wardm 15:2e0d977dbb31 123 bool SDFileSystem::write_validation()
wardm 15:2e0d977dbb31 124 {
wardm 15:2e0d977dbb31 125 //Return whether or not write validation is enabled
wardm 15:2e0d977dbb31 126 return m_WriteValidation;
wardm 15:2e0d977dbb31 127 }
wardm 15:2e0d977dbb31 128
wardm 15:2e0d977dbb31 129 void SDFileSystem::write_validation(bool enabled)
wardm 15:2e0d977dbb31 130 {
wardm 15:2e0d977dbb31 131 //Set whether or not write validation is enabled
wardm 15:2e0d977dbb31 132 m_WriteValidation = enabled;
wardm 15:2e0d977dbb31 133 }
wardm 15:2e0d977dbb31 134
wardm 15:2e0d977dbb31 135 int SDFileSystem::unmount()
wardm 15:2e0d977dbb31 136 {
wardm 15:2e0d977dbb31 137 //Unmount the filesystem
wardm 15:2e0d977dbb31 138 FATFileSystem::unmount();
wardm 15:2e0d977dbb31 139
wardm 15:2e0d977dbb31 140 //Change the status to not initialized, and the card type to unknown
wardm 15:2e0d977dbb31 141 m_Status |= STA_NOINIT;
wardm 15:2e0d977dbb31 142 m_CardType = CARD_UNKNOWN;
wardm 15:2e0d977dbb31 143
wardm 15:2e0d977dbb31 144 //Always succeeds
wardm 15:2e0d977dbb31 145 return 0;
wardm 15:2e0d977dbb31 146 }
wardm 15:2e0d977dbb31 147
wardm 15:2e0d977dbb31 148 int SDFileSystem::disk_initialize()
wardm 15:2e0d977dbb31 149 {
wardm 15:2e0d977dbb31 150 char token;
wardm 15:2e0d977dbb31 151 unsigned int resp;
wardm 15:2e0d977dbb31 152 Timer timer;
wardm 15:2e0d977dbb31 153
wardm 15:2e0d977dbb31 154 //Make sure there's a card in the socket before proceeding
wardm 15:2e0d977dbb31 155 checkSocket();
wardm 15:2e0d977dbb31 156 if (m_Status & STA_NODISK)
wardm 15:2e0d977dbb31 157 return m_Status;
wardm 15:2e0d977dbb31 158
wardm 15:2e0d977dbb31 159 //Make sure we're not already initialized before proceeding
wardm 15:2e0d977dbb31 160 if (!(m_Status & STA_NOINIT))
wardm 15:2e0d977dbb31 161 return m_Status;
wardm 15:2e0d977dbb31 162
wardm 15:2e0d977dbb31 163 //Set the SPI frequency to 400kHz for initialization
wardm 15:2e0d977dbb31 164 m_Spi.frequency(400000);
wardm 15:2e0d977dbb31 165
wardm 15:2e0d977dbb31 166 //Try to reset the card up to 3 times
wardm 15:2e0d977dbb31 167 for (int f = 0; f < 3; f++) {
wardm 15:2e0d977dbb31 168 //Send 80 dummy clocks with /CS deasserted and DI held high
wardm 15:2e0d977dbb31 169 m_Cs = 1;
wardm 15:2e0d977dbb31 170 for (int i = 0; i < 10; i++) {
wardm 15:2e0d977dbb31 171 m_Spi.write(0xFF);
wardm 15:2e0d977dbb31 172 }
wardm 15:2e0d977dbb31 173
wardm 15:2e0d977dbb31 174 //Send CMD0(0x00000000) to reset the card
wardm 15:2e0d977dbb31 175 token = commandTransaction(CMD0, 0x00000000);
wardm 15:2e0d977dbb31 176 if (token == 0x01) {
wardm 15:2e0d977dbb31 177 break;
wardm 15:2e0d977dbb31 178 }
wardm 15:2e0d977dbb31 179 }
wardm 15:2e0d977dbb31 180
wardm 15:2e0d977dbb31 181 //Check if the card reset
wardm 15:2e0d977dbb31 182 if (token != 0x01) {
wardm 15:2e0d977dbb31 183 //Initialization failed
wardm 15:2e0d977dbb31 184 m_CardType = CARD_UNKNOWN;
wardm 15:2e0d977dbb31 185 return m_Status;
wardm 15:2e0d977dbb31 186 }
wardm 15:2e0d977dbb31 187
wardm 15:2e0d977dbb31 188 //Send CMD59(0x00000001) to enable CRC if necessary
wardm 15:2e0d977dbb31 189 if (m_Crc) {
wardm 15:2e0d977dbb31 190 if (commandTransaction(CMD59, 0x00000001) != 0x01) {
wardm 15:2e0d977dbb31 191 //Initialization failed
wardm 15:2e0d977dbb31 192 m_CardType = CARD_UNKNOWN;
wardm 15:2e0d977dbb31 193 return m_Status;
wardm 15:2e0d977dbb31 194 }
wardm 15:2e0d977dbb31 195 }
wardm 15:2e0d977dbb31 196
wardm 15:2e0d977dbb31 197 //Send CMD8(0x000001AA) to see if this is an SDCv2 card
wardm 15:2e0d977dbb31 198 if (commandTransaction(CMD8, 0x000001AA, &resp) == 0x01) {
wardm 15:2e0d977dbb31 199 //This is an SDCv2 card, get the 32-bit return value and verify the voltage range/check pattern
wardm 15:2e0d977dbb31 200 if ((resp & 0xFFF) != 0x1AA) {
wardm 15:2e0d977dbb31 201 //Initialization failed
wardm 15:2e0d977dbb31 202 m_CardType = CARD_UNKNOWN;
wardm 15:2e0d977dbb31 203 return m_Status;
wardm 15:2e0d977dbb31 204 }
wardm 15:2e0d977dbb31 205
wardm 15:2e0d977dbb31 206 //Send CMD58(0x00000000) to read the OCR, and verify that the card supports 3.2-3.3V
wardm 15:2e0d977dbb31 207 if (commandTransaction(CMD58, 0x00000000, &resp) != 0x01 || !(resp & (1 << 20))) {
wardm 15:2e0d977dbb31 208 //Initialization failed
wardm 15:2e0d977dbb31 209 m_CardType = CARD_UNKNOWN;
wardm 15:2e0d977dbb31 210 return m_Status;
wardm 15:2e0d977dbb31 211 }
wardm 15:2e0d977dbb31 212
wardm 15:2e0d977dbb31 213 //Try to initialize the card using ACMD41(0x40100000) for up to 2 seconds
wardm 15:2e0d977dbb31 214 timer.start();
wardm 15:2e0d977dbb31 215 do {
wardm 15:2e0d977dbb31 216 token = commandTransaction(ACMD41, 0x40100000);
wardm 15:2e0d977dbb31 217 } while (token == 0x01 && timer.read_ms() < 2000);
wardm 15:2e0d977dbb31 218 timer.stop();
wardm 15:2e0d977dbb31 219 timer.reset();
wardm 15:2e0d977dbb31 220
wardm 15:2e0d977dbb31 221 //Check if the card initialized
wardm 15:2e0d977dbb31 222 if (token != 0x00) {
wardm 15:2e0d977dbb31 223 //Initialization failed
wardm 15:2e0d977dbb31 224 m_CardType = CARD_UNKNOWN;
wardm 15:2e0d977dbb31 225 return m_Status;
wardm 15:2e0d977dbb31 226 }
wardm 15:2e0d977dbb31 227
wardm 15:2e0d977dbb31 228 //Send CMD58(0x00000000) to read the OCR
wardm 15:2e0d977dbb31 229 if (commandTransaction(CMD58, 0x00000000, &resp) == 0x00) {
wardm 15:2e0d977dbb31 230 //Check the CCS bit to determine if this is a high capacity card
wardm 15:2e0d977dbb31 231 if (resp & (1 << 30))
wardm 15:2e0d977dbb31 232 m_CardType = CARD_SDHC;
wardm 15:2e0d977dbb31 233 else
wardm 15:2e0d977dbb31 234 m_CardType = CARD_SD;
wardm 15:2e0d977dbb31 235
wardm 15:2e0d977dbb31 236 //Increase the SPI frequency to full speed (up to 50MHz for SDCv2)
wardm 15:2e0d977dbb31 237 if (m_FREQ > 25000000) {
wardm 15:2e0d977dbb31 238 if (enableHighSpeedMode()) {
wardm 15:2e0d977dbb31 239 if (m_FREQ > 50000000) {
wardm 15:2e0d977dbb31 240 m_Spi.frequency(50000000);
wardm 15:2e0d977dbb31 241 } else {
wardm 15:2e0d977dbb31 242 m_Spi.frequency(m_FREQ);
wardm 15:2e0d977dbb31 243 }
wardm 15:2e0d977dbb31 244 } else {
wardm 15:2e0d977dbb31 245 m_Spi.frequency(25000000);
wardm 15:2e0d977dbb31 246 }
wardm 15:2e0d977dbb31 247 } else {
wardm 15:2e0d977dbb31 248 m_Spi.frequency(m_FREQ);
wardm 15:2e0d977dbb31 249 }
wardm 15:2e0d977dbb31 250 } else {
wardm 15:2e0d977dbb31 251 //Initialization failed
wardm 15:2e0d977dbb31 252 m_CardType = CARD_UNKNOWN;
wardm 15:2e0d977dbb31 253 return m_Status;
wardm 15:2e0d977dbb31 254 }
wardm 15:2e0d977dbb31 255 } else {
wardm 15:2e0d977dbb31 256 //Didn't respond or illegal command, this is either an SDCv1 or MMC card
wardm 15:2e0d977dbb31 257 //Send CMD58(0x00000000) to read the OCR, and verify that the card supports 3.2-3.3V
wardm 15:2e0d977dbb31 258 if (commandTransaction(CMD58, 0x00000000, &resp) != 0x01 || !(resp & (1 << 20))) {
wardm 15:2e0d977dbb31 259 //Initialization failed
wardm 15:2e0d977dbb31 260 m_CardType = CARD_UNKNOWN;
wardm 15:2e0d977dbb31 261 return m_Status;
wardm 15:2e0d977dbb31 262 }
wardm 15:2e0d977dbb31 263
wardm 15:2e0d977dbb31 264 //Try to initialize the card using ACMD41(0x40100000) for up to 2 seconds
wardm 15:2e0d977dbb31 265 timer.start();
wardm 15:2e0d977dbb31 266 do {
wardm 15:2e0d977dbb31 267 token = commandTransaction(ACMD41, 0x40100000);
wardm 15:2e0d977dbb31 268 } while (token == 0x01 && timer.read_ms() < 2000);
wardm 15:2e0d977dbb31 269 timer.stop();
wardm 15:2e0d977dbb31 270 timer.reset();
wardm 15:2e0d977dbb31 271
wardm 15:2e0d977dbb31 272 //Check if the card initialized
wardm 15:2e0d977dbb31 273 if (token == 0x00) {
wardm 15:2e0d977dbb31 274 //This is an SDCv1 standard capacity card
wardm 15:2e0d977dbb31 275 m_CardType = CARD_SD;
wardm 15:2e0d977dbb31 276
wardm 15:2e0d977dbb31 277 //Increase the SPI frequency to full speed (up to 25MHz for SDCv1)
wardm 15:2e0d977dbb31 278 if (m_FREQ > 25000000)
wardm 15:2e0d977dbb31 279 m_Spi.frequency(25000000);
wardm 15:2e0d977dbb31 280 else
wardm 15:2e0d977dbb31 281 m_Spi.frequency(m_FREQ);
wardm 15:2e0d977dbb31 282 } else {
wardm 15:2e0d977dbb31 283 //Try to initialize the card using CMD1(0x00100000) for up to 2 seconds
wardm 15:2e0d977dbb31 284 timer.start();
wardm 15:2e0d977dbb31 285 do {
wardm 15:2e0d977dbb31 286 token = commandTransaction(CMD1, 0x00100000);
wardm 15:2e0d977dbb31 287 } while (token == 0x01 && timer.read_ms() < 2000);
wardm 15:2e0d977dbb31 288 timer.stop();
wardm 15:2e0d977dbb31 289 timer.reset();
wardm 15:2e0d977dbb31 290
wardm 15:2e0d977dbb31 291 //Check if the card initialized
wardm 15:2e0d977dbb31 292 if (token == 0x00) {
wardm 15:2e0d977dbb31 293 //This is an MMCv3 card
wardm 15:2e0d977dbb31 294 m_CardType = CARD_MMC;
wardm 15:2e0d977dbb31 295
wardm 15:2e0d977dbb31 296 //Increase the SPI frequency to full speed (up to 20MHz for MMCv3)
wardm 15:2e0d977dbb31 297 if (m_FREQ > 20000000)
wardm 15:2e0d977dbb31 298 m_Spi.frequency(20000000);
wardm 15:2e0d977dbb31 299 else
wardm 15:2e0d977dbb31 300 m_Spi.frequency(m_FREQ);
wardm 15:2e0d977dbb31 301 } else {
wardm 15:2e0d977dbb31 302 //Initialization failed
wardm 15:2e0d977dbb31 303 m_CardType = CARD_UNKNOWN;
wardm 15:2e0d977dbb31 304 return m_Status;
wardm 15:2e0d977dbb31 305 }
wardm 15:2e0d977dbb31 306 }
wardm 15:2e0d977dbb31 307 }
wardm 15:2e0d977dbb31 308
wardm 15:2e0d977dbb31 309 //Send ACMD42(0x00000000) to disconnect the internal pull-up resistor on pin 1 if necessary
wardm 15:2e0d977dbb31 310 if (m_CardType != CARD_MMC) {
wardm 15:2e0d977dbb31 311 if (commandTransaction(ACMD42, 0x00000000) != 0x00) {
wardm 15:2e0d977dbb31 312 //Initialization failed
wardm 15:2e0d977dbb31 313 m_CardType = CARD_UNKNOWN;
wardm 15:2e0d977dbb31 314 return m_Status;
wardm 15:2e0d977dbb31 315 }
wardm 15:2e0d977dbb31 316 }
wardm 15:2e0d977dbb31 317
wardm 15:2e0d977dbb31 318 //Send CMD16(0x00000200) to force the block size to 512B if necessary
wardm 15:2e0d977dbb31 319 if (m_CardType != CARD_SDHC) {
wardm 15:2e0d977dbb31 320 if (commandTransaction(CMD16, 0x00000200) != 0x00) {
wardm 15:2e0d977dbb31 321 //Initialization failed
wardm 15:2e0d977dbb31 322 m_CardType = CARD_UNKNOWN;
wardm 15:2e0d977dbb31 323 return m_Status;
wardm 15:2e0d977dbb31 324 }
wardm 15:2e0d977dbb31 325 }
wardm 15:2e0d977dbb31 326
wardm 15:2e0d977dbb31 327 //The card is now initialized
wardm 15:2e0d977dbb31 328 m_Status &= ~STA_NOINIT;
wardm 15:2e0d977dbb31 329
wardm 15:2e0d977dbb31 330 //Return the disk status
wardm 15:2e0d977dbb31 331 return m_Status;
wardm 15:2e0d977dbb31 332 }
wardm 15:2e0d977dbb31 333
wardm 15:2e0d977dbb31 334 int SDFileSystem::disk_status()
wardm 15:2e0d977dbb31 335 {
wardm 15:2e0d977dbb31 336 //Check the card socket
wardm 15:2e0d977dbb31 337 checkSocket();
wardm 15:2e0d977dbb31 338
wardm 15:2e0d977dbb31 339 //Return the disk status
wardm 15:2e0d977dbb31 340 return m_Status;
wardm 15:2e0d977dbb31 341 }
wardm 15:2e0d977dbb31 342
wardm 15:2e0d977dbb31 343 int SDFileSystem::disk_read(uint8_t* buffer, uint32_t sector, uint32_t count)
wardm 15:2e0d977dbb31 344 {
wardm 15:2e0d977dbb31 345 //Make sure the card is initialized before proceeding
wardm 15:2e0d977dbb31 346 if (m_Status & STA_NOINIT)
wardm 15:2e0d977dbb31 347 return RES_NOTRDY;
wardm 15:2e0d977dbb31 348
wardm 15:2e0d977dbb31 349 //Read a single block, or multiple blocks
wardm 15:2e0d977dbb31 350 if (count > 1) {
wardm 15:2e0d977dbb31 351 return readBlocks((char*)buffer, sector, count) ? RES_OK : RES_ERROR;
wardm 15:2e0d977dbb31 352 } else {
wardm 15:2e0d977dbb31 353 return readBlock((char*)buffer, sector) ? RES_OK : RES_ERROR;
wardm 15:2e0d977dbb31 354 }
wardm 15:2e0d977dbb31 355 }
wardm 15:2e0d977dbb31 356
wardm 15:2e0d977dbb31 357 int SDFileSystem::disk_write(const uint8_t* buffer, uint32_t sector, uint32_t count)
wardm 15:2e0d977dbb31 358 {
wardm 15:2e0d977dbb31 359 //Make sure the card is initialized before proceeding
wardm 15:2e0d977dbb31 360 if (m_Status & STA_NOINIT)
wardm 15:2e0d977dbb31 361 return RES_NOTRDY;
wardm 15:2e0d977dbb31 362
wardm 15:2e0d977dbb31 363 //Make sure the card isn't write protected before proceeding
wardm 15:2e0d977dbb31 364 if (m_Status & STA_PROTECT)
wardm 15:2e0d977dbb31 365 return RES_WRPRT;
wardm 15:2e0d977dbb31 366
wardm 15:2e0d977dbb31 367 //Write a single block, or multiple blocks
wardm 15:2e0d977dbb31 368 if (count > 1) {
wardm 15:2e0d977dbb31 369 return writeBlocks((const char*)buffer, sector, count) ? RES_OK : RES_ERROR;
wardm 15:2e0d977dbb31 370 } else {
wardm 15:2e0d977dbb31 371 return writeBlock((const char*)buffer, sector) ? RES_OK : RES_ERROR;
wardm 15:2e0d977dbb31 372 }
wardm 15:2e0d977dbb31 373 }
wardm 15:2e0d977dbb31 374
wardm 15:2e0d977dbb31 375 int SDFileSystem::disk_sync()
wardm 15:2e0d977dbb31 376 {
wardm 15:2e0d977dbb31 377 //Select the card so we're forced to wait for the end of any internal write processes
wardm 15:2e0d977dbb31 378 if (select()) {
wardm 15:2e0d977dbb31 379 deselect();
wardm 15:2e0d977dbb31 380 return RES_OK;
wardm 15:2e0d977dbb31 381 } else {
wardm 15:2e0d977dbb31 382 return RES_ERROR;
wardm 15:2e0d977dbb31 383 }
wardm 15:2e0d977dbb31 384 }
wardm 15:2e0d977dbb31 385
wardm 15:2e0d977dbb31 386 uint32_t SDFileSystem::disk_sectors()
wardm 15:2e0d977dbb31 387 {
wardm 15:2e0d977dbb31 388 //Make sure the card is initialized before proceeding
wardm 15:2e0d977dbb31 389 if (m_Status & STA_NOINIT)
wardm 15:2e0d977dbb31 390 return 0;
wardm 15:2e0d977dbb31 391
wardm 15:2e0d977dbb31 392 //Try to read the CSD register up to 3 times
wardm 15:2e0d977dbb31 393 for (int f = 0; f < 3; f++) {
wardm 15:2e0d977dbb31 394 //Select the card, and wait for ready
wardm 15:2e0d977dbb31 395 if(!select())
wardm 15:2e0d977dbb31 396 break;
wardm 15:2e0d977dbb31 397
wardm 15:2e0d977dbb31 398 //Send CMD9(0x00000000) to read the CSD register
wardm 15:2e0d977dbb31 399 if (writeCommand(CMD9, 0x00000000) == 0x00) {
wardm 15:2e0d977dbb31 400 //Read the 16B CSD data block
wardm 15:2e0d977dbb31 401 char csd[16];
wardm 15:2e0d977dbb31 402 bool success = readData(csd, 16);
wardm 15:2e0d977dbb31 403 deselect();
wardm 15:2e0d977dbb31 404 if (success) {
wardm 15:2e0d977dbb31 405 //Calculate the sector count based on the card type
wardm 15:2e0d977dbb31 406 if ((csd[0] >> 6) == 0x01) {
wardm 15:2e0d977dbb31 407 //Calculate the sector count for a high capacity card
wardm 15:2e0d977dbb31 408 unsigned int size = (((csd[7] & 0x3F) << 16) | (csd[8] << 8) | csd[9]) + 1;
wardm 15:2e0d977dbb31 409 return size << 10;
wardm 15:2e0d977dbb31 410 } else {
wardm 15:2e0d977dbb31 411 //Calculate the sector count for a standard capacity card
wardm 15:2e0d977dbb31 412 unsigned int size = (((csd[6] & 0x03) << 10) | (csd[7] << 2) | ((csd[8] & 0xC0) >> 6)) + 1;
wardm 15:2e0d977dbb31 413 size <<= ((((csd[9] & 0x03) << 1) | ((csd[10] & 0x80) >> 7)) + 2);
wardm 15:2e0d977dbb31 414 size <<= (csd[5] & 0x0F);
wardm 15:2e0d977dbb31 415 return size >> 9;
wardm 15:2e0d977dbb31 416 }
wardm 15:2e0d977dbb31 417 }
wardm 15:2e0d977dbb31 418 } else {
wardm 15:2e0d977dbb31 419 //The command failed, get out
wardm 15:2e0d977dbb31 420 break;
wardm 15:2e0d977dbb31 421 }
wardm 15:2e0d977dbb31 422 }
wardm 15:2e0d977dbb31 423
wardm 15:2e0d977dbb31 424 //The read operation failed 3 times
wardm 15:2e0d977dbb31 425 deselect();
wardm 15:2e0d977dbb31 426 return 0;
wardm 15:2e0d977dbb31 427 }
wardm 15:2e0d977dbb31 428
wardm 15:2e0d977dbb31 429 void SDFileSystem::onCardRemoval()
wardm 15:2e0d977dbb31 430 {
wardm 15:2e0d977dbb31 431 //Check the card socket
wardm 15:2e0d977dbb31 432 checkSocket();
wardm 15:2e0d977dbb31 433 }
wardm 15:2e0d977dbb31 434
wardm 15:2e0d977dbb31 435 inline void SDFileSystem::checkSocket()
wardm 15:2e0d977dbb31 436 {
wardm 15:2e0d977dbb31 437 //Use the card detect switch (if available) to determine if the socket is occupied
wardm 15:2e0d977dbb31 438 if (m_CdAssert != -1) {
wardm 15:2e0d977dbb31 439 if (m_Status & STA_NODISK) {
wardm 15:2e0d977dbb31 440 if (m_Cd == m_CdAssert) {
wardm 15:2e0d977dbb31 441 //The socket is now occupied
wardm 15:2e0d977dbb31 442 m_Status &= ~STA_NODISK;
wardm 15:2e0d977dbb31 443 m_CardType = CARD_UNKNOWN;
wardm 15:2e0d977dbb31 444 }
wardm 15:2e0d977dbb31 445 } else {
wardm 15:2e0d977dbb31 446 if (m_Cd != m_CdAssert) {
wardm 15:2e0d977dbb31 447 //The socket is now empty
wardm 15:2e0d977dbb31 448 m_Status |= (STA_NODISK | STA_NOINIT);
wardm 15:2e0d977dbb31 449 m_CardType = CARD_NONE;
wardm 15:2e0d977dbb31 450 }
wardm 15:2e0d977dbb31 451 }
wardm 15:2e0d977dbb31 452 }
wardm 15:2e0d977dbb31 453 }
wardm 15:2e0d977dbb31 454
wardm 15:2e0d977dbb31 455 inline bool SDFileSystem::waitReady(int timeout)
wardm 15:2e0d977dbb31 456 {
wardm 15:2e0d977dbb31 457 char resp;
wardm 15:2e0d977dbb31 458
wardm 15:2e0d977dbb31 459 //Keep sending dummy clocks with DI held high until the card releases the DO line
wardm 15:2e0d977dbb31 460 m_Timer.start();
wardm 15:2e0d977dbb31 461 do {
wardm 15:2e0d977dbb31 462 resp = m_Spi.write(0xFF);
wardm 15:2e0d977dbb31 463 } while (resp == 0x00 && m_Timer.read_ms() < timeout);
wardm 15:2e0d977dbb31 464 m_Timer.stop();
wardm 15:2e0d977dbb31 465 m_Timer.reset();
wardm 15:2e0d977dbb31 466
wardm 15:2e0d977dbb31 467 //Return success/failure
wardm 15:2e0d977dbb31 468 return (resp > 0x00);
wardm 15:2e0d977dbb31 469 }
wardm 15:2e0d977dbb31 470
wardm 15:2e0d977dbb31 471 inline bool SDFileSystem::select()
wardm 15:2e0d977dbb31 472 {
wardm 15:2e0d977dbb31 473 //Assert /CS
wardm 15:2e0d977dbb31 474 m_Cs = 0;
wardm 15:2e0d977dbb31 475
wardm 15:2e0d977dbb31 476 //Send 8 dummy clocks with DI held high to enable DO
wardm 15:2e0d977dbb31 477 m_Spi.write(0xFF);
wardm 15:2e0d977dbb31 478
wardm 15:2e0d977dbb31 479 //Wait for up to 500ms for the card to become ready
wardm 15:2e0d977dbb31 480 if (waitReady(500)) {
wardm 15:2e0d977dbb31 481 return true;
wardm 15:2e0d977dbb31 482 } else {
wardm 15:2e0d977dbb31 483 //We timed out, deselect and return false
wardm 15:2e0d977dbb31 484 deselect();
wardm 15:2e0d977dbb31 485 return false;
wardm 15:2e0d977dbb31 486 }
wardm 15:2e0d977dbb31 487 }
wardm 15:2e0d977dbb31 488
wardm 15:2e0d977dbb31 489 inline void SDFileSystem::deselect()
wardm 15:2e0d977dbb31 490 {
wardm 15:2e0d977dbb31 491 //Deassert /CS
wardm 15:2e0d977dbb31 492 m_Cs = 1;
wardm 15:2e0d977dbb31 493
wardm 15:2e0d977dbb31 494 //Send 8 dummy clocks with DI held high to disable DO
wardm 15:2e0d977dbb31 495 m_Spi.write(0xFF);
wardm 15:2e0d977dbb31 496 }
wardm 15:2e0d977dbb31 497
wardm 15:2e0d977dbb31 498 inline char SDFileSystem::commandTransaction(char cmd, unsigned int arg, unsigned int* resp)
wardm 15:2e0d977dbb31 499 {
wardm 15:2e0d977dbb31 500 //Select the card, and wait for ready
wardm 15:2e0d977dbb31 501 if(!select())
wardm 15:2e0d977dbb31 502 return 0xFF;
wardm 15:2e0d977dbb31 503
wardm 15:2e0d977dbb31 504 //Perform the command transaction
wardm 15:2e0d977dbb31 505 char token = writeCommand(cmd, arg, resp);
wardm 15:2e0d977dbb31 506
wardm 15:2e0d977dbb31 507 //Deselect the card, and return the R1 response token
wardm 15:2e0d977dbb31 508 deselect();
wardm 15:2e0d977dbb31 509 return token;
wardm 15:2e0d977dbb31 510 }
wardm 15:2e0d977dbb31 511
wardm 15:2e0d977dbb31 512 char SDFileSystem::writeCommand(char cmd, unsigned int arg, unsigned int* resp)
wardm 15:2e0d977dbb31 513 {
wardm 15:2e0d977dbb31 514 char token;
wardm 15:2e0d977dbb31 515
wardm 15:2e0d977dbb31 516 //Try to send the command up to 3 times
wardm 15:2e0d977dbb31 517 for (int f = 0; f < 3; f++) {
wardm 15:2e0d977dbb31 518 //Send CMD55(0x00000000) prior to an application specific command
wardm 15:2e0d977dbb31 519 if (cmd == ACMD22 || cmd == ACMD23 || cmd == ACMD41 || cmd == ACMD42) {
wardm 15:2e0d977dbb31 520 token = writeCommand(CMD55, 0x00000000);
wardm 15:2e0d977dbb31 521 if (token > 0x01)
wardm 15:2e0d977dbb31 522 return token;
wardm 15:2e0d977dbb31 523
wardm 15:2e0d977dbb31 524 //Deselect and reselect the card between CMD55 and an ACMD
wardm 15:2e0d977dbb31 525 deselect();
wardm 15:2e0d977dbb31 526 if(!select())
wardm 15:2e0d977dbb31 527 return 0xFF;
wardm 15:2e0d977dbb31 528 }
wardm 15:2e0d977dbb31 529
wardm 15:2e0d977dbb31 530 //Prepare the command packet
wardm 15:2e0d977dbb31 531 char cmdPacket[6];
wardm 15:2e0d977dbb31 532 cmdPacket[0] = cmd;
wardm 15:2e0d977dbb31 533 cmdPacket[1] = arg >> 24;
wardm 15:2e0d977dbb31 534 cmdPacket[2] = arg >> 16;
wardm 15:2e0d977dbb31 535 cmdPacket[3] = arg >> 8;
wardm 15:2e0d977dbb31 536 cmdPacket[4] = arg;
wardm 15:2e0d977dbb31 537 if (m_Crc || cmd == CMD0 || cmd == CMD8)
wardm 15:2e0d977dbb31 538 cmdPacket[5] = (SDCRC::crc7(cmdPacket, 5) << 1) | 0x01;
wardm 15:2e0d977dbb31 539 else
wardm 15:2e0d977dbb31 540 cmdPacket[5] = 0x01;
wardm 15:2e0d977dbb31 541
wardm 15:2e0d977dbb31 542 //Send the command packet
wardm 15:2e0d977dbb31 543 for (int i = 0; i < 6; i++)
wardm 15:2e0d977dbb31 544 m_Spi.write(cmdPacket[i]);
wardm 15:2e0d977dbb31 545
wardm 15:2e0d977dbb31 546 //Discard the stuff byte immediately following CMD12
wardm 15:2e0d977dbb31 547 if (cmd == CMD12)
wardm 15:2e0d977dbb31 548 m_Spi.write(0xFF);
wardm 15:2e0d977dbb31 549
wardm 15:2e0d977dbb31 550 //Allow up to 8 bytes of delay for the R1 response token
wardm 15:2e0d977dbb31 551 for (int i = 0; i < 9; i++) {
wardm 15:2e0d977dbb31 552 token = m_Spi.write(0xFF);
wardm 15:2e0d977dbb31 553 if (!(token & 0x80))
wardm 15:2e0d977dbb31 554 break;
wardm 15:2e0d977dbb31 555 }
wardm 15:2e0d977dbb31 556
wardm 15:2e0d977dbb31 557 //Verify the R1 response token
wardm 15:2e0d977dbb31 558 if (token == 0xFF) {
wardm 15:2e0d977dbb31 559 //No data was received, get out early
wardm 15:2e0d977dbb31 560 break;
wardm 15:2e0d977dbb31 561 } else if (token & (1 << 3)) {
wardm 15:2e0d977dbb31 562 //There was a CRC error, try again
wardm 15:2e0d977dbb31 563 continue;
wardm 15:2e0d977dbb31 564 } else if (token > 0x01) {
wardm 15:2e0d977dbb31 565 //An error occured, get out early
wardm 15:2e0d977dbb31 566 break;
wardm 15:2e0d977dbb31 567 }
wardm 15:2e0d977dbb31 568
wardm 15:2e0d977dbb31 569 //Handle R2 and R3/R7 response tokens
wardm 15:2e0d977dbb31 570 if (cmd == CMD13 && resp != NULL) {
wardm 15:2e0d977dbb31 571 //Read the R2 response value
wardm 15:2e0d977dbb31 572 *resp = m_Spi.write(0xFF);
wardm 15:2e0d977dbb31 573 } else if ((cmd == CMD8 || cmd == CMD58) && resp != NULL) {
wardm 15:2e0d977dbb31 574 //Read the R3/R7 response value
wardm 15:2e0d977dbb31 575 *resp = (m_Spi.write(0xFF) << 24);
wardm 15:2e0d977dbb31 576 *resp |= (m_Spi.write(0xFF) << 16);
wardm 15:2e0d977dbb31 577 *resp |= (m_Spi.write(0xFF) << 8);
wardm 15:2e0d977dbb31 578 *resp |= m_Spi.write(0xFF);
wardm 15:2e0d977dbb31 579 }
wardm 15:2e0d977dbb31 580
wardm 15:2e0d977dbb31 581 //The command was successful
wardm 15:2e0d977dbb31 582 break;
wardm 15:2e0d977dbb31 583 }
wardm 15:2e0d977dbb31 584
wardm 15:2e0d977dbb31 585 //Return the R1 response token
wardm 15:2e0d977dbb31 586 return token;
wardm 15:2e0d977dbb31 587 }
wardm 15:2e0d977dbb31 588
wardm 15:2e0d977dbb31 589 bool SDFileSystem::readData(char* buffer, int length)
wardm 15:2e0d977dbb31 590 {
wardm 15:2e0d977dbb31 591 char token;
wardm 15:2e0d977dbb31 592 unsigned short crc;
wardm 15:2e0d977dbb31 593
wardm 15:2e0d977dbb31 594 //Wait for up to 500ms for a token to arrive
wardm 15:2e0d977dbb31 595 m_Timer.start();
wardm 15:2e0d977dbb31 596 do {
wardm 15:2e0d977dbb31 597 token = m_Spi.write(0xFF);
wardm 15:2e0d977dbb31 598 } while (token == 0xFF && m_Timer.read_ms() < 500);
wardm 15:2e0d977dbb31 599 m_Timer.stop();
wardm 15:2e0d977dbb31 600 m_Timer.reset();
wardm 15:2e0d977dbb31 601
wardm 15:2e0d977dbb31 602 //Check if a valid start block token was received
wardm 15:2e0d977dbb31 603 if (token != 0xFE)
wardm 15:2e0d977dbb31 604 return false;
wardm 15:2e0d977dbb31 605
wardm 15:2e0d977dbb31 606 //Check if large frames are enabled or not
wardm 15:2e0d977dbb31 607 if (m_LargeFrames) {
wardm 15:2e0d977dbb31 608 //Switch to 16-bit frames for better performance
wardm 15:2e0d977dbb31 609 m_Spi.format(16, 0);
wardm 15:2e0d977dbb31 610
wardm 15:2e0d977dbb31 611 //Read the data block into the buffer
wardm 15:2e0d977dbb31 612 unsigned short dataWord;
wardm 15:2e0d977dbb31 613 for (int i = 0; i < length; i += 2) {
wardm 15:2e0d977dbb31 614 dataWord = m_Spi.write(0xFFFF);
wardm 15:2e0d977dbb31 615 buffer[i] = dataWord >> 8;
wardm 15:2e0d977dbb31 616 buffer[i + 1] = dataWord;
wardm 15:2e0d977dbb31 617 }
wardm 15:2e0d977dbb31 618
wardm 15:2e0d977dbb31 619 //Read the CRC16 checksum for the data block
wardm 15:2e0d977dbb31 620 crc = m_Spi.write(0xFFFF);
wardm 15:2e0d977dbb31 621
wardm 15:2e0d977dbb31 622 //Switch back to 8-bit frames
wardm 15:2e0d977dbb31 623 m_Spi.format(8, 0);
wardm 15:2e0d977dbb31 624 } else {
wardm 15:2e0d977dbb31 625 //Read the data into the buffer
wardm 15:2e0d977dbb31 626 for (int i = 0; i < length; i++)
wardm 15:2e0d977dbb31 627 buffer[i] = m_Spi.write(0xFF);
wardm 15:2e0d977dbb31 628
wardm 15:2e0d977dbb31 629 //Read the CRC16 checksum for the data block
wardm 15:2e0d977dbb31 630 crc = (m_Spi.write(0xFF) << 8);
wardm 15:2e0d977dbb31 631 crc |= m_Spi.write(0xFF);
wardm 15:2e0d977dbb31 632 }
wardm 15:2e0d977dbb31 633
wardm 15:2e0d977dbb31 634 //Return the validity of the CRC16 checksum (if enabled)
wardm 15:2e0d977dbb31 635 return (!m_Crc || crc == SDCRC::crc16(buffer, length));
wardm 15:2e0d977dbb31 636 }
wardm 15:2e0d977dbb31 637
wardm 15:2e0d977dbb31 638 char SDFileSystem::writeData(const char* buffer, char token)
wardm 15:2e0d977dbb31 639 {
wardm 15:2e0d977dbb31 640 //Calculate the CRC16 checksum for the data block (if enabled)
wardm 15:2e0d977dbb31 641 unsigned short crc = (m_Crc) ? SDCRC::crc16(buffer, 512) : 0xFFFF;
wardm 15:2e0d977dbb31 642
wardm 15:2e0d977dbb31 643 //Wait for up to 500ms for the card to become ready
wardm 15:2e0d977dbb31 644 if (!waitReady(500))
wardm 15:2e0d977dbb31 645 return false;
wardm 15:2e0d977dbb31 646
wardm 15:2e0d977dbb31 647 //Send the start block token
wardm 15:2e0d977dbb31 648 m_Spi.write(token);
wardm 15:2e0d977dbb31 649
wardm 15:2e0d977dbb31 650 //Check if large frames are enabled or not
wardm 15:2e0d977dbb31 651 if (m_LargeFrames) {
wardm 15:2e0d977dbb31 652 //Switch to 16-bit frames for better performance
wardm 15:2e0d977dbb31 653 m_Spi.format(16, 0);
wardm 15:2e0d977dbb31 654
wardm 15:2e0d977dbb31 655 //Write the data block from the buffer
wardm 15:2e0d977dbb31 656 for (int i = 0; i < 512; i += 2)
wardm 15:2e0d977dbb31 657 m_Spi.write((buffer[i] << 8) | buffer[i + 1]);
wardm 15:2e0d977dbb31 658
wardm 15:2e0d977dbb31 659 //Send the CRC16 checksum for the data block
wardm 15:2e0d977dbb31 660 m_Spi.write(crc);
wardm 15:2e0d977dbb31 661
wardm 15:2e0d977dbb31 662 //Switch back to 8-bit frames
wardm 15:2e0d977dbb31 663 m_Spi.format(8, 0);
wardm 15:2e0d977dbb31 664 } else {
wardm 15:2e0d977dbb31 665 //Write the data block from the buffer
wardm 15:2e0d977dbb31 666 for (int i = 0; i < 512; i++)
wardm 15:2e0d977dbb31 667 m_Spi.write(buffer[i]);
wardm 15:2e0d977dbb31 668
wardm 15:2e0d977dbb31 669 //Send the CRC16 checksum for the data block
wardm 15:2e0d977dbb31 670 m_Spi.write(crc >> 8);
wardm 15:2e0d977dbb31 671 m_Spi.write(crc);
wardm 15:2e0d977dbb31 672 }
wardm 15:2e0d977dbb31 673
wardm 15:2e0d977dbb31 674 //Return the data response token
wardm 15:2e0d977dbb31 675 return (m_Spi.write(0xFF) & 0x1F);
wardm 15:2e0d977dbb31 676 }
wardm 15:2e0d977dbb31 677
wardm 15:2e0d977dbb31 678 inline bool SDFileSystem::readBlock(char* buffer, unsigned int lba)
wardm 15:2e0d977dbb31 679 {
wardm 15:2e0d977dbb31 680 //Try to read the block up to 3 times
wardm 15:2e0d977dbb31 681 for (int f = 0; f < 3; f++) {
wardm 15:2e0d977dbb31 682 //Select the card, and wait for ready
wardm 15:2e0d977dbb31 683 if(!select())
wardm 15:2e0d977dbb31 684 break;
wardm 15:2e0d977dbb31 685
wardm 15:2e0d977dbb31 686 //Send CMD17(block) to read a single block
wardm 15:2e0d977dbb31 687 if (writeCommand(CMD17, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
wardm 15:2e0d977dbb31 688 //Try to read the block, and deselect the card
wardm 15:2e0d977dbb31 689 bool success = readData(buffer, 512);
wardm 15:2e0d977dbb31 690 deselect();
wardm 15:2e0d977dbb31 691
wardm 15:2e0d977dbb31 692 //Return if successful
wardm 15:2e0d977dbb31 693 if (success)
wardm 15:2e0d977dbb31 694 return true;
wardm 15:2e0d977dbb31 695 } else {
wardm 15:2e0d977dbb31 696 //The command failed, get out
wardm 15:2e0d977dbb31 697 break;
wardm 15:2e0d977dbb31 698 }
wardm 15:2e0d977dbb31 699 }
wardm 15:2e0d977dbb31 700
wardm 15:2e0d977dbb31 701 //The single block read failed
wardm 15:2e0d977dbb31 702 deselect();
wardm 15:2e0d977dbb31 703 return false;
wardm 15:2e0d977dbb31 704 }
wardm 15:2e0d977dbb31 705
wardm 15:2e0d977dbb31 706 inline bool SDFileSystem::readBlocks(char* buffer, unsigned int lba, unsigned int count)
wardm 15:2e0d977dbb31 707 {
wardm 15:2e0d977dbb31 708 //Try to read each block up to 3 times
wardm 15:2e0d977dbb31 709 for (int f = 0; f < 3;) {
wardm 15:2e0d977dbb31 710 //Select the card, and wait for ready
wardm 15:2e0d977dbb31 711 if(!select())
wardm 15:2e0d977dbb31 712 break;
wardm 15:2e0d977dbb31 713
wardm 15:2e0d977dbb31 714 //Send CMD18(block) to read multiple blocks
wardm 15:2e0d977dbb31 715 if (writeCommand(CMD18, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
wardm 15:2e0d977dbb31 716 //Try to read all of the data blocks
wardm 15:2e0d977dbb31 717 do {
wardm 15:2e0d977dbb31 718 //Read the next block, and break on errors
wardm 15:2e0d977dbb31 719 if (!readData(buffer, 512)) {
wardm 15:2e0d977dbb31 720 f++;
wardm 15:2e0d977dbb31 721 break;
wardm 15:2e0d977dbb31 722 }
wardm 15:2e0d977dbb31 723
wardm 15:2e0d977dbb31 724 //Update the variables
wardm 15:2e0d977dbb31 725 lba++;
wardm 15:2e0d977dbb31 726 buffer += 512;
wardm 15:2e0d977dbb31 727 f = 0;
wardm 15:2e0d977dbb31 728 } while (--count);
wardm 15:2e0d977dbb31 729
wardm 15:2e0d977dbb31 730 //Send CMD12(0x00000000) to stop the transmission
wardm 15:2e0d977dbb31 731 if (writeCommand(CMD12, 0x00000000) != 0x00) {
wardm 15:2e0d977dbb31 732 //The command failed, get out
wardm 15:2e0d977dbb31 733 break;
wardm 15:2e0d977dbb31 734 }
wardm 15:2e0d977dbb31 735
wardm 15:2e0d977dbb31 736 //Deselect the card, and return if successful
wardm 15:2e0d977dbb31 737 deselect();
wardm 15:2e0d977dbb31 738 if (count == 0)
wardm 15:2e0d977dbb31 739 return true;
wardm 15:2e0d977dbb31 740 } else {
wardm 15:2e0d977dbb31 741 //The command failed, get out
wardm 15:2e0d977dbb31 742 break;
wardm 15:2e0d977dbb31 743 }
wardm 15:2e0d977dbb31 744 }
wardm 15:2e0d977dbb31 745
wardm 15:2e0d977dbb31 746 //The multiple block read failed
wardm 15:2e0d977dbb31 747 deselect();
wardm 15:2e0d977dbb31 748 return false;
wardm 15:2e0d977dbb31 749 }
wardm 15:2e0d977dbb31 750
wardm 15:2e0d977dbb31 751 inline bool SDFileSystem::writeBlock(const char* buffer, unsigned int lba)
wardm 15:2e0d977dbb31 752 {
wardm 15:2e0d977dbb31 753 //Try to write the block up to 3 times
wardm 15:2e0d977dbb31 754 for (int f = 0; f < 3; f++) {
wardm 15:2e0d977dbb31 755 //Select the card, and wait for ready
wardm 15:2e0d977dbb31 756 if(!select())
wardm 15:2e0d977dbb31 757 break;
wardm 15:2e0d977dbb31 758
wardm 15:2e0d977dbb31 759 //Send CMD24(block) to write a single block
wardm 15:2e0d977dbb31 760 if (writeCommand(CMD24, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
wardm 15:2e0d977dbb31 761 //Try to write the block, and deselect the card
wardm 15:2e0d977dbb31 762 char token = writeData(buffer, 0xFE);
wardm 15:2e0d977dbb31 763 deselect();
wardm 15:2e0d977dbb31 764
wardm 15:2e0d977dbb31 765 //Check the data response token
wardm 15:2e0d977dbb31 766 if (token == 0x0A) {
wardm 15:2e0d977dbb31 767 //A CRC error occured, try again
wardm 15:2e0d977dbb31 768 continue;
wardm 15:2e0d977dbb31 769 } else if (token == 0x0C) {
wardm 15:2e0d977dbb31 770 //A write error occured, get out
wardm 15:2e0d977dbb31 771 break;
wardm 15:2e0d977dbb31 772 }
wardm 15:2e0d977dbb31 773
wardm 15:2e0d977dbb31 774 //Send CMD13(0x00000000) to verify that the programming was successful if enabled
wardm 15:2e0d977dbb31 775 if (m_WriteValidation) {
wardm 15:2e0d977dbb31 776 unsigned int resp;
wardm 15:2e0d977dbb31 777 if (commandTransaction(CMD13, 0x00000000, &resp) != 0x00 || resp != 0x00) {
wardm 15:2e0d977dbb31 778 //Some manner of unrecoverable write error occured during programming, get out
wardm 15:2e0d977dbb31 779 break;
wardm 15:2e0d977dbb31 780 }
wardm 15:2e0d977dbb31 781 }
wardm 15:2e0d977dbb31 782
wardm 15:2e0d977dbb31 783 //The data was written successfully
wardm 15:2e0d977dbb31 784 return true;
wardm 15:2e0d977dbb31 785 } else {
wardm 15:2e0d977dbb31 786 //The command failed, get out
wardm 15:2e0d977dbb31 787 break;
wardm 15:2e0d977dbb31 788 }
wardm 15:2e0d977dbb31 789 }
wardm 15:2e0d977dbb31 790
wardm 15:2e0d977dbb31 791 //The single block write failed
wardm 15:2e0d977dbb31 792 deselect();
wardm 15:2e0d977dbb31 793 return false;
wardm 15:2e0d977dbb31 794 }
wardm 15:2e0d977dbb31 795
wardm 15:2e0d977dbb31 796 inline bool SDFileSystem::writeBlocks(const char* buffer, unsigned int lba, unsigned int count)
wardm 15:2e0d977dbb31 797 {
wardm 15:2e0d977dbb31 798 char token;
wardm 15:2e0d977dbb31 799 const char* currentBuffer = buffer;
wardm 15:2e0d977dbb31 800 unsigned int currentLba = lba;
wardm 15:2e0d977dbb31 801 int currentCount = count;
wardm 15:2e0d977dbb31 802
wardm 15:2e0d977dbb31 803 //Try to write each block up to 3 times
wardm 15:2e0d977dbb31 804 for (int f = 0; f < 3;) {
wardm 15:2e0d977dbb31 805 //If this is an SD card, send ACMD23(count) to set the number of blocks to pre-erase
wardm 15:2e0d977dbb31 806 if (m_CardType != CARD_MMC) {
wardm 15:2e0d977dbb31 807 if (commandTransaction(ACMD23, currentCount) != 0x00) {
wardm 15:2e0d977dbb31 808 //The command failed, get out
wardm 15:2e0d977dbb31 809 break;
wardm 15:2e0d977dbb31 810 }
wardm 15:2e0d977dbb31 811 }
wardm 15:2e0d977dbb31 812
wardm 15:2e0d977dbb31 813 //Select the card, and wait for ready
wardm 15:2e0d977dbb31 814 if(!select())
wardm 15:2e0d977dbb31 815 break;
wardm 15:2e0d977dbb31 816
wardm 15:2e0d977dbb31 817 //Send CMD25(block) to write multiple blocks
wardm 15:2e0d977dbb31 818 if (writeCommand(CMD25, (m_CardType == CARD_SDHC) ? currentLba : currentLba << 9) == 0x00) {
wardm 15:2e0d977dbb31 819 //Try to write all of the data blocks
wardm 15:2e0d977dbb31 820 do {
wardm 15:2e0d977dbb31 821 //Write the next block and break on errors
wardm 15:2e0d977dbb31 822 token = writeData(currentBuffer, 0xFC);
wardm 15:2e0d977dbb31 823 if (token != 0x05) {
wardm 15:2e0d977dbb31 824 f++;
wardm 15:2e0d977dbb31 825 break;
wardm 15:2e0d977dbb31 826 }
wardm 15:2e0d977dbb31 827
wardm 15:2e0d977dbb31 828 //Update the variables
wardm 15:2e0d977dbb31 829 currentBuffer += 512;
wardm 15:2e0d977dbb31 830 f = 0;
wardm 15:2e0d977dbb31 831 } while (--currentCount);
wardm 15:2e0d977dbb31 832
wardm 15:2e0d977dbb31 833 //Wait for up to 500ms for the card to finish processing the last block
wardm 15:2e0d977dbb31 834 if (!waitReady(500))
wardm 15:2e0d977dbb31 835 break;
wardm 15:2e0d977dbb31 836
wardm 15:2e0d977dbb31 837 //Finalize the transmission
wardm 15:2e0d977dbb31 838 if (currentCount == 0) {
wardm 15:2e0d977dbb31 839 //Send the stop tran token, and deselect the card
wardm 15:2e0d977dbb31 840 m_Spi.write(0xFD);
wardm 15:2e0d977dbb31 841 deselect();
wardm 15:2e0d977dbb31 842
wardm 15:2e0d977dbb31 843 //Send CMD13(0x00000000) to verify that the programming was successful if enabled
wardm 15:2e0d977dbb31 844 if (m_WriteValidation) {
wardm 15:2e0d977dbb31 845 unsigned int resp;
wardm 15:2e0d977dbb31 846 if (commandTransaction(CMD13, 0x00000000, &resp) != 0x00 || resp != 0x00) {
wardm 15:2e0d977dbb31 847 //Some manner of unrecoverable write error occured during programming, get out
wardm 15:2e0d977dbb31 848 break;
wardm 15:2e0d977dbb31 849 }
wardm 15:2e0d977dbb31 850 }
wardm 15:2e0d977dbb31 851
wardm 15:2e0d977dbb31 852 //The data was written successfully
wardm 15:2e0d977dbb31 853 return true;
wardm 15:2e0d977dbb31 854 } else {
wardm 15:2e0d977dbb31 855 //Send CMD12(0x00000000) to abort the transmission
wardm 15:2e0d977dbb31 856 if (writeCommand(CMD12, 0x00000000) != 0x00) {
wardm 15:2e0d977dbb31 857 //The command failed, get out
wardm 15:2e0d977dbb31 858 break;
wardm 15:2e0d977dbb31 859 }
wardm 15:2e0d977dbb31 860
wardm 15:2e0d977dbb31 861 //Deselect the card
wardm 15:2e0d977dbb31 862 deselect();
wardm 15:2e0d977dbb31 863
wardm 15:2e0d977dbb31 864 //Check the error token
wardm 15:2e0d977dbb31 865 if (token == 0x0A) {
wardm 15:2e0d977dbb31 866 //Determine the number of well written blocks if possible
wardm 15:2e0d977dbb31 867 unsigned int writtenBlocks = 0;
wardm 15:2e0d977dbb31 868 if (m_CardType != CARD_MMC && select()) {
wardm 15:2e0d977dbb31 869 //Send ACMD22(0x00000000) to get the number of well written blocks
wardm 15:2e0d977dbb31 870 if (writeCommand(ACMD22, 0x00000000) == 0x00) {
wardm 15:2e0d977dbb31 871 //Read the data
wardm 15:2e0d977dbb31 872 char acmdData[4];
wardm 15:2e0d977dbb31 873 if (readData(acmdData, 4)) {
wardm 15:2e0d977dbb31 874 //Extract the number of well written blocks
wardm 15:2e0d977dbb31 875 writtenBlocks = acmdData[0] << 24;
wardm 15:2e0d977dbb31 876 writtenBlocks |= acmdData[1] << 16;
wardm 15:2e0d977dbb31 877 writtenBlocks |= acmdData[2] << 8;
wardm 15:2e0d977dbb31 878 writtenBlocks |= acmdData[3];
wardm 15:2e0d977dbb31 879 }
wardm 15:2e0d977dbb31 880 }
wardm 15:2e0d977dbb31 881 deselect();
wardm 15:2e0d977dbb31 882 }
wardm 15:2e0d977dbb31 883
wardm 15:2e0d977dbb31 884 //Roll back the variables based on the number of well written blocks
wardm 15:2e0d977dbb31 885 currentBuffer = buffer + (writtenBlocks << 9);
wardm 15:2e0d977dbb31 886 currentLba = lba + writtenBlocks;
wardm 15:2e0d977dbb31 887 currentCount = count - writtenBlocks;
wardm 15:2e0d977dbb31 888
wardm 15:2e0d977dbb31 889 //Try again
wardm 15:2e0d977dbb31 890 continue;
wardm 15:2e0d977dbb31 891 } else {
wardm 15:2e0d977dbb31 892 //A write error occured, get out
wardm 15:2e0d977dbb31 893 break;
wardm 15:2e0d977dbb31 894 }
wardm 15:2e0d977dbb31 895 }
wardm 15:2e0d977dbb31 896 } else {
wardm 15:2e0d977dbb31 897 //The command failed, get out
wardm 15:2e0d977dbb31 898 break;
wardm 15:2e0d977dbb31 899 }
wardm 15:2e0d977dbb31 900 }
wardm 15:2e0d977dbb31 901
wardm 15:2e0d977dbb31 902 //The multiple block write failed
wardm 15:2e0d977dbb31 903 deselect();
wardm 15:2e0d977dbb31 904 return false;
wardm 15:2e0d977dbb31 905 }
wardm 15:2e0d977dbb31 906
wardm 15:2e0d977dbb31 907 bool SDFileSystem::enableHighSpeedMode()
wardm 15:2e0d977dbb31 908 {
wardm 15:2e0d977dbb31 909 //Try to issue CMD6 up to 3 times
wardm 15:2e0d977dbb31 910 for (int f = 0; f < 3; f++) {
wardm 15:2e0d977dbb31 911 //Select the card, and wait for ready
wardm 15:2e0d977dbb31 912 if(!select())
wardm 15:2e0d977dbb31 913 break;
wardm 15:2e0d977dbb31 914
wardm 15:2e0d977dbb31 915 //Send CMD6(0x80FFFFF1) to change the access mode to high speed
wardm 15:2e0d977dbb31 916 if (writeCommand(CMD6, 0x80FFFFF1) == 0x00) {
wardm 15:2e0d977dbb31 917 //Read the 64B status data block
wardm 15:2e0d977dbb31 918 char status[64];
wardm 15:2e0d977dbb31 919 bool success = readData(status, 64);
wardm 15:2e0d977dbb31 920 deselect();
wardm 15:2e0d977dbb31 921 if (success) {
wardm 15:2e0d977dbb31 922 //Return whether or not the operation was successful
wardm 15:2e0d977dbb31 923 return ((status[16] & 0x0F) == 0x1);
wardm 15:2e0d977dbb31 924 }
wardm 15:2e0d977dbb31 925 } else {
wardm 15:2e0d977dbb31 926 //The command failed, get out
wardm 15:2e0d977dbb31 927 break;
wardm 15:2e0d977dbb31 928 }
wardm 15:2e0d977dbb31 929 }
wardm 15:2e0d977dbb31 930
wardm 15:2e0d977dbb31 931 //The operation failed 3 times
wardm 15:2e0d977dbb31 932 deselect();
wardm 15:2e0d977dbb31 933 return false;
wardm 15:2e0d977dbb31 934 }