SD card interface

Committer:
lharoon
Date:
Mon Oct 08 11:14:07 2012 +0000
Revision:
0:22612ae617a0
1st edition

Who changed what in which revision?

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