As currently implemented:
-Sequential read: 250kb/sec Sequential write: 240kb/sec
+Sequential read: 424kb/sec Sequential write: 414kb/sec
Tested with a 16GB class 10 SD card, via the commands:
# READ TEST
sudo dd bs=8192 count=100 if=/dev/sdX of=/dev/null
-I am working on updating the slow polling SD card communication to use DMA. I expect the performance to reach 1Mb/sec.
+I am working on updating the SD card communication to use DMA, to allow simultaneous use of the SD and SCSI interfaces. I expect the performance to reach 1Mb/sec.
Compatibility
transfer.currentBlock = 0;\r
scsiDev.phase = DATA_IN;\r
scsiDev.dataLen = 0; // No data yet\r
- sdPrepareRead(0);\r
+ sdPrepareRead();\r
}\r
}\r
\r
{\r
if (scsiDev.dataLen == 0)\r
{\r
- if (sdIsReadReady())\r
- {\r
- sdReadSector();\r
- if ((transfer.currentBlock + 1) < transfer.blocks)\r
- {\r
- sdPrepareRead(1); // Tell SD card to grab data while we send\r
- // buffer to SCSI.\r
- }\r
- }\r
+ sdReadSector();\r
}\r
else if (scsiDev.dataPtr == scsiDev.dataLen)\r
{\r
{\r
scsiDev.phase = STATUS;\r
scsiDiskReset();\r
+ sdCompleteRead();\r
}\r
}\r
}\r
scsiDev.dataPtr = 0;\r
transfer.currentBlock++;\r
if (transfer.currentBlock >= transfer.blocks)\r
- \r
{\r
scsiDev.dataLen = 0;\r
scsiDev.phase = STATUS;\r
scsiDiskReset();\r
- \r
+\r
if (writeOk)\r
{\r
sdCompleteWrite();\r
}\r
\r
\r
-void sdPrepareRead(int nextBlockOffset)\r
+void sdPrepareRead()\r
{\r
- uint32 len = (transfer.lba + transfer.currentBlock + nextBlockOffset);\r
+ uint32 len = (transfer.lba + transfer.currentBlock);\r
if (!sdDev.ccs)\r
{\r
len = len * SCSI_BLOCK_SIZE;\r
}\r
- uint8 v = sdCommandAndResponse(17, len);\r
+ uint8 v = sdCommandAndResponse(SD_READ_MULTIPLE_BLOCK, len);\r
if (v)\r
{\r
scsiDiskReset();\r
}\r
}\r
\r
-int sdIsReadReady()\r
+void sdReadSector()\r
{\r
- uint8 v = sdWaitResp();\r
- if (v == 0xFF)\r
- {\r
- return 0;\r
- }\r
- else if (v == 0xFE)\r
- {\r
- return 1;\r
- }\r
- else\r
+ // Wait for a start-block token.\r
+ uint8 token;\r
+ do\r
{\r
- scsiDiskReset();\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.sense.code = HARDWARE_ERROR;\r
- scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
- scsiDev.phase = STATUS;\r
- return 0;\r
- }\r
-}\r
+ token = sdSpiByte(0xFF);\r
+ } while(token != 0xFE); // TODO don't loop forever here in case of error!\r
\r
-void sdReadSector()\r
-{\r
int prep = 0;\r
int i = 0;\r
while (i < SCSI_BLOCK_SIZE)\r
scsiDev.dataPtr = 0;\r
}\r
\r
+void sdCompleteRead()\r
+{\r
+ //uint8 r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
+ sdSendCommand(SD_STOP_TRANSMISSION, 0);\r
+ sdSpiByte(0xFF); // NEED STUFF BYTE for cmd12\r
+ uint8 r1b = sdReadResp();\r
+ if (r1b)\r
+ {\r
+ scsiDev.status = CHECK_CONDITION;\r
+ scsiDev.sense.code = HARDWARE_ERROR;\r
+ scsiDev.sense.asc = UNRECOVERED_READ_ERROR;\r
+ scsiDev.phase = STATUS;\r
+ }\r
+ \r
+ // R1b has an optional trailing "busy" signal.\r
+ uint8 busy;\r
+ do\r
+ {\r
+ busy = sdSpiByte(0xFF);\r
+ } while (busy == 0);\r
+}\r
+\r
static void sdWaitWriteBusy()\r
{\r
uint8 val;\r
SD_SEND_OP_COND = 1,
SD_SEND_IF_COND = 8, // SD V2
SD_SEND_CSD = 9,
+ SD_STOP_TRANSMISSION = 12,
SD_SET_BLOCKLEN = 16,
+ SD_READ_MULTIPLE_BLOCK = 18,
SD_APP_SET_WR_BLK_ERASE_COUNT = 23,
SD_APP_SEND_OP_COND = 41,
SD_APP_CMD = 55,
int sdWriteSector();
void sdCompleteWrite();
-void sdPrepareRead(int nextBlockOffset);
-int sdIsReadReady();
+void sdPrepareRead();
void sdReadSector();
+void sdCompleteRead();
#endif