ok

Dependents:   USB-MSD_SD_HelloWorld_Mbed-RAMVersion

Fork of USBMSD_SD by Samuel Mokrani

Committer:
avnisha
Date:
Mon Aug 19 04:35:39 2013 +0000
Revision:
3:dbd7383533e6
Parent:
2:055119ccf5a7
ok

Who changed what in which revision?

UserRevisionLine numberNew contents of line
avnisha 3:dbd7383533e6 1
avnisha 3:dbd7383533e6 2 #ifdef OLD
samux 2:055119ccf5a7 3 /* mbed Microcontroller Library
samux 2:055119ccf5a7 4 * Copyright (c) 2006-2012 ARM Limited
samux 0:de50a209c5a9 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
samux 2:055119ccf5a7 131 connect();
samux 0:de50a209c5a9 132 }
samux 0:de50a209c5a9 133
samux 0:de50a209c5a9 134 #define R1_IDLE_STATE (1 << 0)
samux 0:de50a209c5a9 135 #define R1_ERASE_RESET (1 << 1)
samux 0:de50a209c5a9 136 #define R1_ILLEGAL_COMMAND (1 << 2)
samux 0:de50a209c5a9 137 #define R1_COM_CRC_ERROR (1 << 3)
samux 0:de50a209c5a9 138 #define R1_ERASE_SEQUENCE_ERROR (1 << 4)
samux 0:de50a209c5a9 139 #define R1_ADDRESS_ERROR (1 << 5)
samux 0:de50a209c5a9 140 #define R1_PARAMETER_ERROR (1 << 6)
samux 0:de50a209c5a9 141
samux 0:de50a209c5a9 142 // Types
samux 0:de50a209c5a9 143 // - v1.x Standard Capacity
samux 0:de50a209c5a9 144 // - v2.x Standard Capacity
samux 0:de50a209c5a9 145 // - v2.x High Capacity
samux 0:de50a209c5a9 146 // - Not recognised as an SD Card
samux 0:de50a209c5a9 147 #define SDCARD_FAIL 0
samux 0:de50a209c5a9 148 #define SDCARD_V1 1
samux 0:de50a209c5a9 149 #define SDCARD_V2 2
samux 0:de50a209c5a9 150 #define SDCARD_V2HC 3
samux 0:de50a209c5a9 151
samux 0:de50a209c5a9 152 int USBMSD_SD::initialise_card() {
samux 0:de50a209c5a9 153 // Set to 100kHz for initialisation, and clock card with cs = 1
samux 2:055119ccf5a7 154 _spi.frequency(100000);
samux 0:de50a209c5a9 155 _cs = 1;
samux 2:055119ccf5a7 156 for (int i = 0; i < 16; i++) {
samux 0:de50a209c5a9 157 _spi.write(0xFF);
samux 0:de50a209c5a9 158 }
samux 0:de50a209c5a9 159 // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
samux 2:055119ccf5a7 160 if (_cmd(0, 0) != R1_IDLE_STATE) {
samux 2:055119ccf5a7 161 debug("No disk, or could not put SD card in to SPI idle state\n");
samux 0:de50a209c5a9 162 return SDCARD_FAIL;
samux 0:de50a209c5a9 163 }
samux 2:055119ccf5a7 164
samux 0:de50a209c5a9 165 // send CMD8 to determine whther it is ver 2.x
samux 0:de50a209c5a9 166 int r = _cmd8();
samux 2:055119ccf5a7 167 if (r == R1_IDLE_STATE) {
samux 0:de50a209c5a9 168 return initialise_card_v2();
samux 2:055119ccf5a7 169 } else if (r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
samux 0:de50a209c5a9 170 return initialise_card_v1();
samux 0:de50a209c5a9 171 } else {
samux 2:055119ccf5a7 172 debug("Not in idle state after sending CMD8 (not an SD card?)\n");
samux 0:de50a209c5a9 173 return SDCARD_FAIL;
samux 0:de50a209c5a9 174 }
samux 0:de50a209c5a9 175 }
samux 0:de50a209c5a9 176
samux 0:de50a209c5a9 177 int USBMSD_SD::initialise_card_v1() {
samux 2:055119ccf5a7 178 for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
samux 2:055119ccf5a7 179 _cmd(55, 0);
samux 2:055119ccf5a7 180 if (_cmd(41, 0) == 0) {
samux 2:055119ccf5a7 181 cdv = 512;
samux 2:055119ccf5a7 182 debug_if(SD_DBG, "\n\rInit: SEDCARD_V1\n\r");
samux 0:de50a209c5a9 183 return SDCARD_V1;
samux 0:de50a209c5a9 184 }
samux 0:de50a209c5a9 185 }
samux 2:055119ccf5a7 186
samux 2:055119ccf5a7 187 debug("Timeout waiting for v1.x card\n");
samux 0:de50a209c5a9 188 return SDCARD_FAIL;
samux 0:de50a209c5a9 189 }
samux 0:de50a209c5a9 190
samux 0:de50a209c5a9 191 int USBMSD_SD::initialise_card_v2() {
samux 2:055119ccf5a7 192 for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
samux 2:055119ccf5a7 193 wait_ms(50);
samux 2:055119ccf5a7 194 _cmd58();
samux 2:055119ccf5a7 195 _cmd(55, 0);
samux 2:055119ccf5a7 196 if (_cmd(41, 0x40000000) == 0) {
samux 0:de50a209c5a9 197 _cmd58();
samux 2:055119ccf5a7 198 debug_if(SD_DBG, "\n\rInit: SDCARD_V2\n\r");
samux 2:055119ccf5a7 199 cdv = 1;
samux 0:de50a209c5a9 200 return SDCARD_V2;
samux 0:de50a209c5a9 201 }
samux 0:de50a209c5a9 202 }
samux 2:055119ccf5a7 203
samux 2:055119ccf5a7 204 debug("Timeout waiting for v2.x card\n");
samux 0:de50a209c5a9 205 return SDCARD_FAIL;
samux 0:de50a209c5a9 206 }
samux 0:de50a209c5a9 207
samux 0:de50a209c5a9 208 int USBMSD_SD::disk_initialize() {
samux 0:de50a209c5a9 209 int i = initialise_card();
samux 2:055119ccf5a7 210 debug_if(SD_DBG, "init card = %d\n", i);
samux 0:de50a209c5a9 211 _sectors = _sd_sectors();
samux 2:055119ccf5a7 212
samux 0:de50a209c5a9 213 // Set block length to 512 (CMD16)
samux 2:055119ccf5a7 214 if (_cmd(16, 512) != 0) {
samux 2:055119ccf5a7 215 debug("Set 512-byte block timed out\n");
samux 0:de50a209c5a9 216 return 1;
samux 0:de50a209c5a9 217 }
samux 2:055119ccf5a7 218
samux 0:de50a209c5a9 219 _spi.frequency(5000000); // Set to 5MHz for data transfer
samux 2:055119ccf5a7 220
samux 1:923991b026e7 221 // OK
samux 1:923991b026e7 222 _status = 0x00;
samux 2:055119ccf5a7 223
samux 0:de50a209c5a9 224 return 0;
samux 0:de50a209c5a9 225 }
samux 0:de50a209c5a9 226
samux 2:055119ccf5a7 227 int USBMSD_SD::disk_write(const uint8_t *buffer, uint64_t block_number) {
samux 0:de50a209c5a9 228 // set write address for single block (CMD24)
samux 2:055119ccf5a7 229 if (_cmd(24, block_number * cdv) != 0) {
samux 0:de50a209c5a9 230 return 1;
samux 0:de50a209c5a9 231 }
samux 2:055119ccf5a7 232
samux 0:de50a209c5a9 233 // send the data block
samux 2:055119ccf5a7 234 _write(buffer, 512);
samux 2:055119ccf5a7 235 return 0;
samux 0:de50a209c5a9 236 }
samux 0:de50a209c5a9 237
samux 2:055119ccf5a7 238 int USBMSD_SD::disk_read(uint8_t *buffer, uint64_t block_number) {
samux 0:de50a209c5a9 239 // set read address for single block (CMD17)
samux 2:055119ccf5a7 240 if (_cmd(17, block_number * cdv) != 0) {
samux 0:de50a209c5a9 241 return 1;
samux 0:de50a209c5a9 242 }
samux 0:de50a209c5a9 243
samux 0:de50a209c5a9 244 // receive the data
samux 0:de50a209c5a9 245 _read(buffer, 512);
samux 0:de50a209c5a9 246 return 0;
samux 0:de50a209c5a9 247 }
samux 0:de50a209c5a9 248
samux 1:923991b026e7 249 int USBMSD_SD::disk_status() { return _status; }
samux 0:de50a209c5a9 250 int USBMSD_SD::disk_sync() { return 0; }
samux 2:055119ccf5a7 251 uint64_t USBMSD_SD::disk_sectors() { return _sectors; }
samux 2:055119ccf5a7 252
samux 0:de50a209c5a9 253
samux 0:de50a209c5a9 254 // PRIVATE FUNCTIONS
samux 0:de50a209c5a9 255 int USBMSD_SD::_cmd(int cmd, int arg) {
samux 2:055119ccf5a7 256 _cs = 0;
samux 2:055119ccf5a7 257
samux 0:de50a209c5a9 258 // send a command
samux 0:de50a209c5a9 259 _spi.write(0x40 | cmd);
samux 0:de50a209c5a9 260 _spi.write(arg >> 24);
samux 0:de50a209c5a9 261 _spi.write(arg >> 16);
samux 0:de50a209c5a9 262 _spi.write(arg >> 8);
samux 0:de50a209c5a9 263 _spi.write(arg >> 0);
samux 0:de50a209c5a9 264 _spi.write(0x95);
samux 2:055119ccf5a7 265
samux 0:de50a209c5a9 266 // wait for the repsonse (response[7] == 0)
samux 2:055119ccf5a7 267 for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
samux 0:de50a209c5a9 268 int response = _spi.write(0xFF);
samux 2:055119ccf5a7 269 if (!(response & 0x80)) {
samux 0:de50a209c5a9 270 _cs = 1;
samux 0:de50a209c5a9 271 _spi.write(0xFF);
samux 0:de50a209c5a9 272 return response;
samux 0:de50a209c5a9 273 }
samux 0:de50a209c5a9 274 }
samux 0:de50a209c5a9 275 _cs = 1;
samux 0:de50a209c5a9 276 _spi.write(0xFF);
samux 0:de50a209c5a9 277 return -1; // timeout
samux 0:de50a209c5a9 278 }
samux 0:de50a209c5a9 279 int USBMSD_SD::_cmdx(int cmd, int arg) {
samux 2:055119ccf5a7 280 _cs = 0;
samux 2:055119ccf5a7 281
samux 0:de50a209c5a9 282 // send a command
samux 0:de50a209c5a9 283 _spi.write(0x40 | cmd);
samux 0:de50a209c5a9 284 _spi.write(arg >> 24);
samux 0:de50a209c5a9 285 _spi.write(arg >> 16);
samux 0:de50a209c5a9 286 _spi.write(arg >> 8);
samux 0:de50a209c5a9 287 _spi.write(arg >> 0);
samux 0:de50a209c5a9 288 _spi.write(0x95);
samux 2:055119ccf5a7 289
samux 0:de50a209c5a9 290 // wait for the repsonse (response[7] == 0)
samux 2:055119ccf5a7 291 for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
samux 0:de50a209c5a9 292 int response = _spi.write(0xFF);
samux 2:055119ccf5a7 293 if (!(response & 0x80)) {
samux 0:de50a209c5a9 294 return response;
samux 0:de50a209c5a9 295 }
samux 0:de50a209c5a9 296 }
samux 0:de50a209c5a9 297 _cs = 1;
samux 0:de50a209c5a9 298 _spi.write(0xFF);
samux 0:de50a209c5a9 299 return -1; // timeout
samux 0:de50a209c5a9 300 }
samux 0:de50a209c5a9 301
samux 0:de50a209c5a9 302
samux 0:de50a209c5a9 303 int USBMSD_SD::_cmd58() {
samux 2:055119ccf5a7 304 _cs = 0;
samux 0:de50a209c5a9 305 int arg = 0;
samux 0:de50a209c5a9 306
samux 0:de50a209c5a9 307 // send a command
samux 0:de50a209c5a9 308 _spi.write(0x40 | 58);
samux 0:de50a209c5a9 309 _spi.write(arg >> 24);
samux 0:de50a209c5a9 310 _spi.write(arg >> 16);
samux 0:de50a209c5a9 311 _spi.write(arg >> 8);
samux 0:de50a209c5a9 312 _spi.write(arg >> 0);
samux 0:de50a209c5a9 313 _spi.write(0x95);
samux 2:055119ccf5a7 314
samux 0:de50a209c5a9 315 // wait for the repsonse (response[7] == 0)
samux 2:055119ccf5a7 316 for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
samux 0:de50a209c5a9 317 int response = _spi.write(0xFF);
samux 2:055119ccf5a7 318 if (!(response & 0x80)) {
samux 0:de50a209c5a9 319 int ocr = _spi.write(0xFF) << 24;
samux 0:de50a209c5a9 320 ocr |= _spi.write(0xFF) << 16;
samux 0:de50a209c5a9 321 ocr |= _spi.write(0xFF) << 8;
samux 0:de50a209c5a9 322 ocr |= _spi.write(0xFF) << 0;
samux 0:de50a209c5a9 323 _cs = 1;
samux 0:de50a209c5a9 324 _spi.write(0xFF);
samux 0:de50a209c5a9 325 return response;
samux 0:de50a209c5a9 326 }
samux 0:de50a209c5a9 327 }
samux 0:de50a209c5a9 328 _cs = 1;
samux 0:de50a209c5a9 329 _spi.write(0xFF);
samux 0:de50a209c5a9 330 return -1; // timeout
samux 0:de50a209c5a9 331 }
samux 0:de50a209c5a9 332
samux 0:de50a209c5a9 333 int USBMSD_SD::_cmd8() {
samux 2:055119ccf5a7 334 _cs = 0;
samux 0:de50a209c5a9 335
samux 0:de50a209c5a9 336 // send a command
samux 0:de50a209c5a9 337 _spi.write(0x40 | 8); // CMD8
samux 0:de50a209c5a9 338 _spi.write(0x00); // reserved
samux 0:de50a209c5a9 339 _spi.write(0x00); // reserved
samux 0:de50a209c5a9 340 _spi.write(0x01); // 3.3v
samux 0:de50a209c5a9 341 _spi.write(0xAA); // check pattern
samux 0:de50a209c5a9 342 _spi.write(0x87); // crc
samux 2:055119ccf5a7 343
samux 0:de50a209c5a9 344 // wait for the repsonse (response[7] == 0)
samux 2:055119ccf5a7 345 for (int i = 0; i < SD_COMMAND_TIMEOUT * 1000; i++) {
samux 0:de50a209c5a9 346 char response[5];
samux 0:de50a209c5a9 347 response[0] = _spi.write(0xFF);
samux 2:055119ccf5a7 348 if (!(response[0] & 0x80)) {
samux 2:055119ccf5a7 349 for (int j = 1; j < 5; j++) {
samux 2:055119ccf5a7 350 response[i] = _spi.write(0xFF);
samux 2:055119ccf5a7 351 }
samux 2:055119ccf5a7 352 _cs = 1;
samux 2:055119ccf5a7 353 _spi.write(0xFF);
samux 2:055119ccf5a7 354 return response[0];
samux 0:de50a209c5a9 355 }
samux 0:de50a209c5a9 356 }
samux 0:de50a209c5a9 357 _cs = 1;
samux 0:de50a209c5a9 358 _spi.write(0xFF);
samux 0:de50a209c5a9 359 return -1; // timeout
samux 0:de50a209c5a9 360 }
samux 0:de50a209c5a9 361
samux 2:055119ccf5a7 362 int USBMSD_SD::_read(uint8_t *buffer, uint32_t length) {
samux 0:de50a209c5a9 363 _cs = 0;
samux 2:055119ccf5a7 364
samux 0:de50a209c5a9 365 // read until start byte (0xFF)
samux 2:055119ccf5a7 366 while (_spi.write(0xFF) != 0xFE);
samux 2:055119ccf5a7 367
samux 0:de50a209c5a9 368 // read data
samux 2:055119ccf5a7 369 for (int i = 0; i < length; i++) {
samux 0:de50a209c5a9 370 buffer[i] = _spi.write(0xFF);
samux 0:de50a209c5a9 371 }
samux 0:de50a209c5a9 372 _spi.write(0xFF); // checksum
samux 0:de50a209c5a9 373 _spi.write(0xFF);
samux 2:055119ccf5a7 374
samux 2:055119ccf5a7 375 _cs = 1;
samux 0:de50a209c5a9 376 _spi.write(0xFF);
samux 0:de50a209c5a9 377 return 0;
samux 0:de50a209c5a9 378 }
samux 0:de50a209c5a9 379
samux 2:055119ccf5a7 380 int USBMSD_SD::_write(const uint8_t*buffer, uint32_t length) {
samux 0:de50a209c5a9 381 _cs = 0;
samux 0:de50a209c5a9 382
samux 0:de50a209c5a9 383 // indicate start of block
samux 0:de50a209c5a9 384 _spi.write(0xFE);
samux 0:de50a209c5a9 385
samux 0:de50a209c5a9 386 // write the data
samux 2:055119ccf5a7 387 for (int i = 0; i < length; i++) {
samux 0:de50a209c5a9 388 _spi.write(buffer[i]);
samux 0:de50a209c5a9 389 }
samux 0:de50a209c5a9 390
samux 0:de50a209c5a9 391 // write the checksum
samux 2:055119ccf5a7 392 _spi.write(0xFF);
samux 0:de50a209c5a9 393 _spi.write(0xFF);
samux 2:055119ccf5a7 394
samux 2:055119ccf5a7 395 // check the response token
samux 2:055119ccf5a7 396 if ((_spi.write(0xFF) & 0x1F) != 0x05) {
samux 0:de50a209c5a9 397 _cs = 1;
samux 2:055119ccf5a7 398 _spi.write(0xFF);
samux 0:de50a209c5a9 399 return 1;
samux 0:de50a209c5a9 400 }
samux 2:055119ccf5a7 401
samux 0:de50a209c5a9 402 // wait for write to finish
samux 2:055119ccf5a7 403 while (_spi.write(0xFF) == 0);
samux 2:055119ccf5a7 404
samux 2:055119ccf5a7 405 _cs = 1;
samux 0:de50a209c5a9 406 _spi.write(0xFF);
samux 0:de50a209c5a9 407 return 0;
samux 0:de50a209c5a9 408 }
samux 0:de50a209c5a9 409
samux 2:055119ccf5a7 410 static uint32_t ext_bits(unsigned char *data, int msb, int lsb) {
samux 2:055119ccf5a7 411 uint32_t bits = 0;
samux 2:055119ccf5a7 412 uint32_t size = 1 + msb - lsb;
samux 2:055119ccf5a7 413 for (int i = 0; i < size; i++) {
samux 2:055119ccf5a7 414 uint32_t position = lsb + i;
samux 2:055119ccf5a7 415 uint32_t byte = 15 - (position >> 3);
samux 2:055119ccf5a7 416 uint32_t bit = position & 0x7;
samux 2:055119ccf5a7 417 uint32_t value = (data[byte] >> bit) & 1;
samux 0:de50a209c5a9 418 bits |= value << i;
samux 0:de50a209c5a9 419 }
samux 0:de50a209c5a9 420 return bits;
samux 0:de50a209c5a9 421 }
samux 0:de50a209c5a9 422
samux 2:055119ccf5a7 423 uint64_t USBMSD_SD::_sd_sectors() {
samux 2:055119ccf5a7 424 uint32_t c_size, c_size_mult, read_bl_len;
samux 2:055119ccf5a7 425 uint32_t block_len, mult, blocknr, capacity;
samux 2:055119ccf5a7 426 uint32_t hc_c_size;
samux 2:055119ccf5a7 427 uint64_t blocks;
samux 2:055119ccf5a7 428
samux 0:de50a209c5a9 429 // CMD9, Response R2 (R1 byte + 16-byte block read)
samux 2:055119ccf5a7 430 if (_cmdx(9, 0) != 0) {
samux 2:055119ccf5a7 431 debug("Didn't get a response from the disk\n");
samux 0:de50a209c5a9 432 return 0;
samux 0:de50a209c5a9 433 }
samux 0:de50a209c5a9 434
samux 2:055119ccf5a7 435 uint8_t csd[16];
samux 2:055119ccf5a7 436 if (_read(csd, 16) != 0) {
samux 2:055119ccf5a7 437 debug("Couldn't read csd response from disk\n");
samux 0:de50a209c5a9 438 return 0;
samux 0:de50a209c5a9 439 }
samux 2:055119ccf5a7 440
samux 0:de50a209c5a9 441 // csd_structure : csd[127:126]
samux 0:de50a209c5a9 442 // c_size : csd[73:62]
samux 0:de50a209c5a9 443 // c_size_mult : csd[49:47]
samux 0:de50a209c5a9 444 // read_bl_len : csd[83:80] - the *maximum* read block length
samux 2:055119ccf5a7 445
samux 0:de50a209c5a9 446 int csd_structure = ext_bits(csd, 127, 126);
samux 0:de50a209c5a9 447
samux 2:055119ccf5a7 448 switch (csd_structure) {
samux 2:055119ccf5a7 449 case 0:
samux 2:055119ccf5a7 450 cdv = 512;
samux 2:055119ccf5a7 451 c_size = ext_bits(csd, 73, 62);
samux 2:055119ccf5a7 452 c_size_mult = ext_bits(csd, 49, 47);
samux 2:055119ccf5a7 453 read_bl_len = ext_bits(csd, 83, 80);
samux 2:055119ccf5a7 454
samux 2:055119ccf5a7 455 block_len = 1 << read_bl_len;
samux 2:055119ccf5a7 456 mult = 1 << (c_size_mult + 2);
samux 2:055119ccf5a7 457 blocknr = (c_size + 1) * mult;
samux 2:055119ccf5a7 458 capacity = blocknr * block_len;
samux 2:055119ccf5a7 459 blocks = capacity / 512;
samux 2:055119ccf5a7 460 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 461 break;
samux 0:de50a209c5a9 462
samux 2:055119ccf5a7 463 case 1:
samux 2:055119ccf5a7 464 cdv = 1;
samux 2:055119ccf5a7 465 hc_c_size = ext_bits(csd, 63, 48);
samux 2:055119ccf5a7 466 blocks = (hc_c_size+1)*1024;
samux 2:055119ccf5a7 467 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 468 break;
samux 2:055119ccf5a7 469
samux 2:055119ccf5a7 470 default:
samux 2:055119ccf5a7 471 debug("CSD struct unsupported\r\n");
samux 2:055119ccf5a7 472 return 0;
samux 2:055119ccf5a7 473 };
samux 0:de50a209c5a9 474 return blocks;
samux 0:de50a209c5a9 475 }
avnisha 3:dbd7383533e6 476
avnisha 3:dbd7383533e6 477 #endif
avnisha 3:dbd7383533e6 478
avnisha 3:dbd7383533e6 479
avnisha 3:dbd7383533e6 480 #define NEW
avnisha 3:dbd7383533e6 481 #ifdef NEW
avnisha 3:dbd7383533e6 482
avnisha 3:dbd7383533e6 483 #ifdef FOO
avnisha 3:dbd7383533e6 484 You have to inherit from USBMSD and define ALL the following pure virtual functions:
avnisha 3:dbd7383533e6 485 virtual int disk_read(uint8_t * data, uint64_t block): function to read a block
avnisha 3:dbd7383533e6 486 virtual int disk_write(const uint8_t * data, uint64_t block): function to write a block
avnisha 3:dbd7383533e6 487 virtual int disk_initialize(): function to initialize the memory
avnisha 3:dbd7383533e6 488 virtual uint64_t disk_sectors(): return the number of blocks
avnisha 3:dbd7383533e6 489 virtual uint64_t disk_size(): return the memory size
avnisha 3:dbd7383533e6 490 virtual int disk_status(): return the status of the storage chip (0: OK, 1: not initialized, 2: no medium in the drive, 4: write protection)
avnisha 3:dbd7383533e6 491 All functions names are compatible with the fat filesystem library. So you can imagine using your own class with USBMSD and the fat filesystem library in the same program. Just be careful because there are two different parts which will access the sd card. You can do a master/slave system using disk_status().
avnisha 3:dbd7383533e6 492 Once these functions defined, you can call connect() (at the end of the constructor of your class for instance) of USBMSD to connect your mass storage device. connect() will first call disk_status() to test the status of the disk. If disk_status() returns 1 (disk not initialized), then disk_initialize() is called. After this step, connect() will collect information such as the number of blocks and the memory size.
avnisha 3:dbd7383533e6 493 #endif
avnisha 3:dbd7383533e6 494
avnisha 3:dbd7383533e6 495 #include "USBMSD_SD.h"
avnisha 3:dbd7383533e6 496 #include "mbed_debug.h"
avnisha 3:dbd7383533e6 497
avnisha 3:dbd7383533e6 498 #define SD_COMMAND_TIMEOUT 5000
avnisha 3:dbd7383533e6 499 #define SD_DBG 0
avnisha 3:dbd7383533e6 500 #define BLOCKS 16
avnisha 3:dbd7383533e6 501 #define FS BLOCKS*512
avnisha 3:dbd7383533e6 502
avnisha 3:dbd7383533e6 503 LocalFileSystem local("local");
avnisha 3:dbd7383533e6 504
avnisha 3:dbd7383533e6 505 char s[FS];
avnisha 3:dbd7383533e6 506 int status = 1;
avnisha 3:dbd7383533e6 507
avnisha 3:dbd7383533e6 508 USBMSD_SD::USBMSD_SD(PinName mosi, PinName miso, PinName sclk, PinName cs) :
avnisha 3:dbd7383533e6 509 _spi(mosi, miso, sclk), _cs(cs) {
avnisha 3:dbd7383533e6 510 _cs = 1;
avnisha 3:dbd7383533e6 511
avnisha 3:dbd7383533e6 512 printf("cons\n");
avnisha 3:dbd7383533e6 513 connect();
avnisha 3:dbd7383533e6 514 }
avnisha 3:dbd7383533e6 515
avnisha 3:dbd7383533e6 516 int USBMSD_SD::disk_initialize() {
avnisha 3:dbd7383533e6 517
avnisha 3:dbd7383533e6 518 printf("ini\n");
avnisha 3:dbd7383533e6 519 status--;
avnisha 3:dbd7383533e6 520 return 0;
avnisha 3:dbd7383533e6 521 }
avnisha 3:dbd7383533e6 522
avnisha 3:dbd7383533e6 523 int USBMSD_SD::disk_write(const uint8_t *buffer, uint64_t block_number) {
avnisha 3:dbd7383533e6 524
avnisha 3:dbd7383533e6 525 //
avnisha 3:dbd7383533e6 526 // find the correct block and write
avnisha 3:dbd7383533e6 527 //
avnisha 3:dbd7383533e6 528 int offset;
avnisha 3:dbd7383533e6 529 int i;
avnisha 3:dbd7383533e6 530
avnisha 3:dbd7383533e6 531 //printf("write\n");
avnisha 3:dbd7383533e6 532 if (block_number > (BLOCKS -1)) return 1;
avnisha 3:dbd7383533e6 533 offset = 512 * block_number;
avnisha 3:dbd7383533e6 534 for (i = 0; i < 512; i++) {
avnisha 3:dbd7383533e6 535 s[offset + i] = buffer[i];
avnisha 3:dbd7383533e6 536 }
avnisha 3:dbd7383533e6 537 return 0;
avnisha 3:dbd7383533e6 538 }
avnisha 3:dbd7383533e6 539
avnisha 3:dbd7383533e6 540 int USBMSD_SD::disk_read(uint8_t *buffer, uint64_t block_number) {
avnisha 3:dbd7383533e6 541
avnisha 3:dbd7383533e6 542 int offset;
avnisha 3:dbd7383533e6 543 int i;
avnisha 3:dbd7383533e6 544
avnisha 3:dbd7383533e6 545 //printf("read\n");
avnisha 3:dbd7383533e6 546 if (block_number > (BLOCKS -1)) return 1;
avnisha 3:dbd7383533e6 547 offset = 512 * block_number;
avnisha 3:dbd7383533e6 548 for (i = 0; i < 512; i++) {
avnisha 3:dbd7383533e6 549 buffer[i] = s[offset + i];
avnisha 3:dbd7383533e6 550 }
avnisha 3:dbd7383533e6 551 return 0;
avnisha 3:dbd7383533e6 552 }
avnisha 3:dbd7383533e6 553
avnisha 3:dbd7383533e6 554 int USBMSD_SD::disk_status() {
avnisha 3:dbd7383533e6 555 printf("status\n");
avnisha 3:dbd7383533e6 556 return status;
avnisha 3:dbd7383533e6 557 }
avnisha 3:dbd7383533e6 558
avnisha 3:dbd7383533e6 559
avnisha 3:dbd7383533e6 560 int USBMSD_SD::disk_sync() { printf("sync\n"); return 0; }
avnisha 3:dbd7383533e6 561 uint64_t USBMSD_SD::disk_size() { printf("size\n"); return FS;}
avnisha 3:dbd7383533e6 562 uint64_t USBMSD_SD::disk_sectors() { printf("sectors\n"); return BLOCKS; }
avnisha 3:dbd7383533e6 563
avnisha 3:dbd7383533e6 564
avnisha 3:dbd7383533e6 565
avnisha 3:dbd7383533e6 566 #endif