SDHI_driver patch (mbedOS 5.11.5)

Committer:
tvendov
Date:
Mon Mar 18 16:54:40 2019 +0000
Revision:
0:e1f465d87307
Initial_II

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tvendov 0:e1f465d87307 1 /* mbed Microcontroller Library
tvendov 0:e1f465d87307 2 * Copyright (c) 2006-2012 ARM Limited
tvendov 0:e1f465d87307 3 *
tvendov 0:e1f465d87307 4 * Permission is hereby granted, free of charge, to any person obtaining a copy
tvendov 0:e1f465d87307 5 * of this software and associated documentation files (the "Software"), to deal
tvendov 0:e1f465d87307 6 * in the Software without restriction, including without limitation the rights
tvendov 0:e1f465d87307 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
tvendov 0:e1f465d87307 8 * copies of the Software, and to permit persons to whom the Software is
tvendov 0:e1f465d87307 9 * furnished to do so, subject to the following conditions:
tvendov 0:e1f465d87307 10 *
tvendov 0:e1f465d87307 11 * The above copyright notice and this permission notice shall be included in
tvendov 0:e1f465d87307 12 * all copies or substantial portions of the Software.
tvendov 0:e1f465d87307 13 *
tvendov 0:e1f465d87307 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
tvendov 0:e1f465d87307 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
tvendov 0:e1f465d87307 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
tvendov 0:e1f465d87307 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
tvendov 0:e1f465d87307 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
tvendov 0:e1f465d87307 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
tvendov 0:e1f465d87307 20 * SOFTWARE.
tvendov 0:e1f465d87307 21 */
tvendov 0:e1f465d87307 22
tvendov 0:e1f465d87307 23 #if (defined(TARGET_VK_RZ_A1H) || defined(TARGET_VK_RZ_A1LU))
tvendov 0:e1f465d87307 24
tvendov 0:e1f465d87307 25 #include "SDHIBlockDevice.h"
tvendov 0:e1f465d87307 26 #include "mbed_debug.h"
tvendov 0:e1f465d87307 27 #include <errno.h>
tvendov 0:e1f465d87307 28
tvendov 0:e1f465d87307 29 #include "iodefine.h"
tvendov 0:e1f465d87307 30 #include "PeripheralPins.h"
tvendov 0:e1f465d87307 31
tvendov 0:e1f465d87307 32 /* Required version: 5.6.1 and above */
tvendov 0:e1f465d87307 33 #ifdef MBED_MAJOR_VERSION
tvendov 0:e1f465d87307 34 #if (MBED_VERSION < MBED_ENCODE_VERSION(5,6,1))
tvendov 0:e1f465d87307 35 #error "Incompatible mbed-os version detected! Required 5.5.4 and above"
tvendov 0:e1f465d87307 36 #endif
tvendov 0:e1f465d87307 37 #else
tvendov 0:e1f465d87307 38 #warning "mbed-os version 5.6.1 or above required"
tvendov 0:e1f465d87307 39 #endif
tvendov 0:e1f465d87307 40
tvendov 0:e1f465d87307 41
tvendov 0:e1f465d87307 42
tvendov 0:e1f465d87307 43 //#define SD_COMMAND_TIMEOUT 5000 /*!< Timeout in ms for response */
tvendov 0:e1f465d87307 44 //#define SD_CMD0_GO_IDLE_STATE_RETRIES 5 /*!< Number of retries for sending CMDO */
tvendov 0:e1f465d87307 45 #define SD_CMD_TRACE 0 /*!< 1 - Enable SD command tracing */
tvendov 0:e1f465d87307 46
tvendov 0:e1f465d87307 47 //#define SD_BLOCK_DEVICE_ERROR_WOULD_BLOCK -5001 /*!< operation would block */
tvendov 0:e1f465d87307 48 #define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED -5002 /*!< unsupported operation */
tvendov 0:e1f465d87307 49 #define SD_BLOCK_DEVICE_ERROR_PARAMETER -5003 /*!< invalid parameter */
tvendov 0:e1f465d87307 50 #define SD_BLOCK_DEVICE_ERROR_NO_INIT -5004 /*!< uninitialized */
tvendov 0:e1f465d87307 51 #define SD_BLOCK_DEVICE_ERROR_NO_DEVICE -5005 /*!< device is missing or not connected */
tvendov 0:e1f465d87307 52 #define SD_BLOCK_DEVICE_ERROR_WRITE_PROTECTED -5006 /*!< write protected */
tvendov 0:e1f465d87307 53 #define SD_BLOCK_DEVICE_ERROR_UNUSABLE -5007 /*!< unusable card */
tvendov 0:e1f465d87307 54 #define SD_BLOCK_DEVICE_ERROR_NO_RESPONSE -5008 /*!< No response from device */
tvendov 0:e1f465d87307 55 #define SD_BLOCK_DEVICE_ERROR_CRC -5009 /*!< CRC error */
tvendov 0:e1f465d87307 56 #define SD_BLOCK_DEVICE_ERROR_ERASE -5010 /*!< Erase error: reset/sequence */
tvendov 0:e1f465d87307 57 #define SD_BLOCK_DEVICE_ERROR_WRITE -5011 /*!< SPI Write error: !SPI_DATA_ACCEPTED */
tvendov 0:e1f465d87307 58
tvendov 0:e1f465d87307 59 #define BLOCK_SIZE_HC 512 /*!< Block size supported for SD card is 512 bytes */
tvendov 0:e1f465d87307 60 #define WRITE_BL_PARTIAL 0 /*!< Partial block write - Not supported */
tvendov 0:e1f465d87307 61 //
tvendov 0:e1f465d87307 62 // Types
tvendov 0:e1f465d87307 63 #define SDCARD_NONE 0 /**< No card is present */
tvendov 0:e1f465d87307 64 #define SDCARD_V1 1 /**< v1.x Standard Capacity */
tvendov 0:e1f465d87307 65 #define SDCARD_V2 2 /**< v2.x Standard capacity SD card */
tvendov 0:e1f465d87307 66 #define SDCARD_V2HC 3 /**< v2.x High capacity SD card */
tvendov 0:e1f465d87307 67 #define CARD_UNKNOWN 4 /**< Unknown or unsupported card */
tvendov 0:e1f465d87307 68
tvendov 0:e1f465d87307 69 /* R3 Response : OCR Register */
tvendov 0:e1f465d87307 70 #define OCR_HCS_CCS (0x1 << 30)
tvendov 0:e1f465d87307 71 #define OCR_LOW_VOLTAGE (0x01 << 24)
tvendov 0:e1f465d87307 72 #define OCR_3_3V (0x1 << 20)
tvendov 0:e1f465d87307 73
tvendov 0:e1f465d87307 74 #define ESD_SECTOR_SIZE BLOCK_SIZE_HC
tvendov 0:e1f465d87307 75
tvendov 0:e1f465d87307 76 #define REG_CSD_HACK
tvendov 0:e1f465d87307 77
tvendov 0:e1f465d87307 78 #define CSD_CID_LENGTH 16
tvendov 0:e1f465d87307 79
tvendov 0:e1f465d87307 80 #define ARRAYSIZE(arr) (size_t)(sizeof(arr)/sizeof(arr[0]))
tvendov 0:e1f465d87307 81
tvendov 0:e1f465d87307 82 static uint32_t _sd_workbuf[SD_SIZE_OF_INIT/ sizeof(uint32_t)] __attribute__ ((section ("NC_BSS")));
tvendov 0:e1f465d87307 83 static uint32_t _sd_rw_buf[ESD_SECTOR_SIZE/sizeof(uint32_t)] __attribute__ ((section ("NC_BSS")));
tvendov 0:e1f465d87307 84 //static uint8_t _sectorBuff[ESD_SECTOR_SIZE] __attribute__ ((section ("NC_BSS")));
tvendov 0:e1f465d87307 85
tvendov 0:e1f465d87307 86
tvendov 0:e1f465d87307 87 static uint32_t ext_bits(unsigned char *data, size_t datasize, unsigned int msb, unsigned int lsb) {
tvendov 0:e1f465d87307 88 uint32_t bits = 0;
tvendov 0:e1f465d87307 89
tvendov 0:e1f465d87307 90 if ((datasize > 0) && (msb < (datasize<<3)))
tvendov 0:e1f465d87307 91 {
tvendov 0:e1f465d87307 92 uint32_t size = 1 + msb - lsb;
tvendov 0:e1f465d87307 93 for (uint32_t i = 0; i < size; i++)
tvendov 0:e1f465d87307 94 {
tvendov 0:e1f465d87307 95 uint32_t position = lsb + i;
tvendov 0:e1f465d87307 96 int32_t byte = (datasize-1) - (position >> 3);
tvendov 0:e1f465d87307 97 if( byte < 0 )
tvendov 0:e1f465d87307 98 break;
tvendov 0:e1f465d87307 99 uint32_t bit = position & 0x7;
tvendov 0:e1f465d87307 100 uint32_t value = (data[byte] >> bit) & 1;
tvendov 0:e1f465d87307 101 bits |= value << i;
tvendov 0:e1f465d87307 102 }
tvendov 0:e1f465d87307 103 }
tvendov 0:e1f465d87307 104 return bits;
tvendov 0:e1f465d87307 105 }
tvendov 0:e1f465d87307 106
tvendov 0:e1f465d87307 107 #if SDHI_DBG
tvendov 0:e1f465d87307 108 const sderr_t SDHIBlockDevice::_sd_error_msg[]= {
tvendov 0:e1f465d87307 109 {"SD_OK", 0}, /* OK */
tvendov 0:e1f465d87307 110 {"SD_ERR", -1}, /* general error */
tvendov 0:e1f465d87307 111 {"SD_ERR_WP", -2}, /* write protect error */
tvendov 0:e1f465d87307 112 {"SD_ERR_RO", -3}, /* read only error */
tvendov 0:e1f465d87307 113 {"SD_ERR_RES_TOE", -4}, /* response time out error */
tvendov 0:e1f465d87307 114 {"SD_ERR_CARD_TOE", -5}, /* card time out error */
tvendov 0:e1f465d87307 115 {"SD_ERR_END_BIT", -6}, /* end bit error */
tvendov 0:e1f465d87307 116 {"SD_ERR_CRC", -7}, /* CRC error */
tvendov 0:e1f465d87307 117 {"SD_ERR_CARD_RES", -8}, /* card response error */
tvendov 0:e1f465d87307 118 {"SD_ERR_HOST_TOE", -9}, /* host time out error */
tvendov 0:e1f465d87307 119 {"SD_ERR_CARD_ERASE", -10}, /* card erase error */
tvendov 0:e1f465d87307 120 {"SD_ERR_CARD_LOCK", -11}, /* card lock error */
tvendov 0:e1f465d87307 121 {"SD_ERR_CARD_UNLOCK", -12}, /* card unlock error */
tvendov 0:e1f465d87307 122 {"SD_ERR_HOST_CRC", -13}, /* host CRC error */
tvendov 0:e1f465d87307 123 {"SD_ERR_CARD_ECC", -14}, /* card internal ECC error */
tvendov 0:e1f465d87307 124 {"SD_ERR_CARD_CC", -15}, /* card internal error */
tvendov 0:e1f465d87307 125 {"SD_ERR_CARD_ERROR", -16}, /* unknown card error */
tvendov 0:e1f465d87307 126 {"SD_ERR_CARD_TYPE", -17}, /* non support card type */
tvendov 0:e1f465d87307 127 {"SD_ERR_NO_CARD", -18}, /* no card */
tvendov 0:e1f465d87307 128 {"SD_ERR_ILL_READ", -19}, /* illegal buffer read */
tvendov 0:e1f465d87307 129 {"SD_ERR_ILL_WRITE", -20}, /* illegal buffer write */
tvendov 0:e1f465d87307 130 {"SD_ERR_AKE_SEQ", -21}, /* the sequence of authentication process */
tvendov 0:e1f465d87307 131 {"SD_ERR_OVERWRITE", -22}, /* CID/CSD overwrite error */
tvendov 0:e1f465d87307 132 /* 23-29 */
tvendov 0:e1f465d87307 133 {"SD_ERR_CPU_IF", -30}, /* target CPU interface function error */
tvendov 0:e1f465d87307 134 {"SD_ERR_STOP", -31}, /* user stop */
tvendov 0:e1f465d87307 135 /* 32-49 */
tvendov 0:e1f465d87307 136 {"SD_ERR_CSD_VER", -50}, /* CSD register version error */
tvendov 0:e1f465d87307 137 {"SD_ERR_SCR_VER", -51}, /* SCR register version error */
tvendov 0:e1f465d87307 138 {"SD_ERR_FILE_FORMAT", -52}, /* CSD register file format error */
tvendov 0:e1f465d87307 139 {"SD_ERR_NOTSUP_CMD", -53}, /* not supported command */
tvendov 0:e1f465d87307 140 /* 54-59 */
tvendov 0:e1f465d87307 141 {"SD_ERR_ILL_FUNC", -60}, /* invalid function request error */
tvendov 0:e1f465d87307 142 {"SD_ERR_IO_VERIFY", -61}, /* direct write verify error */
tvendov 0:e1f465d87307 143 {"SD_ERR_IO_CAPAB", -62}, /* IO capability error */
tvendov 0:e1f465d87307 144 /* 63-69 */
tvendov 0:e1f465d87307 145 {"SD_ERR_IFCOND_VER", -70}, /* Interface condition version error */
tvendov 0:e1f465d87307 146 {"SD_ERR_IFCOND_VOLT", -71}, /* Interface condition voltage error */
tvendov 0:e1f465d87307 147 {"SD_ERR_IFCOND_ECHO", -72}, /* Interface condition echo back pattern error */
tvendov 0:e1f465d87307 148 /* 73-79 */
tvendov 0:e1f465d87307 149 {"SD_ERR_OUT_OF_RANGE", -80}, /* the argument was out of range */
tvendov 0:e1f465d87307 150 {"SD_ERR_ADDRESS_ERROR", -81},
tvendov 0:e1f465d87307 151 {"SD_ERR_BLOCK_LEN_ERROR", -82},
tvendov 0:e1f465d87307 152 {"SD_ERR_ILLEGAL_COMMAND", -83},
tvendov 0:e1f465d87307 153 {"SD_ERR_RESERVED_ERROR18", -84},
tvendov 0:e1f465d87307 154 {"SD_ERR_RESERVED_ERROR17", -85},
tvendov 0:e1f465d87307 155 {"SD_ERR_CMD_ERROR", -86},
tvendov 0:e1f465d87307 156 {"SD_ERR_CBSY_ERROR", -87},
tvendov 0:e1f465d87307 157 {"SD_ERR_NO_RESP_ERROR", -88},
tvendov 0:e1f465d87307 158 /* 89 */
tvendov 0:e1f465d87307 159 /* 90-95 */
tvendov 0:e1f465d87307 160 {"SD_ERR_ERROR", -96},
tvendov 0:e1f465d87307 161 {"SD_ERR_FUNCTION_NUMBER", -97},
tvendov 0:e1f465d87307 162 {"SD_ERR_COM_CRC_ERROR", -98},
tvendov 0:e1f465d87307 163 {"SD_ERR_INTERNAL", -99}, /* driver software internal error */
tvendov 0:e1f465d87307 164 };
tvendov 0:e1f465d87307 165
tvendov 0:e1f465d87307 166 #endif
tvendov 0:e1f465d87307 167
tvendov 0:e1f465d87307 168 SDHIBlockDevice::SDHIBlockDevice(uint32_t sdport)
tvendov 0:e1f465d87307 169 {
tvendov 0:e1f465d87307 170 _init_ref_count = 0;
tvendov 0:e1f465d87307 171 Initialize(sdport);
tvendov 0:e1f465d87307 172 // for( uint32_t n=0; n < ARRAYSIZE(_sd_error_msg); n++ )
tvendov 0:e1f465d87307 173 // {
tvendov 0:e1f465d87307 174 // _sd_err_map[_sd_error_msg[n].errorno] = _sd_error_msg[n].msg;
tvendov 0:e1f465d87307 175 // }
tvendov 0:e1f465d87307 176 //
tvendov 0:e1f465d87307 177 // if ( sdport < SDHI_COUNT )
tvendov 0:e1f465d87307 178 // {
tvendov 0:e1f465d87307 179 // _sd_channel = sdport;
tvendov 0:e1f465d87307 180 // _regbase = (uint32_t)((_sd_channel == 0ul) ? &SDHI0 : &SDHI1);
tvendov 0:e1f465d87307 181 //
tvendov 0:e1f465d87307 182 // _card_type = SDCARD_NONE;
tvendov 0:e1f465d87307 183 //
tvendov 0:e1f465d87307 184 // // Set default to 100kHz for initialisation and 1MHz for data transfer
tvendov 0:e1f465d87307 185 // _init_sck = 100000;
tvendov 0:e1f465d87307 186 // _transfer_sck = hz;
tvendov 0:e1f465d87307 187 //
tvendov 0:e1f465d87307 188 // // Only HC block size is supported.
tvendov 0:e1f465d87307 189 // _block_size = BLOCK_SIZE_HC;
tvendov 0:e1f465d87307 190 // _erase_size = BLOCK_SIZE_HC;
tvendov 0:e1f465d87307 191 // _mtx_lock = false;
tvendov 0:e1f465d87307 192 //
tvendov 0:e1f465d87307 193 // int32_t sd_err = sd_init( _sd_channel, _regbase, &_sd_workbuf[0], SD_CD_SOCKET );
tvendov 0:e1f465d87307 194 // if ( sd_err != SD_OK)
tvendov 0:e1f465d87307 195 // {
tvendov 0:e1f465d87307 196 // _error(sd_err);
tvendov 0:e1f465d87307 197 //// return SD_BLOCK_DEVICE_ERROR_NO_DEVICE;
tvendov 0:e1f465d87307 198 // }
tvendov 0:e1f465d87307 199 //
tvendov 0:e1f465d87307 200 // void *rw_buff = (void *)&_sd_rw_buf[0];
tvendov 0:e1f465d87307 201 //
tvendov 0:e1f465d87307 202 // sd_err = sd_set_buffer( _sd_channel, rw_buff, (unsigned long)sizeof(_sd_rw_buf) );
tvendov 0:e1f465d87307 203 // if ( sd_err != SD_OK )
tvendov 0:e1f465d87307 204 // {
tvendov 0:e1f465d87307 205 // _error(sd_err);
tvendov 0:e1f465d87307 206 // }
tvendov 0:e1f465d87307 207 //
tvendov 0:e1f465d87307 208 // }
tvendov 0:e1f465d87307 209 // else
tvendov 0:e1f465d87307 210 // {
tvendov 0:e1f465d87307 211 // _sd_channel = -1;
tvendov 0:e1f465d87307 212 // _regbase = 0ul;
tvendov 0:e1f465d87307 213 //
tvendov 0:e1f465d87307 214 // }
tvendov 0:e1f465d87307 215 }
tvendov 0:e1f465d87307 216
tvendov 0:e1f465d87307 217 SDHIBlockDevice::SDHIBlockDevice(PinName sd_CLK, PinName sd_CMD, PinName sd_CD, PinName sd_WP,
tvendov 0:e1f465d87307 218 PinName sd_D0, PinName sd_D1, PinName sd_D2, PinName sd_D3 )
tvendov 0:e1f465d87307 219 {
tvendov 0:e1f465d87307 220 _init_ref_count = 0;
tvendov 0:e1f465d87307 221
tvendov 0:e1f465d87307 222 uint32_t sd_wp = pinmap_peripheral(sd_WP, PinMap_SDHI_WP);
tvendov 0:e1f465d87307 223 uint32_t sd_cd = pinmap_peripheral(sd_CD, PinMap_SDHI_CD);
tvendov 0:e1f465d87307 224 uint32_t sd_clk = pinmap_peripheral(sd_CLK, PinMap_SDHI_CLK);
tvendov 0:e1f465d87307 225 uint32_t sd_cmd = pinmap_peripheral(sd_CMD, PinMap_SDHI_CMD);
tvendov 0:e1f465d87307 226 uint32_t sd_d0 = pinmap_peripheral(sd_D0, PinMap_SDHI_D0);
tvendov 0:e1f465d87307 227 uint32_t sd_d1 = pinmap_peripheral(sd_D1, PinMap_SDHI_D1);
tvendov 0:e1f465d87307 228 uint32_t sd_d2 = pinmap_peripheral(sd_D2, PinMap_SDHI_D2);
tvendov 0:e1f465d87307 229 uint32_t sd_d3 = pinmap_peripheral(sd_D3, PinMap_SDHI_D3);
tvendov 0:e1f465d87307 230
tvendov 0:e1f465d87307 231 uint32_t sd_cntl_1 = pinmap_merge(sd_wp, sd_cd);
tvendov 0:e1f465d87307 232 uint32_t sd_cntl_2 = pinmap_merge(sd_clk, sd_cmd);
tvendov 0:e1f465d87307 233 uint32_t sd_cntl = pinmap_merge(sd_cntl_1, sd_cntl_2);
tvendov 0:e1f465d87307 234
tvendov 0:e1f465d87307 235 uint32_t sd_data_1 = pinmap_merge(sd_d0, sd_d1);
tvendov 0:e1f465d87307 236 uint32_t sd_data_2 = pinmap_merge(sd_d2, sd_d3);
tvendov 0:e1f465d87307 237 uint32_t sd_data = pinmap_merge(sd_data_1, sd_data_2);
tvendov 0:e1f465d87307 238
tvendov 0:e1f465d87307 239 uint32_t sdport = pinmap_merge(sd_cntl, sd_data);
tvendov 0:e1f465d87307 240
tvendov 0:e1f465d87307 241 MBED_ASSERT((int)sdport != NC);
tvendov 0:e1f465d87307 242
tvendov 0:e1f465d87307 243 Initialize(sdport);
tvendov 0:e1f465d87307 244 }
tvendov 0:e1f465d87307 245
tvendov 0:e1f465d87307 246
tvendov 0:e1f465d87307 247
tvendov 0:e1f465d87307 248 SDHIBlockDevice::~SDHIBlockDevice()
tvendov 0:e1f465d87307 249 {
tvendov 0:e1f465d87307 250 if (_is_initialized) {
tvendov 0:e1f465d87307 251 deinit();
tvendov 0:e1f465d87307 252 }
tvendov 0:e1f465d87307 253 }
tvendov 0:e1f465d87307 254
tvendov 0:e1f465d87307 255 void SDHIBlockDevice::Initialize( uint32_t sdport )
tvendov 0:e1f465d87307 256 {
tvendov 0:e1f465d87307 257 #if SDHI_DBG
tvendov 0:e1f465d87307 258 for( uint32_t n=0; n < ARRAYSIZE(_sd_error_msg); n++ )
tvendov 0:e1f465d87307 259 {
tvendov 0:e1f465d87307 260 _sd_err_map[_sd_error_msg[n].errorno] = _sd_error_msg[n].msg;
tvendov 0:e1f465d87307 261 }
tvendov 0:e1f465d87307 262 #endif
tvendov 0:e1f465d87307 263 _sectors = 0;
tvendov 0:e1f465d87307 264 _is_initialized = 0;
tvendov 0:e1f465d87307 265 if ( sdport < SDHI_COUNT )
tvendov 0:e1f465d87307 266 {
tvendov 0:e1f465d87307 267 _sd_channel = sdport;
tvendov 0:e1f465d87307 268 _regbase = (uint32_t)((_sd_channel == SDHI_0) ? &SDHI0 : &SDHI1);
tvendov 0:e1f465d87307 269
tvendov 0:e1f465d87307 270 _card_type = SDCARD_NONE;
tvendov 0:e1f465d87307 271
tvendov 0:e1f465d87307 272 // Only HC block size is supported.
tvendov 0:e1f465d87307 273 _block_size = BLOCK_SIZE_HC;
tvendov 0:e1f465d87307 274 _erase_size = BLOCK_SIZE_HC;
tvendov 0:e1f465d87307 275
tvendov 0:e1f465d87307 276 int32_t sd_err = sd_init( _sd_channel, _regbase, &_sd_workbuf[0], SD_CD_SOCKET );
tvendov 0:e1f465d87307 277 if ( sd_err != SD_OK)
tvendov 0:e1f465d87307 278 {
tvendov 0:e1f465d87307 279 _error(sd_err);
tvendov 0:e1f465d87307 280 }
tvendov 0:e1f465d87307 281
tvendov 0:e1f465d87307 282 void *rw_buff = (void *)&_sd_rw_buf[0];
tvendov 0:e1f465d87307 283
tvendov 0:e1f465d87307 284 sd_err = sd_set_buffer( _sd_channel, rw_buff, (unsigned long)sizeof(_sd_rw_buf) );
tvendov 0:e1f465d87307 285 if ( sd_err != SD_OK )
tvendov 0:e1f465d87307 286 {
tvendov 0:e1f465d87307 287 _error(sd_err);
tvendov 0:e1f465d87307 288 }
tvendov 0:e1f465d87307 289 }
tvendov 0:e1f465d87307 290 else
tvendov 0:e1f465d87307 291 {
tvendov 0:e1f465d87307 292 _sd_channel = -1;
tvendov 0:e1f465d87307 293 _regbase = 0ul;
tvendov 0:e1f465d87307 294
tvendov 0:e1f465d87307 295 }
tvendov 0:e1f465d87307 296
tvendov 0:e1f465d87307 297 }
tvendov 0:e1f465d87307 298
tvendov 0:e1f465d87307 299 int SDHIBlockDevice::_initialise_card()
tvendov 0:e1f465d87307 300 {
tvendov 0:e1f465d87307 301 // Detail debugging is for commands
tvendov 0:e1f465d87307 302 _dbg = SDHI_DBG ? SD_CMD_TRACE : 0;
tvendov 0:e1f465d87307 303
tvendov 0:e1f465d87307 304 int32_t status = BD_ERROR_OK;
tvendov 0:e1f465d87307 305
tvendov 0:e1f465d87307 306 int32_t sd_err;
tvendov 0:e1f465d87307 307
tvendov 0:e1f465d87307 308 if( _regbase )
tvendov 0:e1f465d87307 309 {
tvendov 0:e1f465d87307 310 sd_err = sd_mount(_sd_channel, SDCFG_DRIVER_MODE, SD_VOLT_3_3);
tvendov 0:e1f465d87307 311
tvendov 0:e1f465d87307 312 if ( sd_err != SD_OK )
tvendov 0:e1f465d87307 313 {
tvendov 0:e1f465d87307 314 _error(sd_err);
tvendov 0:e1f465d87307 315 return SD_BLOCK_DEVICE_ERROR_UNUSABLE;
tvendov 0:e1f465d87307 316 }
tvendov 0:e1f465d87307 317 uint8_t card_type;
tvendov 0:e1f465d87307 318 uint8_t card_speed;
tvendov 0:e1f465d87307 319 uint8_t card_capa;
tvendov 0:e1f465d87307 320
tvendov 0:e1f465d87307 321 sd_err=sd_get_type(_sd_channel, &card_type, &card_speed, &card_capa);
tvendov 0:e1f465d87307 322 if( sd_err != SD_OK)
tvendov 0:e1f465d87307 323 {
tvendov 0:e1f465d87307 324 return _error(sd_err);
tvendov 0:e1f465d87307 325 }
tvendov 0:e1f465d87307 326
tvendov 0:e1f465d87307 327 if( (card_type & SD_MEDIA_SD) != SD_MEDIA_SD )
tvendov 0:e1f465d87307 328 {
tvendov 0:e1f465d87307 329 return SD_BLOCK_DEVICE_ERROR_UNUSABLE;
tvendov 0:e1f465d87307 330 }
tvendov 0:e1f465d87307 331
tvendov 0:e1f465d87307 332 uint32_t regOCR;
tvendov 0:e1f465d87307 333 uint8_t regCID[CSD_CID_LENGTH];
tvendov 0:e1f465d87307 334 uint8_t regCSD[CSD_CID_LENGTH];
tvendov 0:e1f465d87307 335 uint8_t regDSR[2];
tvendov 0:e1f465d87307 336 uint8_t regSCR[8];
tvendov 0:e1f465d87307 337
tvendov 0:e1f465d87307 338 sd_err = sd_get_reg(_sd_channel, (uint8_t *)&regOCR, regCID, regCSD, regDSR, regSCR);
tvendov 0:e1f465d87307 339 if (sd_err != SD_OK)
tvendov 0:e1f465d87307 340 {
tvendov 0:e1f465d87307 341 return _error(sd_err);
tvendov 0:e1f465d87307 342 }
tvendov 0:e1f465d87307 343 regOCR = __REV(regOCR);
tvendov 0:e1f465d87307 344 // Check if card supports voltage range: 3.3V
tvendov 0:e1f465d87307 345 if (!(regOCR & OCR_3_3V)) {
tvendov 0:e1f465d87307 346 _card_type = CARD_UNKNOWN;
tvendov 0:e1f465d87307 347 status = SD_BLOCK_DEVICE_ERROR_UNUSABLE;
tvendov 0:e1f465d87307 348 return status;
tvendov 0:e1f465d87307 349 }
tvendov 0:e1f465d87307 350 }
tvendov 0:e1f465d87307 351 else
tvendov 0:e1f465d87307 352 {
tvendov 0:e1f465d87307 353 status = SD_BLOCK_DEVICE_ERROR_NO_INIT;
tvendov 0:e1f465d87307 354 }
tvendov 0:e1f465d87307 355
tvendov 0:e1f465d87307 356 return status;
tvendov 0:e1f465d87307 357 }
tvendov 0:e1f465d87307 358
tvendov 0:e1f465d87307 359
tvendov 0:e1f465d87307 360 int SDHIBlockDevice::init()
tvendov 0:e1f465d87307 361 {
tvendov 0:e1f465d87307 362 vMutex l(&_mutex);
tvendov 0:e1f465d87307 363
tvendov 0:e1f465d87307 364 if(!_is_initialized)
tvendov 0:e1f465d87307 365 _init_ref_count = 0;
tvendov 0:e1f465d87307 366
tvendov 0:e1f465d87307 367 _init_ref_count++;
tvendov 0:e1f465d87307 368
tvendov 0:e1f465d87307 369 if(_init_ref_count != 1)
tvendov 0:e1f465d87307 370 return BD_ERROR_OK;
tvendov 0:e1f465d87307 371
tvendov 0:e1f465d87307 372 int err = _initialise_card();
tvendov 0:e1f465d87307 373 _is_initialized = (err == BD_ERROR_OK);
tvendov 0:e1f465d87307 374 if (!_is_initialized) {
tvendov 0:e1f465d87307 375 debug_if(SDHI_DBG, "Fail to initialize card\n");
tvendov 0:e1f465d87307 376 return err;
tvendov 0:e1f465d87307 377 }
tvendov 0:e1f465d87307 378 debug_if(SDHI_DBG, "init card = %d\r\n", _is_initialized);
tvendov 0:e1f465d87307 379 _sectors = _sd_sectors();
tvendov 0:e1f465d87307 380
tvendov 0:e1f465d87307 381 if (0 == _sectors) {
tvendov 0:e1f465d87307 382 return BD_ERROR_DEVICE_ERROR;
tvendov 0:e1f465d87307 383 }
tvendov 0:e1f465d87307 384
tvendov 0:e1f465d87307 385 return BD_ERROR_OK;
tvendov 0:e1f465d87307 386 }
tvendov 0:e1f465d87307 387
tvendov 0:e1f465d87307 388 int SDHIBlockDevice::deinit()
tvendov 0:e1f465d87307 389 {
tvendov 0:e1f465d87307 390 vMutex l(&_mutex);
tvendov 0:e1f465d87307 391
tvendov 0:e1f465d87307 392 if(!_is_initialized)
tvendov 0:e1f465d87307 393 _init_ref_count = 0;
tvendov 0:e1f465d87307 394
tvendov 0:e1f465d87307 395 _init_ref_count--; //!!!
tvendov 0:e1f465d87307 396
tvendov 0:e1f465d87307 397 if(_init_ref_count)
tvendov 0:e1f465d87307 398 return BD_ERROR_OK;
tvendov 0:e1f465d87307 399
tvendov 0:e1f465d87307 400 _sectors = 0;
tvendov 0:e1f465d87307 401 if ( _is_initialized )
tvendov 0:e1f465d87307 402 {
tvendov 0:e1f465d87307 403 sd_unmount(_sd_channel);
tvendov 0:e1f465d87307 404 debug_if(SDHI_DBG, "card deinited![%d]\r\n", _is_initialized);
tvendov 0:e1f465d87307 405 _is_initialized = false;
tvendov 0:e1f465d87307 406 }
tvendov 0:e1f465d87307 407 return 0;
tvendov 0:e1f465d87307 408 }
tvendov 0:e1f465d87307 409
tvendov 0:e1f465d87307 410
tvendov 0:e1f465d87307 411 int SDHIBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
tvendov 0:e1f465d87307 412 {
tvendov 0:e1f465d87307 413 if (!is_valid_program(addr, size)) {
tvendov 0:e1f465d87307 414 return SD_BLOCK_DEVICE_ERROR_PARAMETER;
tvendov 0:e1f465d87307 415 }
tvendov 0:e1f465d87307 416
tvendov 0:e1f465d87307 417 vMutex l(&_mutex);
tvendov 0:e1f465d87307 418
tvendov 0:e1f465d87307 419 if (!_is_initialized) {
tvendov 0:e1f465d87307 420 return SD_BLOCK_DEVICE_ERROR_NO_INIT;
tvendov 0:e1f465d87307 421 }
tvendov 0:e1f465d87307 422
tvendov 0:e1f465d87307 423 uint8_t* buffer = const_cast<uint8_t*>(static_cast<const uint8_t*>(b));
tvendov 0:e1f465d87307 424 int status = BD_ERROR_OK;
tvendov 0:e1f465d87307 425
tvendov 0:e1f465d87307 426 // Get block count
tvendov 0:e1f465d87307 427 bd_addr_t blockCnt = size / _block_size;
tvendov 0:e1f465d87307 428
tvendov 0:e1f465d87307 429 addr = addr / _block_size;
tvendov 0:e1f465d87307 430
tvendov 0:e1f465d87307 431 // Send command to perform write operation
tvendov 0:e1f465d87307 432 int32_t sd_err = sd_write_sect( _sd_channel, buffer, addr, blockCnt, SD_WRITE_OVERWRITE);
tvendov 0:e1f465d87307 433
tvendov 0:e1f465d87307 434 if (sd_err != SD_OK)
tvendov 0:e1f465d87307 435 {
tvendov 0:e1f465d87307 436 _error(sd_err);
tvendov 0:e1f465d87307 437 status = SD_BLOCK_DEVICE_ERROR_WRITE;
tvendov 0:e1f465d87307 438 }
tvendov 0:e1f465d87307 439
tvendov 0:e1f465d87307 440 return status;
tvendov 0:e1f465d87307 441 }
tvendov 0:e1f465d87307 442
tvendov 0:e1f465d87307 443 int SDHIBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
tvendov 0:e1f465d87307 444 {
tvendov 0:e1f465d87307 445 if (!is_valid_read(addr, size)) {
tvendov 0:e1f465d87307 446 return SD_BLOCK_DEVICE_ERROR_PARAMETER;
tvendov 0:e1f465d87307 447 }
tvendov 0:e1f465d87307 448
tvendov 0:e1f465d87307 449 vMutex l(&_mutex);
tvendov 0:e1f465d87307 450
tvendov 0:e1f465d87307 451 if (!_is_initialized) {
tvendov 0:e1f465d87307 452 return SD_BLOCK_DEVICE_ERROR_NO_INIT;
tvendov 0:e1f465d87307 453 }
tvendov 0:e1f465d87307 454 uint8_t *buffer = static_cast<uint8_t*>(b);
tvendov 0:e1f465d87307 455 int status = BD_ERROR_OK;
tvendov 0:e1f465d87307 456 bd_addr_t blockCnt = size / _block_size;
tvendov 0:e1f465d87307 457
tvendov 0:e1f465d87307 458 addr = addr / _block_size;
tvendov 0:e1f465d87307 459
tvendov 0:e1f465d87307 460 int32_t sd_err = sd_read_sect(_sd_channel, buffer, addr, blockCnt);
tvendov 0:e1f465d87307 461
tvendov 0:e1f465d87307 462 if (sd_err != SD_OK)
tvendov 0:e1f465d87307 463 {
tvendov 0:e1f465d87307 464 _error(sd_err);
tvendov 0:e1f465d87307 465 status = SD_BLOCK_DEVICE_ERROR_NO_RESPONSE;
tvendov 0:e1f465d87307 466 }
tvendov 0:e1f465d87307 467
tvendov 0:e1f465d87307 468 return status;
tvendov 0:e1f465d87307 469 }
tvendov 0:e1f465d87307 470
tvendov 0:e1f465d87307 471 int SDHIBlockDevice::erase(bd_addr_t addr, bd_size_t size)
tvendov 0:e1f465d87307 472 {
tvendov 0:e1f465d87307 473 return 0;
tvendov 0:e1f465d87307 474 }
tvendov 0:e1f465d87307 475
tvendov 0:e1f465d87307 476
tvendov 0:e1f465d87307 477 bool SDHIBlockDevice::_is_valid_trim(bd_addr_t addr, bd_size_t size)
tvendov 0:e1f465d87307 478 {
tvendov 0:e1f465d87307 479 return (
tvendov 0:e1f465d87307 480 addr % _erase_size == 0 &&
tvendov 0:e1f465d87307 481 size % _erase_size == 0 &&
tvendov 0:e1f465d87307 482 addr + size <= this->size());
tvendov 0:e1f465d87307 483 }
tvendov 0:e1f465d87307 484
tvendov 0:e1f465d87307 485 int SDHIBlockDevice::trim(bd_addr_t addr, bd_size_t size)
tvendov 0:e1f465d87307 486 {
tvendov 0:e1f465d87307 487 if (!_is_valid_trim(addr, size)) {
tvendov 0:e1f465d87307 488 return SD_BLOCK_DEVICE_ERROR_PARAMETER;
tvendov 0:e1f465d87307 489 }
tvendov 0:e1f465d87307 490
tvendov 0:e1f465d87307 491 vMutex l(&_mutex);
tvendov 0:e1f465d87307 492
tvendov 0:e1f465d87307 493 if (!_is_initialized) {
tvendov 0:e1f465d87307 494 return SD_BLOCK_DEVICE_ERROR_NO_INIT;
tvendov 0:e1f465d87307 495 }
tvendov 0:e1f465d87307 496 int status = BD_ERROR_OK;
tvendov 0:e1f465d87307 497
tvendov 0:e1f465d87307 498 size -= _block_size;
tvendov 0:e1f465d87307 499 // SDSC Card (CCS=0) uses byte unit address
tvendov 0:e1f465d87307 500 // SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit)
tvendov 0:e1f465d87307 501 if (SDCARD_V2HC == _card_type) {
tvendov 0:e1f465d87307 502 size = size / _block_size;
tvendov 0:e1f465d87307 503 addr = addr / _block_size;
tvendov 0:e1f465d87307 504 }
tvendov 0:e1f465d87307 505
tvendov 0:e1f465d87307 506 return status;
tvendov 0:e1f465d87307 507 }
tvendov 0:e1f465d87307 508
tvendov 0:e1f465d87307 509 bd_size_t SDHIBlockDevice::get_read_size() const
tvendov 0:e1f465d87307 510 {
tvendov 0:e1f465d87307 511 return _block_size;
tvendov 0:e1f465d87307 512 }
tvendov 0:e1f465d87307 513
tvendov 0:e1f465d87307 514 bd_size_t SDHIBlockDevice::get_program_size() const
tvendov 0:e1f465d87307 515 {
tvendov 0:e1f465d87307 516 return _block_size;
tvendov 0:e1f465d87307 517 }
tvendov 0:e1f465d87307 518
tvendov 0:e1f465d87307 519 /*
tvendov 0:e1f465d87307 520 bd_size_t SDHIBlockDevice::get_erase_size() const
tvendov 0:e1f465d87307 521 {
tvendov 0:e1f465d87307 522 return _block_size;
tvendov 0:e1f465d87307 523 }
tvendov 0:e1f465d87307 524 */
tvendov 0:e1f465d87307 525
tvendov 0:e1f465d87307 526 bd_size_t SDHIBlockDevice::size() const
tvendov 0:e1f465d87307 527 {
tvendov 0:e1f465d87307 528 return _block_size*_sectors;
tvendov 0:e1f465d87307 529 }
tvendov 0:e1f465d87307 530
tvendov 0:e1f465d87307 531 void SDHIBlockDevice::debug(bool dbg)
tvendov 0:e1f465d87307 532 {
tvendov 0:e1f465d87307 533 _dbg = dbg;
tvendov 0:e1f465d87307 534 }
tvendov 0:e1f465d87307 535
tvendov 0:e1f465d87307 536 const char *SDHIBlockDevice::get_type() const
tvendov 0:e1f465d87307 537 {
tvendov 0:e1f465d87307 538 return "RZ-SDHI";
tvendov 0:e1f465d87307 539 }
tvendov 0:e1f465d87307 540
tvendov 0:e1f465d87307 541 // PRIVATE FUNCTIONS
tvendov 0:e1f465d87307 542
tvendov 0:e1f465d87307 543 bd_size_t SDHIBlockDevice::_sd_sectors() {
tvendov 0:e1f465d87307 544 uint32_t c_size, c_size_mult, read_bl_len;
tvendov 0:e1f465d87307 545 uint32_t block_len, mult, blocknr;
tvendov 0:e1f465d87307 546 uint32_t hc_c_size;
tvendov 0:e1f465d87307 547 bd_size_t blocks = 0, capacity = 0;
tvendov 0:e1f465d87307 548 uint8_t csd[CSD_CID_LENGTH];
tvendov 0:e1f465d87307 549
tvendov 0:e1f465d87307 550 int32_t sd_err = sd_get_reg(_sd_channel, NULL, NULL, csd, NULL, NULL);
tvendov 0:e1f465d87307 551 if ( sd_err != SD_OK )
tvendov 0:e1f465d87307 552 {
tvendov 0:e1f465d87307 553 debug_if(SDHI_DBG, "Couldn't read csd response from disk\r\n");
tvendov 0:e1f465d87307 554 _error(sd_err);
tvendov 0:e1f465d87307 555 return 0;
tvendov 0:e1f465d87307 556 }
tvendov 0:e1f465d87307 557 for(int i = 0; i < (CSD_CID_LENGTH-1); i++)
tvendov 0:e1f465d87307 558 {
tvendov 0:e1f465d87307 559 csd[i] = csd[i+1];
tvendov 0:e1f465d87307 560 }
tvendov 0:e1f465d87307 561
tvendov 0:e1f465d87307 562 debug_if(SDHI_DBG,"CSD is ");
tvendov 0:e1f465d87307 563 for(unsigned int i = 0; i < sizeof(csd); i++)
tvendov 0:e1f465d87307 564 {
tvendov 0:e1f465d87307 565 debug_if(SDHI_DBG, "%02X ", csd[i]);
tvendov 0:e1f465d87307 566 }
tvendov 0:e1f465d87307 567 debug_if(SDHI_DBG,"\r\n");
tvendov 0:e1f465d87307 568
tvendov 0:e1f465d87307 569 // csd_structure : csd[127:126]
tvendov 0:e1f465d87307 570 int csd_structure = ext_bits(csd, CSD_CID_LENGTH, 127, 126);
tvendov 0:e1f465d87307 571 switch (csd_structure) {
tvendov 0:e1f465d87307 572 case 0:
tvendov 0:e1f465d87307 573 c_size = ext_bits(csd, CSD_CID_LENGTH, 73, 62); // c_size : csd[73:62]
tvendov 0:e1f465d87307 574 c_size_mult = ext_bits(csd, CSD_CID_LENGTH, 49, 47); // c_size_mult : csd[49:47]
tvendov 0:e1f465d87307 575 read_bl_len = ext_bits(csd, CSD_CID_LENGTH, 83, 80); // read_bl_len : csd[83:80] - the *maximum* read block length
tvendov 0:e1f465d87307 576 block_len = 1 << read_bl_len; // BLOCK_LEN = 2^READ_BL_LEN
tvendov 0:e1f465d87307 577 mult = 1 << (c_size_mult + 2); // MULT = 2^C_SIZE_MULT+2 (C_SIZE_MULT < 8)
tvendov 0:e1f465d87307 578 blocknr = (c_size + 1) * mult; // BLOCKNR = (C_SIZE+1) * MULT
tvendov 0:e1f465d87307 579 capacity = blocknr * block_len; // memory capacity = BLOCKNR * BLOCK_LEN
tvendov 0:e1f465d87307 580 blocks = capacity / _block_size;
tvendov 0:e1f465d87307 581 debug_if(SDHI_DBG, "Standard Capacity: c_size: %lu\r\n", c_size);
tvendov 0:e1f465d87307 582 debug_if(SDHI_DBG, "Sectors: 0x%llx : %llu\r\n", blocks, blocks);
tvendov 0:e1f465d87307 583 debug_if(SDHI_DBG, "Capacity: 0x%llx : %llu MB\r\n", capacity, (capacity/(1024U*1024U)));
tvendov 0:e1f465d87307 584
tvendov 0:e1f465d87307 585 // ERASE_BLK_EN = 1: Erase in multiple of 512 bytes supported
tvendov 0:e1f465d87307 586 if (ext_bits(csd, CSD_CID_LENGTH, 46, 46)) {
tvendov 0:e1f465d87307 587 _erase_size = BLOCK_SIZE_HC;
tvendov 0:e1f465d87307 588 } else {
tvendov 0:e1f465d87307 589 // ERASE_BLK_EN = 1: Erase in multiple of SECTOR_SIZE supported
tvendov 0:e1f465d87307 590 _erase_size = BLOCK_SIZE_HC * (ext_bits(csd, CSD_CID_LENGTH, 45, 39) + 1);
tvendov 0:e1f465d87307 591 }
tvendov 0:e1f465d87307 592 break;
tvendov 0:e1f465d87307 593
tvendov 0:e1f465d87307 594 case 1:
tvendov 0:e1f465d87307 595 hc_c_size = ext_bits(csd, CSD_CID_LENGTH, 69, 48); // device size : C_SIZE : [69:48]
tvendov 0:e1f465d87307 596 blocks = (hc_c_size+1) << 10; // block count = C_SIZE+1) * 1K byte (512B is block size)
tvendov 0:e1f465d87307 597 debug_if(SDHI_DBG, "SDHC/SDXC Card: hc_c_size: %lu\r\n", hc_c_size);
tvendov 0:e1f465d87307 598 debug_if(SDHI_DBG, "Sectors: 0x%llx : %llu\r\n", blocks, blocks);
tvendov 0:e1f465d87307 599 debug_if(SDHI_DBG, "Capacity: %llu MB\r\n", (blocks/(2048U)));
tvendov 0:e1f465d87307 600 // ERASE_BLK_EN is fixed to 1, which means host can erase one or multiple of 512 bytes.
tvendov 0:e1f465d87307 601 _erase_size = BLOCK_SIZE_HC;
tvendov 0:e1f465d87307 602 break;
tvendov 0:e1f465d87307 603
tvendov 0:e1f465d87307 604 default:
tvendov 0:e1f465d87307 605 debug_if(SDHI_DBG, "CSD struct unsupported\r\n");
tvendov 0:e1f465d87307 606 return 0;
tvendov 0:e1f465d87307 607 };
tvendov 0:e1f465d87307 608 return blocks;
tvendov 0:e1f465d87307 609 }
tvendov 0:e1f465d87307 610
tvendov 0:e1f465d87307 611 const char * SDHIBlockDevice::_sderr_msg(int32_t errorno)
tvendov 0:e1f465d87307 612 {
tvendov 0:e1f465d87307 613 #if SDHI_DBG
tvendov 0:e1f465d87307 614 map<int32_t, const char *>::iterator it = _sd_err_map.find(errorno);
tvendov 0:e1f465d87307 615
tvendov 0:e1f465d87307 616 if ( it != _sd_err_map.end() )
tvendov 0:e1f465d87307 617 return it->second;
tvendov 0:e1f465d87307 618 else
tvendov 0:e1f465d87307 619 return "SD UNKNWON ERROR NO\n";
tvendov 0:e1f465d87307 620 #else
tvendov 0:e1f465d87307 621 return (const char *)0;
tvendov 0:e1f465d87307 622 #endif
tvendov 0:e1f465d87307 623 }
tvendov 0:e1f465d87307 624
tvendov 0:e1f465d87307 625 int SDHIBlockDevice::_error(int32_t errcode)
tvendov 0:e1f465d87307 626 {
tvendov 0:e1f465d87307 627 int32_t sd_err = errcode;
tvendov 0:e1f465d87307 628 if(_sd_channel >= 0 && _sd_channel < SDHI_COUNT )
tvendov 0:e1f465d87307 629 {
tvendov 0:e1f465d87307 630 int32_t err = sd_get_error(_sd_channel);
tvendov 0:e1f465d87307 631 if ( err != SD_OK)
tvendov 0:e1f465d87307 632 sd_err = err;
tvendov 0:e1f465d87307 633 debug_if(SDHI_DBG, _sderr_msg(sd_err));
tvendov 0:e1f465d87307 634 }
tvendov 0:e1f465d87307 635 return sd_err;
tvendov 0:e1f465d87307 636 }
tvendov 0:e1f465d87307 637
tvendov 0:e1f465d87307 638 #endif