⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sd.c

📁 SdCard_V2.1TinyFatFs.rar是单片机实现SD卡功能的FAT文件系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
**********************************************************************************************
* 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 + -