#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)
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;
}
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;
return sd_waitR1(sd);
}
-
static bool sd_getBlock(Sd *sd, void *buf, size_t len)
{
uint8_t token;
{
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];
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)
#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);
{
LOG_ERR("write single block failed: %04X\n", sd->r1);
sd_select(sd, false);
- return sd->r1;
+ return 0;
}
kfile_putc(SD_STARTTOKEN, fd);
/* 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");
+ }
}
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));
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,
static const KBlockVTable sd_buffered_vt =
{
.readDirect = sd_readDirect,
- .writeBlock = sd_writeBlock,
+ .writeDirect = sd_writeDirect,
.readBuf = kblock_swReadBuf,
.writeBuf = kblock_swWriteBuf,
#define SD_SEND_OP_COND 0x41
#define SD_SEND_OP_COND_CRC 0xF9
-#define SD_START_DELAY ms_to_ticks(10)
-#define SD_INIT_TIMEOUT ms_to_ticks(1000)
+#define SD_START_DELAY 10
+#define SD_INIT_TIMEOUT 1000
#define SD_IDLE_RETRIES 4
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)
{
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);
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
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;