📄 sd.c
字号:
/******************************************************************************
** File Name: sd.c *
** Author: Benjamin.Wang *
** DATE: 01/26/2005 *
** Copyright: 2005 Spreadtrum, Incoporated. All Rights Reserved. *
** Description: This file defines the basic operation interfaces of SD Card. *
** *
******************************************************************************
******************************************************************************
** Edit History *
** ------------------------------------------------------------------------- *
** DATE NAME DESCRIPTION *
** 01/26/2005 Benjamin.Wang Create. *
******************************************************************************/
/**---------------------------------------------------------------------------*
** Dependencies *
**---------------------------------------------------------------------------*/
#include "os_api.h"
#include "sd.h"
#include "spi_drv.h"
#include "sci_types.h"
/**---------------------------------------------------------------------------*
** Debugging Flag *
**---------------------------------------------------------------------------*/
#define DEBUG_SD
#ifdef DEBUG_SD
#define SD_PRINT( _format_string ) SCI_TRACE_LOW _format_string
#else
#define SD_PRINT( _format_string )
#endif
/**---------------------------------------------------------------------------*
** Compiler Flag *
**---------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C"
{
#endif
/**---------------------------------------------------------------------------*
** Macro Definition *
**---------------------------------------------------------------------------*/
#define CS_NONE 0xF
#define SD_BLOCKSIZE 512
#define SD_BLOCKSIZE_NBITS 9
#define SD_DEFAULT_CLOCK 400000
#define SD_DMA_READ_LEN 128
#define SD_DMA_WRITE_LEN 32
#define SD_TIMEOUT 200000
/**---------------------------------------------------------------------------*
** Global Variables *
**---------------------------------------------------------------------------*/
SD_CARD_T* g_sd_ptCardList = NULL;
uint8 g_ucArgument[4];
uint8 g_ucResponse[5];
uint32 g_sd_default_blocksize = SD_BLOCKSIZE;
/**---------------------------------------------------------------------------*
** Constant Variables *
**---------------------------------------------------------------------------*/
/**---------------------------------------------------------------------------*
** Local Function Prototypes *
**---------------------------------------------------------------------------*/
LOCAL uint32 SD_WriteCmd(SD_CARD_T* ptSDCard,
uint8 ucCmd,
uint8 ucRspType,
uint8* pucResponse,
uint8* pucArgument);
LOCAL void SD_Delay(SD_SPIPORT_E eSPIId, uint32 uiCSId, uint32 uiNum);
LOCAL void SD_Packarg(uint8* pucArgument, uint32 uiValue);
LOCAL BOOLEAN SD_RegisterVerify(SD_CARD_T* ptSDCard);
LOCAL uint32 SD_WaitNotBusy (SD_CARD_T* ptSDCard);
/**---------------------------------------------------------------------------*
** Function Definitions *
**---------------------------------------------------------------------------*/
/*****************************************************************************/
// Description: This function is used to register the SPI hardware interface.
// Author: Benjamin.Wang
// Note:
/*****************************************************************************/
PUBLIC SD_CARD_T* SD_Register( // success - return the hardware interface vector
// failure - return NULL
SD_SPIPORT_E eId, // SPI port num
SD_SPICS_E uiCSId, // Chip select id
uint32 uiClockRate, // SPI clock
uint32 uiReadTimeout, // Max read timeout. typical value: uiClockRate / 20
uint32 uiWriteTimeout // Max write timeout. typical value: uiClockRate / 8
)
{
SD_CARD_T* ptNewItem = NULL;
SD_CARD_T* ptCurrentItem = NULL;
SPI_CONFIG_T tSPIConfig;
SPI_PORT_T* ptSPIPort;
tSPIConfig.freq = SD_DEFAULT_CLOCK; /* Start out with a slow SPI clock, 400kHz, as required by the SD spec (for MMC compatibility). */
tSPIConfig.lsb_first = SCI_FALSE;
tSPIConfig.rx_shift_edge = SCI_TRUE;
tSPIConfig.tx_bit_length = 8;
tSPIConfig.tx_shift_edge = SCI_TRUE;
/* Initialize the SPI controller */
ptSPIPort = SPI_Create(eId, &tSPIConfig, SCI_FALSE);
if(ptSPIPort == NULL)
{
/*It has two possibilities:
* 1. Both the SPI port and the CS has been occupied.
* 2. Only SPI port is occupied, but CS is free. This case is all right. But SPI driver hadn't differentiated them.
*/
SD_PRINT(("SDCard: This SPI Port Has been occupied!"));
SCI_PASSERT(SCI_FALSE, ("SDCard: This SPI Port Has been occupied!"));
return NULL;
}
ptCurrentItem = g_sd_ptCardList; //get root element
if(ptCurrentItem != NULL)
{
while(ptCurrentItem->pNextElement != NULL)
{
if(ptCurrentItem->eSPIId == eId)
{
if(ptCurrentItem->uiCSId == uiCSId)
{
SCI_PASSERT(SCI_FALSE, ("This SDCard has been initialized!"));
return NULL;
}
}
ptCurrentItem = ptCurrentItem->pNextElement;
}
ptNewItem = (SD_CARD_T*)SCI_ALLOC(sizeof(SD_CARD_T));
ptNewItem->eSPIId = eId;
ptNewItem->bBusyFlag = SCI_FALSE;
ptNewItem->uiClockRate = uiClockRate;
ptNewItem->uiReadTimeout = uiReadTimeout;
ptNewItem->uiWriteTimeout = uiWriteTimeout;
ptNewItem->uiCSId = uiCSId;
ptNewItem->pPreElement = NULL;
ptNewItem->pNextElement = NULL;
ptCurrentItem->pNextElement = ptNewItem;
ptNewItem->pPreElement = ptCurrentItem;
}
else
{
ptNewItem = (SD_CARD_T*)SCI_ALLOC(sizeof(SD_CARD_T));
ptNewItem->eSPIId = eId;
ptNewItem->bBusyFlag = SCI_FALSE;
ptNewItem->uiClockRate = uiClockRate;
ptNewItem->uiReadTimeout = uiReadTimeout;
ptNewItem->uiWriteTimeout = uiWriteTimeout;
ptNewItem->uiCSId = uiCSId;
ptNewItem->pPreElement = NULL;
ptNewItem->pNextElement = NULL;
g_sd_ptCardList = ptNewItem;
ptNewItem->pPreElement = g_sd_ptCardList;
}
return ptNewItem;
}
/*****************************************************************************/
// Description: This function is used to initialize the SDCard.
// Author: Benjamin.Wang
// Note:
/*****************************************************************************/
PUBLIC uint32 SD_Initialize( // SD_SUCCESS - SDCard init success
// SD_UNREGISTER - the SDCard hardware interface has not been registered.
// SD_FAILURE - SDCard init failure
SD_CARD_T* ptSDCard // SDCard vector
)
{
uint32 i, j;
uint32 result;
if(!SD_RegisterVerify(ptSDCard)) //verify the SDCard vector
{
return SD_UNREGISTER;
}
SPI_SetBusClk(ptSDCard->eSPIId, SD_DEFAULT_CLOCK); /* Start out with a slow SPI clock, 400kHz, as required by the SD spec (for MMC compatibility). */
/* SPI SD initialization sequence:
* CMD0
* CMD55
* ACMD41
* CMD58
* (Note there is no CMD2 or CMD3 in SPI mode. These
* instructions are devoted to addressing on the SD bus.)
*
* SD memory card SD initialization sequence:
* CMD0
* CMD55
* ACMD41
* CMD2
* CMD3
*/
if(ptSDCard != NULL)
{
ptSDCard->bBusyFlag = SCI_FALSE;
for (i = 0; i < 4; i++)
{
g_ucArgument[i] = 0;
}
//wait until sdcard DI pin has no data
SPI_SetCS(ptSDCard->eSPIId, ptSDCard->uiCSId);
ptSDCard->bBusyFlag = SCI_TRUE;
if ((result = SD_WaitNotBusy( ptSDCard)) != SD_SUCCESS)
{
return result;
}
/* Delay for at least 74 clock cycles. This means to actually
* *clock* out at least 74 clock cycles with no data present on
* the clock. In SPI mode, send at least 10 idle bytes (0xFF). */
SPI_SetCS(ptSDCard->eSPIId, CS_NONE);
for(i = 0; i < 10; i++); //Just wait a moment so that the waveform will be more beautiful.
SPI_SetCS(ptSDCard->eSPIId, ptSDCard->uiCSId);
SD_Delay(ptSDCard->eSPIId, ptSDCard->uiCSId, 200);
for(i = 0; i < 5; i++); //we can't set CS at once.
SPI_SetCS(ptSDCard->eSPIId, CS_NONE);
SD_Delay(ptSDCard->eSPIId, CS_NONE, 50);
/* Put the card in the idle state */
do
{
if (SD_WriteCmd(ptSDCard, CMD0, CMD0_R, g_ucResponse, g_ucArgument) != SD_SUCCESS)
{
return SD_INIT_CMD0_ERROR;
}
}
while(g_ucResponse[0] & 0xFE);
/* Now wait until the card goes idle. Retry at most SD_IDLE_WAIT_MAX
times */
j = 0;
do
{
j++;
/* Flag the next command as an application-specific command */
if (SD_WriteCmd(ptSDCard, CMD55, CMD55_R, g_ucResponse, g_ucArgument)== SD_SUCCESS)
{
/* Tell the card to send its OCR */
SD_WriteCmd(ptSDCard, ACMD41, ACMD41_R, g_ucResponse, g_ucArgument);
}
}
while ((g_ucResponse[0] & MSK_IDLE) == MSK_IDLE && j < SD_IDLE_WAIT_MAX);
/* As long as we didn't hit the timeout, assume we're OK. */
if (j >= SD_IDLE_WAIT_MAX)
{
return SD_INIT_WAIT_IDLE_ERROR;
}
//if (SD_WriteCmd(ptSDCard, CMD58, CMD58_R, g_ucResponse, g_ucArgument) == SD_FAILURE)
//{
//return SD_FAILURE - 1;
//}
/* At a very minimum, we must allow 3.3V. */
//if ((g_ucResponse[2] & MSK_OCR_33) != MSK_OCR_33)
//{
//return SD_FAILURE - 2;
//}
/* Set the block length */
//if (sd_set_blocklen (sdc, SD_BLOCKSIZE) != 1)
//return 0;
/* If we got this far, initialization was OK. */
/* Set the maximum SPI clock rate possible */
SPI_SetBusClk(ptSDCard->eSPIId, ptSDCard->uiClockRate);
/*Trace out Card's CSD Info for debug.*/
{
uint8 card_specific_data[16 + 2]; //16Bytes CSD + 2 CRC Bytes
uint32 i = 0;
if(SD_ReadCSD(ptSDCard, (uint8*)card_specific_data) == SD_SUCCESS)
{
for(i = 0; i < 16 + 2; i++)
{
SD_PRINT(("SDCard:CSD[%d]:0x%x", i, card_specific_data[i]));
}
}
}
return SD_SUCCESS;
}
return SCI_ERROR;
}
/*****************************************************************************/
// Description: This function is used to unregister the SDCard hardware interface.
// Author: Benjamin.Wang
// Note:
/*****************************************************************************/
PUBLIC uint32 SD_Close( //SD_SUCCESS - SDCard hardware interface close success
//SD_UNREGISTER - SDCard unregistered
//SD_CARDLIST_NULL - SDCard linklist is null
SD_CARD_T* ptSDCard // SDCard vector
)
{
SD_CARD_T* ptCurrent;
ptCurrent = g_sd_ptCardList;
if(ptCurrent != NULL)
{
if(ptCurrent == ptSDCard) //the first element is the closed.
{
g_sd_ptCardList = ptCurrent->pNextElement; //reset the header
ptCurrent->pNextElement->pPreElement = g_sd_ptCardList;
SPI_Close(ptCurrent->eSPIId);
SCI_FREE(ptCurrent); //free it
return SD_SUCCESS;
}
while(ptCurrent->pNextElement != NULL) //is tail?
{
ptCurrent = ptCurrent->pNextElement;
if(ptCurrent == ptSDCard) //is the closed element?
{
ptCurrent->pPreElement->pNextElement = ptCurrent->pNextElement; //adjust queue pointer
if (ptCurrent->pNextElement != NULL) //modified by xingyun.he 2005/12/24
{
ptCurrent->pNextElement->pPreElement = ptCurrent->pPreElement;
}
SPI_Close(ptCurrent->eSPIId);
SCI_FREE(ptCurrent); //free the element.
return SD_SUCCESS;
}
}
SD_PRINT(("This Card Can't be found in CardList!"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -