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