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

📄 mmcsd.c

📁 老外的一个开源项目
💻 C
📖 第 1 页 / 共 4 页
字号:
// Copyright (c) David Vescovi.  All rights reserved.
// Part of Project DrumStix
// Windows Embedded Developers Interest Group (WE-DIG) community project.
// http://www.we-dig.org
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Portions Copyright (c) SanDisk Corporation.  All rights reserved.
//------------------------------------------------------------------------------
//
//  File: mmcsd.c
//
//  MMC/SD driver
//
//
//------------------------------------------------------------------------------

#include "mmcsd.h"

extern DEVICE_CONTROLLER DeviceController;

/*******************************************************************************
* Name: mmcSDApplCmd - Handle all application commands
*
* Description:
*       Send CMD55 to switch the card into application mode. Then,
*       the application command is sent.
*
* NOTE: buff is a pointer to data buffer. This buffer is ONLY for the
*       command associated with data to/from the card.  For the command
*       without data requirement, this buff should be set to NULL before
*       calling this routine.
*
* Input:
*       UCHAR *buff
*       ULONG multipp
*       UINT16 RCA
*       RESP_TYPE resp
*       UINT16 Cmd
*
* Output:
*       Depending on the type of the command.
*
* Returns:
*       Completion code
* 
********************************************************************************/
MMC_CC mmcSDApplCmd(UCHAR *buff, ULONG multipp, UINT16 noBlocks, UINT16 RCA, RESP_TYPE resp, UINT16 Cmd)
{
	MMC_CC  respErr;
	UINT16  tLength;

	tLength = 0;
	if (Cmd & SECURITY_CMD_BIT)
		tLength = noBlocks;

	// ONLY FOR data transfer when buff is set
	if (buff)
	{
		respErr = mmcSetXferState (RCA);
	}

	// Send CMD55 to the card to start Application Specific Command
	respErr = mmcCommandAndResponse ((((ULONG)RCA) << 16),
									APPL_CMD, 
									0,
									R1 );

/*
The CMD55 is not supported by MMC card.  The MMC card may
not responded or responded with an error to this command.
Check for error here to tell if it is MMC or SD card. 
An SD card should behave well to this command (NO ERROR).
MMC card in SPI mode should reject or not respond to it.
MMC card in MMC mode should reject or not respond to it.
*/
	if ( ( respErr != MMC_NO_ERROR) && (respErr == MMC_COMUNC_ILLEG_COM) )
	{
		DeviceController.error_code = (UINT16)respErr;
		return respErr;
	}

    // Application Specific command follows CMD55.

	respErr = mmcCommandAndResponse (multipp,
								Cmd,
								tLength,
								resp );

	// The buff is ONLY for data transfer. Check it here for that purpose.
	if (buff)
	{
		// Security data will be handled different module
		if (Cmd & SECURITY_CMD_BIT)
			return respErr;

		DeviceController.user_address = (USERADDRESS)buff;
		if (respErr == MMC_NO_ERROR)
		{
			if (Cmd == SD_SEND_SCR)
			{
				tLength = SD_SCR_LENGTH;
			}
			else if (Cmd == SD_STATUS)
			{
				tLength = SD_STATUS_LENGTH;
			}
			respErr = mmcReceiveData(tLength, 1, FALSE);
		}
	}
	return respErr;
}



static UINT16 to_WORD (UCHAR *from)
{
	UINT16 nres;

	nres = ((UINT16) *((UINT16 *)from));
	return (nres);
}

/*******************************************************************************
* Name: mmcReset - Initialize the card
*
* Description:
*       Resets the cards and the MMC or SPI HW port.
*       It must be called after power on before any other commands.
*
*       This function sends reset command (CMD0) to the card and waits for the
*       card to complete the initialization process by polling its status using
*       send_op_condition command (CMD1) to complete its reset process.
*
*       In MMC mode, this function can be used to query a card stack for the
*       the common voltage range or to set a voltage range and initialize
*       the cards to be ready.
*
*       In SPI mode, the reset is card specific. The card number is used for the
*       device to be intialized for the card to be ready.
*
* Output:
*       Initialization process is finished.
*
* Returns:
*       Completion code
* 
********************************************************************************/
MMC_CC mmcReset( void )
{
	UINT32  cardType;
	MMC_CC  resErr;
	UINT16  sdFlag;
	UINT16  readyFlag;
	ULONG	setupInfo;

	UINT16  i, bInterface;
	UINT16  devCount;
	DeviceController.timer = (RESET_DELAY << 2);
	cardType = FALSE;
	readyFlag = FALSE;
	resErr = MMC_NO_ERROR;

	bInterface = 0;
	devCount = 0;

	sdFlag = FALSE;

	setupInfo =  0x00020000L;

DO_ALL_BUS_INTERFACE:
    for (i = 0; i < (CID_BYTE_LENGTH/2);
		DeviceController.LastResponse[i++] = 0);
	Stallms(25);

    while (DeviceController.timer)
    {
/*
There is no way to tell what type of the card is at this
point. The command CMD1 is sent first to test the card.
Because the MMC card is always responded to CMD1, if there
is no response, or an error, on the return, we could assume
that the card is not MMC card, the application command ACMD41
will be sent next to test for SD card.
*/   
		// Now, check for MMC card. SD do not support CMD1 in MMC mode.
		if (!sdFlag)
		{
			resErr = mmcCommandAndResponse (setupInfo,
					SEND_OP_COND,
					0,
					R3 );

			if (resErr == MMC_NO_ERROR)
			{
				// The card is indeed an MMC card.
				cardType = MMC_TYPE;
				readyFlag = to_WORD((UCHAR *)&DeviceController.LastResponse[0]);
			}
/*
CMD1 failed.  There are two ways to explain this:
1. SD card seems not to respond to CMD1 at all (MMC mode).
Therefore, based on the error, this could be an SD card.
Try ACMD41 command to verify this claim.
2. There is no card in the slot.
*/
            else if (resErr == MMC_CARD_IS_NOT_RESPONDING)
            {
				Stallms(55);

				// Try ACMD41 to poll for SD card.
				setupInfo = 0x00FF8000L;
				resErr = mmcSDApplCmd(NULL, setupInfo, 0, 0, R3, SD_SEND_OP_COND);
				if (resErr != MMC_CARD_IS_NOT_RESPONDING)
				{
					// The card is an SD card because it returns an error.
					sdFlag = TRUE;
				}
                if (resErr == MMC_CARD_IS_NOT_RESPONDING)
                {
                    resErr = MMC_INTERFACE_ERROR;
                    goto END_OF_CARDS_SEARCH;
                }
            }
            else
            {
                resErr = MMC_INTERFACE_ERROR;
                goto END_OF_CARDS_SEARCH;
            }
        }

		// Check for SD card.
		if (sdFlag)
		{
			setupInfo = 0x00FF8000L;

/*
Command CMD55 expects an RCA. At this point, the RCA
has not assigned to the card. Since SD card follows
the MMCA protocol, the RCA assignment is occured later.
*/
			resErr = mmcSDApplCmd(NULL, setupInfo, 0, 0, R3, SD_SEND_OP_COND);
			if (resErr == MMC_NO_ERROR)
			{
				cardType = SD_TYPE;
				sdFlag = TRUE;
				readyFlag = to_WORD((UCHAR *)&DeviceController.LastResponse[0]);
			}
		}

		if (resErr == MMC_CARD_IS_NOT_RESPONDING)
		{
			resErr = MMC_INTERFACE_ERROR;
			goto END_OF_CARDS_SEARCH;
		}

		if ( resErr == MMC_NO_ERROR )   /* If no error */
		{
			if ( (readyFlag & CARD_READY_FLAG) )
			{
				break;
			}
			DeviceController.timer--;
			Stallms(1);
			if ( !DeviceController.timer )
			{
				resErr = MMC_CARD_IS_NOT_READY;
				goto END_OF_CARDS_SEARCH;
			}
		}
	}

    // Assign IDs to all devices found
    i = FALSE;
    for (;;)
    {
		DeviceController.drive_active = i;
		if ( mmcIdentify(cardType, i) != MMC_NO_ERROR )
        {
			break;
        }
		if (cardType == SD_TYPE)
		{
			// The RCA is returned in DeviceController.LastResponse[4]
			DeviceController.drive.RCA = DeviceController.LastResponse[4];
		} 
		else
		{
			// For MMC card in MMC mode, the RCA is the (drive number + 1)
			DeviceController.drive.RCA = (UINT16)i + 1;
		}
        DeviceController.drive.card_type = cardType;

		i++;
		if(i>=1)
			break;
	}

	DeviceController.drive_active = FALSE;

	if ( i == FALSE )
	{
		resErr = MMC_INTERFACE_ERROR;
	}

	devCount += i;

END_OF_CARDS_SEARCH:

	if (sdFlag != TRUE)
	{
		if (bInterface < 1 )
		{
			bInterface++;
			sdFlag = TRUE;
			goto DO_ALL_BUS_INTERFACE;
		}
	}
	if ( devCount )
		resErr = MMC_NO_ERROR;

	DeviceController.error_code = (UINT16)resErr;
	return resErr;
}

/***********************************************************************************
* Name: mmcIdentify
*
* Description:
*       Available in MMC mode only. Identifiies and assigns an RCA
*       for a selected MMC card on the bus.
*
*       This function starts card identification cycle and (if a
*       valid response is received) assigns the RCA of the identified
*       card.                                                                    
*
* Input:
*       cardID  Card number for the identified card.
*       cardType Type of the card (MMC, SD, etc.)
* 
* Output:
*       The card is assigned with an RCA.
*
* Returns:
*       Completion code
*
************************************************************************************/
MMC_CC mmcIdentify (UINT32 cardType, UINT16 cardID)
{
	MMC_CC  resErr;
	resErr = mmcCommandAndResponse (0L,
				ALL_SEND_CID, 
				0,
				R2 );
	if ( resErr != MMC_NO_ERROR )
	{
		DeviceController.error_code = (UINT16)resErr;
		return resErr;
	}

	// Check for SD card
	if (cardType == SD_TYPE)
	{
/*
For SD card, the relative address is sent back
in the response DeviceController.LastResponse. If the command
is executed correctly, the RCA is at offset 4
from the starting address of the response.
*/
		resErr = mmcCommandAndResponse (0L,
										SET_RELATIVE_ADDR, 
										0,
										R6);
	}
	else
	{
/*
Assgin an ID to the device. The assigned RCA can be choose
as any 16-bit integer number. To make this assignment as
simplest as possible, the RCA assignment is calculating
by adding an 1 to the given cardID.
*/
		resErr = mmcCommandAndResponse (((((ULONG)cardID) + 1L) << 16),
		SET_RELATIVE_ADDR, 
		0,
		R1 );
	}

	DeviceController.error_code = (UINT16)resErr;
	return resErr;
}

/*******************************************************************************
* Name: mmcSetStandbyState - Set the card in stand by state
*
* Description:
*       In MMC mode, the deselect card command is sent to the card
*       to put it in stand by state.
*
* Input:
*       RCA     The address of the card to be selected.
*
* Output:
*       The card state is set to stand by state.
*
* Returns:
*       Completion code.
*
********************************************************************************/
MMC_CC mmcSetStandbyState (UINT16 RCA)
{
	MMC_CC  resErr;
	INT16   loopCnt;
	UINT16  mmcRCA;

REASSURE_STANDBY_STATE:
	mmcRCA = RCA;
	for (loopCnt = 0; loopCnt < 100; loopCnt++)
	{
		// Get the status from the card
		resErr = mmcCommandAndResponse ((((ULONG)RCA) << 16),
								SEND_STATUS,
								0,
								R1 );

		if (resErr != MMC_NO_ERROR )
			goto DONE_SET_TO_STANDBY_STATE;

		if (DeviceController.currentState == STANDBY)
			goto DONE_SET_TO_STANDBY_STATE;

		if (DeviceController.currentState == TRANSFER)
		{
			mmcRCA = 0;
			break;
		}
    }

    if (loopCnt == 100)
    {
        resErr = MMC_CARD_IS_BUSY;
        goto DONE_SET_TO_STANDBY_STATE;
    }


    // Check for the card current state

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -