Unina_corse / SDFileSystem3

Dependencies:   FATFileSystem

Fork of SDFileSystem1 by Unina_corse

Committer:
NdA994
Date:
Mon Nov 20 22:15:31 2017 +0000
Revision:
7:cfed551cc1a2
Parent:
4:3f40cbfe801c
Child:
8:bb12d57f75e9
Libreria Sd Completa ma si deve documentare. Si potrebbe fare un singleton ma ci sono alcuni problemi per la sua realizzazione.

Who changed what in which revision?

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