Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of Wio_3G-example-sd-driver by
sd-driver/SDBlockDevice.cpp@1:080085a0a3ec, 2018-12-03 (annotated)
- Committer:
- ytsuboi
- Date:
- Mon Dec 03 08:27:31 2018 +0000
- Revision:
- 1:080085a0a3ec
- Parent:
- 0:8eedb2495d52
Added format demo for Handson.
Who changed what in which revision?
User | Revision | Line number | New 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 */ |