mbed-os

Fork of mbed-os by erkin yucel

Committer:
elessair
Date:
Sun Oct 23 15:10:02 2016 +0000
Revision:
0:f269e3021894
Initial commit

Who changed what in which revision?

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