SD card example code for Seeed Wio 3G

Fork of Wio_3G-example-sd-driver by Toyomasa Watarai

Committer:
MACRUM
Date:
Thu Aug 09 01:42:53 2018 +0000
Revision:
0:8eedb2495d52
Initial commit

Who changed what in which revision?

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