Test of Embedded Artists LPCXpresso baseboard ethernet, SD card, audio and OLED display facilities. The program displays the day, date and time on the baseboard OLED and sounds the Big Ben chimes on the hour and quarter hour. On initial startup the program checks that the mbed clock is set and that the chime wav files can be accessed on the SD card. If not it asks to be connected to the internet to obtain the current time and to download the wav files to the SD card.

Dependencies:   EthernetNetIf NTPClient_NetServices mbed EAOLED

Committer:
tom_coxon
Date:
Sat Aug 14 10:33:13 2010 +0000
Revision:
0:f61e8db0570d

        

Who changed what in which revision?

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