A version of the USBMSD_SD library that doesn't try to connect in the constructor. I made this change to support an operation mode where USB MSD can be enabled later in program operation without hanging.

Dependents:   Rocket

Fork of USBMSD_SD by Greg Steiert

Committer:
danjulio
Date:
Sun Jun 11 04:05:51 2017 +0000
Revision:
4:46888c9d5cd7
Parent:
3:cce1e689c548
Changed to not connect in constructor

Who changed what in which revision?

UserRevisionLine numberNew contents of line
samux 2:055119ccf5a7 1 /* mbed Microcontroller Library
samux 2:055119ccf5a7 2 * Copyright (c) 2006-2012 ARM Limited
samux 0:de50a209c5a9 3 *
danjulio 4:46888c9d5cd7 4 * Modified by Dan Julio 5/2017 - do not "connect" during instantiation
danjulio 4:46888c9d5cd7 5 *
samux 0:de50a209c5a9 6 * Permission is hereby granted, free of charge, to any person obtaining a copy
samux 0:de50a209c5a9 7 * of this software and associated documentation files (the "Software"), to deal
samux 0:de50a209c5a9 8 * in the Software without restriction, including without limitation the rights
samux 0:de50a209c5a9 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
samux 0:de50a209c5a9 10 * copies of the Software, and to permit persons to whom the Software is
samux 0:de50a209c5a9 11 * furnished to do so, subject to the following conditions:
samux 0:de50a209c5a9 12 *
samux 0:de50a209c5a9 13 * The above copyright notice and this permission notice shall be included in
samux 0:de50a209c5a9 14 * all copies or substantial portions of the Software.
samux 0:de50a209c5a9 15 *
samux 0:de50a209c5a9 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
samux 0:de50a209c5a9 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
samux 0:de50a209c5a9 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
samux 0:de50a209c5a9 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
samux 0:de50a209c5a9 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
samux 2:055119ccf5a7 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
samux 2:055119ccf5a7 22 * SOFTWARE.
samux 0:de50a209c5a9 23 */
samux 0:de50a209c5a9 24 /* Introduction
samux 0:de50a209c5a9 25 * ------------
samux 0:de50a209c5a9 26 * SD and MMC cards support a number of interfaces, but common to them all
samux 0:de50a209c5a9 27 * is one based on SPI. This is the one I'm implmenting because it means
samux 2:055119ccf5a7 28 * it is much more portable even though not so performant, and we already
samux 0:de50a209c5a9 29 * have the mbed SPI Interface!
samux 0:de50a209c5a9 30 *
samux 2:055119ccf5a7 31 * The main reference I'm using is Chapter 7, "SPI Mode" of:
samux 0:de50a209c5a9 32 * http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
samux 0:de50a209c5a9 33 *
samux 0:de50a209c5a9 34 * SPI Startup
samux 0:de50a209c5a9 35 * -----------
samux 0:de50a209c5a9 36 * The SD card powers up in SD mode. The SPI interface mode is selected by
samux 2:055119ccf5a7 37 * asserting CS low and sending the reset command (CMD0). The card will
samux 0:de50a209c5a9 38 * respond with a (R1) response.
samux 0:de50a209c5a9 39 *
samux 2:055119ccf5a7 40 * CMD8 is optionally sent to determine the voltage range supported, and
samux 2:055119ccf5a7 41 * indirectly determine whether it is a version 1.x SD/non-SD card or
samux 0:de50a209c5a9 42 * version 2.x. I'll just ignore this for now.
samux 0:de50a209c5a9 43 *
samux 0:de50a209c5a9 44 * ACMD41 is repeatedly issued to initialise the card, until "in idle"
samux 0:de50a209c5a9 45 * (bit 0) of the R1 response goes to '0', indicating it is initialised.
samux 0:de50a209c5a9 46 *
samux 0:de50a209c5a9 47 * You should also indicate whether the host supports High Capicity cards,
samux 0:de50a209c5a9 48 * and check whether the card is high capacity - i'll also ignore this
samux 0:de50a209c5a9 49 *
samux 0:de50a209c5a9 50 * SPI Protocol
samux 0:de50a209c5a9 51 * ------------
samux 0:de50a209c5a9 52 * The SD SPI protocol is based on transactions made up of 8-bit words, with
samux 0:de50a209c5a9 53 * the host starting every bus transaction by asserting the CS signal low. The
samux 0:de50a209c5a9 54 * card always responds to commands, data blocks and errors.
samux 2:055119ccf5a7 55 *
samux 2:055119ccf5a7 56 * The protocol supports a CRC, but by default it is off (except for the
samux 0:de50a209c5a9 57 * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
samux 2:055119ccf5a7 58 * I'll leave the CRC off I think!
samux 2:055119ccf5a7 59 *
samux 2:055119ccf5a7 60 * Standard capacity cards have variable data block sizes, whereas High
samux 0:de50a209c5a9 61 * Capacity cards fix the size of data block to 512 bytes. I'll therefore
samux 0:de50a209c5a9 62 * just always use the Standard Capacity cards with a block size of 512 bytes.
samux 0:de50a209c5a9 63 * This is set with CMD16.
samux 0:de50a209c5a9 64 *
samux 2:055119ccf5a7 65 * You can read and write single blocks (CMD17, CMD25) or multiple blocks
samux 0:de50a209c5a9 66 * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
samux 2:055119ccf5a7 67 * the card gets a read command, it responds with a response token, and then
samux 0:de50a209c5a9 68 * a data token or an error.
samux 2:055119ccf5a7 69 *
samux 0:de50a209c5a9 70 * SPI Command Format
samux 0:de50a209c5a9 71 * ------------------
samux 0:de50a209c5a9 72 * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
samux 0:de50a209c5a9 73 *
samux 0:de50a209c5a9 74 * +---------------+------------+------------+-----------+----------+--------------+
samux 0:de50a209c5a9 75 * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
samux 0:de50a209c5a9 76 * +---------------+------------+------------+-----------+----------+--------------+
samux 0:de50a209c5a9 77 *
samux 0:de50a209c5a9 78 * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
samux 0:de50a209c5a9 79 *
samux 0:de50a209c5a9 80 * All Application Specific commands shall be preceded with APP_CMD (CMD55).
samux 0:de50a209c5a9 81 *
samux 0:de50a209c5a9 82 * SPI Response Format
samux 0:de50a209c5a9 83 * -------------------
samux 0:de50a209c5a9 84 * The main response format (R1) is a status byte (normally zero). Key flags:
samux 2:055119ccf5a7 85 * idle - 1 if the card is in an idle state/initialising
samux 0:de50a209c5a9 86 * cmd - 1 if an illegal command code was detected
samux 0:de50a209c5a9 87 *
samux 0:de50a209c5a9 88 * +-------------------------------------------------+
samux 0:de50a209c5a9 89 * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
samux 0:de50a209c5a9 90 * +-------------------------------------------------+
samux 0:de50a209c5a9 91 *
samux 0:de50a209c5a9 92 * R1b is the same, except it is followed by a busy signal (zeros) until
samux 0:de50a209c5a9 93 * the first non-zero byte when it is ready again.
samux 0:de50a209c5a9 94 *
samux 0:de50a209c5a9 95 * Data Response Token
samux 0:de50a209c5a9 96 * -------------------
samux 2:055119ccf5a7 97 * Every data block written to the card is acknowledged by a byte
samux 0:de50a209c5a9 98 * response token
samux 0:de50a209c5a9 99 *
samux 0:de50a209c5a9 100 * +----------------------+
samux 0:de50a209c5a9 101 * | xxx | 0 | status | 1 |
samux 0:de50a209c5a9 102 * +----------------------+
samux 0:de50a209c5a9 103 * 010 - OK!
samux 0:de50a209c5a9 104 * 101 - CRC Error
samux 0:de50a209c5a9 105 * 110 - Write Error
samux 0:de50a209c5a9 106 *
samux 0:de50a209c5a9 107 * Single Block Read and Write
samux 0:de50a209c5a9 108 * ---------------------------
samux 0:de50a209c5a9 109 *
samux 0:de50a209c5a9 110 * Block transfers have a byte header, followed by the data, followed
samux 0:de50a209c5a9 111 * by a 16-bit CRC. In our case, the data will always be 512 bytes.
samux 2:055119ccf5a7 112 *
samux 0:de50a209c5a9 113 * +------+---------+---------+- - - -+---------+-----------+----------+
samux 2:055119ccf5a7 114 * | 0xFE | data[0] | data[1] | | data[n] | crc[15:8] | crc[7:0] |
samux 0:de50a209c5a9 115 * +------+---------+---------+- - - -+---------+-----------+----------+
samux 0:de50a209c5a9 116 */
samux 0:de50a209c5a9 117 #include "USBMSD_SD.h"
samux 2:055119ccf5a7 118 #include "mbed_debug.h"
samux 0:de50a209c5a9 119
samux 0:de50a209c5a9 120 #define SD_COMMAND_TIMEOUT 5000
samux 0:de50a209c5a9 121
samux 2:055119ccf5a7 122 #define SD_DBG 0
samux 2:055119ccf5a7 123
samux 0:de50a209c5a9 124 USBMSD_SD::USBMSD_SD(PinName mosi, PinName miso, PinName sclk, PinName cs) :
samux 2:055119ccf5a7 125 _spi(mosi, miso, sclk), _cs(cs) {
samux 2:055119ccf5a7 126 _cs = 1;
samux 2:055119ccf5a7 127
samux 2:055119ccf5a7 128 //no init
samux 2:055119ccf5a7 129 _status = 0x01;
samux 2:055119ccf5a7 130
danjulio 4:46888c9d5cd7 131 // Modified by Dan Julio 5/2017 to prevent this object from blocking
danjulio 4:46888c9d5cd7 132 // until manually connected by user code
danjulio 4:46888c9d5cd7 133 //connect();
samux 0:de50a209c5a9 134 }
samux 0:de50a209c5a9 135
samux 0:de50a209c5a9 136 #define R1_IDLE_STATE (1 << 0)
samux 0:de50a209c5a9 137 #define R1_ERASE_RESET (1 << 1)
samux 0:de50a209c5a9 138 #define R1_ILLEGAL_COMMAND (1 << 2)
samux 0:de50a209c5a9 139 #define R1_COM_CRC_ERROR (1 << 3)
samux 0:de50a209c5a9 140 #define R1_ERASE_SEQUENCE_ERROR (1 << 4)
samux 0:de50a209c5a9 141 #define R1_ADDRESS_ERROR (1 << 5)
samux 0:de50a209c5a9 142 #define R1_PARAMETER_ERROR (1 << 6)
samux 0:de50a209c5a9 143
samux 0:de50a209c5a9 144 // Types
samux 0:de50a209c5a9 145 // - v1.x Standard Capacity
samux 0:de50a209c5a9 146 // - v2.x Standard Capacity
samux 0:de50a209c5a9 147 // - v2.x High Capacity
samux 0:de50a209c5a9 148 // - Not recognised as an SD Card
samux 0:de50a209c5a9 149 #define SDCARD_FAIL 0
samux 0:de50a209c5a9 150 #define SDCARD_V1 1
samux 0:de50a209c5a9 151 #define SDCARD_V2 2
samux 0:de50a209c5a9 152 #define SDCARD_V2HC 3
samux 0:de50a209c5a9 153
samux 0:de50a209c5a9 154 int USBMSD_SD::initialise_card() {
samux 0:de50a209c5a9 155 // Set to 100kHz for initialisation, and clock card with cs = 1
samux 2:055119ccf5a7 156 _spi.frequency(100000);
samux 0:de50a209c5a9 157 _cs = 1;
samux 2:055119ccf5a7 158 for (int i = 0; i < 16; i++) {
samux 0:de50a209c5a9 159 _spi.write(0xFF);
samux 0:de50a209c5a9 160 }
samux 0:de50a209c5a9 161 // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
samux 2:055119ccf5a7 162 if (_cmd(0, 0) != R1_IDLE_STATE) {
samux 2:055119ccf5a7 163 debug("No disk, or could not put SD card in to SPI idle state\n");
samux 0:de50a209c5a9 164 return SDCARD_FAIL;
samux 0:de50a209c5a9 165 }
samux 2:055119ccf5a7 166
samux 0:de50a209c5a9 167 // send CMD8 to determine whther it is ver 2.x
samux 0:de50a209c5a9 168 int r = _cmd8();
samux 2:055119ccf5a7 169 if (r == R1_IDLE_STATE) {
samux 0:de50a209c5a9 170 return initialise_card_v2();
samux 2:055119ccf5a7 171 } else if (r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
samux 0:de50a209c5a9 172 return initialise_card_v1();
samux 0:de50a209c5a9 173 } else {
samux 2:055119ccf5a7 174 debug("Not in idle state after sending CMD8 (not an SD card?)\n");
samux 0:de50a209c5a9 175 return SDCARD_FAIL;
samux 0:de50a209c5a9 176 }
samux 0:de50a209c5a9 177 }
samux 0:de50a209c5a9 178
samux 0:de50a209c5a9 179 int USBMSD_SD::initialise_card_v1() {
samux 2:055119ccf5a7 180 for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
samux 2:055119ccf5a7 181 _cmd(55, 0);
samux 2:055119ccf5a7 182 if (_cmd(41, 0) == 0) {
samux 2:055119ccf5a7 183 cdv = 512;
samux 2:055119ccf5a7 184 debug_if(SD_DBG, "\n\rInit: SEDCARD_V1\n\r");
samux 0:de50a209c5a9 185 return SDCARD_V1;
samux 0:de50a209c5a9 186 }
samux 0:de50a209c5a9 187 }
samux 2:055119ccf5a7 188
samux 2:055119ccf5a7 189 debug("Timeout waiting for v1.x card\n");
samux 0:de50a209c5a9 190 return SDCARD_FAIL;
samux 0:de50a209c5a9 191 }
samux 0:de50a209c5a9 192
samux 0:de50a209c5a9 193 int USBMSD_SD::initialise_card_v2() {
samux 2:055119ccf5a7 194 for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
samux 2:055119ccf5a7 195 wait_ms(50);
samux 2:055119ccf5a7 196 _cmd58();
samux 2:055119ccf5a7 197 _cmd(55, 0);
samux 2:055119ccf5a7 198 if (_cmd(41, 0x40000000) == 0) {
samux 0:de50a209c5a9 199 _cmd58();
samux 2:055119ccf5a7 200 debug_if(SD_DBG, "\n\rInit: SDCARD_V2\n\r");
samux 2:055119ccf5a7 201 cdv = 1;
samux 0:de50a209c5a9 202 return SDCARD_V2;
samux 0:de50a209c5a9 203 }
samux 0:de50a209c5a9 204 }
samux 2:055119ccf5a7 205
samux 2:055119ccf5a7 206 debug("Timeout waiting for v2.x card\n");
samux 0:de50a209c5a9 207 return SDCARD_FAIL;
samux 0:de50a209c5a9 208 }
samux 0:de50a209c5a9 209
samux 0:de50a209c5a9 210 int USBMSD_SD::disk_initialize() {
samux 0:de50a209c5a9 211 int i = initialise_card();
samux 2:055119ccf5a7 212 debug_if(SD_DBG, "init card = %d\n", i);
samux 0:de50a209c5a9 213 _sectors = _sd_sectors();
samux 2:055119ccf5a7 214
samux 0:de50a209c5a9 215 // Set block length to 512 (CMD16)
samux 2:055119ccf5a7 216 if (_cmd(16, 512) != 0) {
samux 2:055119ccf5a7 217 debug("Set 512-byte block timed out\n");
samux 0:de50a209c5a9 218 return 1;
samux 0:de50a209c5a9 219 }
samux 2:055119ccf5a7 220
samux 0:de50a209c5a9 221 _spi.frequency(5000000); // Set to 5MHz for data transfer
samux 2:055119ccf5a7 222
samux 1:923991b026e7 223 // OK
samux 1:923991b026e7 224 _status = 0x00;
samux 2:055119ccf5a7 225
samux 0:de50a209c5a9 226 return 0;
samux 0:de50a209c5a9 227 }
samux 0:de50a209c5a9 228
switches 3:cce1e689c548 229 int USBMSD_SD::disk_write(const uint8_t* buffer, uint64_t block_number, uint8_t count) {
switches 3:cce1e689c548 230 for (uint64_t b = block_number; b < block_number + count; b++) {
switches 3:cce1e689c548 231 // set write address for single block (CMD24)
switches 3:cce1e689c548 232 if (_cmd(24, b * cdv) != 0) {
switches 3:cce1e689c548 233 return 1;
switches 3:cce1e689c548 234 }
switches 3:cce1e689c548 235
switches 3:cce1e689c548 236 // send the data block
switches 3:cce1e689c548 237 _write(buffer, 512);
switches 3:cce1e689c548 238 buffer += 512;
samux 0:de50a209c5a9 239 }
samux 2:055119ccf5a7 240
samux 2:055119ccf5a7 241 return 0;
samux 0:de50a209c5a9 242 }
samux 0:de50a209c5a9 243
switches 3:cce1e689c548 244 int USBMSD_SD::disk_read(uint8_t* buffer, uint64_t block_number, uint8_t count) {
switches 3:cce1e689c548 245 for (uint64_t b = block_number; b < block_number + count; b++) {
switches 3:cce1e689c548 246 // set read address for single block (CMD17)
switches 3:cce1e689c548 247 if (_cmd(17, b * cdv) != 0) {
switches 3:cce1e689c548 248 return 1;
switches 3:cce1e689c548 249 }
switches 3:cce1e689c548 250
switches 3:cce1e689c548 251 // receive the data
switches 3:cce1e689c548 252 _read(buffer, 512);
switches 3:cce1e689c548 253 buffer += 512;
samux 0:de50a209c5a9 254 }
switches 3:cce1e689c548 255
samux 0:de50a209c5a9 256 return 0;
samux 0:de50a209c5a9 257 }
samux 0:de50a209c5a9 258
samux 1:923991b026e7 259 int USBMSD_SD::disk_status() { return _status; }
samux 0:de50a209c5a9 260 int USBMSD_SD::disk_sync() { return 0; }
samux 2:055119ccf5a7 261 uint64_t USBMSD_SD::disk_sectors() { return _sectors; }
samux 2:055119ccf5a7 262
samux 0:de50a209c5a9 263
samux 0:de50a209c5a9 264 // PRIVATE FUNCTIONS
samux 0:de50a209c5a9 265 int USBMSD_SD::_cmd(int cmd, int arg) {
samux 2:055119ccf5a7 266 _cs = 0;
samux 2:055119ccf5a7 267
samux 0:de50a209c5a9 268 // send a command
samux 0:de50a209c5a9 269 _spi.write(0x40 | cmd);
samux 0:de50a209c5a9 270 _spi.write(arg >> 24);
samux 0:de50a209c5a9 271 _spi.write(arg >> 16);
samux 0:de50a209c5a9 272 _spi.write(arg >> 8);
samux 0:de50a209c5a9 273 _spi.write(arg >> 0);
samux 0:de50a209c5a9 274 _spi.write(0x95);
samux 2:055119ccf5a7 275
samux 0:de50a209c5a9 276 // wait for the repsonse (response[7] == 0)
samux 2:055119ccf5a7 277 for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
samux 0:de50a209c5a9 278 int response = _spi.write(0xFF);
samux 2:055119ccf5a7 279 if (!(response & 0x80)) {
samux 0:de50a209c5a9 280 _cs = 1;
samux 0:de50a209c5a9 281 _spi.write(0xFF);
samux 0:de50a209c5a9 282 return response;
samux 0:de50a209c5a9 283 }
samux 0:de50a209c5a9 284 }
samux 0:de50a209c5a9 285 _cs = 1;
samux 0:de50a209c5a9 286 _spi.write(0xFF);
samux 0:de50a209c5a9 287 return -1; // timeout
samux 0:de50a209c5a9 288 }
samux 0:de50a209c5a9 289 int USBMSD_SD::_cmdx(int cmd, int arg) {
samux 2:055119ccf5a7 290 _cs = 0;
samux 2:055119ccf5a7 291
samux 0:de50a209c5a9 292 // send a command
samux 0:de50a209c5a9 293 _spi.write(0x40 | cmd);
samux 0:de50a209c5a9 294 _spi.write(arg >> 24);
samux 0:de50a209c5a9 295 _spi.write(arg >> 16);
samux 0:de50a209c5a9 296 _spi.write(arg >> 8);
samux 0:de50a209c5a9 297 _spi.write(arg >> 0);
samux 0:de50a209c5a9 298 _spi.write(0x95);
samux 2:055119ccf5a7 299
samux 0:de50a209c5a9 300 // wait for the repsonse (response[7] == 0)
samux 2:055119ccf5a7 301 for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
samux 0:de50a209c5a9 302 int response = _spi.write(0xFF);
samux 2:055119ccf5a7 303 if (!(response & 0x80)) {
samux 0:de50a209c5a9 304 return response;
samux 0:de50a209c5a9 305 }
samux 0:de50a209c5a9 306 }
samux 0:de50a209c5a9 307 _cs = 1;
samux 0:de50a209c5a9 308 _spi.write(0xFF);
samux 0:de50a209c5a9 309 return -1; // timeout
samux 0:de50a209c5a9 310 }
samux 0:de50a209c5a9 311
samux 0:de50a209c5a9 312
samux 0:de50a209c5a9 313 int USBMSD_SD::_cmd58() {
samux 2:055119ccf5a7 314 _cs = 0;
samux 0:de50a209c5a9 315 int arg = 0;
samux 0:de50a209c5a9 316
samux 0:de50a209c5a9 317 // send a command
samux 0:de50a209c5a9 318 _spi.write(0x40 | 58);
samux 0:de50a209c5a9 319 _spi.write(arg >> 24);
samux 0:de50a209c5a9 320 _spi.write(arg >> 16);
samux 0:de50a209c5a9 321 _spi.write(arg >> 8);
samux 0:de50a209c5a9 322 _spi.write(arg >> 0);
samux 0:de50a209c5a9 323 _spi.write(0x95);
samux 2:055119ccf5a7 324
samux 0:de50a209c5a9 325 // wait for the repsonse (response[7] == 0)
samux 2:055119ccf5a7 326 for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
samux 0:de50a209c5a9 327 int response = _spi.write(0xFF);
samux 2:055119ccf5a7 328 if (!(response & 0x80)) {
samux 0:de50a209c5a9 329 int ocr = _spi.write(0xFF) << 24;
samux 0:de50a209c5a9 330 ocr |= _spi.write(0xFF) << 16;
samux 0:de50a209c5a9 331 ocr |= _spi.write(0xFF) << 8;
samux 0:de50a209c5a9 332 ocr |= _spi.write(0xFF) << 0;
samux 0:de50a209c5a9 333 _cs = 1;
samux 0:de50a209c5a9 334 _spi.write(0xFF);
samux 0:de50a209c5a9 335 return response;
samux 0:de50a209c5a9 336 }
samux 0:de50a209c5a9 337 }
samux 0:de50a209c5a9 338 _cs = 1;
samux 0:de50a209c5a9 339 _spi.write(0xFF);
samux 0:de50a209c5a9 340 return -1; // timeout
samux 0:de50a209c5a9 341 }
samux 0:de50a209c5a9 342
samux 0:de50a209c5a9 343 int USBMSD_SD::_cmd8() {
samux 2:055119ccf5a7 344 _cs = 0;
samux 0:de50a209c5a9 345
samux 0:de50a209c5a9 346 // send a command
samux 0:de50a209c5a9 347 _spi.write(0x40 | 8); // CMD8
samux 0:de50a209c5a9 348 _spi.write(0x00); // reserved
samux 0:de50a209c5a9 349 _spi.write(0x00); // reserved
samux 0:de50a209c5a9 350 _spi.write(0x01); // 3.3v
samux 0:de50a209c5a9 351 _spi.write(0xAA); // check pattern
samux 0:de50a209c5a9 352 _spi.write(0x87); // crc
samux 2:055119ccf5a7 353
samux 0:de50a209c5a9 354 // wait for the repsonse (response[7] == 0)
samux 2:055119ccf5a7 355 for (int i = 0; i < SD_COMMAND_TIMEOUT * 1000; i++) {
samux 0:de50a209c5a9 356 char response[5];
samux 0:de50a209c5a9 357 response[0] = _spi.write(0xFF);
samux 2:055119ccf5a7 358 if (!(response[0] & 0x80)) {
samux 2:055119ccf5a7 359 for (int j = 1; j < 5; j++) {
samux 2:055119ccf5a7 360 response[i] = _spi.write(0xFF);
samux 2:055119ccf5a7 361 }
samux 2:055119ccf5a7 362 _cs = 1;
samux 2:055119ccf5a7 363 _spi.write(0xFF);
samux 2:055119ccf5a7 364 return response[0];
samux 0:de50a209c5a9 365 }
samux 0:de50a209c5a9 366 }
samux 0:de50a209c5a9 367 _cs = 1;
samux 0:de50a209c5a9 368 _spi.write(0xFF);
samux 0:de50a209c5a9 369 return -1; // timeout
samux 0:de50a209c5a9 370 }
samux 0:de50a209c5a9 371
samux 2:055119ccf5a7 372 int USBMSD_SD::_read(uint8_t *buffer, uint32_t length) {
samux 0:de50a209c5a9 373 _cs = 0;
samux 2:055119ccf5a7 374
samux 0:de50a209c5a9 375 // read until start byte (0xFF)
samux 2:055119ccf5a7 376 while (_spi.write(0xFF) != 0xFE);
samux 2:055119ccf5a7 377
samux 0:de50a209c5a9 378 // read data
samux 2:055119ccf5a7 379 for (int i = 0; i < length; i++) {
samux 0:de50a209c5a9 380 buffer[i] = _spi.write(0xFF);
samux 0:de50a209c5a9 381 }
samux 0:de50a209c5a9 382 _spi.write(0xFF); // checksum
samux 0:de50a209c5a9 383 _spi.write(0xFF);
samux 2:055119ccf5a7 384
samux 2:055119ccf5a7 385 _cs = 1;
samux 0:de50a209c5a9 386 _spi.write(0xFF);
samux 0:de50a209c5a9 387 return 0;
samux 0:de50a209c5a9 388 }
samux 0:de50a209c5a9 389
samux 2:055119ccf5a7 390 int USBMSD_SD::_write(const uint8_t*buffer, uint32_t length) {
samux 0:de50a209c5a9 391 _cs = 0;
samux 0:de50a209c5a9 392
samux 0:de50a209c5a9 393 // indicate start of block
samux 0:de50a209c5a9 394 _spi.write(0xFE);
samux 0:de50a209c5a9 395
samux 0:de50a209c5a9 396 // write the data
samux 2:055119ccf5a7 397 for (int i = 0; i < length; i++) {
samux 0:de50a209c5a9 398 _spi.write(buffer[i]);
samux 0:de50a209c5a9 399 }
samux 0:de50a209c5a9 400
samux 0:de50a209c5a9 401 // write the checksum
samux 2:055119ccf5a7 402 _spi.write(0xFF);
samux 0:de50a209c5a9 403 _spi.write(0xFF);
samux 2:055119ccf5a7 404
samux 2:055119ccf5a7 405 // check the response token
samux 2:055119ccf5a7 406 if ((_spi.write(0xFF) & 0x1F) != 0x05) {
samux 0:de50a209c5a9 407 _cs = 1;
samux 2:055119ccf5a7 408 _spi.write(0xFF);
samux 0:de50a209c5a9 409 return 1;
samux 0:de50a209c5a9 410 }
samux 2:055119ccf5a7 411
samux 0:de50a209c5a9 412 // wait for write to finish
samux 2:055119ccf5a7 413 while (_spi.write(0xFF) == 0);
samux 2:055119ccf5a7 414
samux 2:055119ccf5a7 415 _cs = 1;
samux 0:de50a209c5a9 416 _spi.write(0xFF);
samux 0:de50a209c5a9 417 return 0;
samux 0:de50a209c5a9 418 }
samux 0:de50a209c5a9 419
samux 2:055119ccf5a7 420 static uint32_t ext_bits(unsigned char *data, int msb, int lsb) {
samux 2:055119ccf5a7 421 uint32_t bits = 0;
samux 2:055119ccf5a7 422 uint32_t size = 1 + msb - lsb;
samux 2:055119ccf5a7 423 for (int i = 0; i < size; i++) {
samux 2:055119ccf5a7 424 uint32_t position = lsb + i;
samux 2:055119ccf5a7 425 uint32_t byte = 15 - (position >> 3);
samux 2:055119ccf5a7 426 uint32_t bit = position & 0x7;
samux 2:055119ccf5a7 427 uint32_t value = (data[byte] >> bit) & 1;
samux 0:de50a209c5a9 428 bits |= value << i;
samux 0:de50a209c5a9 429 }
samux 0:de50a209c5a9 430 return bits;
samux 0:de50a209c5a9 431 }
samux 0:de50a209c5a9 432
samux 2:055119ccf5a7 433 uint64_t USBMSD_SD::_sd_sectors() {
samux 2:055119ccf5a7 434 uint32_t c_size, c_size_mult, read_bl_len;
samux 2:055119ccf5a7 435 uint32_t block_len, mult, blocknr, capacity;
samux 2:055119ccf5a7 436 uint32_t hc_c_size;
samux 2:055119ccf5a7 437 uint64_t blocks;
samux 2:055119ccf5a7 438
samux 0:de50a209c5a9 439 // CMD9, Response R2 (R1 byte + 16-byte block read)
samux 2:055119ccf5a7 440 if (_cmdx(9, 0) != 0) {
samux 2:055119ccf5a7 441 debug("Didn't get a response from the disk\n");
samux 0:de50a209c5a9 442 return 0;
samux 0:de50a209c5a9 443 }
samux 0:de50a209c5a9 444
samux 2:055119ccf5a7 445 uint8_t csd[16];
samux 2:055119ccf5a7 446 if (_read(csd, 16) != 0) {
samux 2:055119ccf5a7 447 debug("Couldn't read csd response from disk\n");
samux 0:de50a209c5a9 448 return 0;
samux 0:de50a209c5a9 449 }
samux 2:055119ccf5a7 450
samux 0:de50a209c5a9 451 // csd_structure : csd[127:126]
samux 0:de50a209c5a9 452 // c_size : csd[73:62]
samux 0:de50a209c5a9 453 // c_size_mult : csd[49:47]
samux 0:de50a209c5a9 454 // read_bl_len : csd[83:80] - the *maximum* read block length
samux 2:055119ccf5a7 455
samux 0:de50a209c5a9 456 int csd_structure = ext_bits(csd, 127, 126);
samux 0:de50a209c5a9 457
samux 2:055119ccf5a7 458 switch (csd_structure) {
samux 2:055119ccf5a7 459 case 0:
samux 2:055119ccf5a7 460 cdv = 512;
samux 2:055119ccf5a7 461 c_size = ext_bits(csd, 73, 62);
samux 2:055119ccf5a7 462 c_size_mult = ext_bits(csd, 49, 47);
samux 2:055119ccf5a7 463 read_bl_len = ext_bits(csd, 83, 80);
samux 2:055119ccf5a7 464
samux 2:055119ccf5a7 465 block_len = 1 << read_bl_len;
samux 2:055119ccf5a7 466 mult = 1 << (c_size_mult + 2);
samux 2:055119ccf5a7 467 blocknr = (c_size + 1) * mult;
samux 2:055119ccf5a7 468 capacity = blocknr * block_len;
samux 2:055119ccf5a7 469 blocks = capacity / 512;
samux 2:055119ccf5a7 470 debug_if(SD_DBG, "\n\rSDCard\n\rc_size: %d \n\rcapacity: %ld \n\rsectors: %lld\n\r", c_size, capacity, blocks);
samux 2:055119ccf5a7 471 break;
samux 0:de50a209c5a9 472
samux 2:055119ccf5a7 473 case 1:
samux 2:055119ccf5a7 474 cdv = 1;
samux 2:055119ccf5a7 475 hc_c_size = ext_bits(csd, 63, 48);
samux 2:055119ccf5a7 476 blocks = (hc_c_size+1)*1024;
samux 2:055119ccf5a7 477 debug_if(SD_DBG, "\n\rSDHC Card \n\rhc_c_size: %d\n\rcapacity: %lld \n\rsectors: %lld\n\r", hc_c_size, blocks*512, blocks);
samux 2:055119ccf5a7 478 break;
samux 2:055119ccf5a7 479
samux 2:055119ccf5a7 480 default:
samux 2:055119ccf5a7 481 debug("CSD struct unsupported\r\n");
samux 2:055119ccf5a7 482 return 0;
samux 2:055119ccf5a7 483 };
samux 0:de50a209c5a9 484 return blocks;
samux 0:de50a209c5a9 485 }