Using the USBFileSystem class to provide SD-card with USBMSD and FATFileSystem support at same time.

Dependents:   SD_USB_FS_HelloWorld

See also helloworld program at http://mbed.org/users/karelv/code/SD_USB_FS_HelloWorld/

Created based on:

  1. comment from Erik Olieman. forum
  2. USBMSD_SD library for the spi-access to SD-card. (no dependency but spi-access code is copied) USBMSD_SD
  3. USBFileSystem libary USBFileSystem

Information

My win7 pc always disconnect/connect the drive and at disconnect it also closes the explorer which show the content of that drive. It does the same with the editor that has the file opened.

Quote:

(by Erik Olieman)

You are correct that that is what happens, got the same on windows 8. The problem is that windows (and probably every other OS) is quite heavy on caching of USB drives. So it reads the data ones, and after that it only writes and assumes its commands have been performed. For example if you have a drive with a bunch of files, and I enable write protection on the library, you can still happily delete the file and windows will tell you it is gone. You can make new files and windows will tell you they are created. Despite nothing actually being done. So the only way to force a refresh is disconnecting/reconnecting. Well not entirely true, I found out if you are writing custom programs you can disable this caching behavior after alot of digging. But in principle it is always on, and you have to reconnect the device. An alternative file browser might have other behavior, but dunno.

So the TL;DR: It is OS behavior that the program can't do anything about. Initially I intended to just use write protection to block the computer from writing, which is why it is still the default, but it doesn't actually work like you want it to work for 99% of the use cases. So reconnecting it is.

Committer:
karelv
Date:
Tue Aug 27 19:41:48 2013 +0000
Revision:
1:88089dd56f0e
Parent:
0:c3d2e89ca30d
update after recommendations of Erik Olieman

Who changed what in which revision?

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