microSDカードからWaveファイルを再生するサンプルです。

Dependencies:   mbed FATFileSystem

Fork of JBB_WavePlayer_test by Jksoft Blue mbed Board Developer

Committer:
jksoft
Date:
Fri May 23 09:41:26 2014 +0000
Revision:
1:9681a1526ecb
Parent:
0:e9f196d85a46
???????????

Who changed what in which revision?

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