X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fdrv%2Fsd.c;h=c12d7592e6660332d57a430c1473e620057ae37a;hb=010a2d0611571ec1e4bace00b4b6efe8462f512f;hp=ca48fb3b398261d762c225053ab078644619f9c0;hpb=b883250b42adfbfab013f265fa5073a3a3455b8b;p=bertos.git diff --git a/bertos/drv/sd.c b/bertos/drv/sd.c index ca48fb3b..c12d7592 100644 --- a/bertos/drv/sd.c +++ b/bertos/drv/sd.c @@ -66,8 +66,7 @@ typedef struct CardCSD #define SD_IN_IDLE 0x01 #define SD_STARTTOKEN 0xFE -#define TIMEOUT_NAC 256 - +#define TIMEOUT_NAC 16384 #define SD_DEFAULT_BLOCKLEN 512 #define SD_BUSY_TIMEOUT ms_to_ticks(200) @@ -78,19 +77,19 @@ static bool sd_select(Sd *sd, bool state) if (state) { + SD_CS_ON(); + ticks_t start = timer_clock(); do { - SD_CS_ON(); if (kfile_getc(fd) == 0xff) return true; - SD_CS_OFF(); - kfile_putc(0xff, fd); - kfile_flush(fd); + cpu_relax(); } while (timer_clock() - start < SD_BUSY_TIMEOUT); + SD_CS_OFF(); LOG_ERR("sd_select timeout\n"); return false; } @@ -109,9 +108,9 @@ static int16_t sd_waitR1(Sd *sd) for (int i = 0; i < TIMEOUT_NAC; i++) { - datain = kfile_getc(sd->ch); - if (datain != 0xff) - return (int16_t)datain; + datain = kfile_getc(sd->ch); + if (datain != 0xff) + return (int16_t)datain; } LOG_ERR("Timeout waiting R1\n"); return EOF; @@ -134,7 +133,6 @@ static int16_t sd_sendCommand(Sd *sd, uint8_t cmd, uint32_t param, uint8_t crc) return sd_waitR1(sd); } - static bool sd_getBlock(Sd *sd, void *buf, size_t len) { uint8_t token; @@ -200,13 +198,13 @@ static int16_t sd_getCSD(Sd *sd, CardCSD *csd) { SD_SELECT(sd); - sd->r1 = sd_sendCommand(sd, SD_SEND_CSD, 0, 0); + int16_t r1 = sd_sendCommand(sd, SD_SEND_CSD, 0, 0); - if (sd->r1) + if (r1) { LOG_ERR("send_csd failed: %04X\n", sd->r1); sd_select(sd, false); - return sd->r1; + return r1; } uint8_t buf[16]; @@ -245,13 +243,18 @@ static size_t sd_readDirect(struct KBlock *b, block_idx_t idx, void *buf, size_t Sd *sd = SD_CAST(b); LOG_INFO("reading from block %ld, offset %d, size %d\n", idx, offset, size); - if ((sd->r1 = sd_setBlockLen(sd, size))) + if (sd->tranfer_len != size) { - LOG_ERR("setBlockLen failed: %04X\n", sd->r1); - return 0; + if ((sd->r1 = sd_setBlockLen(sd, size))) + { + LOG_ERR("setBlockLen failed: %04X\n", sd->r1); + return 0; + } + sd->tranfer_len = size; } SD_SELECT(sd); + sd->r1 = sd_sendCommand(sd, SD_READ_SINGLEBLOCK, idx * SD_DEFAULT_BLOCKLEN + offset, 0); if (sd->r1) @@ -275,16 +278,22 @@ static size_t sd_readDirect(struct KBlock *b, block_idx_t idx, void *buf, size_t #define SD_WRITE_SINGLEBLOCK 0x58 #define SD_DATA_ACCEPTED 0x05 -static int sd_writeBlock(KBlock *b, block_idx_t idx, const void *buf) +static size_t sd_writeDirect(KBlock *b, block_idx_t idx, const void *buf, size_t offset, size_t size) { Sd *sd = SD_CAST(b); KFile *fd = sd->ch; + ASSERT(offset == 0); + ASSERT(size == SD_DEFAULT_BLOCKLEN); LOG_INFO("writing block %ld\n", idx); - if ((sd->r1 = sd_setBlockLen(sd, SD_DEFAULT_BLOCKLEN))) + if (sd->tranfer_len != SD_DEFAULT_BLOCKLEN) { - LOG_ERR("setBlockLen failed: %04X\n", sd->r1); - return sd->r1; + if ((sd->r1 = sd_setBlockLen(sd, SD_DEFAULT_BLOCKLEN))) + { + LOG_ERR("setBlockLen failed: %04X\n", sd->r1); + return 0; + } + sd->tranfer_len = SD_DEFAULT_BLOCKLEN; } SD_SELECT(sd); @@ -295,7 +304,7 @@ static int sd_writeBlock(KBlock *b, block_idx_t idx, const void *buf) { LOG_ERR("write single block failed: %04X\n", sd->r1); sd_select(sd, false); - return sd->r1; + return 0; } kfile_putc(SD_STARTTOKEN, fd); @@ -303,17 +312,28 @@ static int sd_writeBlock(KBlock *b, block_idx_t idx, const void *buf) /* send fake crc */ kfile_putc(0, fd); kfile_putc(0, fd); - uint8_t dataresp = (kfile_getc(fd) & 0x1F); + + uint8_t dataresp = kfile_getc(fd); sd_select(sd, false); - // FIXME: sometimes dataresp is 0, find out why. - if (dataresp != SD_DATA_ACCEPTED) + if ((dataresp & 0x1f) != SD_DATA_ACCEPTED) { - LOG_ERR("write single block failed: %02X\n", dataresp); + LOG_ERR("write block %ld failed: %02X\n", idx, dataresp); return EOF; } - else - return 0; + + return SD_DEFAULT_BLOCKLEN; +} + +void sd_writeTest(Sd *sd) +{ + uint8_t buf[SD_DEFAULT_BLOCKLEN]; + memset(buf, 0, sizeof(buf)); + + for (block_idx_t i = 0; i < sd->b.blk_cnt; i++) + { + LOG_INFO("writing block %ld: %s\n", i, (sd_writeDirect(&sd->b, i, buf, 0, SD_DEFAULT_BLOCKLEN) == SD_DEFAULT_BLOCKLEN) ? "OK" : "FAIL"); + } } @@ -333,7 +353,7 @@ bool sd_test(Sd *sd) kputchar('\n'); } - if (sd_writeBlock(&sd->b, 0, buf) != 0) + if (sd_writeDirect(&sd->b, 0, buf, 0, SD_DEFAULT_BLOCKLEN) != SD_DEFAULT_BLOCKLEN) return false; memset(buf, 0, sizeof(buf)); @@ -358,17 +378,16 @@ static int sd_error(KBlock *b) return sd->r1; } -static int sd_clearerr(KBlock *b) +static void sd_clearerr(KBlock *b) { Sd *sd = SD_CAST(b); sd->r1 = 0; - return 0; } static const KBlockVTable sd_unbuffered_vt = { .readDirect = sd_readDirect, - .writeBlock = sd_writeBlock, + .writeDirect = sd_writeDirect, .error = sd_error, .clearerr = sd_clearerr, @@ -377,7 +396,7 @@ static const KBlockVTable sd_unbuffered_vt = static const KBlockVTable sd_buffered_vt = { .readDirect = sd_readDirect, - .writeBlock = sd_writeBlock, + .writeDirect = sd_writeDirect, .readBuf = kblock_swReadBuf, .writeBuf = kblock_swWriteBuf, @@ -451,6 +470,7 @@ static bool sd_blockInit(Sd *sd, KFile *ch) } sd->r1 = sd_setBlockLen(sd, SD_DEFAULT_BLOCKLEN); + sd->tranfer_len = SD_DEFAULT_BLOCKLEN; if (sd->r1) { @@ -458,8 +478,11 @@ static bool sd_blockInit(Sd *sd, KFile *ch) return false; } - CardCSD csd; + /* Avoid warning for uninitialized csd use (gcc bug?) */ + CardCSD csd = csd; + sd->r1 = sd_getCSD(sd, &csd); + if (sd->r1) { LOG_ERR("getCSD failed: %04X\n", sd->r1); @@ -470,7 +493,6 @@ static bool sd_blockInit(Sd *sd, KFile *ch) sd->b.blk_cnt = csd.block_num * (csd.block_len / SD_DEFAULT_BLOCKLEN); LOG_INFO("blk_size %d, blk_cnt %ld\n", sd->b.blk_size, sd->b.blk_cnt); - #if CONFIG_SD_AUTOASSIGN_FAT disk_assignDrive(&sd->b, 0); #endif @@ -496,7 +518,7 @@ bool sd_initBuf(Sd *sd, KFile *ch) if (sd_blockInit(sd, ch)) { sd->b.priv.buf = sd_buf; - sd->b.priv.flags |= KB_BUFFERED; + sd->b.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE; sd->b.priv.vt = &sd_buffered_vt; sd->b.priv.vt->load(&sd->b, 0); return true;