ELEC351 SUBMISSION - Same as on the DLE

/media/uploads/Luka_Danilovic/elec_315_prototype_assembly.jpg

Committer:
Luka_Danilovic
Date:
Wed Jan 10 09:49:43 2018 +0000
Revision:
0:c66224a27cf8
ELEC351 SUBMISSION - SAme as on the DLE

Who changed what in which revision?

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