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

📄 lpc177x_8x_mci.c

📁 NXPl788上lwip的无操作系统移植,基于Embest开发板
💻 C
📖 第 1 页 / 共 5 页
字号:
	before WRITE_BLOCK only TX related data interrupts are enabled, and before
	READ_BLOCK only RX related data interrupts are enabled. */
	return MCI_FUNC_OK;
}


/************************************************************************//**
 * @brief 		Set output in open drain mode or pushpull mode
 *
 * @param[in]	mode the mode going to set
 *
 * @return 		None
 ***************************************************************************/
void MCI_SetOutputMode(uint32_t mode)
{
	if(mode == MCI_OUTPUT_MODE_OPENDRAIN)
	{
		/* Set Open Drain output control for MMC */
		LPC_MCI->POWER |= (1 << MCI_PWRCTRL_OPENDRAIN_POS) & MCI_PWRCTRL_BMASK;
	}
	else
	{
		/* Clear Open Drain output control for SD */
		LPC_MCI->POWER &= (~(1 << MCI_PWRCTRL_OPENDRAIN_POS) & MCI_PWRCTRL_BMASK);
	}
}


/************************************************************************//**
 * @brief 		The routine is used to send a CMD to the card
 *
 * @param[in]	CmdIndex the command to be sent to cards
 *
 * @param[in]	Argument the argument follows the command
 *
 * @param[in]	ExpectResp the response type for the command. They may be:
 *				- EXPECT_NO_RESP: means no response required
 *				- EXPECT_SHORT_RESP: means a response in a word needed
 *				- EXPECT_LONG_RESP: means a response in 4 words needed
 *
 * @param[in]	AllowTimeout allow timeout the command or not
 *
 * @return 		None
 ***************************************************************************/
void MCI_SendCmd(uint32_t CmdIndex, uint32_t Argument, uint32_t ExpectResp, uint32_t AllowTimeout)
{
	uint32_t i, CmdData = 0;
	uint32_t CmdStatus;

	/* the command engine must be disabled when we modify the argument
	or the peripheral resends */
	while ( (CmdStatus = LPC_MCI->STATUS) & MCI_CMD_ACTIVE )	/* Command in progress. */
	{
		LPC_MCI->COMMAND = 0;
		LPC_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_CMD_TIMER )			/* allow timeout or not */
	{
		CmdData &= ~ MCI_DISABLE_CMD_TIMER;
	}
	else
	{
		CmdData |= MCI_DISABLE_CMD_TIMER;
	}

	/*send the command*/
	CmdData |= (1 << 10);		/* This bit needs to be set last. */

	LPC_MCI->ARGUMENT = Argument;	/* Set the argument first, finally command */

	LPC_MCI->COMMAND = CmdData;

	return;
}


/************************************************************************//**
 * @brief 		The routine is to get the reponse from card after commands.
 *				This function is always used in pair of MCI_SendCmd() func
 *
 * @param[in]	ExpectCmdData specify the command of which the data will be
 *				retrieved. This field should be the same with CmdIndex of
 *				MCI_SendCmd() function.
 *
 * @param[in]	ExpectResp the response type for the command. They may be:
 *				- EXPECT_NO_RESP: means no response required
 *				- EXPECT_SHORT_RESP: means a response in a word needed
 *				- EXPECT_LONG_RESP: means a response in 4 words needed
 *
 * @param[out]	CmdResp the buffer stored the data replied from cards
 *
 * @return 		MCI_FUNC_OK in case of success
 ***************************************************************************/
int32_t MCI_GetCmdResp(uint32_t ExpectCmdData, uint32_t ExpectResp, uint32_t *CmdResp)
{
	uint32_t CmdRespStatus = 0;
	uint32_t LastCmdIndex;

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

	while (1)
	{
		// Get the status of the component
		CmdRespStatus = LPC_MCI->STATUS;

		if ( CmdRespStatus & (MCI_CMD_TIMEOUT) )
		{
			LPC_MCI->CLEAR = CmdRespStatus | MCI_CMD_TIMEOUT;

			LPC_MCI->COMMAND = 0;
			LPC_MCI->ARGUMENT = 0xFFFFFFFF;

			return (CmdRespStatus);
		}

		if (  CmdRespStatus & MCI_CMD_CRC_FAIL )
		{
			LPC_MCI->CLEAR = CmdRespStatus | MCI_CMD_CRC_FAIL;
			LastCmdIndex = LPC_MCI->COMMAND & 0x003F;

			if ( (LastCmdIndex == CMD1_SEND_OP_COND) || (LastCmdIndex == ACMD41_SEND_APP_OP_COND)
													|| (LastCmdIndex == CMD12_STOP_TRANSMISSION) )
			{
				LPC_MCI->COMMAND = 0;
				LPC_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)
		{
			LPC_MCI->CLEAR = CmdRespStatus | MCI_CMD_RESP_END;
			break;	/* cmd response is received, expecting response */
		}
        
	}

	if ((LPC_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 != CMD1_SEND_OP_COND) && (ExpectCmdData != ACMD41_SEND_APP_OP_COND)
					&& (ExpectCmdData != CMD2_ALL_SEND_CID) && (ExpectCmdData != CMD9_SEND_CSD))
		{
			CmdRespStatus = INVALID_RESPONSE;	/* Reuse error status */
			return (INVALID_RESPONSE);
		}
	}

	/* Read MCI_RESP0 register assuming it's not long response. */
	if (CmdResp != NULL)
	{
		if (ExpectResp == EXPECT_SHORT_RESP)
		{
			*(CmdResp + 0) = LPC_MCI->RESP0;
			*(CmdResp + 1) = 0;
			*(CmdResp + 2) = 0;
			*(CmdResp + 3) = 0;
		}
		else if (ExpectResp == EXPECT_LONG_RESP)
		{
			*(CmdResp + 0) = LPC_MCI->RESP0;
			*(CmdResp + 1) = LPC_MCI->RESP1;
			*(CmdResp + 2) = LPC_MCI->RESP2;
			*(CmdResp + 3) = LPC_MCI->RESP3;
		}
		}

	return MCI_FUNC_OK;
}


/************************************************************************//**
 * @brief 		The routine is to send command to cards then get back the 
 *				reponses (if required).
 *
 * @param[in]	CmdIndex the command to be sent to cards
 *
 * @param[in]	Argument the argument follows the command
 *
 * @param[in]	ExpectResp the response type for the command. They may be:
 *				- EXPECT_NO_RESP: means no response required
 *				- EXPECT_SHORT_RESP: means a response in a word needed
 *				- EXPECT_LONG_RESP: means a response in 4 words needed
 *
 * @param[out]	CmdResp the buffer stored the data replied from cards
 *
 * @param[in]	AllowTimeout allow timeout the command or not
 *
 * @return 		MCI_FUNC_OK in case of success
 ***************************************************************************/
int32_t MCI_CmdResp(uint32_t CmdIndex, uint32_t Argument,
								uint32_t ExpectResp, uint32_t *CmdResp, uint32_t AllowTimeout)
{
	int32_t respStatus;

	MCI_SendCmd(CmdIndex, Argument, ExpectResp, AllowTimeout);

	if((CmdResp != NULL) || (ExpectResp != EXPECT_NO_RESP))
	{
		respStatus = MCI_GetCmdResp(CmdIndex, ExpectResp, CmdResp);
	}
	else
	{
		respStatus = MCI_FUNC_BAD_PARAMETERS;
	}

	return respStatus;
}


/************************************************************************//**
 * @brief 		To reset the card, the CMD0 is sent and then the card is put
 *				in idle state. This is the very first command to be sent to
 *				initialize either MMC or SD card.
 *
 * @param		None
 *
 * @return 		Always MCI_FUNC_OK
 ***************************************************************************/
int32_t MCI_CardReset(void)
{
	/* Because CMD0 command to put the device to idle state does not need response 
	since, it's only sending commad */
	MCI_SendCmd(CMD0_GO_IDLE_STATE, 0x00000000, EXPECT_NO_RESP, 0);

	return MCI_FUNC_OK;
}


/************************************************************************//**
 * @brief 		Send CMD1 (SEND_OP_COND) to card.
 *
 * @param		None
 *
 * @return 		MCI_FUNC_OK if all success
 ****************************************************************************/
int32_t MCI_Cmd_SendOpCond( void )
{
	uint32_t i, retryCount;
	uint32_t respStatus;
	uint32_t respValue[4];

	int32_t retval = MCI_FUNC_FAILED;

	retryCount = 0x200;			/* reset retry counter */

	while ( retryCount > 0 )
	{
		respStatus = MCI_CmdResp(CMD1_SEND_OP_COND, OCR_INDEX, EXPECT_SHORT_RESP, (uint32_t *)&respValue[0], ALLOW_CMD_TIMER);

		if(respStatus & MCI_CMD_TIMEOUT)
		{
			retval = MCI_FUNC_TIMEOUT;
		}
		else if ((respValue[0] & 0x80000000) == 0)
		{
			//The card has not finished the power up routine
			retval = MCI_FUNC_BUS_NOT_IDLE;
		}
		else
		{
			retval = MCI_FUNC_OK;
			break;
		}

		for ( i = 0; i < 0x20; i++ );

		retryCount--;
	}

	return(retval);
}


/************************************************************************//**
 * @brief 		Send CMD8 (SEND_IF_COND) for interface condition to card.
 *
 * @param		None
 *
 * @return 		MCI_FUNC_OK if all success
 ****************************************************************************/
int32_t MCI_Cmd_SendIfCond(void)
{
	uint32_t i, retryCount;
	uint32_t CmdArgument;
	uint32_t respStatus;
	uint32_t respValue[4];

	int32_t retval = MCI_FUNC_FAILED;

	uint8_t voltageSupplied = 0x01;//in range 2.7-3.6V
	uint8_t checkPattern = 0xAA;

	CmdArgument = (voltageSupplied << MCI_CMD8_VOLTAGESUPPLIED_POS) | checkPattern;

	retryCount = 20;

	while ( retryCount > 0 )
	{
		respStatus = MCI_CmdResp(CMD8_SEND_IF_COND, CmdArgument, EXPECT_SHORT_RESP, (uint32_t *)&respValue[0], ALLOW_CMD_TIMER);

		if(respStatus & MCI_CMD_TIMEOUT)
		{
			//Consider as no response
			retval = MCI_FUNC_TIMEOUT;
		}
		else if ((respValue[0] & MCI_CMD8_CHECKPATTERN_BMASK) != checkPattern)
		{
			retval = MCI_FUNC_FAILED;
		}
		else if (((respValue[0] >> MCI_CMD8_VOLTAGESUPPLIED_POS) & MCI_CMD8_VOLTAGESUPPLIED_BMASK)
						!= voltageSupplied)
		{
			retval = MCI_FUNC_BAD_PARAMETERS;
		}
		else
		{
			retval = MCI_FUNC_OK;
			break;
		}

		for ( i = 0; i < 0x20; i++ );

		retryCount--;
	}

	return retval;
}


/************************************************************************//**
 * @brief 		Send CMD55 (APP_CMD) to indicate to the card that the next
 *				command is an application specific command rather than a 
 *				standard command. Before an ACMD, call this routine first
 *
 * @param		None
 *
 * @return 		MCI_FUNC_OK if all success
 ****************************************************************************/
int32_t MCI_Cmd_SendACMD( void )
{
	uint32_t i, retryCount;
	uint32_t CmdArgument;
	uint32_t respStatus;
	uint32_t respValue[4];

	int32_t retval = MCI_FUNC_FAILED;

	if ((MCI_CardType == MCI_SDSC_V1_CARD) ||
		(MCI_CardType == MCI_SDSC_V2_CARD) ||
		(MCI_CardType == MCI_SDHC_SDXC_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 )
	{
		respStatus = MCI_CmdResp(CMD55_APP_CMD, CmdArgument, EXPECT_SHORT_RESP, (uint32_t *)&respValue[0], ALLOW_CMD_TIMER);

		if(respStatus != 0)
		{
			retval = MCI_FUNC_FAILED;
		}
		else if (respValue[0] & CARD_STATUS_ACMD_ENABLE)
		{
			retval = MCI_FUNC_OK;
			break;
		}
		else
		{
			retval = MCI_FUNC_NOT_READY;
		}

		for ( i = 0; i < 0x20; i++ );

		retryCount--;
	}

	return retval;
}


/************************************************************************//**
 * @brief 		Send ACMD41 (SEND_APP_OP_COND) to Host Capacity Support (HCS)
 *				information and asks the accessed card to send its operating
 *				condition (OCR).
 *
 * @param[in]	hcsVal input the Host Capacity Support
 *
 * @return 		MCI_FUNC_OK if all success
 *
 * @note		If SEND_APP_OP_COND is timeout, the card in the slot is not MMC
 *				type, try this combination to see if we can communicate with
 *				a SD type.
 ****************************************************************************/
int32_t MCI_Acmd_SendOpCond(uint8_t hcsVal)
{
	uint32_t i, retryCount;
	uint32_t respStatus, argument;
	uint32_t respValue[4];

	int32_t retval = MCI_FUNC_FAILED;

	argument = OCR_INDEX | (hcsVal << MCI_ACMD41_HCS_POS);

	/* 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 )
	{
		/* Clear Open Drain output control for SD */
		MCI_SetOutputMode(MCI_OUTPUT_MODE_PUSHPULL);

		for ( i = 0; i < 0x3000; i++ );

		if ((retval = MCI_Cmd_SendACMD()) == MCI_FUNC_OK)
		{
			respStatus = MCI_CmdResp(ACMD41_SEND_APP_OP_COND, argument, EXPECT_SHORT_RESP, (uint32_t *)&respValue[0], ALLOW_CMD_TIMER);

			if(respStatus & MCI_CMD_TIMEOUT)
			{
				retval = MCI_FUNC_TIMEOUT;
			}
			else if (!(respValue[0] & 0x80000000))
			{
				retval = MCI_FUNC_BUS_NOT_IDLE;
			}
			else
			{
				CCS = (respValue[0]&(1<<30)) ? 1:0;
				retval = MCI_FUNC_OK;
				break;
			}
		}

		for ( i = 0; i < 0x20; i++ );

		retryCount--;
	}

	return retval;
}

/************************************************************************//**

⌨️ 快捷键说明

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