📄 sd.c
字号:
/*
**********************************************************************************************
* Project: FS7805 SD CARD READER
* File: main.c
* Contents:
* The main function is SD and MMC card reader.
*
* $Date: 12/15/06 Derek V1.0
*
* Coments: This is the SD/MMC card reader firmware.
* When read sector,the 512 pingpong FIFO mechanism
* is used to improve performance.But when write sector,
* only single FIFO is used.
*
* $Date: 12/27/06 Derek V1.1
*
* The 512 pingpong FIFO mechanism is also used when
* writting sectors.
*
* $Date: 01/09/07 Derek V1.11
*
* Fix read sector error bug .
* Don't set FIFO_FULL bit in SetBulkInFull() function.
* Setting it in BulkSetDmaIn() function.
*
* $Date: 01/18/07 Derek V1.11
*
* Ignor the OUT_OF_RANGE error in SdSendCmd() when
* multi read the last block.
*
* Copyright (c) 2006 Fameg, Inc. All rights reserved
*
*
***********************************************************************************************
*/
#include "include\Include.h"
#define MAX_CMD_LEN 6
#define MAX_RESP_LEN 17 // Max response length = 136 bits
#define RSP_LEN 6
#define LONG_RSP_LEN 17
#define CARD_CMD_START 0x40
#define CARD_PWRUP_FINISH 0x80
#define OPERATION_VOL_RANGE 0x00FF0000
#define GOOD_CRC16_STS 0x02
/* SD_COMMAND */
#define SD_CMD_ONLY 1
#define SD_CMD_SHORT_RSP 2
#define SD_CMD_LONG_RSP 3
#define SD_CMD_TX_DATA 4
#define SD_CMD_TX_DATA_ONLY 5
#define SD_CMD_RX_DATA 6
#define SD_CMD_RX_DATA_ONLY 7
#define IDLE_STATE 0
#define READY_STATE 1
#define IDENTIFY_STATE 2
#define STANDBY_STATE 3
#define TRANSFER_STATE 4
#define DATA_STATE 5
#define RECEIVE_STATE 6
#define PRGROGAM_STATE 7
#define DISCONNECT_STATE 8
#define BUS_WIDTH_1BIT 0x00
#define BUS_WIDTH_4BIT 0x02
// Command Name Index MMC-3.1 MMC-4.0 SD-1.01 Resp
#define GO_IDLE_STATE 0 // V V V -
#define SEND_OP_COND 1 // V V R3 (OCR)
#define ALL_SEND_CID 2 // V V V R2
#define SEND_RELATIVE_ADDR 3 // R1 R1 R6 See SdGetRespType()
#define SET_DSR 4 // V V V -
#define SWITCH 6 // V R1b
#define CMD6 6 // R1(SD 1.10,2.0)
#define SELECT_CARD 7 // V V V R1
#define SEND_EXT_CSD 8 // V R1
#define SEND_IF_COND 8 // R7(SD2.0)
#define SEND_CSD 9 // V V V R2
#define SEND_CID 10 // V V V R2
#define READ_DAT_UNTIL_STOP 11 // V V R1
#define STOP_TRANS 12 // V V V R1
#define SEND_STATUS 13 // V V V R1
#define GO_INACTIVE_STATE 15 // V V V -
#define SET_BLOCKLEN 16 // V V V R1
#define READ_BLOCK 17 // V V V R1
#define READ_MUL_BLOCK 18 // V V V R1
#define WRITE_DAT_UNTIL_STOP 20 // V V R1
#define SET_BLOCK_COUNT 23 // V V R1
#define WRITE_BLOCK 24 // V V V R1
#define WRITE_MUL_BLOCK 25 // V V V R1
#define PROGRAM_CID 26 // V V R1
#define PROGRAM_CSD 27 // V V V R1
#define SET_WRITE_PROT 28 // V V V R1
#define CLR_WRITE_PROT 29 // V V V R1
#define SEND_WRITE_PROT 30 // V V V R1
#define ERASE_WR_BLK_START 32 // V R1
#define ERASE_WR_BLK_END 33 // V R1
#define ERASE_GROUP_START 35 // V V R1
#define ERASE_GROUP_END 36 // V V R1
#define ERASE 38 // V V V R1
#define FAST_IO 39 // V V R4
#define GO_IRQ_STATE 40 // V V R5
#define LOCK_UNLOCK 42 // V V V R1
#define APP_CMD 55 // V V V R1
#define GEN_CMD 56 // V V V R1
// ACMD Name Index MMC-3.1 MMC-4.0 SD-1.01 Resp
#define SET_BUS_WIDTH 6 // V R1
#define SEND_SD_STATUS 13 // V R1
#define SEND_NUM_WR_BLOCKS 22 // V R1
#define SET_WR_BLK_ERASE_CNT 23 // V R1
#define SD_SEND_OP_COND 41 // V R3 (OCR)
#define SET_CLR_CARD_DETECT 42 // V R1
#define SEND_SCR 51 // V R1
// ??? According to Spec of MMC3.1, MultiMediaCard returns response of
// type R1 to APP_CMD (CMD55). But, according to Spec of SD1.01
// page 23, MultiMediaCard will not respond to APP_CMD - CMD55.
// Is this a confliction ?
#define SdHiClk() SDMI_CTL=(SDMI_CTL|bmSD_CLK_SEL)|bmSD_CLK_EN;
#define SdLoClk() SDMI_CTL=(SDMI_CTL&~bmSD_CLK_SEL)|bmSD_CLK_EN;
#define SdStopClk() SDMI_CTL=SDMI_CTL&~bmSD_CLK_EN & ~bmSD_AUTO_CLK_EN; //06.08.22
#define IsCardBusy() (SDMI_ST&bmSD_BUSY)
#define SdWriteProtect() ((SDMI_ST & bmSD_WR_PROTECT))
#define SdWaitCard()\
{\
CmdTimer = SD_CMD_TIMEOUT;\
while (IsCardBusy() && CmdTimer);\
}
#define SdPowerOn()
#define SdPowerOff()
typedef enum {CARD_SD, CARD_MMC} TCARD_TYPE;
/*************************************************
Global Variables
*************************************************/
xdata BYTE SdGetFlashInfoTimer = 0;
//BYTE xdata SdRespBufForProgCsd[17];
/*************************************************
Local Variables
*************************************************/
static xdata UINT32 SdAvailableBlocks = 0;
static xdata TCARD_TYPE CardType = CARD_SD;
static xdata BYTE SdCmdBuf[MAX_CMD_LEN];
xdata BYTE SdRespBuf[MAX_RESP_LEN];
static xdata UINT32 RCA = 0;
static BOOL MmcProtol;//控制是3.1的卡还是4.0的卡。
xdata BYTE SdHcFlag = 0;//Derek 2007.06.29
xdata BYTE SdVer2Flag = 0;//是否2.00的SD卡
#define TYPE_RESP_NO 0
#define TYPE_RESP_R1 1
#define TYPE_RESP_R2 2
#define TYPE_RESP_R3 3
#define TYPE_RESP_R4 4
#define TYPE_RESP_R5 5
#define TYPE_RESP_R6 6
#define TYPE_RESP_R7 7
/*
*********************************************************************************************************
* SdGetRespType()
*
* Description: Return response type of every command.
*
* Arguments : CmdIndex
*
* Returns : none
*********************************************************************************************************
*/
BYTE SdGetRespType(BYTE CmdIndex)
{
if(CmdIndex == SEND_RELATIVE_ADDR)
{
////if(CardType == CARD_SD)
return TYPE_RESP_R6;
////else
//// return TYPE_RESP_R1;//对MMC,若返回R1会出现illegal command 错误标志
}
switch(CmdIndex)
{
case GO_IDLE_STATE : return TYPE_RESP_NO; break;
case SEND_OP_COND : return TYPE_RESP_R3; break;
case ALL_SEND_CID : return TYPE_RESP_R2; break;
case SET_DSR : return TYPE_RESP_NO; break;
// case SWITCH : return TYPE_RESP_R1; break;
case CMD6 : return TYPE_RESP_R1; break; //Derek 2007.07.02
case SELECT_CARD : return TYPE_RESP_R1; break;
// case SEND_EXT_CSD : return TYPE_RESP_R1; break;
case SEND_IF_COND : return TYPE_RESP_R7; break;//2007.06.29
case SEND_CSD : return TYPE_RESP_R2; break;
case SEND_CID : return TYPE_RESP_R2; break;
case READ_DAT_UNTIL_STOP : return TYPE_RESP_R1; break;
case STOP_TRANS : return TYPE_RESP_R1; break;
case SEND_STATUS : return TYPE_RESP_R1; break;
case GO_INACTIVE_STATE : return TYPE_RESP_NO; break;
case SET_BLOCKLEN : return TYPE_RESP_R1; break;
case READ_BLOCK : return TYPE_RESP_R1; break;
case READ_MUL_BLOCK : return TYPE_RESP_R1; break;
case WRITE_DAT_UNTIL_STOP : return TYPE_RESP_R1; break;
case SET_BLOCK_COUNT : return TYPE_RESP_R1; break;
case WRITE_BLOCK : return TYPE_RESP_R1; break;
case WRITE_MUL_BLOCK : return TYPE_RESP_R1; break;
case PROGRAM_CID : return TYPE_RESP_R1; break;
case PROGRAM_CSD : return TYPE_RESP_R1; break;
case SET_WRITE_PROT : return TYPE_RESP_R1; break;
case CLR_WRITE_PROT : return TYPE_RESP_R1; break;
case SEND_WRITE_PROT : return TYPE_RESP_R1; break;
case ERASE_WR_BLK_START : return TYPE_RESP_R1; break;
case ERASE_WR_BLK_END : return TYPE_RESP_R1; break;
case ERASE_GROUP_START : return TYPE_RESP_R1; break;
case ERASE_GROUP_END : return TYPE_RESP_R1; break;
case ERASE : return TYPE_RESP_R1; break;
case FAST_IO : return TYPE_RESP_R4; break;
case GO_IRQ_STATE : return TYPE_RESP_R5; break;
case LOCK_UNLOCK : return TYPE_RESP_R1; break;
case APP_CMD : return TYPE_RESP_R1; break;
case GEN_CMD : return TYPE_RESP_R1; break;
// APP_CMDs
case SEND_NUM_WR_BLOCKS : return TYPE_RESP_R1; break;
case SD_SEND_OP_COND : return TYPE_RESP_R3; break;
case SEND_SCR : return TYPE_RESP_R1; break;
default : return TYPE_RESP_NO; break;
}
// Following commands are with identical index and response type:
// 1. SET_BUS_WIDTH (ACMD6) Response R1
// SWITCH (CMD6) Response R1
// 2. SEND_SD_STATUS (ACMD13) Response R1
// SEND_STATUS (CMD13) Response R1
// 3. SET_WR_BLK_ERASE_CNT (ACMD23) Response R1
// SET_BLOCK_COUNT (CMD23) Response R1
// 4. SET_CLR_CARD_DETECT (ACMD42) Response R1
// LOCK_UNLOCK (CMD42) Response R1
}
/*
*********************************************************************************************************
* SdSendCmd()
*
* Description: Send command to SD/MMC.
*
* Arguments : CmdIndex: command index value
* CmdBuf : pointer to command coments buffer
*
* Returns : none
*********************************************************************************************************
*/
STATUS SdSendCmd(BYTE CmdIndex, PBYTE CmdBuf)
{
BYTE RespType , RespLen , CmdType;
//BYTE Status;
BYTE i;
BYTE RetryCount = 0;
RespType = SdGetRespType(CmdIndex);
if((CmdIndex == READ_BLOCK)||
(CmdIndex == READ_MUL_BLOCK)||
(CmdIndex == SEND_SCR))//11.30 DEREK.
{ //SEND_EXT_CSD命令,和读数据是同一类型的命令。处理方法一样。
RespLen = 6; //见MMC4.0 spec。page42-43
CmdType = SD_CMD_RX_DATA;
}
else if((CmdIndex == WRITE_BLOCK)||
(CmdIndex == WRITE_MUL_BLOCK))
{
RespLen = 6;
CmdType = SD_CMD_TX_DATA;
}
else if((CmdIndex == CMD6)&&(SdVer2Flag)) //2007.07.02
{ //V1.10,V2.00 SD的CMD6,特殊处理
RespLen = 6;
CmdType = SD_CMD_RX_DATA; //V1.10,V2.00 SD CMD6有返回数据
}
else if(RespType == TYPE_RESP_NO)
{
RespLen = 0;
CmdType = SD_CMD_ONLY;
}
else if(RespType == TYPE_RESP_R2)
{
RespLen = 17;
CmdType = SD_CMD_LONG_RSP;
}
else
{
RespLen = 6;
CmdType = SD_CMD_SHORT_RSP;
}
if (CmdIndex == 0x5)
{
RespLen = 6;
CmdType = SD_CMD_SHORT_RSP;
}
for( ; RetryCount < 5; RetryCount++)
{
SDMCMDRESBUF00 = CARD_CMD_START | CmdIndex;
for(i = 1; i <= 4; i++) //The next 4 bytes
((BYTE xdata *)(&SDMCMDRESBUF00))[i]=CmdBuf[i];
//CRC由硬件自动发送
SDMI_CMD=CmdType;
CmdTimer = 5; // 50ms
while(CmdTimer > 0)
{
if((SDMI_INT&bmSD_COMPLETE_INT)!=0) //等待命令执行完毕
{
SDMI_INT&=~bmSD_COMPLETE_INT;
break;
}
}//*/
if(CmdTimer == 0) // Timeout
{
SdCtrlReset(); // ???
continue;
}
if(RespType == TYPE_RESP_NO)
return STATUS_SUCCESS;
if(RespType == TYPE_RESP_R3)
{
// The response type of SD_SEND_OP_COND (ACMD41) and
// SEND_OP_COND (CMD1) are both R3, which is not protected
// by CRC7. But hardware could still report CRC7 error for
// these command's response. So, to prevent from affecting
// next command, we clear CRC7-ERR INT bit here.
SDMI_ST&=~bmSD_CRC7_ERR;
for(i = 0; i < RespLen; i++)
SdRespBuf[i] = ((BYTE xdata *)(&SDMCMDRESBUF00))[i];
return STATUS_SUCCESS;
}
if(SDMI_ST&bmSD_CRC7_ERR) // CRC7 Error
{
SDMI_ST&=~bmSD_CRC7_ERR; // Clear INT
continue;
}
for(i = 0; i < RespLen; i++)
SdRespBuf[i] = ((BYTE xdata *)(&SDMCMDRESBUF00))[i];
if(RespType == TYPE_RESP_R1)
{
// Check following error bits in Card Status:
// 31 OUT_OF_RANGE SdRespBuf[1].7
// 30 ADDRESS_ERROR SdRespBuf[1].6
// 29 BLOCK_LEN_ERROR SdRespBuf[1].5
// 28 ERASE_SEQ_ERROR SdRespBuf[1].4
// 27 ERASE_PARAM SdRespBuf[1].3
// 26 WP_VIOLATION SdRespBuf[1].2
// 24 LOCK_UNLOCK_FAILED SdRespBuf[1].0
// 23 COM_CRC_ERR SdRespBuf[2].7
// 22 ILLEGAL_COMMAND SdRespBuf[2].6
// 21 CARD_ECC_FAILED SdRespBuf[2].5
// 20 CC_ERROR SdRespBuf[2].4
// 19 ERROR SdRespBuf[2].3
if( ( (SdRespBuf[1] & 0xFD) == 0 ) && // 8'b1111_1101
( (SdRespBuf[2] & 0xB8) == 0 ) ) // 从8'b1111_1000修正到8'b1011_1000,
//某些MMC卡,例如PQI,会出现ILLEGAL_COMMAND错误,将该位屏蔽。--Derek 2007.07.27
return STATUS_SUCCESS; // No error
else
if( ( SdRespBuf[1] == 0x80 ) && //ignor OUT_OF_RANGE error--2007.01.18
( SdRespBuf[2] == 0 ) )// && // when multi read last block
//(( SectorStart >= SdAvailableBlocks-5)&&
// ( SectorStart <= SdAvailableBlocks))) //见MMC 4.0 SPEC--4.6.3(page 49)
return STATUS_SUCCESS; //不同的卡,出错的位置不同,这里确定为最后5个block.
else //如果想一劳永逸,可以屏蔽掉这个错误位.
continue;
}
else
return STATUS_SUCCESS;
}
return STATUS_FLASH_ERROR;
}
/*
*********************************************************************************************************
* SdSendAppCmd()
*
* Description: Send App command to SD.
*
* Arguments : AppCmdIndex: App command index value
* CmdBuf : pointer to App command coments buffer
*
* Returns : none
*********************************************************************************************************
*/
STATUS SdSendAppCmd(BYTE AppCmdIndex, PBYTE AppCmdBuf)
{
STATUS Status;
int RetryCount;
BYTE CmdBuf55[MAX_CMD_LEN]; // for APP_CMD (CMD55)
for(RetryCount = 0; RetryCount < 3; RetryCount++)
{
*((UINT32 *)(&CmdBuf55[1])) = RCA;
Status = SdSendCmd(APP_CMD, CmdBuf55);
if(Status != STATUS_SUCCESS)
{
continue;
}
Status = SdSendCmd(AppCmdIndex, AppCmdBuf);
if(Status != STATUS_SUCCESS)
continue;
else
return STATUS_SUCCESS;
}
return STATUS_FLASH_ERROR;
}
/*
*********************************************************************************************************
* SdChangeBusWidth()
*
* Description: Change SD/MMC bus width.
*
* Arguments : BYTE busWidth.
* For SD card,1,4 are available.
* For MMC 4.0 card,1,4 and 8 are available.
*
* Returns : none
*********************************************************************************************************
*/
STATUS SdChangeBusWidth(BYTE busWidth) //busWidth只能取值1或4或8
{
STATUS Status=0;
if(CardType == CARD_SD)
{
if(busWidth==4)
*((INT32U *)(&SdCmdBuf[1])) = RCA | 0x02; //4bits bus width
else
*((INT32U *)(&SdCmdBuf[1])) = RCA;
Status = SdSendAppCmd(SET_BUS_WIDTH,SdCmdBuf);
if(Status == STATUS_SUCCESS)
{
if(busWidth==4)
{
SDMI_CTL&=~bmSD_BUS_8BIT_EN;
SDMI_CTL|=bmSD_BUS_4BIT_EN;
}
else
{
SDMI_CTL&=~bmSD_BUS_8BIT_EN;
SDMI_CTL&=~bmSD_BUS_4BIT_EN;
}
}
}
else // MMC
{
if(MmcProtol) // MMC 4.0 支持1/4/8 bits mode//
{
if(busWidth==8) //8 BIT
*((INT32U *)(&SdCmdBuf[1])) = 0x03b70200;
else if(busWidth==4)//4 BIT
*((INT32U *)(&SdCmdBuf[1])) = 0x03b70100;
else //1 BIT
*((INT32U *)(&SdCmdBuf[1])) = 0x03b70000;
Status = SdSendCmd(SWITCH, SdCmdBuf);
if(Status == STATUS_SUCCESS)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -