📄 sdmmc_spi.c
字号:
// Send command
return SendCommand(pSd);
}
//------------------------------------------------------------------------------
/// Move SD card to transfer state. The buffer size must be at
/// least 512 byte long. This function checks the SD card status register and
/// address the card if required before sending the transfer command.
/// Returns 0 if successful; otherwise returns an code describing the error.
/// \param pSd Pointer to a SD card driver instance.
/// \param address Address of the block to transfer.
/// \param nbBlocks Number of blocks to be transfer.
/// \param pData Data buffer whose size is at least the block size.
/// \param isRead 1 for read data and 0 for write data.
//------------------------------------------------------------------------------
static unsigned char MoveToTransferState(SdCard *pSd,
unsigned int address,
unsigned short nbBlocks,
unsigned char *pData,
unsigned char isRead)
{
unsigned int status;
unsigned char error;
SdDriver *pSdDriver = pSd->pSdDriver;
if((pSd->state == SD_STATE_DATA)
|| (pSd->state == SD_STATE_RCV)) {
// SD SPI mode uses stop transmission token to stop multiple block write.
if ((pSd->state == SD_STATE_RCV) ) { //&& (pSd->mode == SD_SPI_MODE)) {
SDSPI_StopTranToken((SdSpi *)pSdDriver);
pSd->state = SD_STATE_STBY;
while (SDSPI_WaitDataBusy((SdSpi *)pSdDriver) == 1);
while (SDSPI_WaitDataBusy((SdSpi *)pSdDriver) == 1);
}
else {
error = Cmd12(pSd);
if (error) {
return error;
}
}
}
pSd->preBlock = address + (nbBlocks-1);
if(isRead) {
//TRACE_DEBUG("Read\n\r");
// Wait for card to be ready for data transfers
do {
//TRACE_DEBUG("state = 0x%X\n\r", (status & STATUS_STATE) >> 9);
error = Cmd13(pSd, &status);
if (error) {
TRACE_DEBUG("Pb MTTS cmd13\n\r");
return error;
}
break;
}
while (((status & STATUS_READY_FOR_DATA) == 0) ||
((status & STATUS_STATE) != STATUS_TRAN));
// Read data
// Move to Sending data state
error = Cmd18(pSd, nbBlocks, pData, SD_ADDRESS(pSd,address));
if (error) {
return error;
}
}
else {
//TRACE_DEBUG("Write\n\r");
// Wait for card to be ready for data transfers
do {
error = Cmd13(pSd, &status);
if (error) {
TRACE_DEBUG("error cmd 13\n\r");
return error;
}
break;
}
while ((status & STATUS_READY_FOR_DATA) == 0);
// Move to Sending data state
error = Cmd25(pSd, nbBlocks, pData, SD_ADDRESS(pSd,address));
if (error) {
TRACE_DEBUG("error cmd 25\n\r");
return error;
}
}
return error;
}
//------------------------------------------------------------------------------
// Global functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Read Block of data in a buffer pointed by pData. The buffer size must be at
/// least 512 byte long. This function checks the SD card status register and
/// address the card if required before sending the read command.
/// Returns 0 if successful; otherwise returns an code describing the error.
/// \param pSd Pointer to a SD card driver instance.
/// \param address Address of the block to read.
/// \param nbBlocks Number of blocks to be read.
/// \param pData Data buffer whose size is at least the block size.
//------------------------------------------------------------------------------
unsigned char SD_ReadBlock(SdCard *pSd,
unsigned int address,
unsigned short nbBlocks,
unsigned char *pData)
{
unsigned char error;
SANITY_CHECK(pSd);
SANITY_CHECK(pData);
SANITY_CHECK(nbBlocks);
if((pSd->state == SD_STATE_DATA)
&& ((pSd->preBlock + 1) == address)) {
#if defined(at91rm9200)
error = Cmd12(pSd);
if (error) {
return error;
}
#else
TRACE_DEBUG("SD_ReadBlock:ContinuousRead\n\r");
error = ContinuousRead(pSd, nbBlocks, pData, SD_ADDRESS(pSd,address));
pSd->preBlock = address + (nbBlocks-1);
#endif
}
else {
error = MoveToTransferState(pSd, address, nbBlocks, pData, 1);
}
return error;
}
//------------------------------------------------------------------------------
/// Write Block of data pointed by pData. The buffer size must be at
/// least 512 byte long. This function checks the SD card status register and
/// address the card if required before sending the read command.
/// Returns 0 if successful; otherwise returns an SD_ERROR code.
/// \param pSd Pointer to a SD card driver instance.
/// \param address Address of block to write.
/// \param nbBlocks Number of blocks to be read
/// \param pData Pointer to a 512 bytes buffer to be transfered
//------------------------------------------------------------------------------
unsigned char SD_WriteBlock(SdCard *pSd,
unsigned int address,
unsigned short nbBlocks,
const unsigned char *pData)
{
unsigned char error;
SANITY_CHECK(pSd);
SANITY_CHECK(pData);
SANITY_CHECK(nbBlocks);
if((pSd->state == SD_STATE_RCV)
&& ((pSd->preBlock + 1) == address)) {
TRACE_DEBUG("SD_WriteBlock:ContinuousWrite\n\r");
error = ContinuousWrite(pSd, nbBlocks, pData, SD_ADDRESS(pSd,address));
pSd->preBlock = address + (nbBlocks-1);
}
else {
//TRACE_FATAL("SD_WriteBlock:MoveToTransferState\n\r");
error = MoveToTransferState(pSd, address, nbBlocks,
(unsigned char *)pData, 0);
}
return error;
}
//------------------------------------------------------------------------------
/// Run the SDcard SPI Mode initialization sequence. This function runs the
/// initialisation procedure and the identification process, then it sets the SD
/// card in transfer state to set the block length.
/// Returns 0 if successful; otherwise returns an SD_ERROR code.
/// \param pSd Pointer to a SD card driver instance.
/// \param pSdDriver Pointer to SD driver already initialized.
//------------------------------------------------------------------------------
unsigned char SD_SPI_Init(SdCard *pSd, SdDriver *pSpi)
{
unsigned char isCCSet;
unsigned char error;
unsigned char cmd8Retries = 2;
unsigned char cmd1Retries = 1;
unsigned int pOCR;
// The command GO_IDLE_STATE (CMD0) is the software reset command and sets card into Idle State
// regardless of the current card state.
error = Cmd0(pSd);
if (error) {
TRACE_ERROR("Error during initialization (%d)\n\r", error);
return error;
}
// CMD8 is newly added in the Physical Layer Specification Version 2.00 to support multiple voltage
// ranges and used to check whether the card supports supplied voltage. The version 2.00 host shall
// issue CMD8 and verify voltage before card initialization.
// The host that does not support CMD8 shall supply high voltage range...
do {
error = Cmd8(pSd, 1);
}
while ((error == SD_ERROR_NORESPONSE) && (cmd8Retries-- > 0));
if (error == SD_ERROR_NORESPONSE) {
// No response : Ver2.00 or later SD Memory Card(voltage mismatch)
// or Ver1.X SD Memory Card
// or not SD Memory Card
TRACE_DEBUG("No response to Cmd8\n\r");
// CMD58 ? !
error = Cmd58(pSd, &pOCR);
if (error) {
TRACE_ERROR("Error during initialization (%d), 8\n\r", error);
return error;
}
// ACMD41 is a synchronization command used to negotiate the operation voltage range and to poll the
// cards until they are out of their power-up sequence.
error = Acmd41(pSd, 0, &isCCSet);
if (error) {
// Acmd41 failed : MMC card or unknown card
error = Cmd0(pSd);
if (error) {
TRACE_ERROR("Error during initialization (%d)\n\r", error);
return error;
}
do {
error = Cmd1(pSd);
}
while ((error) && (cmd1Retries-- > 0));
if (error) {
TRACE_ERROR("Error during initialization (%d)\n\r", error);
return error;
}
else {
pSd->cardType = CARD_MMC;
}
}
else {
if(isCCSet == 0) {
TRACE_DEBUG("CARD SD\n\r");
pSd->cardType = CARD_SD;
}
}
}
else if (!error) {
error = Cmd58(pSd, &pOCR);
if (error) {
TRACE_ERROR("Error during initialization (%d), 8\n\r", error);
return error;
}
// Valid response : Ver2.00 or later SD Memory Card
error = Acmd41(pSd, 1, &isCCSet);
if (error) {
TRACE_ERROR("Error during initialization (%d)\n\r", error);
return error;
}
error = Cmd58(pSd, &pOCR);
if (error) {
TRACE_ERROR("Error during initialization (%d), 8\n\r", error);
return error;
}
if (isCCSet) {
TRACE_DEBUG("CARD SDHC\n\r");
pSd->cardType = CARD_SDHC;
}
else {
TRACE_DEBUG("CARD SD\n\r");
pSd->cardType = CARD_SD;
}
}
else {
TRACE_ERROR("Error during initialization (%d)\n\r", error);
return error;
}
if (pSd->cardType != CARD_MMC) {
// The host issues CRC_ON_OFF (CMD59) to set data CRC on/off
// The host can turn the CRC option on and off using the CRC_ON_OFF command (CMD59).
// Host should enable CRC verification before issuing ACMD41.
error = Cmd59(pSd,0); // turn crc option OFF
if (error) {
TRACE_ERROR("Error during initialization (%d)\n\r, 59", error);
return error;
}
}
// The host issues SEND_CSD (CMD9) to obtain the Card Specific Data (CSD register),
// e.g. block length, card storage capacity, etc...
error = Cmd9(pSd);
if (error) {
TRACE_ERROR("Error during initialization (%d), 9\n\r", error);
return error;
}
return 0;
}
//
//------------------------------------------------------------------------------
/// Run the SDcard initialization sequence. This function runs the initialisation
/// procedure and the identification process, then it sets the SD card in transfer
/// state to set the block length and the bus width.
/// Returns 0 if successful; otherwise returns an SD_ERROR code.
/// \param pSd Pointer to a SD card driver instance.
/// \param pSdDriver Pointer to SD driver already initialized.
/// \param mode Select SD or SPI access mode
//------------------------------------------------------------------------------
unsigned char SD_Init(SdCard *pSd, SdDriver *pSdDriver)
{
unsigned char error;
//TRACE_DEBUG("SD_Init()\n\r");
// Initialize SdCard structure
pSd->pSdDriver = pSdDriver;
pSd->cardAddress = 0;
pSd->preBlock = 0xffffffff;
pSd->state = SD_STATE_STBY;
pSd->cardType = UNKNOWN_CARD;
memset(&(pSd->command), 0, sizeof(SdCmd));
// Initialization delay: The maximum of 1 msec, 74 clock cycles and supply ramp up time
// 慡upply ramp up time
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -