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

📄 mci.c

📁 NXP产品LPC23XX的开发板的源文件
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* Disable all interrupts for now */
    MCI_MASK0 = 0;
    MCI_MASK1 = MCI_MASK0;    

	/* Due to reversed H/W logic in the MCB2300 board, the MCI power pin
	needs to be configured as GPIO pin that I need to set it active low manually, 
	once it's set as MCI power pin, it will be active high. */
	/*connect MCI signals to P0.19-P0.22, and P2.11-P2.13*/
#if MCB2300_VERSION_0
	PINSEL1 = 0x2280;
	PINSEL4 = 0x0A800000;
	IODIR0 = 1 << 21;		/* MCI_PWR as GPIO output */
	IOCLR0 = 1 << 21;
#else
    PINSEL1 = 0x2A80;
	PINSEL4 = 0x0A800000;
#endif

	/*set up clocking default mode, clear any registers as needed */
    MCI_COMMAND = 0;
    MCI_DATA_CTRL = 0;			
    MCI_CLEAR = 0x7FF;		/* clear all pending interrupts */

	MCI_POWER = 0x02;		/* power up */
	while ( !(MCI_POWER & 0x02) );
	for ( i = 0; i < 0x100; i++ );

	/* During identification phase, the clock should be less than
	400Khz. Once we pass this phase, the normal clock can be set up
	to 25Mhz on SD card and 20Mhz on MMC card. */	
	Set_MCIClock( SLOW_RATE );
	MCI_POWER |= 0x01;		/* bit 1 is set already, from power up to power on */
	
	for ( i = 0; i < 0x2000; i++ );
    if ( install_irq( MCI_INT, (void *)MCI_Handler, HIGHEST_PRIORITY ) == FALSE )
    {
		return ( FALSE );
    }

	/* During the initialization phase, to simplify the process, the CMD related 
	interrupts are disabled. The DATA related interrupts are enabled when
	the FIFOs are used and just before WRITE_BLOCK READ_BLOCK cmds are issues, and 
	disabled after the data block has been written and read. Please also note,
	before WRITE_BLOCK only TX related data interrupts are enabled, and before
	READ_BLOCK only RX related data interrupts are enabled. */   
    return (TRUE);
}

/******************************************************************************
** Function name:		MCI_SendCmd
**
** Descriptions:		The routine is used to send a CMD to the card		
**
** parameters:			CmdIndex, Argument, ExpectResp Flag, AllowTimeout flag
** Returned value:		None
** 
******************************************************************************/
void MCI_SendCmd( DWORD CmdIndex, DWORD Argument, DWORD ExpectResp, DWORD AllowTimeout )
{
    DWORD i, CmdData = 0;
	DWORD CmdStatus;
	
	/* the command engine must be disabled when we modify the argument
     or the peripheral resends */
	while ( (CmdStatus = MCI_STATUS) & MCI_CMD_ACTIVE )	/* Command in progress. */
	{
		MCI_COMMAND = 0;
		MCI_CLEAR = CmdStatus | MCI_CMD_ACTIVE;
	}
	for ( i = 0; i < 0x100; i++ );	

    /*set the command details, the CmdIndex should 0 through 0x3F only */
	CmdData |= (CmdIndex & 0x3F);	/* bit 0 through 5 only */
	if ( ExpectResp == EXPECT_NO_RESP )			/* no response */
	{
		CmdData &= ~((1 << 6) | (1 << 7));		/* Clear long response bit as well */
	}
	else if ( ExpectResp == EXPECT_SHORT_RESP )	/* expect short response */
	{
		CmdData |= (1 << 6);
	}
	else if ( ExpectResp == EXPECT_LONG_RESP )	/* expect long response */
	{
		CmdData |= (1 << 6) | (1 << 7);
	}

	if ( AllowTimeout )			/* allow timeout or not */
	{
		CmdData |= (1 << 8);
	}
	else
	{
		CmdData &= ~(1 << 8);
	}

	/*send the command*/
	CmdData |= (1 << 10);		/* This bit needs to be set last. */
	MCI_ARGUMENT = Argument;	/* Set the argument first, finally command */
	MCI_COMMAND = CmdData;
	return;

}

/******************************************************************************
** Function name:		MCI_GetCmdResp
**
** Descriptions:		Get response from the card. This module is always used
**						in pair with MCI_SendCmd()		
**
** parameters:			Expected cmd data, expect response flag, pointer to the 
**						response
**						Expected cmd data should be the same as that in SendCmd()
**						expect response flag could be	EXPECT_NO_RESP
**														EXPECT_SHORT_RESP
**														EXPECT_LONG_RESP
**						if GetCmdResp() is 0, check the pointer to the response
**						field to get the response value, if GetCmdResp() returns 
**						non-zero, no need to check the response field, just resend
**						command or bailout. 
** Returned value:		Response status, 0 is valid response. 
** 
******************************************************************************/
DWORD MCI_GetCmdResp( DWORD ExpectCmdData, DWORD ExpectResp, DWORD *CmdResp )
{
	DWORD CmdRespStatus = 0;
	DWORD LastCmdIndex;

    if ( ExpectResp == EXPECT_NO_RESP )
	{
		return ( 0 );
	}

	while ( 1 )
	{
		CmdRespStatus = MCI_STATUS;	
		if ( CmdRespStatus & (MCI_CMD_TIMEOUT) )
		{
			MCI_CLEAR = CmdRespStatus | MCI_CMD_TIMEOUT;
			MCI_COMMAND = 0;
			MCI_ARGUMENT = 0xFFFFFFFF;
			return ( CmdRespStatus );
		}
		if (  CmdRespStatus & MCI_CMD_CRC_FAIL )
		{
			MCI_CLEAR = CmdRespStatus | MCI_CMD_CRC_FAIL;
			LastCmdIndex = MCI_COMMAND & 0x003F;
			if ( (LastCmdIndex == SEND_OP_COND) || (LastCmdIndex == SEND_APP_OP_COND) 
					|| (LastCmdIndex == STOP_TRANSMISSION) )
			{
				MCI_COMMAND = 0;
				MCI_ARGUMENT = 0xFFFFFFFF;	 
				break;			/* ignore CRC error if it's a resp for SEND_OP_COND 
								or STOP_TRANSMISSION. */
			}
			else
			{ 
				return ( CmdRespStatus );
			}
		}
		else if ( CmdRespStatus & MCI_CMD_RESP_END )
		{
			MCI_CLEAR = CmdRespStatus | MCI_CMD_RESP_END;
			break;	/* cmd response is received, expecting response */
		}
	}
	
	if ( (MCI_RESP_CMD & 0x3F) != ExpectCmdData )
	{
		/* If the response is not R1, in the response field, the Expected Cmd data
		won't be the same as the CMD data in SendCmd(). Below four cmds have
		R2 or R3 response. We don't need to check if MCI_RESP_CMD is the same
		as the Expected or not. */
		if ( (ExpectCmdData != SEND_OP_COND) && (ExpectCmdData != SEND_APP_OP_COND) 
				&& (ExpectCmdData != ALL_SEND_CID) && (ExpectCmdData != SEND_CSD) )
		{
			CmdRespStatus = INVALID_RESPONSE;	/* Reuse error status */
			return ( INVALID_RESPONSE );
		}
	}

	if ( ExpectResp == EXPECT_SHORT_RESP )
	{
		*CmdResp = MCI_RESP0;
	}
	else if ( ExpectResp == EXPECT_LONG_RESP )
	{
		*CmdResp = MCI_RESP0;
		*(CmdResp+1) = MCI_RESP1;
		*(CmdResp+2) = MCI_RESP2;
		*(CmdResp+3) = MCI_RESP3;
	}
	return ( 0 );	/* Read MCI_RESP0 register assuming it's not long response. */
}

/******************************************************************************
** Function name:		MCI_Go_Idle_State
**
** Descriptions:		CMD0, the very first command to be sent to initialize
**						either MMC or SD card.		
**
** parameters:			None
** Returned value:		true or false, true if card has been initialized.
** 
******************************************************************************/
DWORD MCI_Go_Idle_State( void )
{
	DWORD retryCount;
	DWORD respStatus;
	DWORD respValue[4];

	retryCount = 0x20;
	while ( retryCount > 0 )
	{
		/* Send CMD0 command repeatedly until the response is back correctly */
    	MCI_SendCmd( GO_IDLE_STATE, 0x00000000, EXPECT_NO_RESP, 0 );
		respStatus = MCI_GetCmdResp( GO_IDLE_STATE, EXPECT_NO_RESP, (DWORD *)respValue );
		if ( respStatus == 0 )
		{
			break;
		}
		retryCount--;
	}
	
	if ( respStatus != 0 )		/* timeout, give up */
	{
		return ( FALSE );
	}
	return( TRUE );
}

/******************************************************************************
** Function name:		MCI_Send_OP_Cond
**
** Descriptions:		CMD1 for MMC		
**
** parameters:			None
** Returned value:		true or false, true if card has response back before
**						timeout, false is timeout on the command.
** 
******************************************************************************/
DWORD MCI_Send_OP_Cond( void )
{
	DWORD i, retryCount;
	DWORD respStatus;
	DWORD respValue[4];

	retryCount = 0x200;			/* reset retry counter */
	while ( retryCount > 0 )
	{
		/* Send CMD1 command repeatedly until the response is back correctly */
		MCI_SendCmd( SEND_OP_COND, OCR_INDEX, EXPECT_SHORT_RESP, 0 );
		respStatus = MCI_GetCmdResp( SEND_OP_COND, EXPECT_SHORT_RESP, (DWORD *)&respValue[0] );
		/* bit 0 and bit 2 must be zero, or it's timeout or CRC error */
		if ( !(respStatus & MCI_CMD_TIMEOUT) && (respValue[0] & 0x80000000) )
		{
			return ( TRUE );	/* response is back and correct. */
		}
		for ( i = 0; i < 0x20; i++ );
		retryCount--;
	}
	return( FALSE );
}

/******************************************************************************
** Function name:		MCI_Send_ACMD
**
** Descriptions:		CMD55, before sending an ACMD, call this routine first  		
**
** parameters:			None
** Returned value:		true or false, true if card has responded before timeout.
**						false is timeout.
** 
******************************************************************************/
DWORD MCI_Send_ACMD( void )
{
	DWORD i, retryCount;
	DWORD CmdArgument;
	DWORD respStatus;
	DWORD respValue[4];

	if ( CardType == SD_CARD )
	{
		CmdArgument = CardRCA;	/* Use the address from SET_RELATIVE_ADDR cmd */
	}
	else			/* if MMC or unknown card type, use 0x0. */
	{
		CmdArgument = 0x00000000;
	}

	retryCount = 20;
	while ( retryCount > 0 )
	{
		/* Send CMD55 command followed by an ACMD */
		MCI_SendCmd( APP_CMD, CmdArgument, EXPECT_SHORT_RESP, 0 );
		respStatus = MCI_GetCmdResp( APP_CMD, EXPECT_SHORT_RESP, (DWORD *)&respValue[0] );
		if ( !respStatus && (respValue[0] & CARD_STATUS_ACMD_ENABLE) )	/* Check if APP_CMD enabled */
		{
			return( TRUE );
		}
		for ( i = 0; i < 0x20; i++ );
		retryCount--;
	}
	return( FALSE );
}

/******************************************************************************
** Function name:		MCI_Send_ACMD_OP_Cond
**
** Descriptions:		If Send_OP_Cond is timeout, it's not a MMC card, try 
**						this combination to see if we can communicate with 
**						a SD card. 		
**
** parameters:			None
** Returned value:		true or false, true if card has been initialized.
** 
******************************************************************************/
DWORD MCI_Send_ACMD_OP_Cond( void )
{
	DWORD i, retryCount;
	DWORD respStatus;
	DWORD respValue[4];

	/* timeout on SEND_OP_COND command on MMC, now, try SEND_APP_OP_COND 
	command to SD */
	retryCount = 0x200;			/* reset retry counter */
	while ( retryCount > 0 )
	{
		MCI_POWER &= ~(1 << 6 );	/* Clear Open Drain output control for SD */
		for ( i = 0; i < 0x3000; i++ );

		if ( MCI_Send_ACMD() == FALSE )
		{
			continue;
		}
			
		/* Send ACMD41 command repeatedly until the response is back correctly */
		MCI_SendCmd( SEND_APP_OP_COND, OCR_INDEX, EXPECT_SHORT_RESP, 0 );
		respStatus = MCI_GetCmdResp( SEND_APP_OP_COND, EXPECT_SHORT_RESP, (DWORD *)&respValue[0] );
		if ( !(respStatus & MCI_CMD_TIMEOUT) && (respValue[0] & 0x80000000) )
		{
			return ( TRUE );	/* response is back and correct. */
		}
		for ( i = 0; i < 0x20; i++ );
		retryCount--;
	}
	return( FALSE );
}

/******************************************************************************
** Function name:		MCI_CardInit
**
** Descriptions:		Try CMD1 first for MMC, if it's timeout, try CMD55 
**						and CMD41 for SD, if both failed, initialization faliure, 
**						bailout with unknown card type. Otherwise, return the
**						card type, either MMC or SD.		
**
** parameters:			None
** Returned value:		Card type.
** 
******************************************************************************/
DWORD MCI_CardInit( void )
{
	DWORD i, CardType;

	if ( MCI_Go_Idle_State() == FALSE )
	{
		return( CARD_UNKNOWN );
	}

	MCI_POWER |= (1 << 6 );		/* Set Open Drain output control for MMC */
	for ( i = 0; i < 0x3000; i++ );

	/* Try CMD1 first for MMC, if it's timeout, try CMD55 and CMD41 for SD,
	if both failed, initialization faliure, bailout. */
	if ( MCI_Send_OP_Cond() == TRUE )	
	{
		CardType = MMC_CARD;
		return ( CardType );	/* Found the card, it's a MMC */
	}
	else if ( MCI_Send_ACMD_OP_Cond() == TRUE )
	{
		CardType = SD_CARD;
		return ( CardType );	/* Found the card, it's a SD */
	}	
	/* tried both MMC and SD card, give up */
	return ( CARD_UNKNOWN );
}

/******************************************************************************
** Function name:		MCI_Check_CID
**
** Descriptions:		Send CMD2, ALL_SEND_CID		
**
** parameters:			None
** Returned value:		If not timeout, return true.
** 
******************************************************************************/
DWORD MCI_Check_CID( void )
{
	DWORD i, retryCount;
	DWORD respStatus;
	DWORD respValue[4];

	/* This command is normally after CMD1(MMC) or ACMD41(SD). */
	retryCount = 0x20;			/* reset retry counter */
	while ( retryCount > 0 )
	{
		/* Send CMD2 command repeatedly until the response is back correctly */
		MCI_SendCmd( ALL_SEND_CID, 0, EXPECT_LONG_RESP, 0 );
		respStatus = MCI_GetCmdResp( ALL_SEND_CID, EXPECT_LONG_RESP, (DWORD *)&respValue[0] );
		/* bit 0 and bit 2 must be zero, or it's timeout or CRC error */
		if ( !(respStatus & MCI_CMD_TIMEOUT) )
		{
			return ( TRUE );	/* response is back and correct. */
		}
		for ( i = 0; i < 0x20; i++ );
		retryCount--;
	}
	return ( FALSE );
}

/******************************************************************************
** Function name:		MCI_Set_Address
**
** Descriptions:		Send CMD3, STE_RELATIVE_ADDR, should after CMD2		
**
** parameters:			None
** Returned value:		TRUE if response is back before timeout.
** 
******************************************************************************/
DWORD MCI_Set_Address( void )
{
	DWORD i, retryCount;
	DWORD respStatus;
	DWORD respValue[4];
	DWORD CmdArgument;

	/* If it's a SD card, SET_RELATIVE_ADDR is to get the address
	from the card and use this value in RCA, if it's a MMC, set default
	RCA addr. 0x00010000. */ 
	if ( CardType == SD_CARD )
	{
		CmdArgument = 0;
	}
	else			/* If it's unknown or MMC_CARD, fix the RCA address */
	{
		CmdArgument = 0x00010000;
	}

⌨️ 快捷键说明

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