Updated
SDBlockDevice.cpp@0:19febeae2548, 2019-01-05 (annotated)
- Committer:
- Swabey89
- Date:
- Sat Jan 05 15:02:34 2019 +0000
- Revision:
- 0:19febeae2548
Updated
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Swabey89 | 0:19febeae2548 | 1 | /* mbed Microcontroller Library |
Swabey89 | 0:19febeae2548 | 2 | * Copyright (c) 2006-2012 ARM Limited |
Swabey89 | 0:19febeae2548 | 3 | * |
Swabey89 | 0:19febeae2548 | 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
Swabey89 | 0:19febeae2548 | 5 | * of this software and associated documentation files (the "Software"), to deal |
Swabey89 | 0:19febeae2548 | 6 | * in the Software without restriction, including without limitation the rights |
Swabey89 | 0:19febeae2548 | 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
Swabey89 | 0:19febeae2548 | 8 | * copies of the Software, and to permit persons to whom the Software is |
Swabey89 | 0:19febeae2548 | 9 | * furnished to do so, subject to the following conditions: |
Swabey89 | 0:19febeae2548 | 10 | * |
Swabey89 | 0:19febeae2548 | 11 | * The above copyright notice and this permission notice shall be included in |
Swabey89 | 0:19febeae2548 | 12 | * all copies or substantial portions of the Software. |
Swabey89 | 0:19febeae2548 | 13 | * |
Swabey89 | 0:19febeae2548 | 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
Swabey89 | 0:19febeae2548 | 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
Swabey89 | 0:19febeae2548 | 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
Swabey89 | 0:19febeae2548 | 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
Swabey89 | 0:19febeae2548 | 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
Swabey89 | 0:19febeae2548 | 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
Swabey89 | 0:19febeae2548 | 20 | * SOFTWARE. |
Swabey89 | 0:19febeae2548 | 21 | */ |
Swabey89 | 0:19febeae2548 | 22 | /* Introduction |
Swabey89 | 0:19febeae2548 | 23 | * ------------ |
Swabey89 | 0:19febeae2548 | 24 | * SD and MMC cards support a number of interfaces, but common to them all |
Swabey89 | 0:19febeae2548 | 25 | * is one based on SPI. Since we already have the mbed SPI Interface, it will |
Swabey89 | 0:19febeae2548 | 26 | * be used for SD cards. |
Swabey89 | 0:19febeae2548 | 27 | * |
Swabey89 | 0:19febeae2548 | 28 | * The main reference I'm using is Chapter 7, "SPI Mode" of: |
Swabey89 | 0:19febeae2548 | 29 | * http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf |
Swabey89 | 0:19febeae2548 | 30 | * |
Swabey89 | 0:19febeae2548 | 31 | * SPI Startup |
Swabey89 | 0:19febeae2548 | 32 | * ----------- |
Swabey89 | 0:19febeae2548 | 33 | * The SD card powers up in SD mode. The start-up procedure is complicated |
Swabey89 | 0:19febeae2548 | 34 | * by the requirement to support older SDCards in a backwards compatible |
Swabey89 | 0:19febeae2548 | 35 | * way with the new higher capacity variants SDHC and SDHC. |
Swabey89 | 0:19febeae2548 | 36 | * |
Swabey89 | 0:19febeae2548 | 37 | * The following figures from the specification with associated text describe |
Swabey89 | 0:19febeae2548 | 38 | * the SPI mode initialisation process: |
Swabey89 | 0:19febeae2548 | 39 | * - Figure 7-1: SD Memory Card State Diagram (SPI mode) |
Swabey89 | 0:19febeae2548 | 40 | * - Figure 7-2: SPI Mode Initialization Flow |
Swabey89 | 0:19febeae2548 | 41 | * |
Swabey89 | 0:19febeae2548 | 42 | * Firstly, a low initial clock should be selected (in the range of 100- |
Swabey89 | 0:19febeae2548 | 43 | * 400kHZ). After initialisation has been completed, the switch to a |
Swabey89 | 0:19febeae2548 | 44 | * higher clock speed can be made (e.g. 1MHz). Newer cards will support |
Swabey89 | 0:19febeae2548 | 45 | * higher speeds than the default _transfer_sck defined here. |
Swabey89 | 0:19febeae2548 | 46 | * |
Swabey89 | 0:19febeae2548 | 47 | * Next, note the following from the SDCard specification (note to |
Swabey89 | 0:19febeae2548 | 48 | * Figure 7-1): |
Swabey89 | 0:19febeae2548 | 49 | * |
Swabey89 | 0:19febeae2548 | 50 | * In any of the cases CMD1 is not recommended because it may be difficult for the host |
Swabey89 | 0:19febeae2548 | 51 | * to distinguish between MultiMediaCard and SD Memory Card |
Swabey89 | 0:19febeae2548 | 52 | * |
Swabey89 | 0:19febeae2548 | 53 | * Hence CMD1 is not used for the initialisation sequence. |
Swabey89 | 0:19febeae2548 | 54 | * |
Swabey89 | 0:19febeae2548 | 55 | * The SPI interface mode is selected by asserting CS low and sending the |
Swabey89 | 0:19febeae2548 | 56 | * reset command (CMD0). The card will respond with a (R1) response. |
Swabey89 | 0:19febeae2548 | 57 | * In practice many cards initially respond with 0xff or invalid data |
Swabey89 | 0:19febeae2548 | 58 | * which is ignored. Data is read until a valid response is received |
Swabey89 | 0:19febeae2548 | 59 | * or the number of re-reads has exceeded a maximim count. If a valid |
Swabey89 | 0:19febeae2548 | 60 | * response is not received then the CMD0 can be retried. This |
Swabey89 | 0:19febeae2548 | 61 | * has been found to successfully initialise cards where the SPI master |
Swabey89 | 0:19febeae2548 | 62 | * (on MCU) has been reset but the SDCard has not, so the first |
Swabey89 | 0:19febeae2548 | 63 | * CMD0 may be lost. |
Swabey89 | 0:19febeae2548 | 64 | * |
Swabey89 | 0:19febeae2548 | 65 | * CMD8 is optionally sent to determine the voltage range supported, and |
Swabey89 | 0:19febeae2548 | 66 | * indirectly determine whether it is a version 1.x SD/non-SD card or |
Swabey89 | 0:19febeae2548 | 67 | * version 2.x. I'll just ignore this for now. |
Swabey89 | 0:19febeae2548 | 68 | * |
Swabey89 | 0:19febeae2548 | 69 | * ACMD41 is repeatedly issued to initialise the card, until "in idle" |
Swabey89 | 0:19febeae2548 | 70 | * (bit 0) of the R1 response goes to '0', indicating it is initialised. |
Swabey89 | 0:19febeae2548 | 71 | * |
Swabey89 | 0:19febeae2548 | 72 | * You should also indicate whether the host supports High Capicity cards, |
Swabey89 | 0:19febeae2548 | 73 | * and check whether the card is high capacity - i'll also ignore this |
Swabey89 | 0:19febeae2548 | 74 | * |
Swabey89 | 0:19febeae2548 | 75 | * SPI Protocol |
Swabey89 | 0:19febeae2548 | 76 | * ------------ |
Swabey89 | 0:19febeae2548 | 77 | * The SD SPI protocol is based on transactions made up of 8-bit words, with |
Swabey89 | 0:19febeae2548 | 78 | * the host starting every bus transaction by asserting the CS signal low. The |
Swabey89 | 0:19febeae2548 | 79 | * card always responds to commands, data blocks and errors. |
Swabey89 | 0:19febeae2548 | 80 | * |
Swabey89 | 0:19febeae2548 | 81 | * The protocol supports a CRC, but by default it is off (except for the |
Swabey89 | 0:19febeae2548 | 82 | * first reset CMD0, where the CRC can just be pre-calculated, and CMD8) |
Swabey89 | 0:19febeae2548 | 83 | * I'll leave the CRC off I think! |
Swabey89 | 0:19febeae2548 | 84 | * |
Swabey89 | 0:19febeae2548 | 85 | * Standard capacity cards have variable data block sizes, whereas High |
Swabey89 | 0:19febeae2548 | 86 | * Capacity cards fix the size of data block to 512 bytes. I'll therefore |
Swabey89 | 0:19febeae2548 | 87 | * just always use the Standard Capacity cards with a block size of 512 bytes. |
Swabey89 | 0:19febeae2548 | 88 | * This is set with CMD16. |
Swabey89 | 0:19febeae2548 | 89 | * |
Swabey89 | 0:19febeae2548 | 90 | * You can read and write single blocks (CMD17, CMD25) or multiple blocks |
Swabey89 | 0:19febeae2548 | 91 | * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When |
Swabey89 | 0:19febeae2548 | 92 | * the card gets a read command, it responds with a response token, and then |
Swabey89 | 0:19febeae2548 | 93 | * a data token or an error. |
Swabey89 | 0:19febeae2548 | 94 | * |
Swabey89 | 0:19febeae2548 | 95 | * SPI Command Format |
Swabey89 | 0:19febeae2548 | 96 | * ------------------ |
Swabey89 | 0:19febeae2548 | 97 | * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC. |
Swabey89 | 0:19febeae2548 | 98 | * |
Swabey89 | 0:19febeae2548 | 99 | * +---------------+------------+------------+-----------+----------+--------------+ |
Swabey89 | 0:19febeae2548 | 100 | * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 | |
Swabey89 | 0:19febeae2548 | 101 | * +---------------+------------+------------+-----------+----------+--------------+ |
Swabey89 | 0:19febeae2548 | 102 | * |
Swabey89 | 0:19febeae2548 | 103 | * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95) |
Swabey89 | 0:19febeae2548 | 104 | * |
Swabey89 | 0:19febeae2548 | 105 | * All Application Specific commands shall be preceded with APP_CMD (CMD55). |
Swabey89 | 0:19febeae2548 | 106 | * |
Swabey89 | 0:19febeae2548 | 107 | * SPI Response Format |
Swabey89 | 0:19febeae2548 | 108 | * ------------------- |
Swabey89 | 0:19febeae2548 | 109 | * The main response format (R1) is a status byte (normally zero). Key flags: |
Swabey89 | 0:19febeae2548 | 110 | * idle - 1 if the card is in an idle state/initialising |
Swabey89 | 0:19febeae2548 | 111 | * cmd - 1 if an illegal command code was detected |
Swabey89 | 0:19febeae2548 | 112 | * |
Swabey89 | 0:19febeae2548 | 113 | * +-------------------------------------------------+ |
Swabey89 | 0:19febeae2548 | 114 | * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle | |
Swabey89 | 0:19febeae2548 | 115 | * +-------------------------------------------------+ |
Swabey89 | 0:19febeae2548 | 116 | * |
Swabey89 | 0:19febeae2548 | 117 | * R1b is the same, except it is followed by a busy signal (zeros) until |
Swabey89 | 0:19febeae2548 | 118 | * the first non-zero byte when it is ready again. |
Swabey89 | 0:19febeae2548 | 119 | * |
Swabey89 | 0:19febeae2548 | 120 | * Data Response Token |
Swabey89 | 0:19febeae2548 | 121 | * ------------------- |
Swabey89 | 0:19febeae2548 | 122 | * Every data block written to the card is acknowledged by a byte |
Swabey89 | 0:19febeae2548 | 123 | * response token |
Swabey89 | 0:19febeae2548 | 124 | * |
Swabey89 | 0:19febeae2548 | 125 | * +----------------------+ |
Swabey89 | 0:19febeae2548 | 126 | * | xxx | 0 | status | 1 | |
Swabey89 | 0:19febeae2548 | 127 | * +----------------------+ |
Swabey89 | 0:19febeae2548 | 128 | * 010 - OK! |
Swabey89 | 0:19febeae2548 | 129 | * 101 - CRC Error |
Swabey89 | 0:19febeae2548 | 130 | * 110 - Write Error |
Swabey89 | 0:19febeae2548 | 131 | * |
Swabey89 | 0:19febeae2548 | 132 | * Single Block Read and Write |
Swabey89 | 0:19febeae2548 | 133 | * --------------------------- |
Swabey89 | 0:19febeae2548 | 134 | * |
Swabey89 | 0:19febeae2548 | 135 | * Block transfers have a byte header, followed by the data, followed |
Swabey89 | 0:19febeae2548 | 136 | * by a 16-bit CRC. In our case, the data will always be 512 bytes. |
Swabey89 | 0:19febeae2548 | 137 | * |
Swabey89 | 0:19febeae2548 | 138 | * +------+---------+---------+- - - -+---------+-----------+----------+ |
Swabey89 | 0:19febeae2548 | 139 | * | 0xFE | data[0] | data[1] | | data[n] | crc[15:8] | crc[7:0] | |
Swabey89 | 0:19febeae2548 | 140 | * +------+---------+---------+- - - -+---------+-----------+----------+ |
Swabey89 | 0:19febeae2548 | 141 | */ |
Swabey89 | 0:19febeae2548 | 142 | |
Swabey89 | 0:19febeae2548 | 143 | /* If the target has no SPI support then SDCard is not supported */ |
Swabey89 | 0:19febeae2548 | 144 | #ifdef DEVICE_SPI |
Swabey89 | 0:19febeae2548 | 145 | |
Swabey89 | 0:19febeae2548 | 146 | #include "SDBlockDevice.h" |
Swabey89 | 0:19febeae2548 | 147 | #include "mbed_debug.h" |
Swabey89 | 0:19febeae2548 | 148 | #include <errno.h> |
Swabey89 | 0:19febeae2548 | 149 | |
Swabey89 | 0:19febeae2548 | 150 | /* Required version: 5.6.1 and above */ |
Swabey89 | 0:19febeae2548 | 151 | #ifdef MBED_MAJOR_VERSION |
Swabey89 | 0:19febeae2548 | 152 | #if (MBED_VERSION < MBED_ENCODE_VERSION(5,6,1)) |
Swabey89 | 0:19febeae2548 | 153 | #error "Incompatible mbed-os version detected! Required 5.5.4 and above" |
Swabey89 | 0:19febeae2548 | 154 | #endif |
Swabey89 | 0:19febeae2548 | 155 | #else |
Swabey89 | 0:19febeae2548 | 156 | #warning "mbed-os version 5.6.1 or above required" |
Swabey89 | 0:19febeae2548 | 157 | #endif |
Swabey89 | 0:19febeae2548 | 158 | |
Swabey89 | 0:19febeae2548 | 159 | #define SD_COMMAND_TIMEOUT 5000 /*!< Timeout in ms for response */ |
Swabey89 | 0:19febeae2548 | 160 | #define SD_CMD0_GO_IDLE_STATE_RETRIES 5 /*!< Number of retries for sending CMDO */ |
Swabey89 | 0:19febeae2548 | 161 | #define SD_DBG 0 /*!< 1 - Enable debugging */ |
Swabey89 | 0:19febeae2548 | 162 | #define SD_CMD_TRACE 0 /*!< 1 - Enable SD command tracing */ |
Swabey89 | 0:19febeae2548 | 163 | |
Swabey89 | 0:19febeae2548 | 164 | #define SD_BLOCK_DEVICE_ERROR_WOULD_BLOCK -5001 /*!< operation would block */ |
Swabey89 | 0:19febeae2548 | 165 | #define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED -5002 /*!< unsupported operation */ |
Swabey89 | 0:19febeae2548 | 166 | #define SD_BLOCK_DEVICE_ERROR_PARAMETER -5003 /*!< invalid parameter */ |
Swabey89 | 0:19febeae2548 | 167 | #define SD_BLOCK_DEVICE_ERROR_NO_INIT -5004 /*!< uninitialized */ |
Swabey89 | 0:19febeae2548 | 168 | #define SD_BLOCK_DEVICE_ERROR_NO_DEVICE -5005 /*!< device is missing or not connected */ |
Swabey89 | 0:19febeae2548 | 169 | #define SD_BLOCK_DEVICE_ERROR_WRITE_PROTECTED -5006 /*!< write protected */ |
Swabey89 | 0:19febeae2548 | 170 | #define SD_BLOCK_DEVICE_ERROR_UNUSABLE -5007 /*!< unusable card */ |
Swabey89 | 0:19febeae2548 | 171 | #define SD_BLOCK_DEVICE_ERROR_NO_RESPONSE -5008 /*!< No response from device */ |
Swabey89 | 0:19febeae2548 | 172 | #define SD_BLOCK_DEVICE_ERROR_CRC -5009 /*!< CRC error */ |
Swabey89 | 0:19febeae2548 | 173 | #define SD_BLOCK_DEVICE_ERROR_ERASE -5010 /*!< Erase error: reset/sequence */ |
Swabey89 | 0:19febeae2548 | 174 | #define SD_BLOCK_DEVICE_ERROR_WRITE -5011 /*!< SPI Write error: !SPI_DATA_ACCEPTED */ |
Swabey89 | 0:19febeae2548 | 175 | |
Swabey89 | 0:19febeae2548 | 176 | #define BLOCK_SIZE_HC 512 /*!< Block size supported for SD card is 512 bytes */ |
Swabey89 | 0:19febeae2548 | 177 | #define WRITE_BL_PARTIAL 0 /*!< Partial block write - Not supported */ |
Swabey89 | 0:19febeae2548 | 178 | #define CRC_SUPPORT 0 /*!< CRC - Not supported */ |
Swabey89 | 0:19febeae2548 | 179 | #define SPI_CMD(x) (0x40 | (x & 0x3f)) |
Swabey89 | 0:19febeae2548 | 180 | |
Swabey89 | 0:19febeae2548 | 181 | /* R1 Response Format */ |
Swabey89 | 0:19febeae2548 | 182 | #define R1_NO_RESPONSE (0xFF) |
Swabey89 | 0:19febeae2548 | 183 | #define R1_RESPONSE_RECV (0x80) |
Swabey89 | 0:19febeae2548 | 184 | #define R1_IDLE_STATE (1 << 0) |
Swabey89 | 0:19febeae2548 | 185 | #define R1_ERASE_RESET (1 << 1) |
Swabey89 | 0:19febeae2548 | 186 | #define R1_ILLEGAL_COMMAND (1 << 2) |
Swabey89 | 0:19febeae2548 | 187 | #define R1_COM_CRC_ERROR (1 << 3) |
Swabey89 | 0:19febeae2548 | 188 | #define R1_ERASE_SEQUENCE_ERROR (1 << 4) |
Swabey89 | 0:19febeae2548 | 189 | #define R1_ADDRESS_ERROR (1 << 5) |
Swabey89 | 0:19febeae2548 | 190 | #define R1_PARAMETER_ERROR (1 << 6) |
Swabey89 | 0:19febeae2548 | 191 | |
Swabey89 | 0:19febeae2548 | 192 | // Types |
Swabey89 | 0:19febeae2548 | 193 | #define SDCARD_NONE 0 /**< No card is present */ |
Swabey89 | 0:19febeae2548 | 194 | #define SDCARD_V1 1 /**< v1.x Standard Capacity */ |
Swabey89 | 0:19febeae2548 | 195 | #define SDCARD_V2 2 /**< v2.x Standard capacity SD card */ |
Swabey89 | 0:19febeae2548 | 196 | #define SDCARD_V2HC 3 /**< v2.x High capacity SD card */ |
Swabey89 | 0:19febeae2548 | 197 | #define CARD_UNKNOWN 4 /**< Unknown or unsupported card */ |
Swabey89 | 0:19febeae2548 | 198 | |
Swabey89 | 0:19febeae2548 | 199 | /* SIZE in Bytes */ |
Swabey89 | 0:19febeae2548 | 200 | #define PACKET_SIZE 6 /*!< SD Packet size CMD+ARG+CRC */ |
Swabey89 | 0:19febeae2548 | 201 | #define R1_RESPONSE_SIZE 1 /*!< Size of R1 response */ |
Swabey89 | 0:19febeae2548 | 202 | #define R2_RESPONSE_SIZE 2 /*!< Size of R2 response */ |
Swabey89 | 0:19febeae2548 | 203 | #define R3_R7_RESPONSE_SIZE 5 /*!< Size of R3/R7 response */ |
Swabey89 | 0:19febeae2548 | 204 | |
Swabey89 | 0:19febeae2548 | 205 | /* R1b Response */ |
Swabey89 | 0:19febeae2548 | 206 | #define DEVICE_BUSY (0x00) |
Swabey89 | 0:19febeae2548 | 207 | |
Swabey89 | 0:19febeae2548 | 208 | /* R2 Response Format */ |
Swabey89 | 0:19febeae2548 | 209 | #define R2_CARD_LOCKED (1 << 0) |
Swabey89 | 0:19febeae2548 | 210 | #define R2_CMD_FAILED (1 << 1) |
Swabey89 | 0:19febeae2548 | 211 | #define R2_ERROR (1 << 2) |
Swabey89 | 0:19febeae2548 | 212 | #define R2_CC_ERROR (1 << 3) |
Swabey89 | 0:19febeae2548 | 213 | #define R2_CC_FAILED (1 << 4) |
Swabey89 | 0:19febeae2548 | 214 | #define R2_WP_VIOLATION (1 << 5) |
Swabey89 | 0:19febeae2548 | 215 | #define R2_ERASE_PARAM (1 << 6) |
Swabey89 | 0:19febeae2548 | 216 | #define R2_OUT_OF_RANGE (1 << 7) |
Swabey89 | 0:19febeae2548 | 217 | |
Swabey89 | 0:19febeae2548 | 218 | /* R3 Response : OCR Register */ |
Swabey89 | 0:19febeae2548 | 219 | #define OCR_HCS_CCS (0x1 << 30) |
Swabey89 | 0:19febeae2548 | 220 | #define OCR_LOW_VOLTAGE (0x01 << 24) |
Swabey89 | 0:19febeae2548 | 221 | #define OCR_3_3V (0x1 << 20) |
Swabey89 | 0:19febeae2548 | 222 | |
Swabey89 | 0:19febeae2548 | 223 | /* R7 response pattern for CMD8 */ |
Swabey89 | 0:19febeae2548 | 224 | #define CMD8_PATTERN (0xAA) |
Swabey89 | 0:19febeae2548 | 225 | |
Swabey89 | 0:19febeae2548 | 226 | /* CRC Enable */ |
Swabey89 | 0:19febeae2548 | 227 | #define CRC_ENABLE (0) /*!< CRC 1 - Enable 0 - Disable */ |
Swabey89 | 0:19febeae2548 | 228 | |
Swabey89 | 0:19febeae2548 | 229 | /* Control Tokens */ |
Swabey89 | 0:19febeae2548 | 230 | #define SPI_DATA_RESPONSE_MASK (0x1F) |
Swabey89 | 0:19febeae2548 | 231 | #define SPI_DATA_ACCEPTED (0x05) |
Swabey89 | 0:19febeae2548 | 232 | #define SPI_DATA_CRC_ERROR (0x0B) |
Swabey89 | 0:19febeae2548 | 233 | #define SPI_DATA_WRITE_ERROR (0x0D) |
Swabey89 | 0:19febeae2548 | 234 | #define SPI_START_BLOCK (0xFE) /*!< For Single Block Read/Write and Multiple Block Read */ |
Swabey89 | 0:19febeae2548 | 235 | #define SPI_START_BLK_MUL_WRITE (0xFC) /*!< Start Multi-block write */ |
Swabey89 | 0:19febeae2548 | 236 | #define SPI_STOP_TRAN (0xFD) /*!< Stop Multi-block write */ |
Swabey89 | 0:19febeae2548 | 237 | |
Swabey89 | 0:19febeae2548 | 238 | #define SPI_DATA_READ_ERROR_MASK (0xF) /*!< Data Error Token: 4 LSB bits */ |
Swabey89 | 0:19febeae2548 | 239 | #define SPI_READ_ERROR (0x1 << 0) /*!< Error */ |
Swabey89 | 0:19febeae2548 | 240 | #define SPI_READ_ERROR_CC (0x1 << 1) /*!< CC Error*/ |
Swabey89 | 0:19febeae2548 | 241 | #define SPI_READ_ERROR_ECC_C (0x1 << 2) /*!< Card ECC failed */ |
Swabey89 | 0:19febeae2548 | 242 | #define SPI_READ_ERROR_OFR (0x1 << 3) /*!< Out of Range */ |
Swabey89 | 0:19febeae2548 | 243 | |
Swabey89 | 0:19febeae2548 | 244 | SDBlockDevice::SDBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName cs, uint64_t hz) |
Swabey89 | 0:19febeae2548 | 245 | : _spi(mosi, miso, sclk), _cs(cs), _is_initialized(0) |
Swabey89 | 0:19febeae2548 | 246 | { |
Swabey89 | 0:19febeae2548 | 247 | _cs = 1; |
Swabey89 | 0:19febeae2548 | 248 | _card_type = SDCARD_NONE; |
Swabey89 | 0:19febeae2548 | 249 | |
Swabey89 | 0:19febeae2548 | 250 | // Set default to 100kHz for initialisation and 1MHz for data transfer |
Swabey89 | 0:19febeae2548 | 251 | _init_sck = 100000; |
Swabey89 | 0:19febeae2548 | 252 | _transfer_sck = hz; |
Swabey89 | 0:19febeae2548 | 253 | |
Swabey89 | 0:19febeae2548 | 254 | // Only HC block size is supported. |
Swabey89 | 0:19febeae2548 | 255 | _block_size = BLOCK_SIZE_HC; |
Swabey89 | 0:19febeae2548 | 256 | } |
Swabey89 | 0:19febeae2548 | 257 | |
Swabey89 | 0:19febeae2548 | 258 | SDBlockDevice::~SDBlockDevice() |
Swabey89 | 0:19febeae2548 | 259 | { |
Swabey89 | 0:19febeae2548 | 260 | if (_is_initialized) { |
Swabey89 | 0:19febeae2548 | 261 | deinit(); |
Swabey89 | 0:19febeae2548 | 262 | } |
Swabey89 | 0:19febeae2548 | 263 | } |
Swabey89 | 0:19febeae2548 | 264 | |
Swabey89 | 0:19febeae2548 | 265 | int SDBlockDevice::_initialise_card() |
Swabey89 | 0:19febeae2548 | 266 | { |
Swabey89 | 0:19febeae2548 | 267 | // Detail debugging is for commands |
Swabey89 | 0:19febeae2548 | 268 | _dbg = SD_DBG ? SD_CMD_TRACE : 0; |
Swabey89 | 0:19febeae2548 | 269 | int32_t status = BD_ERROR_OK; |
Swabey89 | 0:19febeae2548 | 270 | uint32_t response, arg; |
Swabey89 | 0:19febeae2548 | 271 | |
Swabey89 | 0:19febeae2548 | 272 | // Initialize the SPI interface: Card by default is in SD mode |
Swabey89 | 0:19febeae2548 | 273 | _spi_init(); |
Swabey89 | 0:19febeae2548 | 274 | |
Swabey89 | 0:19febeae2548 | 275 | // The card is transitioned from SDCard mode to SPI mode by sending the CMD0 + CS Asserted("0") |
Swabey89 | 0:19febeae2548 | 276 | if (_go_idle_state() != R1_IDLE_STATE) { |
Swabey89 | 0:19febeae2548 | 277 | debug_if(SD_DBG, "No disk, or could not put SD card in to SPI idle state\n"); |
Swabey89 | 0:19febeae2548 | 278 | return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; |
Swabey89 | 0:19febeae2548 | 279 | } |
Swabey89 | 0:19febeae2548 | 280 | |
Swabey89 | 0:19febeae2548 | 281 | // Send CMD8, if the card rejects the command then it's probably using the |
Swabey89 | 0:19febeae2548 | 282 | // legacy protocol, or is a MMC, or just flat-out broken |
Swabey89 | 0:19febeae2548 | 283 | status = _cmd8(); |
Swabey89 | 0:19febeae2548 | 284 | if (BD_ERROR_OK != status && SD_BLOCK_DEVICE_ERROR_UNSUPPORTED != status) { |
Swabey89 | 0:19febeae2548 | 285 | return status; |
Swabey89 | 0:19febeae2548 | 286 | } |
Swabey89 | 0:19febeae2548 | 287 | |
Swabey89 | 0:19febeae2548 | 288 | // Read OCR - CMD58 Response contains OCR register |
Swabey89 | 0:19febeae2548 | 289 | if (BD_ERROR_OK != (status = _cmd(CMD58_READ_OCR, 0x0, 0x0, &response))) { |
Swabey89 | 0:19febeae2548 | 290 | return status; |
Swabey89 | 0:19febeae2548 | 291 | } |
Swabey89 | 0:19febeae2548 | 292 | |
Swabey89 | 0:19febeae2548 | 293 | // Check if card supports voltage range: 3.3V |
Swabey89 | 0:19febeae2548 | 294 | if (!(response & OCR_3_3V)) { |
Swabey89 | 0:19febeae2548 | 295 | _card_type = CARD_UNKNOWN; |
Swabey89 | 0:19febeae2548 | 296 | status = SD_BLOCK_DEVICE_ERROR_UNUSABLE; |
Swabey89 | 0:19febeae2548 | 297 | return status; |
Swabey89 | 0:19febeae2548 | 298 | } |
Swabey89 | 0:19febeae2548 | 299 | |
Swabey89 | 0:19febeae2548 | 300 | // HCS is set 1 for HC/XC capacity cards for ACMD41, if supported |
Swabey89 | 0:19febeae2548 | 301 | arg = 0x0; |
Swabey89 | 0:19febeae2548 | 302 | if (SDCARD_V2 == _card_type) { |
Swabey89 | 0:19febeae2548 | 303 | arg |= OCR_HCS_CCS; |
Swabey89 | 0:19febeae2548 | 304 | } |
Swabey89 | 0:19febeae2548 | 305 | |
Swabey89 | 0:19febeae2548 | 306 | /* Idle state bit in the R1 response of ACMD41 is used by the card to inform the host |
Swabey89 | 0:19febeae2548 | 307 | * if initialization of ACMD41 is completed. "1" indicates that the card is still initializing. |
Swabey89 | 0:19febeae2548 | 308 | * "0" indicates completion of initialization. The host repeatedly issues ACMD41 until |
Swabey89 | 0:19febeae2548 | 309 | * this bit is set to "0". |
Swabey89 | 0:19febeae2548 | 310 | */ |
Swabey89 | 0:19febeae2548 | 311 | _spi_timer.start(); |
Swabey89 | 0:19febeae2548 | 312 | do { |
Swabey89 | 0:19febeae2548 | 313 | status = _cmd(ACMD41_SD_SEND_OP_COND, arg, 1, &response); |
Swabey89 | 0:19febeae2548 | 314 | } while ((response & R1_IDLE_STATE) && (_spi_timer.read_ms() < SD_COMMAND_TIMEOUT)); |
Swabey89 | 0:19febeae2548 | 315 | _spi_timer.stop(); |
Swabey89 | 0:19febeae2548 | 316 | |
Swabey89 | 0:19febeae2548 | 317 | // Initialization complete: ACMD41 successful |
Swabey89 | 0:19febeae2548 | 318 | if ((BD_ERROR_OK != status) || (0x00 != response)) { |
Swabey89 | 0:19febeae2548 | 319 | _card_type = CARD_UNKNOWN; |
Swabey89 | 0:19febeae2548 | 320 | debug_if(SD_DBG, "Timeout waiting for card\n"); |
Swabey89 | 0:19febeae2548 | 321 | return status; |
Swabey89 | 0:19febeae2548 | 322 | } |
Swabey89 | 0:19febeae2548 | 323 | |
Swabey89 | 0:19febeae2548 | 324 | if (SDCARD_V2 == _card_type) { |
Swabey89 | 0:19febeae2548 | 325 | // Get the card capacity CCS: CMD58 |
Swabey89 | 0:19febeae2548 | 326 | if (BD_ERROR_OK == (status = _cmd(CMD58_READ_OCR, 0x0, 0x0, &response))) { |
Swabey89 | 0:19febeae2548 | 327 | // High Capacity card |
Swabey89 | 0:19febeae2548 | 328 | if (response & OCR_HCS_CCS) { |
Swabey89 | 0:19febeae2548 | 329 | _card_type = SDCARD_V2HC; |
Swabey89 | 0:19febeae2548 | 330 | debug_if(SD_DBG, "Card Initialized: High Capacity Card \n"); |
Swabey89 | 0:19febeae2548 | 331 | } else { |
Swabey89 | 0:19febeae2548 | 332 | debug_if(SD_DBG, "Card Initialized: Standard Capacity Card: Version 2.x \n"); |
Swabey89 | 0:19febeae2548 | 333 | } |
Swabey89 | 0:19febeae2548 | 334 | } |
Swabey89 | 0:19febeae2548 | 335 | } else { |
Swabey89 | 0:19febeae2548 | 336 | _card_type = SDCARD_V1; |
Swabey89 | 0:19febeae2548 | 337 | debug_if(SD_DBG, "Card Initialized: Version 1.x Card\n"); |
Swabey89 | 0:19febeae2548 | 338 | } |
Swabey89 | 0:19febeae2548 | 339 | |
Swabey89 | 0:19febeae2548 | 340 | // Disable CRC |
Swabey89 | 0:19febeae2548 | 341 | status = _cmd(CMD59_CRC_ON_OFF, 0); |
Swabey89 | 0:19febeae2548 | 342 | |
Swabey89 | 0:19febeae2548 | 343 | return status; |
Swabey89 | 0:19febeae2548 | 344 | } |
Swabey89 | 0:19febeae2548 | 345 | |
Swabey89 | 0:19febeae2548 | 346 | |
Swabey89 | 0:19febeae2548 | 347 | int SDBlockDevice::init() |
Swabey89 | 0:19febeae2548 | 348 | { |
Swabey89 | 0:19febeae2548 | 349 | _lock.lock(); |
Swabey89 | 0:19febeae2548 | 350 | int err = _initialise_card(); |
Swabey89 | 0:19febeae2548 | 351 | _is_initialized = (err == BD_ERROR_OK); |
Swabey89 | 0:19febeae2548 | 352 | if (!_is_initialized) { |
Swabey89 | 0:19febeae2548 | 353 | debug_if(SD_DBG, "Fail to initialize card\n"); |
Swabey89 | 0:19febeae2548 | 354 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 355 | return err; |
Swabey89 | 0:19febeae2548 | 356 | } |
Swabey89 | 0:19febeae2548 | 357 | debug_if(SD_DBG, "init card = %d\n", _is_initialized); |
Swabey89 | 0:19febeae2548 | 358 | _sectors = _sd_sectors(); |
Swabey89 | 0:19febeae2548 | 359 | // CMD9 failed |
Swabey89 | 0:19febeae2548 | 360 | if (0 == _sectors) { |
Swabey89 | 0:19febeae2548 | 361 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 362 | return BD_ERROR_DEVICE_ERROR; |
Swabey89 | 0:19febeae2548 | 363 | } |
Swabey89 | 0:19febeae2548 | 364 | |
Swabey89 | 0:19febeae2548 | 365 | // Set block length to 512 (CMD16) |
Swabey89 | 0:19febeae2548 | 366 | if (_cmd(CMD16_SET_BLOCKLEN, _block_size) != 0) { |
Swabey89 | 0:19febeae2548 | 367 | debug_if(SD_DBG, "Set %d-byte block timed out\n", _block_size); |
Swabey89 | 0:19febeae2548 | 368 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 369 | return BD_ERROR_DEVICE_ERROR; |
Swabey89 | 0:19febeae2548 | 370 | } |
Swabey89 | 0:19febeae2548 | 371 | |
Swabey89 | 0:19febeae2548 | 372 | // Set SCK for data transfer |
Swabey89 | 0:19febeae2548 | 373 | err = _freq(); |
Swabey89 | 0:19febeae2548 | 374 | if (err) { |
Swabey89 | 0:19febeae2548 | 375 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 376 | return err; |
Swabey89 | 0:19febeae2548 | 377 | } |
Swabey89 | 0:19febeae2548 | 378 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 379 | return BD_ERROR_OK; |
Swabey89 | 0:19febeae2548 | 380 | } |
Swabey89 | 0:19febeae2548 | 381 | |
Swabey89 | 0:19febeae2548 | 382 | int SDBlockDevice::deinit() |
Swabey89 | 0:19febeae2548 | 383 | { |
Swabey89 | 0:19febeae2548 | 384 | _lock.lock(); |
Swabey89 | 0:19febeae2548 | 385 | _is_initialized = false; |
Swabey89 | 0:19febeae2548 | 386 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 387 | return 0; |
Swabey89 | 0:19febeae2548 | 388 | } |
Swabey89 | 0:19febeae2548 | 389 | |
Swabey89 | 0:19febeae2548 | 390 | |
Swabey89 | 0:19febeae2548 | 391 | int SDBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size) |
Swabey89 | 0:19febeae2548 | 392 | { |
Swabey89 | 0:19febeae2548 | 393 | if (!is_valid_program(addr, size)) { |
Swabey89 | 0:19febeae2548 | 394 | return SD_BLOCK_DEVICE_ERROR_PARAMETER; |
Swabey89 | 0:19febeae2548 | 395 | } |
Swabey89 | 0:19febeae2548 | 396 | |
Swabey89 | 0:19febeae2548 | 397 | _lock.lock(); |
Swabey89 | 0:19febeae2548 | 398 | if (!_is_initialized) { |
Swabey89 | 0:19febeae2548 | 399 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 400 | return SD_BLOCK_DEVICE_ERROR_NO_INIT; |
Swabey89 | 0:19febeae2548 | 401 | } |
Swabey89 | 0:19febeae2548 | 402 | |
Swabey89 | 0:19febeae2548 | 403 | const uint8_t *buffer = static_cast<const uint8_t*>(b); |
Swabey89 | 0:19febeae2548 | 404 | int status = BD_ERROR_OK; |
Swabey89 | 0:19febeae2548 | 405 | uint8_t response; |
Swabey89 | 0:19febeae2548 | 406 | |
Swabey89 | 0:19febeae2548 | 407 | // Get block count |
Swabey89 | 0:19febeae2548 | 408 | bd_addr_t blockCnt = size / _block_size; |
Swabey89 | 0:19febeae2548 | 409 | |
Swabey89 | 0:19febeae2548 | 410 | // SDSC Card (CCS=0) uses byte unit address |
Swabey89 | 0:19febeae2548 | 411 | // SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit) |
Swabey89 | 0:19febeae2548 | 412 | if(SDCARD_V2HC == _card_type) { |
Swabey89 | 0:19febeae2548 | 413 | addr = addr / _block_size; |
Swabey89 | 0:19febeae2548 | 414 | } |
Swabey89 | 0:19febeae2548 | 415 | |
Swabey89 | 0:19febeae2548 | 416 | // Send command to perform write operation |
Swabey89 | 0:19febeae2548 | 417 | if (blockCnt == 1) { |
Swabey89 | 0:19febeae2548 | 418 | // Single block write command |
Swabey89 | 0:19febeae2548 | 419 | if (BD_ERROR_OK != (status = _cmd(CMD24_WRITE_BLOCK, addr))) { |
Swabey89 | 0:19febeae2548 | 420 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 421 | return status; |
Swabey89 | 0:19febeae2548 | 422 | } |
Swabey89 | 0:19febeae2548 | 423 | |
Swabey89 | 0:19febeae2548 | 424 | // Write data |
Swabey89 | 0:19febeae2548 | 425 | response = _write(buffer, SPI_START_BLOCK, _block_size); |
Swabey89 | 0:19febeae2548 | 426 | |
Swabey89 | 0:19febeae2548 | 427 | // Only CRC and general write error are communicated via response token |
Swabey89 | 0:19febeae2548 | 428 | if ((response == SPI_DATA_CRC_ERROR) || (response == SPI_DATA_WRITE_ERROR)) { |
Swabey89 | 0:19febeae2548 | 429 | debug_if(SD_DBG, "Single Block Write failed: 0x%x \n", response); |
Swabey89 | 0:19febeae2548 | 430 | status = SD_BLOCK_DEVICE_ERROR_WRITE; |
Swabey89 | 0:19febeae2548 | 431 | } |
Swabey89 | 0:19febeae2548 | 432 | } else { |
Swabey89 | 0:19febeae2548 | 433 | // Pre-erase setting prior to multiple block write operation |
Swabey89 | 0:19febeae2548 | 434 | _cmd(ACMD23_SET_WR_BLK_ERASE_COUNT, blockCnt, 1); |
Swabey89 | 0:19febeae2548 | 435 | |
Swabey89 | 0:19febeae2548 | 436 | // Multiple block write command |
Swabey89 | 0:19febeae2548 | 437 | if (BD_ERROR_OK != (status = _cmd(CMD25_WRITE_MULTIPLE_BLOCK, addr))) { |
Swabey89 | 0:19febeae2548 | 438 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 439 | return status; |
Swabey89 | 0:19febeae2548 | 440 | } |
Swabey89 | 0:19febeae2548 | 441 | |
Swabey89 | 0:19febeae2548 | 442 | // Write the data: one block at a time |
Swabey89 | 0:19febeae2548 | 443 | do { |
Swabey89 | 0:19febeae2548 | 444 | response = _write(buffer, SPI_START_BLK_MUL_WRITE, _block_size); |
Swabey89 | 0:19febeae2548 | 445 | if (response != SPI_DATA_ACCEPTED) { |
Swabey89 | 0:19febeae2548 | 446 | debug_if(SD_DBG, "Multiple Block Write failed: 0x%x \n", response); |
Swabey89 | 0:19febeae2548 | 447 | break; |
Swabey89 | 0:19febeae2548 | 448 | } |
Swabey89 | 0:19febeae2548 | 449 | buffer += _block_size; |
Swabey89 | 0:19febeae2548 | 450 | }while (--blockCnt); // Receive all blocks of data |
Swabey89 | 0:19febeae2548 | 451 | |
Swabey89 | 0:19febeae2548 | 452 | /* In a Multiple Block write operation, the stop transmission will be done by |
Swabey89 | 0:19febeae2548 | 453 | * sending 'Stop Tran' token instead of 'Start Block' token at the beginning |
Swabey89 | 0:19febeae2548 | 454 | * of the next block |
Swabey89 | 0:19febeae2548 | 455 | */ |
Swabey89 | 0:19febeae2548 | 456 | _spi.write(SPI_STOP_TRAN); |
Swabey89 | 0:19febeae2548 | 457 | } |
Swabey89 | 0:19febeae2548 | 458 | |
Swabey89 | 0:19febeae2548 | 459 | _deselect(); |
Swabey89 | 0:19febeae2548 | 460 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 461 | return status; |
Swabey89 | 0:19febeae2548 | 462 | } |
Swabey89 | 0:19febeae2548 | 463 | |
Swabey89 | 0:19febeae2548 | 464 | int SDBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) |
Swabey89 | 0:19febeae2548 | 465 | { |
Swabey89 | 0:19febeae2548 | 466 | if (!is_valid_read(addr, size)) { |
Swabey89 | 0:19febeae2548 | 467 | return SD_BLOCK_DEVICE_ERROR_PARAMETER; |
Swabey89 | 0:19febeae2548 | 468 | } |
Swabey89 | 0:19febeae2548 | 469 | |
Swabey89 | 0:19febeae2548 | 470 | _lock.lock(); |
Swabey89 | 0:19febeae2548 | 471 | if (!_is_initialized) { |
Swabey89 | 0:19febeae2548 | 472 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 473 | return SD_BLOCK_DEVICE_ERROR_PARAMETER; |
Swabey89 | 0:19febeae2548 | 474 | } |
Swabey89 | 0:19febeae2548 | 475 | |
Swabey89 | 0:19febeae2548 | 476 | uint8_t *buffer = static_cast<uint8_t *>(b); |
Swabey89 | 0:19febeae2548 | 477 | int status = BD_ERROR_OK; |
Swabey89 | 0:19febeae2548 | 478 | bd_addr_t blockCnt = size / _block_size; |
Swabey89 | 0:19febeae2548 | 479 | |
Swabey89 | 0:19febeae2548 | 480 | // SDSC Card (CCS=0) uses byte unit address |
Swabey89 | 0:19febeae2548 | 481 | // SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit) |
Swabey89 | 0:19febeae2548 | 482 | if (SDCARD_V2HC == _card_type) { |
Swabey89 | 0:19febeae2548 | 483 | addr = addr / _block_size; |
Swabey89 | 0:19febeae2548 | 484 | } |
Swabey89 | 0:19febeae2548 | 485 | |
Swabey89 | 0:19febeae2548 | 486 | // Write command ro receive data |
Swabey89 | 0:19febeae2548 | 487 | if (blockCnt > 1) { |
Swabey89 | 0:19febeae2548 | 488 | status = _cmd(CMD18_READ_MULTIPLE_BLOCK, addr); |
Swabey89 | 0:19febeae2548 | 489 | } else { |
Swabey89 | 0:19febeae2548 | 490 | status = _cmd(CMD17_READ_SINGLE_BLOCK, addr); |
Swabey89 | 0:19febeae2548 | 491 | } |
Swabey89 | 0:19febeae2548 | 492 | if (BD_ERROR_OK != status) { |
Swabey89 | 0:19febeae2548 | 493 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 494 | return status; |
Swabey89 | 0:19febeae2548 | 495 | } |
Swabey89 | 0:19febeae2548 | 496 | |
Swabey89 | 0:19febeae2548 | 497 | // receive the data : one block at a time |
Swabey89 | 0:19febeae2548 | 498 | while (blockCnt) { |
Swabey89 | 0:19febeae2548 | 499 | if (0 != _read(buffer, _block_size)) { |
Swabey89 | 0:19febeae2548 | 500 | status = SD_BLOCK_DEVICE_ERROR_NO_RESPONSE; |
Swabey89 | 0:19febeae2548 | 501 | break; |
Swabey89 | 0:19febeae2548 | 502 | } |
Swabey89 | 0:19febeae2548 | 503 | buffer += _block_size; |
Swabey89 | 0:19febeae2548 | 504 | --blockCnt; |
Swabey89 | 0:19febeae2548 | 505 | } |
Swabey89 | 0:19febeae2548 | 506 | _deselect(); |
Swabey89 | 0:19febeae2548 | 507 | |
Swabey89 | 0:19febeae2548 | 508 | // Send CMD12(0x00000000) to stop the transmission for multi-block transfer |
Swabey89 | 0:19febeae2548 | 509 | if (size > _block_size) { |
Swabey89 | 0:19febeae2548 | 510 | status = _cmd(CMD12_STOP_TRANSMISSION, 0x0); |
Swabey89 | 0:19febeae2548 | 511 | } |
Swabey89 | 0:19febeae2548 | 512 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 513 | return status; |
Swabey89 | 0:19febeae2548 | 514 | } |
Swabey89 | 0:19febeae2548 | 515 | |
Swabey89 | 0:19febeae2548 | 516 | bool SDBlockDevice::_is_valid_trim(bd_addr_t addr, bd_size_t size) |
Swabey89 | 0:19febeae2548 | 517 | { |
Swabey89 | 0:19febeae2548 | 518 | return ( |
Swabey89 | 0:19febeae2548 | 519 | addr % _erase_size == 0 && |
Swabey89 | 0:19febeae2548 | 520 | size % _erase_size == 0 && |
Swabey89 | 0:19febeae2548 | 521 | addr + size <= this->size()); |
Swabey89 | 0:19febeae2548 | 522 | } |
Swabey89 | 0:19febeae2548 | 523 | |
Swabey89 | 0:19febeae2548 | 524 | int SDBlockDevice::trim(bd_addr_t addr, bd_size_t size) |
Swabey89 | 0:19febeae2548 | 525 | { |
Swabey89 | 0:19febeae2548 | 526 | if (!_is_valid_trim(addr, size)) { |
Swabey89 | 0:19febeae2548 | 527 | return SD_BLOCK_DEVICE_ERROR_PARAMETER; |
Swabey89 | 0:19febeae2548 | 528 | } |
Swabey89 | 0:19febeae2548 | 529 | |
Swabey89 | 0:19febeae2548 | 530 | _lock.lock(); |
Swabey89 | 0:19febeae2548 | 531 | if (!_is_initialized) { |
Swabey89 | 0:19febeae2548 | 532 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 533 | return SD_BLOCK_DEVICE_ERROR_NO_INIT; |
Swabey89 | 0:19febeae2548 | 534 | } |
Swabey89 | 0:19febeae2548 | 535 | int status = BD_ERROR_OK; |
Swabey89 | 0:19febeae2548 | 536 | |
Swabey89 | 0:19febeae2548 | 537 | size -= _block_size; |
Swabey89 | 0:19febeae2548 | 538 | // SDSC Card (CCS=0) uses byte unit address |
Swabey89 | 0:19febeae2548 | 539 | // SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit) |
Swabey89 | 0:19febeae2548 | 540 | if (SDCARD_V2HC == _card_type) { |
Swabey89 | 0:19febeae2548 | 541 | size = size / _block_size; |
Swabey89 | 0:19febeae2548 | 542 | addr = addr / _block_size; |
Swabey89 | 0:19febeae2548 | 543 | } |
Swabey89 | 0:19febeae2548 | 544 | |
Swabey89 | 0:19febeae2548 | 545 | // Start lba sent in start command |
Swabey89 | 0:19febeae2548 | 546 | if (BD_ERROR_OK != (status = _cmd(CMD32_ERASE_WR_BLK_START_ADDR, addr))) { |
Swabey89 | 0:19febeae2548 | 547 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 548 | return status; |
Swabey89 | 0:19febeae2548 | 549 | } |
Swabey89 | 0:19febeae2548 | 550 | |
Swabey89 | 0:19febeae2548 | 551 | // End lba = addr+size sent in end addr command |
Swabey89 | 0:19febeae2548 | 552 | if (BD_ERROR_OK != (status = _cmd(CMD33_ERASE_WR_BLK_END_ADDR, addr+size))) { |
Swabey89 | 0:19febeae2548 | 553 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 554 | return status; |
Swabey89 | 0:19febeae2548 | 555 | } |
Swabey89 | 0:19febeae2548 | 556 | status = _cmd(CMD38_ERASE, 0x0); |
Swabey89 | 0:19febeae2548 | 557 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 558 | return status; |
Swabey89 | 0:19febeae2548 | 559 | } |
Swabey89 | 0:19febeae2548 | 560 | |
Swabey89 | 0:19febeae2548 | 561 | bd_size_t SDBlockDevice::get_read_size() const |
Swabey89 | 0:19febeae2548 | 562 | { |
Swabey89 | 0:19febeae2548 | 563 | return _block_size; |
Swabey89 | 0:19febeae2548 | 564 | } |
Swabey89 | 0:19febeae2548 | 565 | |
Swabey89 | 0:19febeae2548 | 566 | bd_size_t SDBlockDevice::get_program_size() const |
Swabey89 | 0:19febeae2548 | 567 | { |
Swabey89 | 0:19febeae2548 | 568 | return _block_size; |
Swabey89 | 0:19febeae2548 | 569 | } |
Swabey89 | 0:19febeae2548 | 570 | |
Swabey89 | 0:19febeae2548 | 571 | bd_size_t SDBlockDevice::size() const |
Swabey89 | 0:19febeae2548 | 572 | { |
Swabey89 | 0:19febeae2548 | 573 | bd_size_t sectors = 0; |
Swabey89 | 0:19febeae2548 | 574 | _lock.lock(); |
Swabey89 | 0:19febeae2548 | 575 | if (_is_initialized) { |
Swabey89 | 0:19febeae2548 | 576 | sectors = _sectors; |
Swabey89 | 0:19febeae2548 | 577 | } |
Swabey89 | 0:19febeae2548 | 578 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 579 | return _block_size*sectors; |
Swabey89 | 0:19febeae2548 | 580 | } |
Swabey89 | 0:19febeae2548 | 581 | |
Swabey89 | 0:19febeae2548 | 582 | void SDBlockDevice::debug(bool dbg) |
Swabey89 | 0:19febeae2548 | 583 | { |
Swabey89 | 0:19febeae2548 | 584 | _dbg = dbg; |
Swabey89 | 0:19febeae2548 | 585 | } |
Swabey89 | 0:19febeae2548 | 586 | |
Swabey89 | 0:19febeae2548 | 587 | int SDBlockDevice::frequency(uint64_t freq) |
Swabey89 | 0:19febeae2548 | 588 | { |
Swabey89 | 0:19febeae2548 | 589 | _lock.lock(); |
Swabey89 | 0:19febeae2548 | 590 | _transfer_sck = freq; |
Swabey89 | 0:19febeae2548 | 591 | int err = _freq(); |
Swabey89 | 0:19febeae2548 | 592 | _lock.unlock(); |
Swabey89 | 0:19febeae2548 | 593 | return err; |
Swabey89 | 0:19febeae2548 | 594 | } |
Swabey89 | 0:19febeae2548 | 595 | |
Swabey89 | 0:19febeae2548 | 596 | // PRIVATE FUNCTIONS |
Swabey89 | 0:19febeae2548 | 597 | int SDBlockDevice::_freq(void) |
Swabey89 | 0:19febeae2548 | 598 | { |
Swabey89 | 0:19febeae2548 | 599 | // Max frequency supported is 25MHZ |
Swabey89 | 0:19febeae2548 | 600 | if (_transfer_sck <= 25000000) { |
Swabey89 | 0:19febeae2548 | 601 | _spi.frequency(_transfer_sck); |
Swabey89 | 0:19febeae2548 | 602 | return 0; |
Swabey89 | 0:19febeae2548 | 603 | } else { // TODO: Switch function to be implemented for higher frequency |
Swabey89 | 0:19febeae2548 | 604 | _transfer_sck = 25000000; |
Swabey89 | 0:19febeae2548 | 605 | _spi.frequency(_transfer_sck); |
Swabey89 | 0:19febeae2548 | 606 | return -EINVAL; |
Swabey89 | 0:19febeae2548 | 607 | } |
Swabey89 | 0:19febeae2548 | 608 | } |
Swabey89 | 0:19febeae2548 | 609 | |
Swabey89 | 0:19febeae2548 | 610 | uint8_t SDBlockDevice::_cmd_spi(SDBlockDevice::cmdSupported cmd, uint32_t arg) { |
Swabey89 | 0:19febeae2548 | 611 | uint8_t response; |
Swabey89 | 0:19febeae2548 | 612 | char cmdPacket[PACKET_SIZE]; |
Swabey89 | 0:19febeae2548 | 613 | |
Swabey89 | 0:19febeae2548 | 614 | // Prepare the command packet |
Swabey89 | 0:19febeae2548 | 615 | cmdPacket[0] = SPI_CMD(cmd); |
Swabey89 | 0:19febeae2548 | 616 | cmdPacket[1] = (arg >> 24); |
Swabey89 | 0:19febeae2548 | 617 | cmdPacket[2] = (arg >> 16); |
Swabey89 | 0:19febeae2548 | 618 | cmdPacket[3] = (arg >> 8); |
Swabey89 | 0:19febeae2548 | 619 | cmdPacket[4] = (arg >> 0); |
Swabey89 | 0:19febeae2548 | 620 | // CMD0 is executed in SD mode, hence should have correct CRC |
Swabey89 | 0:19febeae2548 | 621 | // CMD8 CRC verification is always enabled |
Swabey89 | 0:19febeae2548 | 622 | switch(cmd) { |
Swabey89 | 0:19febeae2548 | 623 | case CMD0_GO_IDLE_STATE: |
Swabey89 | 0:19febeae2548 | 624 | cmdPacket[5] = 0x95; |
Swabey89 | 0:19febeae2548 | 625 | break; |
Swabey89 | 0:19febeae2548 | 626 | case CMD8_SEND_IF_COND: |
Swabey89 | 0:19febeae2548 | 627 | cmdPacket[5] = 0x87; |
Swabey89 | 0:19febeae2548 | 628 | break; |
Swabey89 | 0:19febeae2548 | 629 | default: |
Swabey89 | 0:19febeae2548 | 630 | cmdPacket[5] = 0xFF; // Make sure bit 0-End bit is high |
Swabey89 | 0:19febeae2548 | 631 | break; |
Swabey89 | 0:19febeae2548 | 632 | } |
Swabey89 | 0:19febeae2548 | 633 | |
Swabey89 | 0:19febeae2548 | 634 | // send a command |
Swabey89 | 0:19febeae2548 | 635 | for (int i = 0; i < PACKET_SIZE; i++) { |
Swabey89 | 0:19febeae2548 | 636 | _spi.write(cmdPacket[i]); |
Swabey89 | 0:19febeae2548 | 637 | } |
Swabey89 | 0:19febeae2548 | 638 | |
Swabey89 | 0:19febeae2548 | 639 | // The received byte immediataly following CMD12 is a stuff byte, |
Swabey89 | 0:19febeae2548 | 640 | // it should be discarded before receive the response of the CMD12. |
Swabey89 | 0:19febeae2548 | 641 | if (CMD12_STOP_TRANSMISSION == cmd) { |
Swabey89 | 0:19febeae2548 | 642 | _spi.write(SPI_FILL_CHAR); |
Swabey89 | 0:19febeae2548 | 643 | } |
Swabey89 | 0:19febeae2548 | 644 | |
Swabey89 | 0:19febeae2548 | 645 | // Loop for response: Response is sent back within command response time (NCR), 0 to 8 bytes for SDC |
Swabey89 | 0:19febeae2548 | 646 | for (int i = 0; i < 0x10; i++) { |
Swabey89 | 0:19febeae2548 | 647 | response = _spi.write(SPI_FILL_CHAR); |
Swabey89 | 0:19febeae2548 | 648 | // Got the response |
Swabey89 | 0:19febeae2548 | 649 | if (!(response & R1_RESPONSE_RECV)) { |
Swabey89 | 0:19febeae2548 | 650 | break; |
Swabey89 | 0:19febeae2548 | 651 | } |
Swabey89 | 0:19febeae2548 | 652 | } |
Swabey89 | 0:19febeae2548 | 653 | return response; |
Swabey89 | 0:19febeae2548 | 654 | } |
Swabey89 | 0:19febeae2548 | 655 | |
Swabey89 | 0:19febeae2548 | 656 | int SDBlockDevice::_cmd(SDBlockDevice::cmdSupported cmd, uint32_t arg, bool isAcmd, uint32_t *resp) { |
Swabey89 | 0:19febeae2548 | 657 | int32_t status = BD_ERROR_OK; |
Swabey89 | 0:19febeae2548 | 658 | uint32_t response; |
Swabey89 | 0:19febeae2548 | 659 | |
Swabey89 | 0:19febeae2548 | 660 | // Select card and wait for card to be ready before sending next command |
Swabey89 | 0:19febeae2548 | 661 | // Note: next command will fail if card is not ready |
Swabey89 | 0:19febeae2548 | 662 | _select(); |
Swabey89 | 0:19febeae2548 | 663 | |
Swabey89 | 0:19febeae2548 | 664 | // No need to wait for card to be ready when sending the stop command |
Swabey89 | 0:19febeae2548 | 665 | if (CMD12_STOP_TRANSMISSION != cmd) { |
Swabey89 | 0:19febeae2548 | 666 | if (false == _wait_ready(SD_COMMAND_TIMEOUT)) { |
Swabey89 | 0:19febeae2548 | 667 | debug_if(SD_DBG, "Card not ready yet \n"); |
Swabey89 | 0:19febeae2548 | 668 | } |
Swabey89 | 0:19febeae2548 | 669 | } |
Swabey89 | 0:19febeae2548 | 670 | |
Swabey89 | 0:19febeae2548 | 671 | // Re-try command |
Swabey89 | 0:19febeae2548 | 672 | for(int i = 0; i < 3; i++) { |
Swabey89 | 0:19febeae2548 | 673 | // Send CMD55 for APP command first |
Swabey89 | 0:19febeae2548 | 674 | if (isAcmd) { |
Swabey89 | 0:19febeae2548 | 675 | response = _cmd_spi(CMD55_APP_CMD, 0x0); |
Swabey89 | 0:19febeae2548 | 676 | // Wait for card to be ready after CMD55 |
Swabey89 | 0:19febeae2548 | 677 | if (false == _wait_ready(SD_COMMAND_TIMEOUT)) { |
Swabey89 | 0:19febeae2548 | 678 | debug_if(SD_DBG, "Card not ready yet \n"); |
Swabey89 | 0:19febeae2548 | 679 | } |
Swabey89 | 0:19febeae2548 | 680 | } |
Swabey89 | 0:19febeae2548 | 681 | |
Swabey89 | 0:19febeae2548 | 682 | // Send command over SPI interface |
Swabey89 | 0:19febeae2548 | 683 | response = _cmd_spi(cmd, arg); |
Swabey89 | 0:19febeae2548 | 684 | if (R1_NO_RESPONSE == response) { |
Swabey89 | 0:19febeae2548 | 685 | debug_if(SD_DBG, "No response CMD:%d \n", cmd); |
Swabey89 | 0:19febeae2548 | 686 | continue; |
Swabey89 | 0:19febeae2548 | 687 | } |
Swabey89 | 0:19febeae2548 | 688 | break; |
Swabey89 | 0:19febeae2548 | 689 | } |
Swabey89 | 0:19febeae2548 | 690 | |
Swabey89 | 0:19febeae2548 | 691 | // Pass the response to the command call if required |
Swabey89 | 0:19febeae2548 | 692 | if (NULL != resp) { |
Swabey89 | 0:19febeae2548 | 693 | *resp = response; |
Swabey89 | 0:19febeae2548 | 694 | } |
Swabey89 | 0:19febeae2548 | 695 | |
Swabey89 | 0:19febeae2548 | 696 | // Process the response R1 : Exit on CRC/Illegal command error/No response |
Swabey89 | 0:19febeae2548 | 697 | if (R1_NO_RESPONSE == response) { |
Swabey89 | 0:19febeae2548 | 698 | _deselect(); |
Swabey89 | 0:19febeae2548 | 699 | debug_if(SD_DBG, "No response CMD:%d response: 0x%x\n",cmd, response); |
Swabey89 | 0:19febeae2548 | 700 | return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; // No device |
Swabey89 | 0:19febeae2548 | 701 | } |
Swabey89 | 0:19febeae2548 | 702 | if (response & R1_COM_CRC_ERROR) { |
Swabey89 | 0:19febeae2548 | 703 | _deselect(); |
Swabey89 | 0:19febeae2548 | 704 | debug_if(SD_DBG, "CRC error CMD:%d response 0x%x \n",cmd, response); |
Swabey89 | 0:19febeae2548 | 705 | return SD_BLOCK_DEVICE_ERROR_CRC; // CRC error |
Swabey89 | 0:19febeae2548 | 706 | } |
Swabey89 | 0:19febeae2548 | 707 | if (response & R1_ILLEGAL_COMMAND) { |
Swabey89 | 0:19febeae2548 | 708 | _deselect(); |
Swabey89 | 0:19febeae2548 | 709 | debug_if(SD_DBG, "Illegal command CMD:%d response 0x%x\n",cmd, response); |
Swabey89 | 0:19febeae2548 | 710 | if (CMD8_SEND_IF_COND == cmd) { // Illegal command is for Ver1 or not SD Card |
Swabey89 | 0:19febeae2548 | 711 | _card_type = CARD_UNKNOWN; |
Swabey89 | 0:19febeae2548 | 712 | } |
Swabey89 | 0:19febeae2548 | 713 | return SD_BLOCK_DEVICE_ERROR_UNSUPPORTED; // Command not supported |
Swabey89 | 0:19febeae2548 | 714 | } |
Swabey89 | 0:19febeae2548 | 715 | |
Swabey89 | 0:19febeae2548 | 716 | debug_if(_dbg, "CMD:%d \t arg:0x%x \t Response:0x%x \n", cmd, arg, response); |
Swabey89 | 0:19febeae2548 | 717 | // Set status for other errors |
Swabey89 | 0:19febeae2548 | 718 | if ((response & R1_ERASE_RESET) || (response & R1_ERASE_SEQUENCE_ERROR)) { |
Swabey89 | 0:19febeae2548 | 719 | status = SD_BLOCK_DEVICE_ERROR_ERASE; // Erase error |
Swabey89 | 0:19febeae2548 | 720 | }else if ((response & R1_ADDRESS_ERROR) || (response & R1_PARAMETER_ERROR)) { |
Swabey89 | 0:19febeae2548 | 721 | // Misaligned address / invalid address block length |
Swabey89 | 0:19febeae2548 | 722 | status = SD_BLOCK_DEVICE_ERROR_PARAMETER; |
Swabey89 | 0:19febeae2548 | 723 | } |
Swabey89 | 0:19febeae2548 | 724 | |
Swabey89 | 0:19febeae2548 | 725 | // Get rest of the response part for other commands |
Swabey89 | 0:19febeae2548 | 726 | switch(cmd) { |
Swabey89 | 0:19febeae2548 | 727 | case CMD8_SEND_IF_COND: // Response R7 |
Swabey89 | 0:19febeae2548 | 728 | debug_if(_dbg, "V2-Version Card\n"); |
Swabey89 | 0:19febeae2548 | 729 | _card_type = SDCARD_V2; |
Swabey89 | 0:19febeae2548 | 730 | // Note: No break here, need to read rest of the response |
Swabey89 | 0:19febeae2548 | 731 | case CMD58_READ_OCR: // Response R3 |
Swabey89 | 0:19febeae2548 | 732 | response = (_spi.write(SPI_FILL_CHAR) << 24); |
Swabey89 | 0:19febeae2548 | 733 | response |= (_spi.write(SPI_FILL_CHAR) << 16); |
Swabey89 | 0:19febeae2548 | 734 | response |= (_spi.write(SPI_FILL_CHAR) << 8); |
Swabey89 | 0:19febeae2548 | 735 | response |= _spi.write(SPI_FILL_CHAR); |
Swabey89 | 0:19febeae2548 | 736 | debug_if(_dbg, "R3/R7: 0x%x \n", response); |
Swabey89 | 0:19febeae2548 | 737 | break; |
Swabey89 | 0:19febeae2548 | 738 | |
Swabey89 | 0:19febeae2548 | 739 | case CMD12_STOP_TRANSMISSION: // Response R1b |
Swabey89 | 0:19febeae2548 | 740 | case CMD38_ERASE: |
Swabey89 | 0:19febeae2548 | 741 | _wait_ready(SD_COMMAND_TIMEOUT); |
Swabey89 | 0:19febeae2548 | 742 | break; |
Swabey89 | 0:19febeae2548 | 743 | |
Swabey89 | 0:19febeae2548 | 744 | case ACMD13_SD_STATUS: // Response R2 |
Swabey89 | 0:19febeae2548 | 745 | response = _spi.write(SPI_FILL_CHAR); |
Swabey89 | 0:19febeae2548 | 746 | debug_if(_dbg, "R2: 0x%x \n", response); |
Swabey89 | 0:19febeae2548 | 747 | break; |
Swabey89 | 0:19febeae2548 | 748 | |
Swabey89 | 0:19febeae2548 | 749 | default: // Response R1 |
Swabey89 | 0:19febeae2548 | 750 | break; |
Swabey89 | 0:19febeae2548 | 751 | } |
Swabey89 | 0:19febeae2548 | 752 | |
Swabey89 | 0:19febeae2548 | 753 | // Pass the updated response to the command |
Swabey89 | 0:19febeae2548 | 754 | if (NULL != resp) { |
Swabey89 | 0:19febeae2548 | 755 | *resp = response; |
Swabey89 | 0:19febeae2548 | 756 | } |
Swabey89 | 0:19febeae2548 | 757 | |
Swabey89 | 0:19febeae2548 | 758 | // Do not deselect card if read is in progress. |
Swabey89 | 0:19febeae2548 | 759 | if (((CMD9_SEND_CSD == cmd) || (ACMD22_SEND_NUM_WR_BLOCKS == cmd) || |
Swabey89 | 0:19febeae2548 | 760 | (CMD24_WRITE_BLOCK == cmd) || (CMD25_WRITE_MULTIPLE_BLOCK == cmd) || |
Swabey89 | 0:19febeae2548 | 761 | (CMD17_READ_SINGLE_BLOCK == cmd) || (CMD18_READ_MULTIPLE_BLOCK == cmd)) |
Swabey89 | 0:19febeae2548 | 762 | && (BD_ERROR_OK == status)) { |
Swabey89 | 0:19febeae2548 | 763 | return BD_ERROR_OK; |
Swabey89 | 0:19febeae2548 | 764 | } |
Swabey89 | 0:19febeae2548 | 765 | // Deselect card |
Swabey89 | 0:19febeae2548 | 766 | _deselect(); |
Swabey89 | 0:19febeae2548 | 767 | return status; |
Swabey89 | 0:19febeae2548 | 768 | } |
Swabey89 | 0:19febeae2548 | 769 | |
Swabey89 | 0:19febeae2548 | 770 | int SDBlockDevice::_cmd8() { |
Swabey89 | 0:19febeae2548 | 771 | uint32_t arg = (CMD8_PATTERN << 0); // [7:0]check pattern |
Swabey89 | 0:19febeae2548 | 772 | uint32_t response = 0; |
Swabey89 | 0:19febeae2548 | 773 | int32_t status = BD_ERROR_OK; |
Swabey89 | 0:19febeae2548 | 774 | |
Swabey89 | 0:19febeae2548 | 775 | arg |= (0x1 << 8); // 2.7-3.6V // [11:8]supply voltage(VHS) |
Swabey89 | 0:19febeae2548 | 776 | |
Swabey89 | 0:19febeae2548 | 777 | status = _cmd(CMD8_SEND_IF_COND, arg, 0x0, &response); |
Swabey89 | 0:19febeae2548 | 778 | // Verify voltage and pattern for V2 version of card |
Swabey89 | 0:19febeae2548 | 779 | if ((BD_ERROR_OK == status) && (SDCARD_V2 == _card_type)) { |
Swabey89 | 0:19febeae2548 | 780 | // If check pattern is not matched, CMD8 communication is not valid |
Swabey89 | 0:19febeae2548 | 781 | if((response & 0xFFF) != arg) |
Swabey89 | 0:19febeae2548 | 782 | { |
Swabey89 | 0:19febeae2548 | 783 | debug_if(SD_DBG, "CMD8 Pattern mismatch 0x%x : 0x%x\n", arg, response); |
Swabey89 | 0:19febeae2548 | 784 | _card_type = CARD_UNKNOWN; |
Swabey89 | 0:19febeae2548 | 785 | status = SD_BLOCK_DEVICE_ERROR_UNUSABLE; |
Swabey89 | 0:19febeae2548 | 786 | } |
Swabey89 | 0:19febeae2548 | 787 | } |
Swabey89 | 0:19febeae2548 | 788 | return status; |
Swabey89 | 0:19febeae2548 | 789 | } |
Swabey89 | 0:19febeae2548 | 790 | |
Swabey89 | 0:19febeae2548 | 791 | uint32_t SDBlockDevice::_go_idle_state() { |
Swabey89 | 0:19febeae2548 | 792 | uint32_t response; |
Swabey89 | 0:19febeae2548 | 793 | |
Swabey89 | 0:19febeae2548 | 794 | /* Reseting the MCU SPI master may not reset the on-board SDCard, in which |
Swabey89 | 0:19febeae2548 | 795 | * case when MCU power-on occurs the SDCard will resume operations as |
Swabey89 | 0:19febeae2548 | 796 | * though there was no reset. In this scenario the first CMD0 will |
Swabey89 | 0:19febeae2548 | 797 | * not be interpreted as a command and get lost. For some cards retrying |
Swabey89 | 0:19febeae2548 | 798 | * the command overcomes this situation. */ |
Swabey89 | 0:19febeae2548 | 799 | for (int i = 0; i < SD_CMD0_GO_IDLE_STATE_RETRIES; i++) { |
Swabey89 | 0:19febeae2548 | 800 | _cmd(CMD0_GO_IDLE_STATE, 0x0, 0x0, &response); |
Swabey89 | 0:19febeae2548 | 801 | if (R1_IDLE_STATE == response) |
Swabey89 | 0:19febeae2548 | 802 | break; |
Swabey89 | 0:19febeae2548 | 803 | wait_ms(1); |
Swabey89 | 0:19febeae2548 | 804 | } |
Swabey89 | 0:19febeae2548 | 805 | return response; |
Swabey89 | 0:19febeae2548 | 806 | } |
Swabey89 | 0:19febeae2548 | 807 | |
Swabey89 | 0:19febeae2548 | 808 | int SDBlockDevice::_read_bytes(uint8_t *buffer, uint32_t length) { |
Swabey89 | 0:19febeae2548 | 809 | uint16_t crc; |
Swabey89 | 0:19febeae2548 | 810 | |
Swabey89 | 0:19febeae2548 | 811 | // read until start byte (0xFE) |
Swabey89 | 0:19febeae2548 | 812 | if (false == _wait_token(SPI_START_BLOCK)) { |
Swabey89 | 0:19febeae2548 | 813 | debug_if(SD_DBG, "Read timeout\n"); |
Swabey89 | 0:19febeae2548 | 814 | _deselect(); |
Swabey89 | 0:19febeae2548 | 815 | return SD_BLOCK_DEVICE_ERROR_NO_RESPONSE; |
Swabey89 | 0:19febeae2548 | 816 | } |
Swabey89 | 0:19febeae2548 | 817 | |
Swabey89 | 0:19febeae2548 | 818 | // read data |
Swabey89 | 0:19febeae2548 | 819 | for (uint32_t i = 0; i < length; i++) { |
Swabey89 | 0:19febeae2548 | 820 | buffer[i] = _spi.write(SPI_FILL_CHAR); |
Swabey89 | 0:19febeae2548 | 821 | } |
Swabey89 | 0:19febeae2548 | 822 | |
Swabey89 | 0:19febeae2548 | 823 | // Read the CRC16 checksum for the data block |
Swabey89 | 0:19febeae2548 | 824 | crc = (_spi.write(SPI_FILL_CHAR) << 8); |
Swabey89 | 0:19febeae2548 | 825 | crc |= _spi.write(SPI_FILL_CHAR); |
Swabey89 | 0:19febeae2548 | 826 | |
Swabey89 | 0:19febeae2548 | 827 | _deselect(); |
Swabey89 | 0:19febeae2548 | 828 | return 0; |
Swabey89 | 0:19febeae2548 | 829 | } |
Swabey89 | 0:19febeae2548 | 830 | |
Swabey89 | 0:19febeae2548 | 831 | int SDBlockDevice::_read(uint8_t *buffer, uint32_t length) { |
Swabey89 | 0:19febeae2548 | 832 | uint16_t crc; |
Swabey89 | 0:19febeae2548 | 833 | |
Swabey89 | 0:19febeae2548 | 834 | // read until start byte (0xFE) |
Swabey89 | 0:19febeae2548 | 835 | if (false == _wait_token(SPI_START_BLOCK)) { |
Swabey89 | 0:19febeae2548 | 836 | debug_if(SD_DBG, "Read timeout\n"); |
Swabey89 | 0:19febeae2548 | 837 | _deselect(); |
Swabey89 | 0:19febeae2548 | 838 | return SD_BLOCK_DEVICE_ERROR_NO_RESPONSE; |
Swabey89 | 0:19febeae2548 | 839 | } |
Swabey89 | 0:19febeae2548 | 840 | |
Swabey89 | 0:19febeae2548 | 841 | // read data |
Swabey89 | 0:19febeae2548 | 842 | _spi.write(NULL, 0, (char*)buffer, length); |
Swabey89 | 0:19febeae2548 | 843 | |
Swabey89 | 0:19febeae2548 | 844 | // Read the CRC16 checksum for the data block |
Swabey89 | 0:19febeae2548 | 845 | crc = (_spi.write(SPI_FILL_CHAR) << 8); |
Swabey89 | 0:19febeae2548 | 846 | crc |= _spi.write(SPI_FILL_CHAR); |
Swabey89 | 0:19febeae2548 | 847 | |
Swabey89 | 0:19febeae2548 | 848 | return 0; |
Swabey89 | 0:19febeae2548 | 849 | } |
Swabey89 | 0:19febeae2548 | 850 | |
Swabey89 | 0:19febeae2548 | 851 | uint8_t SDBlockDevice::_write(const uint8_t *buffer, uint8_t token, uint32_t length) { |
Swabey89 | 0:19febeae2548 | 852 | uint16_t crc = 0xFFFF; |
Swabey89 | 0:19febeae2548 | 853 | uint8_t response = 0xFF; |
Swabey89 | 0:19febeae2548 | 854 | |
Swabey89 | 0:19febeae2548 | 855 | // indicate start of block |
Swabey89 | 0:19febeae2548 | 856 | _spi.write(token); |
Swabey89 | 0:19febeae2548 | 857 | |
Swabey89 | 0:19febeae2548 | 858 | // write the data |
Swabey89 | 0:19febeae2548 | 859 | _spi.write((char*)buffer, length, NULL, 0); |
Swabey89 | 0:19febeae2548 | 860 | |
Swabey89 | 0:19febeae2548 | 861 | // write the checksum CRC16 |
Swabey89 | 0:19febeae2548 | 862 | _spi.write(crc >> 8); |
Swabey89 | 0:19febeae2548 | 863 | _spi.write(crc); |
Swabey89 | 0:19febeae2548 | 864 | |
Swabey89 | 0:19febeae2548 | 865 | // check the response token |
Swabey89 | 0:19febeae2548 | 866 | response = _spi.write(SPI_FILL_CHAR); |
Swabey89 | 0:19febeae2548 | 867 | |
Swabey89 | 0:19febeae2548 | 868 | // Wait for last block to be written |
Swabey89 | 0:19febeae2548 | 869 | if (false == _wait_ready(SD_COMMAND_TIMEOUT)) { |
Swabey89 | 0:19febeae2548 | 870 | debug_if(SD_DBG, "Card not ready yet \n"); |
Swabey89 | 0:19febeae2548 | 871 | } |
Swabey89 | 0:19febeae2548 | 872 | |
Swabey89 | 0:19febeae2548 | 873 | return (response & SPI_DATA_RESPONSE_MASK); |
Swabey89 | 0:19febeae2548 | 874 | } |
Swabey89 | 0:19febeae2548 | 875 | |
Swabey89 | 0:19febeae2548 | 876 | static uint32_t ext_bits(unsigned char *data, int msb, int lsb) { |
Swabey89 | 0:19febeae2548 | 877 | uint32_t bits = 0; |
Swabey89 | 0:19febeae2548 | 878 | uint32_t size = 1 + msb - lsb; |
Swabey89 | 0:19febeae2548 | 879 | for (uint32_t i = 0; i < size; i++) { |
Swabey89 | 0:19febeae2548 | 880 | uint32_t position = lsb + i; |
Swabey89 | 0:19febeae2548 | 881 | uint32_t byte = 15 - (position >> 3); |
Swabey89 | 0:19febeae2548 | 882 | uint32_t bit = position & 0x7; |
Swabey89 | 0:19febeae2548 | 883 | uint32_t value = (data[byte] >> bit) & 1; |
Swabey89 | 0:19febeae2548 | 884 | bits |= value << i; |
Swabey89 | 0:19febeae2548 | 885 | } |
Swabey89 | 0:19febeae2548 | 886 | return bits; |
Swabey89 | 0:19febeae2548 | 887 | } |
Swabey89 | 0:19febeae2548 | 888 | |
Swabey89 | 0:19febeae2548 | 889 | uint32_t SDBlockDevice::_sd_sectors() { |
Swabey89 | 0:19febeae2548 | 890 | uint32_t c_size, c_size_mult, read_bl_len; |
Swabey89 | 0:19febeae2548 | 891 | uint32_t block_len, mult, blocknr; |
Swabey89 | 0:19febeae2548 | 892 | uint32_t hc_c_size; |
Swabey89 | 0:19febeae2548 | 893 | bd_size_t blocks = 0, capacity = 0; |
Swabey89 | 0:19febeae2548 | 894 | |
Swabey89 | 0:19febeae2548 | 895 | // CMD9, Response R2 (R1 byte + 16-byte block read) |
Swabey89 | 0:19febeae2548 | 896 | if (_cmd(CMD9_SEND_CSD, 0x0) != 0x0) { |
Swabey89 | 0:19febeae2548 | 897 | debug_if(SD_DBG, "Didn't get a response from the disk\n"); |
Swabey89 | 0:19febeae2548 | 898 | return 0; |
Swabey89 | 0:19febeae2548 | 899 | } |
Swabey89 | 0:19febeae2548 | 900 | uint8_t csd[16]; |
Swabey89 | 0:19febeae2548 | 901 | if (_read_bytes(csd, 16) != 0) { |
Swabey89 | 0:19febeae2548 | 902 | debug_if(SD_DBG, "Couldn't read csd response from disk\n"); |
Swabey89 | 0:19febeae2548 | 903 | return 0; |
Swabey89 | 0:19febeae2548 | 904 | } |
Swabey89 | 0:19febeae2548 | 905 | |
Swabey89 | 0:19febeae2548 | 906 | // csd_structure : csd[127:126] |
Swabey89 | 0:19febeae2548 | 907 | int csd_structure = ext_bits(csd, 127, 126); |
Swabey89 | 0:19febeae2548 | 908 | switch (csd_structure) { |
Swabey89 | 0:19febeae2548 | 909 | case 0: |
Swabey89 | 0:19febeae2548 | 910 | c_size = ext_bits(csd, 73, 62); // c_size : csd[73:62] |
Swabey89 | 0:19febeae2548 | 911 | c_size_mult = ext_bits(csd, 49, 47); // c_size_mult : csd[49:47] |
Swabey89 | 0:19febeae2548 | 912 | read_bl_len = ext_bits(csd, 83, 80); // read_bl_len : csd[83:80] - the *maximum* read block length |
Swabey89 | 0:19febeae2548 | 913 | block_len = 1 << read_bl_len; // BLOCK_LEN = 2^READ_BL_LEN |
Swabey89 | 0:19febeae2548 | 914 | mult = 1 << (c_size_mult + 2); // MULT = 2^C_SIZE_MULT+2 (C_SIZE_MULT < 8) |
Swabey89 | 0:19febeae2548 | 915 | blocknr = (c_size + 1) * mult; // BLOCKNR = (C_SIZE+1) * MULT |
Swabey89 | 0:19febeae2548 | 916 | capacity = blocknr * block_len; // memory capacity = BLOCKNR * BLOCK_LEN |
Swabey89 | 0:19febeae2548 | 917 | blocks = capacity / _block_size; |
Swabey89 | 0:19febeae2548 | 918 | debug_if(SD_DBG, "Standard Capacity: c_size: %d \n", c_size); |
Swabey89 | 0:19febeae2548 | 919 | debug_if(SD_DBG, "Sectors: 0x%x : %llu\n", blocks, blocks); |
Swabey89 | 0:19febeae2548 | 920 | debug_if(SD_DBG, "Capacity: 0x%x : %llu MB\n", capacity, (capacity/(1024U*1024U))); |
Swabey89 | 0:19febeae2548 | 921 | |
Swabey89 | 0:19febeae2548 | 922 | // ERASE_BLK_EN = 1: Erase in multiple of 512 bytes supported |
Swabey89 | 0:19febeae2548 | 923 | if (ext_bits(csd, 46, 46)) { |
Swabey89 | 0:19febeae2548 | 924 | _erase_size = BLOCK_SIZE_HC; |
Swabey89 | 0:19febeae2548 | 925 | } else { |
Swabey89 | 0:19febeae2548 | 926 | // ERASE_BLK_EN = 1: Erase in multiple of SECTOR_SIZE supported |
Swabey89 | 0:19febeae2548 | 927 | _erase_size = BLOCK_SIZE_HC * (ext_bits(csd, 45, 39) + 1); |
Swabey89 | 0:19febeae2548 | 928 | } |
Swabey89 | 0:19febeae2548 | 929 | break; |
Swabey89 | 0:19febeae2548 | 930 | |
Swabey89 | 0:19febeae2548 | 931 | case 1: |
Swabey89 | 0:19febeae2548 | 932 | hc_c_size = ext_bits(csd, 69, 48); // device size : C_SIZE : [69:48] |
Swabey89 | 0:19febeae2548 | 933 | blocks = (hc_c_size+1) << 10; // block count = C_SIZE+1) * 1K byte (512B is block size) |
Swabey89 | 0:19febeae2548 | 934 | debug_if(SD_DBG, "SDHC/SDXC Card: hc_c_size: %d \n", hc_c_size); |
Swabey89 | 0:19febeae2548 | 935 | debug_if(SD_DBG, "Sectors: 0x%x : %llu\n", blocks, blocks); |
Swabey89 | 0:19febeae2548 | 936 | debug_if(SD_DBG, "Capacity: %llu MB\n", (blocks/(2048U))); |
Swabey89 | 0:19febeae2548 | 937 | // ERASE_BLK_EN is fixed to 1, which means host can erase one or multiple of 512 bytes. |
Swabey89 | 0:19febeae2548 | 938 | _erase_size = BLOCK_SIZE_HC; |
Swabey89 | 0:19febeae2548 | 939 | break; |
Swabey89 | 0:19febeae2548 | 940 | |
Swabey89 | 0:19febeae2548 | 941 | default: |
Swabey89 | 0:19febeae2548 | 942 | debug_if(SD_DBG, "CSD struct unsupported\r\n"); |
Swabey89 | 0:19febeae2548 | 943 | return 0; |
Swabey89 | 0:19febeae2548 | 944 | }; |
Swabey89 | 0:19febeae2548 | 945 | return blocks; |
Swabey89 | 0:19febeae2548 | 946 | } |
Swabey89 | 0:19febeae2548 | 947 | |
Swabey89 | 0:19febeae2548 | 948 | // SPI function to wait till chip is ready and sends start token |
Swabey89 | 0:19febeae2548 | 949 | bool SDBlockDevice::_wait_token(uint8_t token) { |
Swabey89 | 0:19febeae2548 | 950 | _spi_timer.reset(); |
Swabey89 | 0:19febeae2548 | 951 | _spi_timer.start(); |
Swabey89 | 0:19febeae2548 | 952 | |
Swabey89 | 0:19febeae2548 | 953 | do { |
Swabey89 | 0:19febeae2548 | 954 | if (token == _spi.write(SPI_FILL_CHAR)) { |
Swabey89 | 0:19febeae2548 | 955 | _spi_timer.stop(); |
Swabey89 | 0:19febeae2548 | 956 | return true; |
Swabey89 | 0:19febeae2548 | 957 | } |
Swabey89 | 0:19febeae2548 | 958 | } while (_spi_timer.read_ms() < 300); // Wait for 300 msec for start token |
Swabey89 | 0:19febeae2548 | 959 | _spi_timer.stop(); |
Swabey89 | 0:19febeae2548 | 960 | debug_if(SD_DBG, "_wait_token: timeout\n"); |
Swabey89 | 0:19febeae2548 | 961 | return false; |
Swabey89 | 0:19febeae2548 | 962 | } |
Swabey89 | 0:19febeae2548 | 963 | |
Swabey89 | 0:19febeae2548 | 964 | // SPI function to wait till chip is ready |
Swabey89 | 0:19febeae2548 | 965 | // The host controller should wait for end of the process until DO goes high (a 0xFF is received). |
Swabey89 | 0:19febeae2548 | 966 | bool SDBlockDevice::_wait_ready(uint16_t ms) { |
Swabey89 | 0:19febeae2548 | 967 | uint8_t response; |
Swabey89 | 0:19febeae2548 | 968 | _spi_timer.reset(); |
Swabey89 | 0:19febeae2548 | 969 | _spi_timer.start(); |
Swabey89 | 0:19febeae2548 | 970 | do { |
Swabey89 | 0:19febeae2548 | 971 | response = _spi.write(SPI_FILL_CHAR); |
Swabey89 | 0:19febeae2548 | 972 | if (response == 0xFF) { |
Swabey89 | 0:19febeae2548 | 973 | _spi_timer.stop(); |
Swabey89 | 0:19febeae2548 | 974 | return true; |
Swabey89 | 0:19febeae2548 | 975 | } |
Swabey89 | 0:19febeae2548 | 976 | } while (_spi_timer.read_ms() < ms); |
Swabey89 | 0:19febeae2548 | 977 | _spi_timer.stop(); |
Swabey89 | 0:19febeae2548 | 978 | return false; |
Swabey89 | 0:19febeae2548 | 979 | } |
Swabey89 | 0:19febeae2548 | 980 | |
Swabey89 | 0:19febeae2548 | 981 | // SPI function to wait for count |
Swabey89 | 0:19febeae2548 | 982 | void SDBlockDevice::_spi_wait(uint8_t count) |
Swabey89 | 0:19febeae2548 | 983 | { |
Swabey89 | 0:19febeae2548 | 984 | for (uint8_t i = 0; i < count; ++i) { |
Swabey89 | 0:19febeae2548 | 985 | _spi.write(SPI_FILL_CHAR); |
Swabey89 | 0:19febeae2548 | 986 | } |
Swabey89 | 0:19febeae2548 | 987 | } |
Swabey89 | 0:19febeae2548 | 988 | |
Swabey89 | 0:19febeae2548 | 989 | void SDBlockDevice::_spi_init() { |
Swabey89 | 0:19febeae2548 | 990 | _spi.lock(); |
Swabey89 | 0:19febeae2548 | 991 | // Set to SCK for initialization, and clock card with cs = 1 |
Swabey89 | 0:19febeae2548 | 992 | _spi.frequency(_init_sck); |
Swabey89 | 0:19febeae2548 | 993 | _spi.format(8, 0); |
Swabey89 | 0:19febeae2548 | 994 | _spi.set_default_write_value(SPI_FILL_CHAR); |
Swabey89 | 0:19febeae2548 | 995 | // Initial 74 cycles required for few cards, before selecting SPI mode |
Swabey89 | 0:19febeae2548 | 996 | _cs = 1; |
Swabey89 | 0:19febeae2548 | 997 | _spi_wait(10); |
Swabey89 | 0:19febeae2548 | 998 | _spi.unlock(); |
Swabey89 | 0:19febeae2548 | 999 | } |
Swabey89 | 0:19febeae2548 | 1000 | |
Swabey89 | 0:19febeae2548 | 1001 | void SDBlockDevice::_select() { |
Swabey89 | 0:19febeae2548 | 1002 | _spi.lock(); |
Swabey89 | 0:19febeae2548 | 1003 | _spi.write(SPI_FILL_CHAR); |
Swabey89 | 0:19febeae2548 | 1004 | _cs = 0; |
Swabey89 | 0:19febeae2548 | 1005 | } |
Swabey89 | 0:19febeae2548 | 1006 | |
Swabey89 | 0:19febeae2548 | 1007 | void SDBlockDevice::_deselect() { |
Swabey89 | 0:19febeae2548 | 1008 | _cs = 1; |
Swabey89 | 0:19febeae2548 | 1009 | _spi.write(SPI_FILL_CHAR); |
Swabey89 | 0:19febeae2548 | 1010 | _spi.unlock(); |
Swabey89 | 0:19febeae2548 | 1011 | } |
Swabey89 | 0:19febeae2548 | 1012 | |
Swabey89 | 0:19febeae2548 | 1013 | #endif /* DEVICE_SPI */ |