Dependencies:   mbed

Committer:
DaveStyles
Date:
Wed Nov 25 22:37:12 2009 +0000
Revision:
0:b545e012d041

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
DaveStyles 0:b545e012d041 1 /* mbed Microcontroller Library - SDFileSystem
DaveStyles 0:b545e012d041 2 * Copyright (c) 2008-2009, sford
DaveStyles 0:b545e012d041 3 *
DaveStyles 0:b545e012d041 4 * Introduction
DaveStyles 0:b545e012d041 5 * ------------
DaveStyles 0:b545e012d041 6 * SD and MMC cards support a number of interfaces, but common to them all
DaveStyles 0:b545e012d041 7 * is one based on SPI. This is the one I'm implmenting because it means
DaveStyles 0:b545e012d041 8 * it is much more portable even though not so performant, and we already
DaveStyles 0:b545e012d041 9 * have the mbed SPI Interface!
DaveStyles 0:b545e012d041 10 *
DaveStyles 0:b545e012d041 11 * The main reference I'm using is Chapter 7, "SPI Mode" of:
DaveStyles 0:b545e012d041 12 * http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
DaveStyles 0:b545e012d041 13 *
DaveStyles 0:b545e012d041 14 * SPI Startup
DaveStyles 0:b545e012d041 15 * -----------
DaveStyles 0:b545e012d041 16 * The SD card powers up in SD mode. The SPI interface mode is selected by
DaveStyles 0:b545e012d041 17 * asserting CS low and sending the reset command (CMD0). The card will
DaveStyles 0:b545e012d041 18 * respond with a (R1) response.
DaveStyles 0:b545e012d041 19 *
DaveStyles 0:b545e012d041 20 * CMD8 is optionally sent to determine the voltage range supported, and
DaveStyles 0:b545e012d041 21 * indirectly determine whether it is a version 1.x SD/non-SD card or
DaveStyles 0:b545e012d041 22 * version 2.x. I'll just ignore this for now.
DaveStyles 0:b545e012d041 23 *
DaveStyles 0:b545e012d041 24 * ACMD41 is repeatedly issued to initialise the card, until "in idle"
DaveStyles 0:b545e012d041 25 * (bit 0) of the R1 response goes to '0', indicating it is initialised.
DaveStyles 0:b545e012d041 26 *
DaveStyles 0:b545e012d041 27 * You should also indicate whether the host supports High Capicity cards,
DaveStyles 0:b545e012d041 28 * and check whether the card is high capacity - i'll also ignore this
DaveStyles 0:b545e012d041 29 *
DaveStyles 0:b545e012d041 30 * SPI Protocol
DaveStyles 0:b545e012d041 31 * ------------
DaveStyles 0:b545e012d041 32 * The SD SPI protocol is based on transactions made up of 8-bit words, with
DaveStyles 0:b545e012d041 33 * the host starting every bus transaction by asserting the CS signal low. The
DaveStyles 0:b545e012d041 34 * card always responds to commands, data blocks and errors.
DaveStyles 0:b545e012d041 35 *
DaveStyles 0:b545e012d041 36 * The protocol supports a CRC, but by default it is off (except for the
DaveStyles 0:b545e012d041 37 * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
DaveStyles 0:b545e012d041 38 * I'll leave the CRC off I think!
DaveStyles 0:b545e012d041 39 *
DaveStyles 0:b545e012d041 40 * Standard capacity cards have variable data block sizes, whereas High
DaveStyles 0:b545e012d041 41 * Capacity cards fix the size of data block to 512 bytes. I'll therefore
DaveStyles 0:b545e012d041 42 * just always use the Standard Capacity cards with a block size of 512 bytes.
DaveStyles 0:b545e012d041 43 * This is set with CMD16.
DaveStyles 0:b545e012d041 44 *
DaveStyles 0:b545e012d041 45 * You can read and write single blocks (CMD17, CMD25) or multiple blocks
DaveStyles 0:b545e012d041 46 * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
DaveStyles 0:b545e012d041 47 * the card gets a read command, it responds with a response token, and then
DaveStyles 0:b545e012d041 48 * a data token or an error.
DaveStyles 0:b545e012d041 49 *
DaveStyles 0:b545e012d041 50 * SPI Command Format
DaveStyles 0:b545e012d041 51 * ------------------
DaveStyles 0:b545e012d041 52 * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
DaveStyles 0:b545e012d041 53 *
DaveStyles 0:b545e012d041 54 * +---------------+------------+------------+-----------+----------+--------------+
DaveStyles 0:b545e012d041 55 * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
DaveStyles 0:b545e012d041 56 * +---------------+------------+------------+-----------+----------+--------------+
DaveStyles 0:b545e012d041 57 *
DaveStyles 0:b545e012d041 58 * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
DaveStyles 0:b545e012d041 59 *
DaveStyles 0:b545e012d041 60 * All Application Specific commands shall be preceded with APP_CMD (CMD55).
DaveStyles 0:b545e012d041 61 *
DaveStyles 0:b545e012d041 62 * SPI Response Format
DaveStyles 0:b545e012d041 63 * -------------------
DaveStyles 0:b545e012d041 64 * The main response format (R1) is a status byte (normally zero). Key flags:
DaveStyles 0:b545e012d041 65 * idle - 1 if the card is in an idle state/initialising
DaveStyles 0:b545e012d041 66 * cmd - 1 if an illegal command code was detected
DaveStyles 0:b545e012d041 67 *
DaveStyles 0:b545e012d041 68 * +-------------------------------------------------+
DaveStyles 0:b545e012d041 69 * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
DaveStyles 0:b545e012d041 70 * +-------------------------------------------------+
DaveStyles 0:b545e012d041 71 *
DaveStyles 0:b545e012d041 72 * R1b is the same, except it is followed by a busy signal (zeros) until
DaveStyles 0:b545e012d041 73 * the first non-zero byte when it is ready again.
DaveStyles 0:b545e012d041 74 *
DaveStyles 0:b545e012d041 75 * Data Response Token
DaveStyles 0:b545e012d041 76 * -------------------
DaveStyles 0:b545e012d041 77 * Every data block written to the card is acknowledged by a byte
DaveStyles 0:b545e012d041 78 * response token
DaveStyles 0:b545e012d041 79 *
DaveStyles 0:b545e012d041 80 * +----------------------+
DaveStyles 0:b545e012d041 81 * | xxx | 0 | status | 1 |
DaveStyles 0:b545e012d041 82 * +----------------------+
DaveStyles 0:b545e012d041 83 * 010 - OK!
DaveStyles 0:b545e012d041 84 * 101 - CRC Error
DaveStyles 0:b545e012d041 85 * 110 - Write Error
DaveStyles 0:b545e012d041 86 *
DaveStyles 0:b545e012d041 87 * Single Block Read and Write
DaveStyles 0:b545e012d041 88 * ---------------------------
DaveStyles 0:b545e012d041 89 *
DaveStyles 0:b545e012d041 90 * Block transfers have a byte header, followed by the data, followed
DaveStyles 0:b545e012d041 91 * by a 16-bit CRC. In our case, the data will always be 512 bytes.
DaveStyles 0:b545e012d041 92 *
DaveStyles 0:b545e012d041 93 * +------+---------+---------+- - - -+---------+-----------+----------+
DaveStyles 0:b545e012d041 94 * | 0xFE | data[0] | data[1] | | data[n] | crc[15:8] | crc[7:0] |
DaveStyles 0:b545e012d041 95 * +------+---------+---------+- - - -+---------+-----------+----------+
DaveStyles 0:b545e012d041 96 */
DaveStyles 0:b545e012d041 97
DaveStyles 0:b545e012d041 98 #include "SDFileSystem.h"
DaveStyles 0:b545e012d041 99
DaveStyles 0:b545e012d041 100 #define SD_COMMAND_TIMEOUT 5000
DaveStyles 0:b545e012d041 101
DaveStyles 0:b545e012d041 102 SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) :
DaveStyles 0:b545e012d041 103 FATFileSystem(name), _spi(mosi, miso, sclk), _cs(cs) {
DaveStyles 0:b545e012d041 104 _cs = 1;
DaveStyles 0:b545e012d041 105 }
DaveStyles 0:b545e012d041 106
DaveStyles 0:b545e012d041 107 int SDFileSystem::disk_initialize() {
DaveStyles 0:b545e012d041 108
DaveStyles 0:b545e012d041 109 fprintf(stderr,"Initialising\n");
DaveStyles 0:b545e012d041 110
DaveStyles 0:b545e012d041 111
DaveStyles 0:b545e012d041 112 _spi.frequency(1000); // Set to 100kHz for initialisation
DaveStyles 0:b545e012d041 113
DaveStyles 0:b545e012d041 114 // Initialise the card by clocking it a bit (cs = 1)
DaveStyles 0:b545e012d041 115 for(int i=0; i<16; i++) {
DaveStyles 0:b545e012d041 116 _spi.write(0xFF);
DaveStyles 0:b545e012d041 117 }
DaveStyles 0:b545e012d041 118
DaveStyles 0:b545e012d041 119 // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
DaveStyles 0:b545e012d041 120 if(_cmd(0, 0) != 0x01) {
DaveStyles 0:b545e012d041 121 fprintf(stderr, "Not in idle state\n");
DaveStyles 0:b545e012d041 122 return 1;
DaveStyles 0:b545e012d041 123 }
DaveStyles 0:b545e012d041 124
DaveStyles 0:b545e012d041 125 // ACMD41 to give host capacity support (repeat until not busy)
DaveStyles 0:b545e012d041 126 // ACMD41 is application specific command, so we send APP_CMD (CMD55) beforehand
DaveStyles 0:b545e012d041 127 for(int i=0;; i++) {
DaveStyles 0:b545e012d041 128 _cmd(55, 0);
DaveStyles 0:b545e012d041 129 int response = _cmd(41, 0);
DaveStyles 0:b545e012d041 130 if(response == 0) {
DaveStyles 0:b545e012d041 131 break;
DaveStyles 0:b545e012d041 132 } else if(i > SD_COMMAND_TIMEOUT) {
DaveStyles 0:b545e012d041 133 fprintf(stderr, "Timeout waiting for card\n");
DaveStyles 0:b545e012d041 134 return 1;
DaveStyles 0:b545e012d041 135 }
DaveStyles 0:b545e012d041 136 }
DaveStyles 0:b545e012d041 137
DaveStyles 0:b545e012d041 138 _sectors = _sd_sectors();
DaveStyles 0:b545e012d041 139
DaveStyles 0:b545e012d041 140 // Set block length to 512 (CMD16)
DaveStyles 0:b545e012d041 141 if(_cmd(16, 512) != 0) {
DaveStyles 0:b545e012d041 142 fprintf(stderr, "Set block timeout\n");
DaveStyles 0:b545e012d041 143 return 1;
DaveStyles 0:b545e012d041 144 }
DaveStyles 0:b545e012d041 145
DaveStyles 0:b545e012d041 146 _spi.frequency(1000000); // Set to 1MHz for data transfer
DaveStyles 0:b545e012d041 147 return 0;
DaveStyles 0:b545e012d041 148 }
DaveStyles 0:b545e012d041 149
DaveStyles 0:b545e012d041 150 int SDFileSystem::disk_write(const char *buffer, int block_number) {
DaveStyles 0:b545e012d041 151 // set write address for single block (CMD24)
DaveStyles 0:b545e012d041 152 if(_cmd(24, block_number * 512) != 0) {
DaveStyles 0:b545e012d041 153 return 1;
DaveStyles 0:b545e012d041 154 }
DaveStyles 0:b545e012d041 155
DaveStyles 0:b545e012d041 156 // send the data block
DaveStyles 0:b545e012d041 157 _write(buffer, 512);
DaveStyles 0:b545e012d041 158 return 0;
DaveStyles 0:b545e012d041 159 }
DaveStyles 0:b545e012d041 160
DaveStyles 0:b545e012d041 161 int SDFileSystem::disk_read(char *buffer, int block_number) {
DaveStyles 0:b545e012d041 162 // set read address for single block (CMD17)
DaveStyles 0:b545e012d041 163 if(_cmd(17, block_number * 512) != 0) {
DaveStyles 0:b545e012d041 164 return 1;
DaveStyles 0:b545e012d041 165 }
DaveStyles 0:b545e012d041 166
DaveStyles 0:b545e012d041 167 // receive the data
DaveStyles 0:b545e012d041 168 _read(buffer, 512);
DaveStyles 0:b545e012d041 169 return 0;
DaveStyles 0:b545e012d041 170 }
DaveStyles 0:b545e012d041 171
DaveStyles 0:b545e012d041 172 int SDFileSystem::disk_status() { return 0; }
DaveStyles 0:b545e012d041 173 int SDFileSystem::disk_sync() { return 0; }
DaveStyles 0:b545e012d041 174 int SDFileSystem::disk_sectors() { return _sectors; }
DaveStyles 0:b545e012d041 175
DaveStyles 0:b545e012d041 176 // PRIVATE FUNCTIONS
DaveStyles 0:b545e012d041 177
DaveStyles 0:b545e012d041 178 int SDFileSystem::_cmd(int cmd, int arg) {
DaveStyles 0:b545e012d041 179 _cs = 0;
DaveStyles 0:b545e012d041 180
DaveStyles 0:b545e012d041 181 // send a command
DaveStyles 0:b545e012d041 182 _spi.write(0x40 | cmd);
DaveStyles 0:b545e012d041 183 _spi.write(arg >> 24);
DaveStyles 0:b545e012d041 184 _spi.write(arg >> 16);
DaveStyles 0:b545e012d041 185 _spi.write(arg >> 8);
DaveStyles 0:b545e012d041 186 _spi.write(arg >> 0);
DaveStyles 0:b545e012d041 187 _spi.write(0x95);
DaveStyles 0:b545e012d041 188
DaveStyles 0:b545e012d041 189 // wait for the repsonse (response[7] == 0)
DaveStyles 0:b545e012d041 190 for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
DaveStyles 0:b545e012d041 191 int response = _spi.write(0xFF);
DaveStyles 0:b545e012d041 192 if(!(response & 0x80)) {
DaveStyles 0:b545e012d041 193 _cs = 1;
DaveStyles 0:b545e012d041 194 return response;
DaveStyles 0:b545e012d041 195 }
DaveStyles 0:b545e012d041 196 }
DaveStyles 0:b545e012d041 197 _cs = 1;
DaveStyles 0:b545e012d041 198 return -1; // timeout
DaveStyles 0:b545e012d041 199 }
DaveStyles 0:b545e012d041 200
DaveStyles 0:b545e012d041 201 int SDFileSystem::_read(char *buffer, int length) {
DaveStyles 0:b545e012d041 202 _cs = 0;
DaveStyles 0:b545e012d041 203
DaveStyles 0:b545e012d041 204 // read until start byte (0xFF)
DaveStyles 0:b545e012d041 205 while(_spi.write(0xFF) != 0xFE);
DaveStyles 0:b545e012d041 206
DaveStyles 0:b545e012d041 207 // read data
DaveStyles 0:b545e012d041 208 for(int i=0; i<length; i++) {
DaveStyles 0:b545e012d041 209 buffer[i] = _spi.write(0xFF);
DaveStyles 0:b545e012d041 210 }
DaveStyles 0:b545e012d041 211 _spi.write(0xFF); // checksum
DaveStyles 0:b545e012d041 212 _spi.write(0xFF);
DaveStyles 0:b545e012d041 213
DaveStyles 0:b545e012d041 214 _cs = 1;
DaveStyles 0:b545e012d041 215 return 0;
DaveStyles 0:b545e012d041 216 }
DaveStyles 0:b545e012d041 217
DaveStyles 0:b545e012d041 218 int SDFileSystem::_write(const char *buffer, int length) {
DaveStyles 0:b545e012d041 219 _cs = 0;
DaveStyles 0:b545e012d041 220
DaveStyles 0:b545e012d041 221 // indicate start of block
DaveStyles 0:b545e012d041 222 _spi.write(0xFE);
DaveStyles 0:b545e012d041 223
DaveStyles 0:b545e012d041 224 // write the data
DaveStyles 0:b545e012d041 225 for(int i=0; i<length; i++) {
DaveStyles 0:b545e012d041 226 _spi.write(buffer[i]);
DaveStyles 0:b545e012d041 227 }
DaveStyles 0:b545e012d041 228
DaveStyles 0:b545e012d041 229 // write the checksum
DaveStyles 0:b545e012d041 230 _spi.write(0xFF);
DaveStyles 0:b545e012d041 231 _spi.write(0xFF);
DaveStyles 0:b545e012d041 232
DaveStyles 0:b545e012d041 233 // check the repsonse token
DaveStyles 0:b545e012d041 234 if((_spi.write(0xFF) & 0x1F) != 0x05) {
DaveStyles 0:b545e012d041 235 _cs = 1;
DaveStyles 0:b545e012d041 236 return 1;
DaveStyles 0:b545e012d041 237 }
DaveStyles 0:b545e012d041 238
DaveStyles 0:b545e012d041 239 // wait for write to finish
DaveStyles 0:b545e012d041 240 while(_spi.write(0xFF) == 0);
DaveStyles 0:b545e012d041 241
DaveStyles 0:b545e012d041 242 _cs = 1;
DaveStyles 0:b545e012d041 243 return 0;
DaveStyles 0:b545e012d041 244 }
DaveStyles 0:b545e012d041 245
DaveStyles 0:b545e012d041 246 static int ext_bits(char *data, int msb, int lsb) {
DaveStyles 0:b545e012d041 247 int bits = 0;
DaveStyles 0:b545e012d041 248 int size = 1 + msb - lsb;
DaveStyles 0:b545e012d041 249 for(int i=0; i<size; i++) {
DaveStyles 0:b545e012d041 250 int position = lsb + i;
DaveStyles 0:b545e012d041 251 int byte = 15 - (position >> 3);
DaveStyles 0:b545e012d041 252 int bit = position & 0x7;
DaveStyles 0:b545e012d041 253 int value = (data[byte] >> bit) & 1;
DaveStyles 0:b545e012d041 254 bits |= value << i;
DaveStyles 0:b545e012d041 255 }
DaveStyles 0:b545e012d041 256 return bits;
DaveStyles 0:b545e012d041 257 }
DaveStyles 0:b545e012d041 258
DaveStyles 0:b545e012d041 259 int SDFileSystem::_sd_sectors() {
DaveStyles 0:b545e012d041 260
DaveStyles 0:b545e012d041 261 // CMD9, Response R2 (R1 byte + 16-byte block read)
DaveStyles 0:b545e012d041 262 if(_cmd(9, 0) != 0) {
DaveStyles 0:b545e012d041 263 fprintf(stderr, "Didn't get a response from the disk\n");
DaveStyles 0:b545e012d041 264 return 0;
DaveStyles 0:b545e012d041 265 }
DaveStyles 0:b545e012d041 266
DaveStyles 0:b545e012d041 267 char csd[16];
DaveStyles 0:b545e012d041 268 if(_read(csd, 16) != 0) {
DaveStyles 0:b545e012d041 269 fprintf(stderr, "Couldn't read csd response from disk\n");
DaveStyles 0:b545e012d041 270 return 0;
DaveStyles 0:b545e012d041 271 }
DaveStyles 0:b545e012d041 272
DaveStyles 0:b545e012d041 273 // csd_structure : csd[127:126]
DaveStyles 0:b545e012d041 274 // c_size : csd[73:62]
DaveStyles 0:b545e012d041 275 // c_size_mult : csd[49:47]
DaveStyles 0:b545e012d041 276 // read_bl_len : csd[83:80]
DaveStyles 0:b545e012d041 277
DaveStyles 0:b545e012d041 278 int csd_structure = ext_bits(csd, 127, 126);
DaveStyles 0:b545e012d041 279 int c_size = ext_bits(csd, 73, 62);
DaveStyles 0:b545e012d041 280 int c_size_mult = ext_bits(csd, 49, 47);
DaveStyles 0:b545e012d041 281 int read_bl_len = ext_bits(csd, 83, 80);
DaveStyles 0:b545e012d041 282
DaveStyles 0:b545e012d041 283 if(csd_structure != 0) {
DaveStyles 0:b545e012d041 284 fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures");
DaveStyles 0:b545e012d041 285 return 0;
DaveStyles 0:b545e012d041 286 }
DaveStyles 0:b545e012d041 287
DaveStyles 0:b545e012d041 288 int blocks = (c_size + 1) * (1 << (c_size_mult + 2));
DaveStyles 0:b545e012d041 289 int block_size = 1 << read_bl_len;
DaveStyles 0:b545e012d041 290
DaveStyles 0:b545e012d041 291 if(block_size != 512) {
DaveStyles 0:b545e012d041 292 fprintf(stderr, "This disk tastes funny! I only like 512-byte blocks");
DaveStyles 0:b545e012d041 293 return 0;
DaveStyles 0:b545e012d041 294 }
DaveStyles 0:b545e012d041 295
DaveStyles 0:b545e012d041 296 return blocks;
DaveStyles 0:b545e012d041 297 }