A re-written SDFileSystem library with improved compatibility, CRC support, and card removal/replacement support.

Dependencies:   FATFileSystem

Fork of SDFileSystem by Neil Thiessen

Committer:
neilt6
Date:
Wed Apr 13 16:51:25 2016 +0000
Revision:
23:6bb3c1987511
Parent:
22:3fa5eaf48e81
Added high-speed mode (50MHz) support for v2.00 or later SD cards

Who changed what in which revision?

UserRevisionLine numberNew contents of line
neilt6 0:2a6d8a096edc 1 /* SD/MMC File System Library
neilt6 22:3fa5eaf48e81 2 * Copyright (c) 2016 Neil Thiessen
neilt6 0:2a6d8a096edc 3 *
neilt6 0:2a6d8a096edc 4 * Licensed under the Apache License, Version 2.0 (the "License");
neilt6 0:2a6d8a096edc 5 * you may not use this file except in compliance with the License.
neilt6 0:2a6d8a096edc 6 * You may obtain a copy of the License at
neilt6 0:2a6d8a096edc 7 *
neilt6 0:2a6d8a096edc 8 * http://www.apache.org/licenses/LICENSE-2.0
neilt6 0:2a6d8a096edc 9 *
neilt6 0:2a6d8a096edc 10 * Unless required by applicable law or agreed to in writing, software
neilt6 0:2a6d8a096edc 11 * distributed under the License is distributed on an "AS IS" BASIS,
neilt6 0:2a6d8a096edc 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
neilt6 0:2a6d8a096edc 13 * See the License for the specific language governing permissions and
neilt6 0:2a6d8a096edc 14 * limitations under the License.
neilt6 0:2a6d8a096edc 15 */
neilt6 0:2a6d8a096edc 16
neilt6 0:2a6d8a096edc 17 #ifndef SD_FILE_SYSTEM_H
neilt6 0:2a6d8a096edc 18 #define SD_FILE_SYSTEM_H
neilt6 0:2a6d8a096edc 19
neilt6 0:2a6d8a096edc 20 #include "mbed.h"
neilt6 0:2a6d8a096edc 21 #include "FATFileSystem.h"
neilt6 0:2a6d8a096edc 22
neilt6 0:2a6d8a096edc 23 /** SDFileSystem class.
neilt6 0:2a6d8a096edc 24 * Used for creating a virtual file system for accessing SD/MMC cards via SPI.
neilt6 0:2a6d8a096edc 25 *
neilt6 0:2a6d8a096edc 26 * Example:
neilt6 0:2a6d8a096edc 27 * @code
neilt6 0:2a6d8a096edc 28 * #include "mbed.h"
neilt6 0:2a6d8a096edc 29 * #include "SDFileSystem.h"
neilt6 0:2a6d8a096edc 30 *
neilt6 0:2a6d8a096edc 31 * //Create an SDFileSystem object
neilt6 16:c2c1f0b16380 32 * SDFileSystem sd(p5, p6, p7, p20, "sd");
neilt6 0:2a6d8a096edc 33 *
neilt6 0:2a6d8a096edc 34 * int main()
neilt6 0:2a6d8a096edc 35 * {
neilt6 16:c2c1f0b16380 36 * //Mount the filesystem
neilt6 16:c2c1f0b16380 37 * sd.mount();
neilt6 16:c2c1f0b16380 38 *
neilt6 0:2a6d8a096edc 39 * //Perform a write test
neilt6 0:2a6d8a096edc 40 * printf("\nWriting to SD card...");
neilt6 0:2a6d8a096edc 41 * FILE *fp = fopen("/sd/sdtest.txt", "w");
neilt6 0:2a6d8a096edc 42 * if (fp != NULL) {
neilt6 0:2a6d8a096edc 43 * fprintf(fp, "We're writing to an SD card!");
neilt6 0:2a6d8a096edc 44 * fclose(fp);
neilt6 0:2a6d8a096edc 45 * printf("success!\n");
neilt6 0:2a6d8a096edc 46 * } else {
neilt6 0:2a6d8a096edc 47 * printf("failed!\n");
neilt6 0:2a6d8a096edc 48 * }
neilt6 0:2a6d8a096edc 49 *
neilt6 0:2a6d8a096edc 50 * //Perform a read test
neilt6 0:2a6d8a096edc 51 * printf("Reading from SD card...");
neilt6 0:2a6d8a096edc 52 * fp = fopen("/sd/sdtest.txt", "r");
neilt6 0:2a6d8a096edc 53 * if (fp != NULL) {
neilt6 0:2a6d8a096edc 54 * char c = fgetc(fp);
neilt6 0:2a6d8a096edc 55 * if (c == 'W')
neilt6 0:2a6d8a096edc 56 * printf("success!\n");
neilt6 0:2a6d8a096edc 57 * else
neilt6 0:2a6d8a096edc 58 * printf("incorrect char (%c)!\n", c);
neilt6 0:2a6d8a096edc 59 * fclose(fp);
neilt6 0:2a6d8a096edc 60 * } else {
neilt6 0:2a6d8a096edc 61 * printf("failed!\n");
neilt6 0:2a6d8a096edc 62 * }
neilt6 16:c2c1f0b16380 63 *
neilt6 16:c2c1f0b16380 64 * //Unmount the filesystem
neilt6 16:c2c1f0b16380 65 * sd.unmount();
neilt6 0:2a6d8a096edc 66 * }
neilt6 0:2a6d8a096edc 67 * @endcode
neilt6 0:2a6d8a096edc 68 */
neilt6 0:2a6d8a096edc 69 class SDFileSystem : public FATFileSystem
neilt6 0:2a6d8a096edc 70 {
neilt6 0:2a6d8a096edc 71 public:
neilt6 1:25f4ba436b81 72 /** Represents the different card detect switch types
neilt6 1:25f4ba436b81 73 */
neilt6 1:25f4ba436b81 74 enum SwitchType {
neilt6 16:c2c1f0b16380 75 SWITCH_NONE, /**< No card detect switch (assumes socket is always occupied) */
neilt6 12:eebddab6eff2 76 SWITCH_POS_NO, /**< Switch shorts to VDD when the socket is occupied (positive logic, normally open) */
neilt6 12:eebddab6eff2 77 SWITCH_POS_NC, /**< Switch shorts to VDD when the socket is empty (positive logic, normally closed) */
neilt6 12:eebddab6eff2 78 SWITCH_NEG_NO, /**< Switch shorts to GND when the socket is occupied (negative logic, normally open) */
neilt6 12:eebddab6eff2 79 SWITCH_NEG_NC /**< Switch shorts to GND when the socket is empty (negative logic, normally closed) */
neilt6 1:25f4ba436b81 80 };
neilt6 1:25f4ba436b81 81
neilt6 0:2a6d8a096edc 82 /** Represents the different SD/MMC card types
neilt6 0:2a6d8a096edc 83 */
neilt6 0:2a6d8a096edc 84 enum CardType {
neilt6 0:2a6d8a096edc 85 CARD_NONE, /**< No card is present */
neilt6 0:2a6d8a096edc 86 CARD_MMC, /**< MMC card */
neilt6 0:2a6d8a096edc 87 CARD_SD, /**< Standard capacity SD card */
neilt6 0:2a6d8a096edc 88 CARD_SDHC, /**< High capacity SD card */
neilt6 0:2a6d8a096edc 89 CARD_UNKNOWN /**< Unknown or unsupported card */
neilt6 0:2a6d8a096edc 90 };
neilt6 0:2a6d8a096edc 91
neilt6 0:2a6d8a096edc 92 /** Create a virtual file system for accessing SD/MMC cards via SPI
neilt6 0:2a6d8a096edc 93 *
neilt6 0:2a6d8a096edc 94 * @param mosi The SPI data out pin.
neilt6 0:2a6d8a096edc 95 * @param miso The SPI data in pin.
neilt6 0:2a6d8a096edc 96 * @param sclk The SPI clock pin.
neilt6 0:2a6d8a096edc 97 * @param cs The SPI chip select pin.
neilt6 3:7cf3d1835ef5 98 * @param name The name used to access the virtual filesystem.
neilt6 1:25f4ba436b81 99 * @param cd The card detect pin.
neilt6 12:eebddab6eff2 100 * @param cdtype The type of card detect switch.
neilt6 0:2a6d8a096edc 101 * @param hz The SPI bus frequency (defaults to 1MHz).
neilt6 0:2a6d8a096edc 102 */
neilt6 16:c2c1f0b16380 103 SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name, PinName cd = NC, SwitchType cdtype = SWITCH_NONE, int hz = 1000000);
neilt6 0:2a6d8a096edc 104
neilt6 20:2c1e8d442f68 105 /** Determine whether or not a card is present
neilt6 20:2c1e8d442f68 106 *
neilt6 20:2c1e8d442f68 107 * @returns
neilt6 20:2c1e8d442f68 108 * 'true' if a card is present,
neilt6 20:2c1e8d442f68 109 * 'false' if no card is present.
neilt6 20:2c1e8d442f68 110 */
neilt6 20:2c1e8d442f68 111 bool card_present();
neilt6 20:2c1e8d442f68 112
neilt6 0:2a6d8a096edc 113 /** Get the detected SD/MMC card type
neilt6 0:2a6d8a096edc 114 *
neilt6 0:2a6d8a096edc 115 * @returns The detected card type as a CardType enum.
neilt6 20:2c1e8d442f68 116 *
neilt6 20:2c1e8d442f68 117 * @note Valid after the filesystem has been mounted.
neilt6 0:2a6d8a096edc 118 */
neilt6 0:2a6d8a096edc 119 SDFileSystem::CardType card_type();
neilt6 0:2a6d8a096edc 120
neilt6 6:55a26a56046a 121 /** Get whether or not CRC is enabled for commands and data
neilt6 6:55a26a56046a 122 *
neilt6 6:55a26a56046a 123 * @returns
neilt6 6:55a26a56046a 124 * 'true' if CRC is enabled for commands and data,
neilt6 6:55a26a56046a 125 * 'false' if CRC is disabled for commands and data.
neilt6 6:55a26a56046a 126 */
neilt6 7:61db99e52c0d 127 bool crc();
neilt6 6:55a26a56046a 128
neilt6 6:55a26a56046a 129 /** Set whether or not CRC is enabled for commands and data
neilt6 6:55a26a56046a 130 *
neilt6 6:55a26a56046a 131 * @param enabled Whether or not to enable CRC for commands and data.
neilt6 6:55a26a56046a 132 */
neilt6 7:61db99e52c0d 133 void crc(bool enabled);
neilt6 6:55a26a56046a 134
neilt6 6:55a26a56046a 135 /** Get whether or not 16-bit frames are enabled for data read/write operations
neilt6 6:55a26a56046a 136 *
neilt6 6:55a26a56046a 137 * @returns
neilt6 6:55a26a56046a 138 * 'true' if 16-bit frames will be used during data read/write operations,
neilt6 6:55a26a56046a 139 * 'false' if 8-bit frames will be used during data read/write operations.
neilt6 6:55a26a56046a 140 */
neilt6 6:55a26a56046a 141 bool large_frames();
neilt6 6:55a26a56046a 142
neilt6 6:55a26a56046a 143 /** Set whether or not 16-bit frames are enabled for data read/write operations
neilt6 6:55a26a56046a 144 *
neilt6 6:55a26a56046a 145 * @param enabled Whether or not 16-bit frames are enabled for data read/write operations.
neilt6 6:55a26a56046a 146 */
neilt6 6:55a26a56046a 147 void large_frames(bool enabled);
neilt6 6:55a26a56046a 148
neilt6 13:635147efa748 149 /** Get whether or not write validation is enabled for data write operations
neilt6 13:635147efa748 150 *
neilt6 13:635147efa748 151 * @returns
neilt6 13:635147efa748 152 * 'true' if data writes will be verified using CMD13,
neilt6 13:635147efa748 153 * 'false' if data writes will not be verified.
neilt6 13:635147efa748 154 */
neilt6 13:635147efa748 155 bool write_validation();
neilt6 13:635147efa748 156
neilt6 13:635147efa748 157 /** Set whether or not write validation is enabled for data write operations
neilt6 13:635147efa748 158 *
neilt6 13:635147efa748 159 * @param enabled Whether or not write validation is enabled for data write operations.
neilt6 13:635147efa748 160 */
neilt6 13:635147efa748 161 void write_validation(bool enabled);
neilt6 13:635147efa748 162
neilt6 11:67ddc53e3983 163 virtual int unmount();
neilt6 0:2a6d8a096edc 164 virtual int disk_initialize();
neilt6 0:2a6d8a096edc 165 virtual int disk_status();
neilt6 21:d10a519c0910 166 virtual int disk_read(uint8_t* buffer, uint32_t sector, uint32_t count);
neilt6 21:d10a519c0910 167 virtual int disk_write(const uint8_t* buffer, uint32_t sector, uint32_t count);
neilt6 0:2a6d8a096edc 168 virtual int disk_sync();
neilt6 21:d10a519c0910 169 virtual uint32_t disk_sectors();
neilt6 0:2a6d8a096edc 170
neilt6 0:2a6d8a096edc 171 private:
neilt6 0:2a6d8a096edc 172 //Commands
neilt6 0:2a6d8a096edc 173 enum Command {
neilt6 4:49b29888eca7 174 CMD0 = (0x40 | 0), /**< GO_IDLE_STATE */
neilt6 4:49b29888eca7 175 CMD1 = (0x40 | 1), /**< SEND_OP_COND */
neilt6 23:6bb3c1987511 176 CMD6 = (0x40 | 6), /**< SWITCH_FUNC */
neilt6 4:49b29888eca7 177 CMD8 = (0x40 | 8), /**< SEND_IF_COND */
neilt6 4:49b29888eca7 178 CMD9 = (0x40 | 9), /**< SEND_CSD */
neilt6 11:67ddc53e3983 179 CMD12 = (0x40 | 12), /**< STOP_TRANSMISSION */
neilt6 11:67ddc53e3983 180 CMD13 = (0x40 | 13), /**< SEND_STATUS */
neilt6 4:49b29888eca7 181 CMD16 = (0x40 | 16), /**< SET_BLOCKLEN */
neilt6 4:49b29888eca7 182 CMD17 = (0x40 | 17), /**< READ_SINGLE_BLOCK */
neilt6 11:67ddc53e3983 183 CMD18 = (0x40 | 18), /**< READ_MULTIPLE_BLOCK */
neilt6 11:67ddc53e3983 184 ACMD22 = (0x40 | 22), /**< SEND_NUM_WR_BLOCKS */
neilt6 11:67ddc53e3983 185 ACMD23 = (0x40 | 23), /**< SET_WR_BLK_ERASE_COUNT */
neilt6 4:49b29888eca7 186 CMD24 = (0x40 | 24), /**< WRITE_BLOCK */
neilt6 11:67ddc53e3983 187 CMD25 = (0x40 | 25), /**< WRITE_MULTIPLE_BLOCK */
neilt6 5:6befff2300d0 188 ACMD41 = (0x40 | 41), /**< SD_SEND_OP_COND */
neilt6 5:6befff2300d0 189 ACMD42 = (0x40 | 42), /**< SET_CLR_CARD_DETECT */
neilt6 4:49b29888eca7 190 CMD55 = (0x40 | 55), /**< APP_CMD */
neilt6 4:49b29888eca7 191 CMD58 = (0x40 | 58), /**< READ_OCR */
neilt6 4:49b29888eca7 192 CMD59 = (0x40 | 59) /**< CRC_ON_OFF */
neilt6 0:2a6d8a096edc 193 };
neilt6 0:2a6d8a096edc 194
neilt6 0:2a6d8a096edc 195 //Member variables
neilt6 13:635147efa748 196 Timer m_Timer;
neilt6 7:61db99e52c0d 197 SPI m_Spi;
neilt6 7:61db99e52c0d 198 DigitalOut m_Cs;
neilt6 7:61db99e52c0d 199 InterruptIn m_Cd;
neilt6 12:eebddab6eff2 200 int m_CdAssert;
neilt6 6:55a26a56046a 201 const int m_FREQ;
neilt6 6:55a26a56046a 202 SDFileSystem::CardType m_CardType;
neilt6 7:61db99e52c0d 203 bool m_Crc;
neilt6 6:55a26a56046a 204 bool m_LargeFrames;
neilt6 13:635147efa748 205 bool m_WriteValidation;
neilt6 0:2a6d8a096edc 206 int m_Status;
neilt6 0:2a6d8a096edc 207
neilt6 0:2a6d8a096edc 208 //Internal methods
neilt6 13:635147efa748 209 void onCardRemoval();
neilt6 0:2a6d8a096edc 210 void checkSocket();
neilt6 0:2a6d8a096edc 211 bool waitReady(int timeout);
neilt6 0:2a6d8a096edc 212 bool select();
neilt6 0:2a6d8a096edc 213 void deselect();
neilt6 11:67ddc53e3983 214 char commandTransaction(char cmd, unsigned int arg, unsigned int* resp = NULL);
neilt6 13:635147efa748 215 char writeCommand(char cmd, unsigned int arg, unsigned int* resp = NULL);
neilt6 0:2a6d8a096edc 216 bool readData(char* buffer, int length);
neilt6 11:67ddc53e3983 217 char writeData(const char* buffer, char token);
neilt6 17:a47f74caa04e 218 bool readBlock(char* buffer, unsigned int lba);
neilt6 17:a47f74caa04e 219 bool readBlocks(char* buffer, unsigned int lba, unsigned int count);
neilt6 17:a47f74caa04e 220 bool writeBlock(const char* buffer, unsigned int lba);
neilt6 17:a47f74caa04e 221 bool writeBlocks(const char* buffer, unsigned int lba, unsigned int count);
neilt6 23:6bb3c1987511 222 bool enableHighSpeedMode();
neilt6 0:2a6d8a096edc 223 };
neilt6 0:2a6d8a096edc 224
neilt6 0:2a6d8a096edc 225 #endif