SD

Committer:
mikekelly99
Date:
Tue Nov 17 17:03:36 2020 +0000
Revision:
0:6db20bbdc767
Wow, never committed the code once so first and final commit, code produces the lat and long values as well as speed.

Who changed what in which revision?

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