Amundson OCE 360 homework 7 SD card library
Fork of SDFileSystem by
Revision 0:2a6d8a096edc, committed 2014-07-29
- Comitter:
- neilt6
- Date:
- Tue Jul 29 20:12:23 2014 +0000
- Child:
- 1:25f4ba436b81
- Commit message:
- Initial commit
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CRC16.cpp Tue Jul 29 20:12:23 2014 +0000 @@ -0,0 +1,67 @@ +/* SD/MMC File System Library + * Copyright (c) 2014 Neil Thiessen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CRC16.h" + +namespace +{ +const unsigned short m_CRC16Table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 +}; +} + +unsigned short CRC16(const char* data, int length) +{ + //Calculate the CRC16 checksum for the specified data block + unsigned short crc = 0; + for (int i = 0; i < length; i++) { + crc = (crc << 8) ^ m_CRC16Table[((crc >> 8) ^ data[i]) & 0x00FF]; + } + + //Return the calculated checksum + return crc; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CRC16.h Tue Jul 29 20:12:23 2014 +0000 @@ -0,0 +1,24 @@ +/* SD/MMC File System Library + * Copyright (c) 2014 Neil Thiessen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CRC16_H +#define CRC16_H + +#include "mbed.h" + +unsigned short CRC16(const char* data, int length); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CRC7.cpp Tue Jul 29 20:12:23 2014 +0000 @@ -0,0 +1,67 @@ +/* SD/MMC File System Library + * Copyright (c) 2014 Neil Thiessen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CRC7.h" + +namespace +{ +const char m_CRC7Table[] = { + 0x00, 0x09, 0x12, 0x1B, 0x24, 0x2D, 0x36, 0x3F, + 0x48, 0x41, 0x5A, 0x53, 0x6C, 0x65, 0x7E, 0x77, + 0x19, 0x10, 0x0B, 0x02, 0x3D, 0x34, 0x2F, 0x26, + 0x51, 0x58, 0x43, 0x4A, 0x75, 0x7C, 0x67, 0x6E, + 0x32, 0x3B, 0x20, 0x29, 0x16, 0x1F, 0x04, 0x0D, + 0x7A, 0x73, 0x68, 0x61, 0x5E, 0x57, 0x4C, 0x45, + 0x2B, 0x22, 0x39, 0x30, 0x0F, 0x06, 0x1D, 0x14, + 0x63, 0x6A, 0x71, 0x78, 0x47, 0x4E, 0x55, 0x5C, + 0x64, 0x6D, 0x76, 0x7F, 0x40, 0x49, 0x52, 0x5B, + 0x2C, 0x25, 0x3E, 0x37, 0x08, 0x01, 0x1A, 0x13, + 0x7D, 0x74, 0x6F, 0x66, 0x59, 0x50, 0x4B, 0x42, + 0x35, 0x3C, 0x27, 0x2E, 0x11, 0x18, 0x03, 0x0A, + 0x56, 0x5F, 0x44, 0x4D, 0x72, 0x7B, 0x60, 0x69, + 0x1E, 0x17, 0x0C, 0x05, 0x3A, 0x33, 0x28, 0x21, + 0x4F, 0x46, 0x5D, 0x54, 0x6B, 0x62, 0x79, 0x70, + 0x07, 0x0E, 0x15, 0x1C, 0x23, 0x2A, 0x31, 0x38, + 0x41, 0x48, 0x53, 0x5A, 0x65, 0x6C, 0x77, 0x7E, + 0x09, 0x00, 0x1B, 0x12, 0x2D, 0x24, 0x3F, 0x36, + 0x58, 0x51, 0x4A, 0x43, 0x7C, 0x75, 0x6E, 0x67, + 0x10, 0x19, 0x02, 0x0B, 0x34, 0x3D, 0x26, 0x2F, + 0x73, 0x7A, 0x61, 0x68, 0x57, 0x5E, 0x45, 0x4C, + 0x3B, 0x32, 0x29, 0x20, 0x1F, 0x16, 0x0D, 0x04, + 0x6A, 0x63, 0x78, 0x71, 0x4E, 0x47, 0x5C, 0x55, + 0x22, 0x2B, 0x30, 0x39, 0x06, 0x0F, 0x14, 0x1D, + 0x25, 0x2C, 0x37, 0x3E, 0x01, 0x08, 0x13, 0x1A, + 0x6D, 0x64, 0x7F, 0x76, 0x49, 0x40, 0x5B, 0x52, + 0x3C, 0x35, 0x2E, 0x27, 0x18, 0x11, 0x0A, 0x03, + 0x74, 0x7D, 0x66, 0x6F, 0x50, 0x59, 0x42, 0x4B, + 0x17, 0x1E, 0x05, 0x0C, 0x33, 0x3A, 0x21, 0x28, + 0x5F, 0x56, 0x4D, 0x44, 0x7B, 0x72, 0x69, 0x60, + 0x0E, 0x07, 0x1C, 0x15, 0x2A, 0x23, 0x38, 0x31, + 0x46, 0x4F, 0x54, 0x5D, 0x62, 0x6B, 0x70, 0x79 +}; +} + +char CRC7(const char* data, int length) +{ + //Calculate the CRC7 checksum for the specified data block + char crc = 0; + for (int i = 0; i < length; i++) { + crc = m_CRC7Table[(crc << 1) ^ data[i]]; + } + + //Return the calculated checksum + return crc; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CRC7.h Tue Jul 29 20:12:23 2014 +0000 @@ -0,0 +1,24 @@ +/* SD/MMC File System Library + * Copyright (c) 2014 Neil Thiessen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CRC7_H +#define CRC7_H + +#include "mbed.h" + +char CRC7(const char* data, int length); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FATFileSystem.lib Tue Jul 29 20:12:23 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/mbed-official/code/FATFileSystem/#e960e2b81a3c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDFileSystem.cpp Tue Jul 29 20:12:23 2014 +0000 @@ -0,0 +1,496 @@ +/* SD/MMC File System Library + * Copyright (c) 2014 Neil Thiessen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SDFileSystem.h" +#include "diskio.h" +#include "CRC7.h" +#include "CRC16.h" + +SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName cd, const char* name, int hz) : FATFileSystem(name), m_SPI(mosi, miso, sclk), m_CS(cs, 1), m_CD(cd) +{ + //Initialize the member variables + m_SpiFreq = hz; + m_Status = STA_NOINIT; + m_CardType = CARD_NONE; + + //Configure the SPI bus + m_SPI.format(8, 0); + + //Configure the card detect pin + m_CD.mode(PullUp); + m_CD.fall(this, &SDFileSystem::checkSocket); +} + +SDFileSystem::CardType SDFileSystem::card_type() +{ + //Check the card socket + checkSocket(); + + //If a card is present but not initialized, initialize it + if (!(m_Status & STA_NODISK) && (m_Status & STA_NOINIT)) + disk_initialize(); + + //Return the card type + return m_CardType; +} + +int SDFileSystem::disk_initialize() +{ + char resp; + + //Make sure there's a card in the socket before proceeding + checkSocket(); + if (m_Status & STA_NODISK) + return m_Status; + + //Make sure we're not already initialized before proceeding + if (!(m_Status & STA_NOINIT)) + return m_Status; + + //Set the SPI frequency to 100kHz for initialization + m_SPI.frequency(100000); + + //Send 80 dummy clocks with /CS and DI held high + m_CS = 1; + for (int i = 0; i < 10; i++) + m_SPI.write(0xFF); + + //Write CMD0(0), and check for a valid response + resp = writeCommand(CMD0, 0); + if (resp != 0x01) { + //Initialization failed + m_CardType = CARD_UNKNOWN; + return m_Status; + } + + //Write CMD8(0x000001AA) to see if this is an SDCv2 card + resp = writeCommand(CMD8, 0x000001AA); + if (resp == 0x01) { + //This is an SDCv2 card, get the 32-bit return value and verify the voltage range/check pattern + if ((readReturn() & 0xFFF) != 0x1AA) { + //Initialization failed + m_CardType = CARD_UNKNOWN; + return m_Status; + } + + //Send CMD58(0) to read the OCR, and verify that the card supports 3.2-3.3V + resp = writeCommand(CMD58, 0); + if (resp != 0x01 || !(readReturn() & (1 << 20))) { + //Initialization failed + deselect(); + m_CardType = CARD_UNKNOWN; + return m_Status; + } + + //Send ACMD41(0x40100000) repeatedly for up to 1 second to initialize the card + for (int i = 0; i < 1000; i++) { + resp = writeCommand(ACMD41, 0x40100000); + if (resp != 0x01) + break; + wait_ms(1); + } + + //Check if the card initialized + if (resp != 0x00) { + //Initialization failed + m_CardType = CARD_UNKNOWN; + return m_Status; + } + + //Send CMD58(0) to read the OCR + resp = writeCommand(CMD58, 0); + if (resp == 0x00) { + //Check the CCS bit to determine if this is a high capacity card + if (readReturn() & 0x40000000) + m_CardType = CARD_SDHC; + else + m_CardType = CARD_SD; + } else { + //Initialization failed + m_CardType = CARD_UNKNOWN; + return m_Status; + } + } else { + //Didn't respond or illegal command, this is either an SDCv1 or MMC card + deselect(); + + //Send CMD58(0) to read the OCR, and verify that the card supports 3.2-3.3V + resp = writeCommand(CMD58, 0); + if (resp != 0x01 || !(readReturn() & (1 << 20))) { + //Initialization failed + deselect(); + m_CardType = CARD_UNKNOWN; + return m_Status; + } + + //Try to initialize the card using ACMD41(0x00100000) for 1 second + for (int i = 0; i < 1000; i++) { + resp = writeCommand(ACMD41, 0x00100000); + if (resp != 0x01) + break; + wait_ms(1); + } + + //Check if the card initialized + if (resp == 0x00) { + //This is an SDCv1 standard capacity card + m_CardType = CARD_SD; + } else { + //Try to initialize the card using CMD1(0x00100000) for 1 second + for (int i = 0; i < 1000; i++) { + resp = writeCommand(CMD1, 0x00100000); + if (resp != 0x01) + break; + wait_ms(1); + } + + //Check if the card initialized + if (resp == 0x00) { + //This is an MMCv3 card + m_CardType = CARD_MMC; + } else { + //Initialization failed + m_CardType = CARD_UNKNOWN; + return m_Status; + } + } + } + + //Send CMD59(0x00000001) to re-enable CRC + resp = writeCommand(CMD59, 0x00000001); + if (resp != 0x00) { + //Initialization failed + m_CardType = CARD_UNKNOWN; + return m_Status; + } + + //Send CMD16(0x00000200) to force the block size to 512B if necessary + if (m_CardType != CARD_SDHC) { + resp = writeCommand(CMD16, 0x00000200); + if (resp != 0x00) { + //Initialization failed + m_CardType = CARD_UNKNOWN; + return m_Status; + } + } + + //The card is now initialized + m_Status &= ~STA_NOINIT; + + //Increase the SPI frequency to full speed (limited to 20MHz for MMC, or 25MHz for SDC) + if (m_CardType == CARD_MMC && m_SpiFreq > 20000000) + m_SPI.frequency(20000000); + else if (m_SpiFreq > 25000000) + m_SPI.frequency(25000000); + else + m_SPI.frequency(m_SpiFreq); + + //Return the device status + return m_Status; +} + +int SDFileSystem::disk_status() +{ + //Check if there's a card in the socket + checkSocket(); + + //Return the device status + return m_Status; +} + +int SDFileSystem::disk_read(uint8_t* buffer, uint64_t sector) +{ + //Make sure the device is initialized before proceeding + if (m_Status & STA_NOINIT) + return RES_NOTRDY; + + //Convert from LBA to a byte address for standard capacity cards + if (m_CardType != CARD_SDHC) + sector *= 512; + + //Try to read the block up to 3 times + for (int i = 0; i < 3; i++) { + //Send CMD17(sector) to read a single block + char resp = writeCommand(CMD17, sector); + if (resp == 0x00) { + //Try to read the sector, and return if successful + if (readData((char*)buffer, 512)) + return RES_OK; + } else { + //The command failed + deselect(); + return RES_ERROR; + } + } + + //The read operation failed 3 times (CRC most likely) + return RES_ERROR; +} + +int SDFileSystem::disk_write(const uint8_t* buffer, uint64_t sector) +{ + //Make sure the device is initialized before proceeding + if (m_Status & STA_NOINIT) + return RES_NOTRDY; + + //Make sure the device isn't write protected before proceeding + if (m_Status & STA_PROTECT) + return RES_WRPRT; + + //Convert from LBA to a byte address for older cards + if (m_CardType != CARD_SDHC) + sector *= 512; + + //Try to write the block up to 3 times + for (int i = 0; i < 3; i++) { + //Send CMD24(sector) to write a single block + if (writeCommand(CMD24, sector) == 0x00) { + //Wait for up to 500ms for the card to become ready + if (!waitReady(500)) { + //We timed out + deselect(); + continue; + } + + //Send the write data token + m_SPI.write(0xFE); + + //Write the data block from the buffer + for (int b = 0; b < 512; b++) + m_SPI.write(buffer[b]); + + //Calculate the CRC16 checksum for the data block and send it + unsigned short crc = CRC16((char*)buffer, 512); + m_SPI.write(crc >> 8); + m_SPI.write(crc); + + //Receive the data response, and deselect the card + char resp = m_SPI.write(0xFF) & 0x1F; + deselect(); + + //Check the response + if (resp == 0x05) + return RES_OK; + else if (resp == 0x0D) + return RES_ERROR; + } else { + //The command failed + deselect(); + return RES_ERROR; + } + } + + //The operation either timed out 3 times, failed the CRC check 3 times, or experienced a write error + return RES_ERROR; +} + +int SDFileSystem::disk_sync() +{ + //Select the card so we're forced to wait for the end of any internal write processes + bool ret = select(); + deselect(); + + //Return success/failure + return (ret) ? RES_OK : RES_ERROR; +} + +uint64_t SDFileSystem::disk_sectors() +{ + //Make sure the device is initialized before proceeding + if (m_Status & STA_NOINIT) + return 0; + + //Try to read the CSD register up to 3 times + for (int i = 0; i < 3; i++) { + //Send CMD9(0) to read the CSD register + if (writeCommand(CMD9, 0) == 0x00) { + //Receive the 16B CSD data + char csd[16]; + if (readData(csd, 16)) { + //Calculate the sector count based on the card type + if ((csd[0] >> 6) == 0x01) { + //Calculate the sector count a high capacity card + uint64_t sectors = (((csd[7] & 0x3F) << 16) | (csd[8] << 8) | csd[9]) + 1; + return sectors << 10; + } else { + //Calculate the sector count standard capacity card + uint64_t sectors = (((csd[6] & 0x03) << 10) | (csd[7] << 2) | ((csd[8] & 0xC0) >> 6)) + 1; + sectors <<= ((((csd[9] & 0x03) << 1) | ((csd[10] & 0x80) >> 7)) + 2); + sectors <<= (csd[5] & 0x0F); + return sectors >> 9; + } + } + } else { + //The command failed + deselect(); + return 0; + } + } + + //The read operation failed 3 times (CRC most likely) + return 0; +} + +void SDFileSystem::checkSocket() +{ + //Check if a card is in the socket + if (m_CD) { + //The socket is occupied, clear the STA_NODISK flag + m_Status &= ~STA_NODISK; + } else { + //The socket is empty + m_Status |= (STA_NODISK | STA_NOINIT); + m_CardType = CARD_NONE; + } +} + +inline bool SDFileSystem::waitReady(int timeout) +{ + //Wait for the specified timeout for the card to become ready + for (int i = 0; i < timeout; i++) { + if (m_SPI.write(0xFF) == 0xFF) + return true; + wait_ms(1); + } + + //We timed out + return false; +} + +inline bool SDFileSystem::select() +{ + //Pull /CS low + m_CS = 0; + + //Send a dummy clock to enable DO + m_SPI.write(0xFF); + + //Wait for up to 500ms for the card to become ready + if (waitReady(500)) + return true; + + //We timed out, deselect and return false + deselect(); + return false; +} + +inline void SDFileSystem::deselect() +{ + //Pull /CS high + m_CS = 1; + + //Send a dummy byte to release DO + m_SPI.write(0xFF); +} + +char SDFileSystem::writeCommand(char cmd, unsigned int arg) +{ + char resp; + + //Try to send the command up to 3 times + for (int i = 0; i < 3; i++) { + //Send a CMD55 prior to an ACMD + if (cmd == ACMD41) { + resp = writeCommand(CMD55, 0); + if (resp > 0x01) + return resp; + } + + //Select the card and wait for ready + if (!select()) + return 0xFF; + + //Prepare the command packet + char cmdPacket[6]; + cmdPacket[0] = 0x40 | cmd; + cmdPacket[1] = arg >> 24; + cmdPacket[2] = arg >> 16; + cmdPacket[3] = arg >> 8; + cmdPacket[4] = arg; + cmdPacket[5] = (CRC7(cmdPacket, 5) << 1) | 0x01; + + //Send the command packet + for (int b = 0; b < 6; b++) + m_SPI.write(cmdPacket[b]); + + //Allow up to 10 bytes of delay for the command response + for (int b = 0; b < 10; b++) { + resp = m_SPI.write(0xFF); + if (!(resp & 0x80)) + break; + } + + //Deselect the card unless there's more data to read/write + if (resp == 0xFF || (resp & (1 << 3)) || !(cmd == CMD8 || cmd == CMD9 || cmd == CMD17 || cmd == CMD24 || cmd == CMD55 || cmd == CMD58)) + deselect(); + + //Return the response if there were no CRC errors + if (resp == 0xFF || !(resp & (1 << 3))) + return resp; + } + + //The command failed 3 times due to CRC errors + return 0xFF; +} + +unsigned int SDFileSystem::readReturn() +{ + unsigned int ret; + + //Read the 32-bit response value + ret = (m_SPI.write(0xFF) << 24); + ret |= (m_SPI.write(0xFF) << 16); + ret |= (m_SPI.write(0xFF) << 8); + ret |= m_SPI.write(0xFF); + + //Deselect the card + deselect(); + + //Return the response value + return ret; +} + +bool SDFileSystem::readData(char* buffer, int length) +{ + char token; + + //Wait for up to 200ms for the DataStart token to arrive + for (int i = 0; i < 200; i++) { + token = m_SPI.write(0xFF); + if (token != 0xFF) + break; + wait_ms(1); + } + + //Make sure the token is valid + if (token != 0xFE) + return false; + + //Read the data into the buffer + for (int i = 0; i < length; i++) + buffer[i] = m_SPI.write(0xFF); + + //Read the CRC16 checksum for the data block, and deselect the card + unsigned short crc = (m_SPI.write(0xFF) << 8); + crc |= m_SPI.write(0xFF); + deselect(); + + //Indicate whether the CRC16 checksum was valid or not + if (crc == CRC16(buffer, length)) + return true; + else + return false; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDFileSystem.h Tue Jul 29 20:12:23 2014 +0000 @@ -0,0 +1,136 @@ +/* SD/MMC File System Library + * Copyright (c) 2014 Neil Thiessen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SD_FILE_SYSTEM_H +#define SD_FILE_SYSTEM_H + +#include "mbed.h" +#include "FATFileSystem.h" +#include <stdint.h> + +/** SDFileSystem class. + * Used for creating a virtual file system for accessing SD/MMC cards via SPI. + * + * Example: + * @code + * #include "mbed.h" + * #include "SDFileSystem.h" + * + * //Create an SDFileSystem object + * SDFileSystem sd(p5, p6, p7, p19, p20, "sd") + * + * int main() + * { + * //Perform a write test + * printf("\nWriting to SD card..."); + * FILE *fp = fopen("/sd/sdtest.txt", "w"); + * if (fp != NULL) { + * fprintf(fp, "We're writing to an SD card!"); + * fclose(fp); + * printf("success!\n"); + * } else { + * printf("failed!\n"); + * } + * + * //Perform a read test + * printf("Reading from SD card..."); + * fp = fopen("/sd/sdtest.txt", "r"); + * if (fp != NULL) { + * char c = fgetc(fp); + * if (c == 'W') + * printf("success!\n"); + * else + * printf("incorrect char (%c)!\n", c); + * fclose(fp); + * } else { + * printf("failed!\n"); + * } + * } + * @endcode + */ +class SDFileSystem : public FATFileSystem +{ +public: + /** Represents the different SD/MMC card types + */ + enum CardType { + CARD_NONE, /**< No card is present */ + CARD_MMC, /**< MMC card */ + CARD_SD, /**< Standard capacity SD card */ + CARD_SDHC, /**< High capacity SD card */ + CARD_UNKNOWN /**< Unknown or unsupported card */ + }; + + /** Create a virtual file system for accessing SD/MMC cards via SPI + * + * @param mosi The SPI data out pin. + * @param miso The SPI data in pin. + * @param sclk The SPI clock pin. + * @param cs The SPI chip select pin. + * @param cd The active-high card detect pin. + * @param name The name used to access the virtual filesystem. + * @param hz The SPI bus frequency (defaults to 1MHz). + */ + SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName cd, const char* name, int hz = 1000000); + + /** Get the detected SD/MMC card type + * + * @returns The detected card type as a CardType enum. + */ + SDFileSystem::CardType card_type(); + + virtual int disk_initialize(); + virtual int disk_status(); + virtual int disk_read(uint8_t* buffer, uint64_t sector); + virtual int disk_write(const uint8_t* buffer, uint64_t sector); + virtual int disk_sync(); + virtual uint64_t disk_sectors(); + +private: + //Commands + enum Command { + CMD0 = 0, /**< GO_IDLE_STATE */ + CMD1 = 1, /**< SEND_OP_COND */ + ACMD41 = 41, /**< APP_SEND_OP_COND */ + CMD8 = 8, /**< SEND_IF_COND */ + CMD9 = 9, /**< SEND_CSD */ + CMD16 = 16, /**< SET_BLOCKLEN */ + CMD17 = 17, /**< READ_SINGLE_BLOCK */ + CMD24 = 24, /**< WRITE_BLOCK */ + CMD55 = 55, /**< APP_CMD */ + CMD58 = 58, /**< READ_OCR */ + CMD59 = 59 /**< CRC_ON_OFF */ + }; + + //Member variables + SPI m_SPI; + DigitalOut m_CS; + InterruptIn m_CD; + int m_SpiFreq; + int m_Status; + SDFileSystem::CardType m_CardType; + + //Internal methods + void checkSocket(); + bool waitReady(int timeout); + bool select(); + void deselect(); + char writeCommand(char cmd, unsigned int arg); + unsigned int readReturn(); + bool readData(char* buffer, int length); +}; + +#endif