Block access only to a SD Flash card conected via SPI. Based on SDFileSystem, but without any file system support.

Dependents:   SDcard

Committer:
johnvanlaanen
Date:
Fri Jun 21 16:50:37 2013 +0000
Revision:
0:99935a94f153
Create SDFlashDisk library

Who changed what in which revision?

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