sd_spi.c
Go to the documentation of this file.
00001 00038 #include "hw/hw_sd.h" 00039 #include "cfg/cfg_sd.h" 00040 00041 #include <io/kfile.h> 00042 #include <io/kblock.h> 00043 00044 #include <drv/sd.h> 00045 #include <drv/timer.h> 00046 00047 #include <fs/fat.h> 00048 00049 #define LOG_LEVEL SD_LOG_LEVEL 00050 #define LOG_FORMAT SD_LOG_FORMAT 00051 #include <cfg/log.h> 00052 #include <cpu/power.h> 00053 00054 #include <string.h> /* memset */ 00055 00056 00057 struct SdHardware 00058 { 00059 uint16_t tranfer_len; 00060 }; 00061 00062 00063 #define SD_IN_IDLE 0x01 00064 #define SD_STARTTOKEN 0xFE 00065 00066 #define TIMEOUT_NAC 16384 00067 #define SD_BUSY_TIMEOUT ms_to_ticks(200) 00068 00069 static bool sd_select(Sd *sd, bool state) 00070 { 00071 KFile *fd = sd->ch; 00072 00073 if (state) 00074 { 00075 SD_CS_ON(); 00076 00077 ticks_t start = timer_clock(); 00078 do 00079 { 00080 if (kfile_getc(fd) == 0xff) 00081 return true; 00082 00083 cpu_relax(); 00084 } 00085 while (timer_clock() - start < SD_BUSY_TIMEOUT); 00086 00087 SD_CS_OFF(); 00088 LOG_ERR("sd_select timeout\n"); 00089 return false; 00090 } 00091 else 00092 { 00093 kfile_putc(0xff, fd); 00094 kfile_flush(fd); 00095 SD_CS_OFF(); 00096 return true; 00097 } 00098 } 00099 00100 static int16_t sd_waitR1(Sd *sd) 00101 { 00102 uint8_t datain; 00103 00104 for (int i = 0; i < TIMEOUT_NAC; i++) 00105 { 00106 datain = kfile_getc(sd->ch); 00107 if (datain != 0xff) 00108 return (int16_t)datain; 00109 } 00110 LOG_ERR("Timeout waiting R1\n"); 00111 return EOF; 00112 } 00113 00114 static int16_t sd_sendCommand(Sd *sd, uint8_t cmd, uint32_t param, uint8_t crc) 00115 { 00116 KFile *fd = sd->ch; 00117 /* The 7th bit of command must be a 1 */ 00118 kfile_putc(cmd | 0x40, fd); 00119 00120 /* send parameter */ 00121 kfile_putc((param >> 24) & 0xFF, fd); 00122 kfile_putc((param >> 16) & 0xFF, fd); 00123 kfile_putc((param >> 8) & 0xFF, fd); 00124 kfile_putc((param) & 0xFF, fd); 00125 00126 kfile_putc(crc, fd); 00127 00128 return sd_waitR1(sd); 00129 } 00130 00131 static bool sd_getBlock(Sd *sd, void *buf, size_t len) 00132 { 00133 uint8_t token; 00134 uint16_t crc; 00135 00136 KFile *fd = sd->ch; 00137 00138 for (int i = 0; i < TIMEOUT_NAC; i++) 00139 { 00140 token = kfile_getc(fd); 00141 if (token != 0xff) 00142 { 00143 if (token == SD_STARTTOKEN) 00144 { 00145 if (kfile_read(fd, buf, len) == len) 00146 { 00147 if (kfile_read(fd, &crc, sizeof(crc)) == sizeof(crc)) 00148 /* check CRC here if needed */ 00149 return true; 00150 else 00151 LOG_ERR("get_block error getting crc\n"); 00152 } 00153 else 00154 LOG_ERR("get_block len error: %d\n", (int)len); 00155 } 00156 else 00157 LOG_ERR("get_block token error: %02X\n", token); 00158 00159 return false; 00160 } 00161 } 00162 00163 LOG_ERR("get_block timeout waiting token\n"); 00164 return false; 00165 } 00166 00167 #define SD_SELECT(sd) \ 00168 do \ 00169 { \ 00170 if (!sd_select((sd), true)) \ 00171 { \ 00172 LOG_ERR("%s failed, card busy\n", __func__); \ 00173 return EOF; \ 00174 } \ 00175 } \ 00176 while (0) 00177 00178 #define SD_SETBLOCKLEN 0x50 00179 00180 static int16_t sd_setBlockLen(Sd *sd, uint32_t newlen) 00181 { 00182 SD_SELECT(sd); 00183 00184 sd->status = sd_sendCommand(sd, SD_SETBLOCKLEN, newlen, 0); 00185 00186 sd_select(sd, false); 00187 return sd->status; 00188 } 00189 00190 #define SD_SEND_CSD 0x49 00191 00192 static int16_t sd_getCSD(Sd *sd, SdCSD *csd) 00193 { 00194 SD_SELECT(sd); 00195 00196 int16_t r1 = sd_sendCommand(sd, SD_SEND_CSD, 0, 0); 00197 00198 if (r1) 00199 { 00200 LOG_ERR("send_csd failed: %08lX\n", sd->status); 00201 sd_select(sd, false); 00202 return r1; 00203 } 00204 00205 uint8_t buf[16]; 00206 bool res = sd_getBlock(sd, buf, sizeof(buf)); 00207 sd_select(sd, false); 00208 00209 if (res) 00210 { 00211 #if LOG_LEVEL >= LOG_LVL_INFO 00212 LOG_INFO("CSD: ["); 00213 for (int i = 0; i < 16; i++) 00214 kprintf("%02X ", buf[i]); 00215 kprintf("]\n"); 00216 #endif 00217 00218 uint16_t mult = (1L << ((((buf[9] & 0x03) << 1) | ((buf[10] & 0x80) >> 7)) + 2)); 00219 uint16_t c_size = (((uint16_t)(buf[6] & 0x03)) << 10) | (((uint16_t)buf[7]) << 2) | 00220 (((uint16_t)(buf[8] & 0xC0)) >> 6); 00221 00222 csd->block_len = (1L << (buf[5] & 0x0F)); 00223 csd->block_num = (c_size + 1) * mult; 00224 csd->capacity = (csd->block_len * csd->block_num) >> 20; // in MB 00225 00226 LOG_INFO("block_len %d bytes, block_num %ld, total capacity %dMB\n", csd->block_len, csd->block_num, csd->capacity); 00227 return 0; 00228 } 00229 else 00230 return EOF; 00231 } 00232 00233 #define SD_START_DELAY 10 00234 #define SD_INIT_TIMEOUT ms_to_ticks(2000) 00235 #define SD_IDLE_RETRIES 4 00236 #define SD_READ_SINGLEBLOCK 0x51 00237 00238 static size_t sd_SpiReadDirect(struct KBlock *b, block_idx_t idx, void *buf, size_t offset, size_t size) 00239 { 00240 00241 Sd *sd = SD_CAST(b); 00242 LOG_INFO("reading from block %ld, offset %d, size %d\n", idx, offset, size); 00243 00244 if (sd->hw->tranfer_len != size) 00245 { 00246 if ((sd->status = sd_setBlockLen(sd, size))) 00247 { 00248 LOG_ERR("setBlockLen failed: %08lX\n", sd->status); 00249 return 0; 00250 } 00251 sd->hw->tranfer_len = size; 00252 } 00253 00254 SD_SELECT(sd); 00255 00256 sd->status = sd_sendCommand(sd, SD_READ_SINGLEBLOCK, idx * SD_DEFAULT_BLOCKLEN + offset, 0); 00257 00258 if (sd->status) 00259 { 00260 LOG_ERR("read single block failed: %08lX\n", sd->status); 00261 sd_select(sd, false); 00262 return 0; 00263 } 00264 00265 bool res = sd_getBlock(sd, buf, size); 00266 sd_select(sd, false); 00267 if (!res) 00268 { 00269 LOG_ERR("read single block failed reading data\n"); 00270 return 0; 00271 } 00272 else 00273 return size; 00274 } 00275 00276 #define SD_WRITE_SINGLEBLOCK 0x58 00277 #define SD_DATA_ACCEPTED 0x05 00278 00279 static size_t sd_SpiWriteDirect(KBlock *b, block_idx_t idx, const void *buf, size_t offset, size_t size) 00280 { 00281 Sd *sd = SD_CAST(b); 00282 KFile *fd = sd->ch; 00283 ASSERT(offset == 0); 00284 ASSERT(size == SD_DEFAULT_BLOCKLEN); 00285 00286 LOG_INFO("writing block %ld\n", idx); 00287 if (sd->hw->tranfer_len != SD_DEFAULT_BLOCKLEN) 00288 { 00289 if ((sd->status = sd_setBlockLen(sd, SD_DEFAULT_BLOCKLEN))) 00290 { 00291 LOG_ERR("setBlockLen failed: %08lX\n", sd->status); 00292 return 0; 00293 } 00294 sd->hw->tranfer_len = SD_DEFAULT_BLOCKLEN; 00295 } 00296 00297 SD_SELECT(sd); 00298 00299 sd->status = sd_sendCommand(sd, SD_WRITE_SINGLEBLOCK, idx * SD_DEFAULT_BLOCKLEN, 0); 00300 00301 if (sd->status) 00302 { 00303 LOG_ERR("write single block failed: %08lX\n", sd->status); 00304 sd_select(sd, false); 00305 return 0; 00306 } 00307 00308 kfile_putc(SD_STARTTOKEN, fd); 00309 kfile_write(fd, buf, SD_DEFAULT_BLOCKLEN); 00310 /* send fake crc */ 00311 kfile_putc(0, fd); 00312 kfile_putc(0, fd); 00313 00314 uint8_t dataresp = kfile_getc(fd); 00315 sd_select(sd, false); 00316 00317 if ((dataresp & 0x1f) != SD_DATA_ACCEPTED) 00318 { 00319 LOG_ERR("write block %ld failed: %02X\n", idx, dataresp); 00320 return EOF; 00321 } 00322 00323 return SD_DEFAULT_BLOCKLEN; 00324 } 00325 00326 static int sd_SpiError(KBlock *b) 00327 { 00328 Sd *sd = SD_CAST(b); 00329 return sd->status; 00330 } 00331 00332 static void sd_SpiClearerr(KBlock *b) 00333 { 00334 Sd *sd = SD_CAST(b); 00335 sd->status = 0; 00336 } 00337 00338 00339 00340 #define SD_GO_IDLE_STATE 0x40 00341 #define SD_GO_IDLE_STATE_CRC 0x95 00342 #define SD_SEND_OP_COND 0x41 00343 #define SD_SEND_OP_COND_CRC 0xF9 00344 00345 static bool sd_blockInit(Sd *sd, KFile *ch) 00346 { 00347 ASSERT(sd); 00348 ASSERT(ch); 00349 memset(sd, 0, sizeof(*sd)); 00350 DB(sd->b.priv.type = KBT_SD); 00351 00352 sd->ch = ch; 00353 00354 SD_CS_INIT(); 00355 SD_CS_OFF(); 00356 00357 /* Wait a few moments for supply voltage to stabilize */ 00358 timer_delay(SD_START_DELAY); 00359 00360 /* Give 80 clk pulses to wake up the card */ 00361 for (int i = 0; i < 10; i++) 00362 kfile_putc(0xff, ch); 00363 kfile_flush(ch); 00364 00365 for (int i = 0; i < SD_IDLE_RETRIES; i++) 00366 { 00367 SD_SELECT(sd); 00368 sd->status = sd_sendCommand(sd, SD_GO_IDLE_STATE, 0, SD_GO_IDLE_STATE_CRC); 00369 sd_select(sd, false); 00370 00371 if (sd->status == SD_IN_IDLE) 00372 break; 00373 } 00374 00375 if (sd->status != SD_IN_IDLE) 00376 { 00377 LOG_ERR("go_idle_state failed: %08lX\n", sd->status); 00378 return false; 00379 } 00380 00381 ticks_t start = timer_clock(); 00382 00383 /* Wait for card to start */ 00384 do 00385 { 00386 SD_SELECT(sd); 00387 sd->status = sd_sendCommand(sd, SD_SEND_OP_COND, 0, SD_SEND_OP_COND_CRC); 00388 sd_select(sd, false); 00389 cpu_relax(); 00390 } 00391 while (sd->status != 0 && timer_clock() - start < SD_INIT_TIMEOUT); 00392 00393 if (sd->status) 00394 { 00395 LOG_ERR("send_op_cond failed: %08lX\n", sd->status); 00396 return false; 00397 } 00398 00399 sd->status = sd_setBlockLen(sd, SD_DEFAULT_BLOCKLEN); 00400 sd->hw->tranfer_len = SD_DEFAULT_BLOCKLEN; 00401 00402 if (sd->status) 00403 { 00404 LOG_ERR("setBlockLen failed: %08lX\n", sd->status); 00405 return false; 00406 } 00407 00408 /* Avoid warning for uninitialized csd use (gcc bug?) */ 00409 SdCSD csd = csd; 00410 00411 sd->status = sd_getCSD(sd, &csd); 00412 00413 if (sd->status) 00414 { 00415 LOG_ERR("getCSD failed: %08lX\n", sd->status); 00416 return false; 00417 } 00418 00419 sd->b.blk_size = SD_DEFAULT_BLOCKLEN; 00420 sd->b.blk_cnt = csd.block_num * (csd.block_len / SD_DEFAULT_BLOCKLEN); 00421 LOG_INFO("blk_size %d, blk_cnt %ld\n", sd->b.blk_size, sd->b.blk_cnt); 00422 00423 #if CONFIG_SD_AUTOASSIGN_FAT 00424 disk_assignDrive(&sd->b, 0); 00425 #endif 00426 00427 return true; 00428 } 00429 00430 static const KBlockVTable sd_unbuffered_vt = 00431 { 00432 .readDirect = sd_SpiReadDirect, 00433 .writeDirect = sd_SpiWriteDirect, 00434 00435 .error = sd_SpiError, 00436 .clearerr = sd_SpiClearerr, 00437 }; 00438 00439 static const KBlockVTable sd_buffered_vt = 00440 { 00441 .readDirect = sd_SpiReadDirect, 00442 .writeDirect = sd_SpiWriteDirect, 00443 00444 .readBuf = kblock_swReadBuf, 00445 .writeBuf = kblock_swWriteBuf, 00446 .load = kblock_swLoad, 00447 .store = kblock_swStore, 00448 00449 .error = sd_SpiError, 00450 .clearerr = sd_SpiClearerr, 00451 }; 00452 00453 struct SdHardware sd_spi_hw; 00454 00455 bool sd_spi_initUnbuf(Sd *sd, KFile *ch) 00456 { 00457 if (sd_blockInit(sd, ch)) 00458 { 00459 sd->b.priv.vt = &sd_unbuffered_vt; 00460 sd->hw = &sd_spi_hw; 00461 return true; 00462 } 00463 else 00464 return false; 00465 } 00466 00467 static uint8_t sd_buf[SD_DEFAULT_BLOCKLEN]; 00468 00469 bool sd_spi_initBuf(Sd *sd, KFile *ch) 00470 { 00471 if (sd_blockInit(sd, ch)) 00472 { 00473 sd->b.priv.buf = sd_buf; 00474 sd->b.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE; 00475 sd->b.priv.vt = &sd_buffered_vt; 00476 sd->b.priv.vt->load(&sd->b, 0); 00477 sd->hw = &sd_spi_hw; 00478 return true; 00479 } 00480 else 00481 return false; 00482 } 00483 00484
![(please configure the [header_logo] section in trac.ini)](/chrome/site/bertos_logo.png)