Reliability improvements for SD init and reads.

This commit is contained in:
Michael McMaster 2013-12-09 22:00:49 +10:00
parent a835e7a1d3
commit b50aad09c8
17 changed files with 137 additions and 108 deletions

View File

@ -1,7 +1,7 @@
/*******************************************************************************
* FILENAME: cydevice.h
* OBSOLETE: Do not use this file. Use the _trm version instead.
* PSoC Creator 3.0
* PSoC Creator 3.0 Component Pack 7
*
* DESCRIPTION:
* This file provides all of the address values for the entire PSoC device.

View File

@ -1,7 +1,7 @@
/*******************************************************************************
* FILENAME: cydevice_trm.h
*
* PSoC Creator 3.0
* PSoC Creator 3.0 Component Pack 7
*
* DESCRIPTION:
* This file provides all of the address values for the entire PSoC device.

View File

@ -1,7 +1,7 @@
/*******************************************************************************
* FILENAME: cydevicegnu.inc
* OBSOLETE: Do not use this file. Use the _trm version instead.
* PSoC Creator 3.0
* PSoC Creator 3.0 Component Pack 7
*
* DESCRIPTION:
* This file provides all of the address values for the entire PSoC device.

View File

@ -1,7 +1,7 @@
/*******************************************************************************
* FILENAME: cydevicegnu_trm.inc
*
* PSoC Creator 3.0
* PSoC Creator 3.0 Component Pack 7
*
* DESCRIPTION:
* This file provides all of the address values for the entire PSoC device.

View File

@ -1,7 +1,7 @@
;
; FILENAME: cydeviceiar.inc
; OBSOLETE: Do not use this file. Use the _trm version instead.
; PSoC Creator 3.0
; PSoC Creator 3.0 Component Pack 7
;
; DESCRIPTION:
; This file provides all of the address values for the entire PSoC device.

View File

@ -1,7 +1,7 @@
;
; FILENAME: cydeviceiar_trm.inc
;
; PSoC Creator 3.0
; PSoC Creator 3.0 Component Pack 7
;
; DESCRIPTION:
; This file provides all of the address values for the entire PSoC device.

View File

@ -1,7 +1,7 @@
;
; FILENAME: cydevicerv.inc
; OBSOLETE: Do not use this file. Use the _trm version instead.
; PSoC Creator 3.0
; PSoC Creator 3.0 Component Pack 7
;
; DESCRIPTION:
; This file provides all of the address values for the entire PSoC device.

View File

@ -1,7 +1,7 @@
;
; FILENAME: cydevicerv_trm.inc
;
; PSoC Creator 3.0
; PSoC Creator 3.0 Component Pack 7
;
; DESCRIPTION:
; This file provides all of the address values for the entire PSoC device.

View File

@ -1,6 +1,6 @@
/*******************************************************************************
* FILENAME: cyfitter_cfg.c
* PSoC Creator 3.0
* PSoC Creator 3.0 Component Pack 7
*
* Description:
* This file is automatically generated by PSoC Creator with device

View File

@ -1,6 +1,6 @@
/*******************************************************************************
* FILENAME: cyfitter_cfg.h
* PSoC Creator 3.0
* PSoC Creator 3.0 Component Pack 7
*
* Description:
* This file is automatically generated by PSoC Creator.

View File

@ -1,7 +1,7 @@
/*******************************************************************************
* FILENAME: cymetadata.c
*
* PSoC Creator 3.0
* PSoC Creator 3.0 Component Pack 7
*
* DESCRIPTION:
* This file defines all extra memory spaces that need to be included.

View File

@ -1,6 +1,6 @@
/*******************************************************************************
* File Name: project.h
* PSoC Creator 3.0
* PSoC Creator 3.0 Component Pack 7
*
* Description:
* This file is automatically generated by PSoC Creator and should not

View File

@ -418,7 +418,7 @@ void scsiDiskInit()
}
#endif
//if (SD_CD_Read() == 0)
if (SD_CD_Read() == 1)
{
blockDev.state = blockDev.state | DISK_PRESENT;

View File

@ -73,16 +73,10 @@ static void process_MessageIn()
// back to MESSAGE_OUT first, get out parity error message, then come
// back here.
}
else if (scsiDev.msgIn == MSG_COMMAND_COMPLETE)
else /*if (scsiDev.msgIn == MSG_COMMAND_COMPLETE)*/
{
enter_BusFree();
}
else
{
// MESSAGE_REJECT. Go back to command phase
// TODO MESSAGE_REJECT moved to messageReject method.
scsiDev.phase = COMMAND;
}
}
static void messageReject()
@ -361,8 +355,12 @@ static void enter_SelectionPhase()
scsiDev.parityError = 0;
scsiDev.dataPtr = 0;
scsiDev.savedDataPtr = 0;
scsiDev.dataLen = 0;
scsiDev.status = GOOD;
scsiDev.phase = SELECTION;
transfer.blocks = 0;
transfer.currentBlock = 0;
}
static void process_SelectionPhase()
@ -507,7 +505,7 @@ static void process_MessageOut()
(scsiDev.msgOut & 0x7) // We only support LUN 0!
)
{
enter_MessageIn(MSG_REJECT);
messageReject();
}
}
else if (scsiDev.msgOut >= 0x20 && scsiDev.msgOut <= 0x2F)

View File

@ -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));
} while(i-- && (v & 0x80));
return v;
}
static uint8 sdWaitResp()
{
uint8 v;
uint8 i = 255;
do
{
v = sdSpiByte(0xFF);
} while(i-- && (v != 0xFE));
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();
SDCard_WriteTxData(scsiDev.data[i]);
}
while(!(SDCard_ReadTxStatus() & SDCard_STS_SPI_DONE)) {}
SDCard_ClearFIFO();
sdSpiByte(0x00); // CRC
sdSpiByte(0x00); // CRC
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)
// 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();
uint8 r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);
(void) r1b;
sdSpiByte(0xFF);
// R1b has an optional trailing "busy" signal.
uint8 busy;
do
{
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);
busy = sdSpiByte(0xFF);
} while (busy == 0);
// Wait for the card to come out of busy.
sdWaitWriteBusy();
// Wait for the card to come out of busy.
sdWaitWriteBusy();
scsiDiskReset();
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;
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;

View File

@ -24,6 +24,7 @@ typedef enum
SD_SEND_IF_COND = 8, // SD V2
SD_SEND_CSD = 9,
SD_STOP_TRANSMISSION = 12,
SD_SEND_STATUS = 13,
SD_SET_BLOCKLEN = 16,
SD_READ_MULTIPLE_BLOCK = 18,
SD_APP_SET_WR_BLK_ERASE_COUNT = 23,