#include "config.h"\r
#include "disk.h"\r
#include "sd.h"\r
+#include "led.h"\r
\r
#include <string.h>\r
\r
static uint8 sdSpiByte(uint8 value)\r
{\r
SDCard_WriteTxData(value);\r
- while(!(SDCard_ReadTxStatus() & SDCard_STS_SPI_DONE))\r
- {}\r
- while (!SDCard_GetRxBufferSize()) {}\r
+ while (!(SDCard_ReadRxStatus() & SDCard_STS_RX_FIFO_NOT_EMPTY)) {}\r
return SDCard_ReadRxData();\r
}\r
\r
sdSpiByte(send[cmd]);\r
}\r
// Allow command to process before reading result code.\r
- sdSpiByte(0xFF); \r
+ sdSpiByte(0xFF);\r
}\r
\r
static uint8 sdReadResp()\r
do\r
{\r
v = sdSpiByte(0xFF);\r
- } while(i-- && (v == 0xFF));\r
- return v;\r
-}\r
-\r
-static uint8 sdWaitResp()\r
-{\r
- uint8 v;\r
- uint8 i = 255;\r
- do\r
- {\r
- v = sdSpiByte(0xFF);\r
- } while(i-- && (v != 0xFE));\r
+ } while(i-- && (v & 0x80));\r
return v;\r
}\r
\r
-\r
static uint8 sdCommandAndResponse(uint8 cmd, uint32 param)\r
{\r
- SDCard_ClearRxBuffer();\r
sdSpiByte(0xFF);\r
sdSendCommand(cmd, param);\r
return sdReadResp();\r
\r
static uint8 sdCRCCommandAndResponse(uint8 cmd, uint32 param)\r
{\r
- SDCard_ClearRxBuffer();\r
sdSpiByte(0xFF);\r
sdSendCRCCommand(cmd, param);\r
return sdReadResp();\r
}\r
\r
+// Clear the sticky status bits on error.\r
+static void sdClearStatus()\r
+{\r
+ uint8 r2hi = sdCRCCommandAndResponse(SD_SEND_STATUS, 0);\r
+ uint8 r2lo = sdSpiByte(0xFF);\r
+ (void) r2hi; (void) r2lo;\r
+}\r
+\r
\r
void sdPrepareRead()\r
{\r
if (v)\r
{\r
scsiDiskReset();\r
+ sdClearStatus();\r
\r
scsiDev.status = CHECK_CONDITION;\r
scsiDev.sense.code = HARDWARE_ERROR;\r
\r
void sdCompleteRead()\r
{\r
- int counter = 512;\r
- uint8 r1b;\r
- do\r
- {\r
- r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
- } while (r1b && (counter-- > 0));\r
+ // We cannot send even a single "padding" byte, as we normally would when\r
+ // sending a command. If we've just finished reading the very last block\r
+ // on the card, then reading an additional dummy byte will just trigger\r
+ // an error condition as we're trying to read past-the-end of the storage\r
+ // device.\r
+ // ie. do not use sdCommandAndResponse here.\r
+ sdSendCommand(SD_STOP_TRANSMISSION, 0);\r
+ uint8 r1b = sdReadResp();\r
+\r
if (r1b)\r
{\r
+ // Try very hard to make sure the transmission stops\r
+ int retries = 255;\r
+ while (r1b && retries)\r
+ {\r
+ r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
+ retries--;\r
+ }\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
+\r
// R1b has an optional trailing "busy" signal.\r
uint8 busy;\r
do\r
// Wait for a previously-written sector to complete.\r
sdWaitWriteBusy();\r
\r
- sdSpiByte(0xFC); // MULTIPLE byte start token\r
- int i;\r
- for (i = 0; i < SCSI_BLOCK_SIZE; i++)\r
- {\r
- while(!(SDCard_ReadTxStatus() & SDCard_STS_TX_FIFO_NOT_FULL))\r
- {}\r
- SDCard_WriteTxData(scsiDev.data[i]);\r
- }\r
- while(!(SDCard_ReadTxStatus() & SDCard_STS_SPI_DONE))\r
+ sdSpiByte(0xFC); // MULTIPLE byte start token\r
+ int i;\r
+ for (i = 0; i < SCSI_BLOCK_SIZE; i++)\r
+ {\r
+ while(!(SDCard_ReadTxStatus() & SDCard_STS_TX_FIFO_NOT_FULL))\r
{}\r
- SDCard_ReadRxData();\r
- SDCard_ReadRxData();\r
- SDCard_ReadRxData();\r
- SDCard_ReadRxData();\r
- SDCard_ReadRxData(); \r
-\r
- sdSpiByte(0x00); // CRC\r
- sdSpiByte(0x00); // CRC\r
- \r
- // Don't wait more than 1000ms.\r
- // My 2g Kingston micro-sd card doesn't respond immediately.\r
- // My 16Gb card does.\r
- int maxWait = 1000;\r
- uint8 dataToken = sdSpiByte(0xFF); // Response\r
- while (dataToken == 0xFF && maxWait-- > 0)\r
- {\r
- CyDelay(1); // 1ms. \r
- dataToken = sdSpiByte(0xFF); \r
- }\r
- if (((dataToken & 0x1F) >> 1) != 0x2) // Accepted.\r
- {\r
- sdWaitWriteBusy();\r
- \r
- int counter = 512;\r
- uint8 r1b;\r
- do\r
- {\r
- r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
- } while (r1b && (counter-- > 0));\r
- // R1b has an optional trailing "busy" signal.\r
- uint8 busy;\r
- do\r
- {\r
- busy = sdSpiByte(0xFF);\r
- } while (busy == 0); \r
-\r
- // Wait for the card to come out of busy.\r
- sdWaitWriteBusy();\r
-\r
- scsiDiskReset();\r
+ SDCard_WriteTxData(scsiDev.data[i]);\r
+ }\r
+ while(!(SDCard_ReadTxStatus() & SDCard_STS_SPI_DONE)) {}\r
+ SDCard_ClearFIFO();\r
+ \r
+ sdSpiByte(0x00); // CRC\r
+ sdSpiByte(0x00); // CRC\r
+\r
+ // Don't wait more than 1000ms.\r
+ // My 2g Kingston micro-sd card doesn't respond immediately.\r
+ // My 16Gb card does.\r
+ int maxWait = 1000;\r
+ uint8 dataToken = sdSpiByte(0xFF); // Response\r
+ while (dataToken == 0xFF && maxWait-- > 0)\r
+ {\r
+ CyDelay(1); // 1ms. \r
+ dataToken = sdSpiByte(0xFF);\r
+ }\r
+ if (((dataToken & 0x1F) >> 1) != 0x2) // Accepted.\r
+ {\r
+ sdWaitWriteBusy();\r
\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.sense.code = HARDWARE_ERROR;\r
- scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
- scsiDev.phase = STATUS;\r
- result = 0;\r
- }\r
- else\r
+ uint8 r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
+ (void) r1b;\r
+ sdSpiByte(0xFF);\r
+\r
+ // R1b has an optional trailing "busy" signal.\r
+ uint8 busy;\r
+ do\r
{\r
- // The card is probably in the busy state.\r
- // Don't wait, as we could read the SCSI interface instead.\r
- result = 1;\r
+ busy = sdSpiByte(0xFF);\r
+ } while (busy == 0);\r
+\r
+ // Wait for the card to come out of busy.\r
+ sdWaitWriteBusy();\r
+\r
+ scsiDiskReset();\r
+ sdClearStatus();\r
+\r
+ scsiDev.status = CHECK_CONDITION;\r
+ scsiDev.sense.code = HARDWARE_ERROR;\r
+ scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
+ scsiDev.phase = STATUS;\r
+ result = 0;\r
+ }\r
+ else\r
+ {\r
+ // The card is probably in the busy state.\r
+ // Don't wait, as we could read the SCSI interface instead.\r
+ result = 1;\r
}\r
\r
return result;\r
sdSpiByte(0xFD); // STOP TOKEN\r
// Wait for the card to come out of busy.\r
sdWaitWriteBusy();\r
- \r
+\r
uint8 r1 = sdCommandAndResponse(13, 0); // send status\r
uint8 r2 = sdSpiByte(0xFF);\r
if (r1 || r2)\r
{\r
+ sdClearStatus();\r
scsiDev.status = CHECK_CONDITION;\r
scsiDev.sense.code = HARDWARE_ERROR;\r
scsiDev.sense.asc = WRITE_ERROR_AUTO_REALLOCATION_FAILED;\r
{\r
// Version 1 card.\r
sdDev.version = 1;\r
+ sdClearStatus();\r
break;\r
}\r
+\r
+ sdClearStatus();\r
} while (--retries > 0);\r
\r
return retries > 0;\r
sdCRCCommandAndResponse(SD_APP_CMD, 0);\r
// Host Capacity Support = 1 (SDHC/SDXC supported)\r
status = sdCRCCommandAndResponse(SD_APP_SEND_OP_COND, 0x40000000);\r
+\r
+ sdClearStatus();\r
} while ((status != 0) && (--retries > 0));\r
\r
return retries > 0;\r
{\r
uint8 status = sdCRCCommandAndResponse(SD_SEND_CSD, 0);\r
if(status){goto bad;}\r
- status = sdWaitResp();\r
- if (status != 0xFE) { goto bad; }\r
+ \r
+ uint8 startToken;\r
+ int maxWait = 1023;\r
+ do\r
+ {\r
+ startToken = sdSpiByte(0xFF);\r
+ } while(maxWait-- && (startToken != 0xFE));\r
+ if (startToken != 0xFE) { goto bad; }\r
\r
uint8 buf[16];\r
int i;\r
}\r
\r
int sdInit()\r
-{ \r
+{\r
sdDev.version = 0;\r
sdDev.ccs = 0;\r
sdDev.capacity = 0;\r
uint8 v = sdCRCCommandAndResponse(SD_GO_IDLE_STATE, 0);\r
if(v != 1){goto bad;}\r
\r
+ ledOn();\r
if (!sendIfCond()) goto bad; // Sets V1 or V2 flag\r
if (!sdOpCond()) goto bad;\r
if (!sdReadOCR()) goto bad;\r
if(v){goto bad;}\r
\r
// now set the sd card up for full speed\r
+ // The SD Card spec says we can run SPI @ 25MHz\r
+ // But the PSoC 5LP SPIM datasheet says the most we can do is 18MHz.\r
+ // I've confirmed that no data is ever put into the RX FIFO when run at\r
+ // 20MHz or 25MHz.\r
+ // ... and then we get timing analysis failures if the BUS_CLK is over 62MHz.\r
+ // So we run the MASTER_CLK and BUS_CLK at 60MHz, and run the SPI clock at 30MHz\r
+ // (15MHz SPI transfer clock).\r
+ SDCard_Stop();\r
SD_Data_Clk_Start(); // Turn on the fast clock\r
SD_Clk_Ctl_Write(1); // Select the fast clock source.\r
SD_Init_Clk_Stop(); // Stop the slow clock.\r
+ CyDelayUs(1);\r
+ SDCard_Start();\r
+\r
+ // Clear out rubbish data through clock change\r
+ CyDelayUs(1);\r
+ SDCard_ReadRxStatus();\r
+ SDCard_ReadTxStatus();\r
+ SDCard_ClearFIFO();\r
\r
if (!sdReadCSD()) goto bad;\r
\r
sdDev.capacity = 0;\r
\r
out:\r
+ sdClearStatus();\r
+ ledOff();\r
return result;\r
\r
}\r
if (v)\r
{\r
scsiDiskReset();\r
-\r
+ sdClearStatus();\r
scsiDev.status = CHECK_CONDITION;\r
scsiDev.sense.code = HARDWARE_ERROR;\r
scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r