ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Committer:
group-onsemi
Date:
Wed Jan 25 20:34:15 2017 +0000
Revision:
0:098463de4c5d
Initial commit

Who changed what in which revision?

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