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