STM32F4X SDIO (6) Routine explanation-SD_PowerON
- Routine explanation-SD_PowerON
-
- SDIO pin initialization and clock initialization
- SDIO initialization (single wire mode)
- CMD0:GO_IDLE_STATE
-
- command sender
- command responder
- CMD8:SEND_IF_COND
-
- CMD8 parameters
- command sender
- command responder
- CMD55:APP_CMD
-
- CMD55 command parameters
- command sent
- command response
- ACMD41:SD_SEND_OP_COND
-
- ACMD41 parameters
- command sent
- command response
- SD card power-on process
- Wildfire Electronics SD card power-on procedure
Starting from this section, the use of SD card will be explained with actual routines, including SDIO controller initialization, SD card initialization, SD card erasure, SD card reading and writing, etc. This routine will be explained using Yefire Electronics’ STM32F407 SD card read and write routine.
Routine explanation-SD_PowerON
The SD_PowerON function is mainly to configure the SDIO pins, query the working voltage of the SD card and Configure SD card clock
SDIO pin initialization and clock initialization
Before using the STM32F4X SDIO controller, you need to initialize the SDIO GPIO pins.
The SDIO of STM32F4X requires 6 pins
- PC8:SDIO data line pin 0
- PC9:SDIO data line pin 1
- PC10:SDIO data line pin 2
- PC11:SDIO data line pin 3
- PC12:SDIO clock pin
- PD12:SDIO command pin
void SD_LowLevel_Init(void) {<!-- --> GPIO_InitTypeDef GPIO_InitStructure; /* Enable GPIOC and GPIOD clocks */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD, ENABLE); /* Multiplex GPIOC8, GPIOC9, GPIOC10, GPIOC11, GPIOC12 and GPIOD2 as SDIO */ GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_SDIO); GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_SDIO); GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SDIO); GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SDIO); GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SDIO); GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_SDIO); /* Configure GPIOC8, GPIOC9, GPIOC10, GPIOC11, GPIOC12 and GPIOD2 pin properties */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOC, & amp;GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_Init(GPIOD, & amp;GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOC, & amp;GPIO_InitStructure); /* Enable SDIO clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE); /*Enable DMA clock */ RCC_AHB1PeriphClockCmd(SD_SDIO_DMA_CLK, ENABLE); }
The SDIO pin and clock are initialized in the SD_LowLevel_Init function.
SDIO initialization (single-wire mode)
When the SD card is first initialized after power-on, the default bus width is 1 bit bus width, and its communication frequency is 400KHz font> or so, so when the SD card is powered on, the bus width and operating frequency of SDIO also need to be configured.
SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV; // SDIOCLK frequency division coefficient SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising; // SDIO_CK sampling mode SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;//SDIO_CK enablement SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable; // Whether SDIO_CK uses energy-saving mode SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b; // SDIO bus width SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable; // Whether to use hardware flow control SDIO_Init( &SDIO_InitStructure);
What needs to be noted here is the frequency calculation of SDIO_CK
According to the data sheet, you can know the calculation formula of SDIO_CK. The SDIOCLK clock frequency of STM32F4X is 48MHz, the SDIO_INIT_CLK_DIV value is 0x76, then the SDIO_CK frequency is calculated as follows
SDIO_CK = SDIOCLK / (0x76 + 2) = 400KHz
It just meets the frequency requirements of the SD card when it is powered on.
CMD0:GO_IDLE_STATE
The first step in SD card initialization is to send the CMD0 command to reset the SD card and let the SD card enter the IDLE state.
Command sending program
SDIO_CmdInitStructure.SDIO_Argument = 0x0; // No parameters SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_GO_IDLE_STATE; // CMD0 SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No; // No response SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; // Do not wait SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; // Enable CPSM state machine SDIO_SendCommand( & amp;SDIO_CmdInitStructure); errorstatus = CmdError(); // Determine error status
Call the SDIO_SendCommand function to send the CMD0 command to the SD card
Command Responder
After sending CMD0, you need to determine whether the transmission is incorrect. Since CMD0 has no response data, you only need to determine the status of the SDIO controller.
static SD_Error CmdError(void) {<!-- --> SD_Error errorstatus = SD_OK; uint32_t timeout; timeout = SDIO_CMD0TIMEOUT; /*!< 10000 */ while ((timeout > 0) & amp; & amp; (SDIO_GetFlagStatus(SDIO_FLAG_CMDSENT) == RESET)) {<!-- --> timeout--; } if (timeout == 0) {<!-- --> errorstatus = SD_CMD_RSP_TIMEOUT; return(errorstatus); } /*!< Clear all the static flags */ SDIO_ClearFlag(SDIO_STATIC_FLAGS); return(errorstatus); }
CMD8:SEND_IF_COND
The CMD8 command has two functions, namely voltage verification and extending existing commands and responses.
After the SD card enters IDLE mode, the next step is to send a voltage verification command to the SD card through CMD8.
CMD8 parameters
bit[39:8] is the parameter of CMD8.
- bit[39:20]: reserved bit, which is 0
- bit[19:16]: The supported voltage range can be known from the table. Here we write 1
- bit[15:8]: According to the manual, bit[15:8] should be 0xAA.
So the input parameter of CMD8 parameter is 0x1AA
Command sending program
SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN; // Parameter, 0x1AA SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND; // Command number CMD8 SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; // Short response SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; // Do not wait SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; // Use CPSM state machine SDIO_SendCommand( & amp;SDIO_CmdInitStructure);
Command Responder
The response type of CMD8 is R7. If the SD card accepts the provided voltage range, it will return an R7 response, otherwise it will not return an R7 response.
/* Check R7 response */ static SD_Error CmdResp7Error(void) {<!-- --> SD_Error errorstatus = SD_OK; uint32_t status; uint32_t timeout = SDIO_CMD0TIMEOUT; status = SDIO->STA; while (!(status & amp; (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) & amp; & amp; (timeout > 0)) {<!-- --> timeout--; status = SDIO->STA; } if ((timeout == 0) || (status & amp; SDIO_FLAG_CTIMEOUT)) {<!-- --> /*!< Card is not V2.0 compliant or card does not support the set voltage range */ errorstatus = SD_CMD_RSP_TIMEOUT; SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT); return(errorstatus); } if (status & SDIO_FLAG_CMDREND) {<!-- --> /*!< Card is SD V2.0 compliant */ errorstatus = SD_OK; SDIO_ClearFlag(SDIO_FLAG_CMDREND); return(errorstatus); } return(errorstatus); }
If the SD card responds to the CMD8 command, it means that the SD card is SD2.0 or above.
SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN; SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND; SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; SDIO_SendCommand( & amp;SDIO_CmdInitStructure); errorstatus = CmdResp7Error(); if (errorstatus == SD_OK) {<!-- --> CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0; /*!< SD Card 2.0 */ SDType = SD_HIGH_CAPACITY; }
CMD55:APP_CMD
After the host sends the CMD8 command, if the SD card responds to the CMD8 command, then the host needs to send the CMD55 command to tell the SD card that what follows the CMD55 command is a special application command.
CMD55 command parameters
- bit[31:16]: RCA, the address of the SD card. Since the SD card address has not been obtained yet, it is set to 0.
- bit[15:0]: Generally 0
Command sending
SDIO_CmdInitStructure.SDIO_Argument = 0x00; // CMD55 parameter SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD; // Command index CMD55 SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; // Short response SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; // Do not wait SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; //CPSM state machine enable SDIO_SendCommand( & amp;SDIO_CmdInitStructure);
Command response
The command response of CMD55 is R1. The R1 command will return the status of the SD card. Therefore, when judging the R1 response, you need to determine whether the status of the SD card is normal.
The card status returned by R1 response is as follows
static SD_Error CmdResp1Error(uint8_t cmd) {<!-- --> SD_Error errorstatus = SD_OK; uint32_t status; uint32_t response_r1; status = SDIO->STA; /* Determine the status of the SDIO controller */ while (!(status & amp; (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT))) {<!-- --> status = SDIO->STA; } if (status & SDIO_FLAG_CTIMEOUT) {<!-- --> errorstatus = SD_CMD_RSP_TIMEOUT; SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT); return(errorstatus); } else if (status & SDIO_FLAG_CCRCFAIL) {<!-- --> errorstatus = SD_CMD_CRC_FAIL; SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL); return(errorstatus); } /*!< Whether the command number is the command number sent */ if (SDIO_GetCommandResponse() != cmd) {<!-- --> errorstatus = SD_ILLEGAL_CMD; return(errorstatus); } /*!< Clear all the static flags */ SDIO_ClearFlag(SDIO_STATIC_FLAGS); /*!< Judge the SD card status bits in sequence */ response_r1 = SDIO_GetResponse(SDIO_RESP1); if ((response_r1 & amp; SD_OCR_ERRORBITS) == SD_ALLZERO) {<!-- --> return(errorstatus); } if (response_r1 & SD_OCR_ADDR_OUT_OF_RANGE) {<!-- --> return(SD_ADDR_OUT_OF_RANGE); } if (response_r1 & SD_OCR_ADDR_MISALIGNED) {<!-- --> return(SD_ADDR_MISALIGNED); } if (response_r1 & SD_OCR_BLOCK_LEN_ERR) {<!-- --> return(SD_BLOCK_LEN_ERR); } if (response_r1 & SD_OCR_ERASE_SEQ_ERR) {<!-- --> return(SD_ERASE_SEQ_ERR); } if (response_r1 & SD_OCR_BAD_ERASE_PARAM) {<!-- --> return(SD_BAD_ERASE_PARAM); } if (response_r1 & SD_OCR_WRITE_PROT_VIOLATION) {<!-- --> return(SD_WRITE_PROT_VIOLATION); } if (response_r1 & SD_OCR_LOCK_UNLOCK_FAILED) {<!-- --> return(SD_LOCK_UNLOCK_FAILED); } if (response_r1 & SD_OCR_COM_CRC_FAILED) {<!-- --> return(SD_COM_CRC_FAILED); } if (response_r1 & SD_OCR_ILLEGAL_CMD) {<!-- --> return(SD_ILLEGAL_CMD); } if (response_r1 & SD_OCR_CARD_ECC_FAILED) {<!-- --> return(SD_CARD_ECC_FAILED); } if (response_r1 & SD_OCR_CC_ERROR) {<!-- --> return(SD_CC_ERROR); } if (response_r1 & SD_OCR_GENERAL_UNKNOWN_ERROR) {<!-- --> return(SD_GENERAL_UNKNOWN_ERROR); } if (response_r1 & SD_OCR_STREAM_READ_UNDERRUN) {<!-- --> return(SD_STREAM_READ_UNDERRUN); } if (response_r1 & SD_OCR_STREAM_WRITE_OVERRUN) {<!-- --> return(SD_STREAM_WRITE_OVERRUN); } if (response_r1 & SD_OCR_CID_CSD_OVERWRIETE) {<!-- --> return(SD_CID_CSD_OVERWRITE); } if (response_r1 & SD_OCR_WP_ERASE_SKIP) {<!-- --> return(SD_WP_ERASE_SKIP); } if (response_r1 & SD_OCR_CARD_ECC_DISABLED) {<!-- --> return(SD_CARD_ECC_DISABLED); } if (response_r1 & SD_OCR_ERASE_RESET) {<!-- --> return(SD_ERASE_RESET); } if (response_r1 & SD_OCR_AKE_SEQ_ERROR) {<!-- --> return(SD_AKE_SEQ_ERROR); } return(errorstatus); }
The steps to determine the response of R1 in the routine are as follows:
- First determine whether the status of SDIO control is wrong.
- Determine whether the command number responded by R1 is CMD55
- Finally, judgments are made sequentially based on the SD card status bits responded by R1.
According to the waveform diagram, the returned SD card status bit is 0x120, that is, bit5 and bit8 are set to 1.
ACMD41:SD_SEND_OP_COND
The purpose of sending ACMD41 is to tell the SD card whether the host supports large-capacity cards and to determine whether the SD card has been powered on.
ACMD41 parameters
The ACMD41 parameters are defined based on the OCR register of the SD card. The following is the definition table of the OCR register.
Here we need to pay attention to the following bits
- bit[30]: Card capacity bit, if it is a high-capacity card, set to 1, if it is a standard card, set to 0.
- bit[31]: Card power-on status bit. This status bit is set after the card power-on process is completed.
In the program, we need to set both bit30 and bit31 to 1, and set the card voltage to 3.2-3.3, that is, bit20 is 1, then the input parameter of AMCD41 is 0xC0100000
Command sending
SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDType; // Parameter 0xC0100000 SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND; // Command index ACMD41 SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; // Short response SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; // Do not wait SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; //CPSM state machine enable SDIO_SendCommand( & amp;SDIO_CmdInitStructure);
Command response
The response of ACMD41 is the R3 response
In the routine, it is necessary to determine whether the bit[31] in the OCR register of R3 response is 1. If it is not 1, you need to send CMD55 and ACMD41 in a loop until the OCR register is reached. The total bit31 is 1
while ((!validvoltage) & amp; & amp; (count < SD_MAX_VOLT_TRIAL)) {<!-- --> /*!< SEND CMD55 APP_CMD with RCA as 0 */ SDIO_CmdInitStructure.SDIO_Argument = 0x00; SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD; SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; SDIO_SendCommand( & amp;SDIO_CmdInitStructure); errorstatus = CmdResp1Error(SD_CMD_APP_CMD); if (errorstatus != SD_OK) {<!-- --> return(errorstatus); } SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDType; SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND; SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; SDIO_SendCommand( & amp;SDIO_CmdInitStructure); errorstatus = CmdResp3Error(); if (errorstatus != SD_OK) {<!-- --> return(errorstatus); } response = SDIO_GetResponse(SDIO_RESP1); validvoltage = (((response >> 31) == 1) ? 1 : 0); // Determine whether bit31 is 1. If it is 1, it means the SD card is powered on. count + + ; } if (count >= SD_MAX_VOLT_TRIAL) {<!-- --> errorstatus = SD_INVALID_VOLTRANGE; return(errorstatus); } if (response &= SD_HIGH_CAPACITY) {<!-- --> CardType = SDIO_HIGH_CAPACITY_SD_CARD; }
At this point, the SD card power-on part is completed. Let’s briefly introduce the SD card power-on process.
SD card power-on process
- Initialize SDIO pins and clock
- Initialize the SDIO controller, set the bus width to 1, and the SDIO_CK frequency is not higher than 400KHz
- The CMD0 command occurs to put the SD card into IDLE mode.
- The CMD8 command occurs to determine whether the SD card supports the set voltage range.
- SendCMD55 command
- Send the ACMD41 command and determine whether the SD card is powered on. If not, repeat steps 5 and 6.
- SD card power-on completed
Wildfire Electronics SD card power-on procedure
SD_Error SD_PowerON(void) { __IO SD_Error errorstatus = SD_OK; uint32_t response = 0, count = 0, validvoltage = 0; uint32_t SDType = SD_STD_CAPACITY; /*!< Power ON Sequence ----------------------------------------------- ----------*/ /*!< Configure the SDIO peripheral */ /*!< SDIO_CK = SDIOCLK / (SDIO_INIT_CLK_DIV + 2) */ /*!< on STM32F4xx devices, SDIOCLK is fixed to 48MHz */ /*!< SDIO_CK for initialization should not exceed 400 KHz */ SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV; SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising; SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable; SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable; SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b; SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable; SDIO_Init( &SDIO_InitStructure); /*!< Set Power State to ON */ SDIO_SetPowerState(SDIO_PowerState_ON); /*!< Enable SDIO Clock */ SDIO_ClockCmd(ENABLE); /*!< CMD0: GO_IDLE_STATE ----------------------------------------------- --------*/ /*!< No CMD response required */ SDIO_CmdInitStructure.SDIO_Argument = 0x0; SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_GO_IDLE_STATE; SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No; SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; SDIO_SendCommand( & amp;SDIO_CmdInitStructure); errorstatus = CmdError(); if (errorstatus != SD_OK) { /*!< CMD Response TimeOut (wait for CMDSENT flag) */ return(errorstatus); } /*!< CMD8: SEND_IF_COND ----------------------------------------------- ---------*/ /*!< Send CMD8 to verify SD card interface operating condition */ /*!< Argument: - [31:12]: Reserved (shall be set to '0') - [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V) - [7:0]: Check Pattern (recommended 0xAA) */ /*!< CMD Response: R7 */ SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN; SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND; SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; SDIO_SendCommand( & amp;SDIO_CmdInitStructure); errorstatus = CmdResp7Error(); if (errorstatus == SD_OK) {<!-- --> CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0; /*!< SD Card 2.0 */ SDType = SD_HIGH_CAPACITY; } else { /*!< CMD55 */ SDIO_CmdInitStructure.SDIO_Argument = 0x00; SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD; SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; SDIO_SendCommand( & amp;SDIO_CmdInitStructure); errorstatus = CmdResp1Error(SD_CMD_APP_CMD); } /*!< CMD55 */ SDIO_CmdInitStructure.SDIO_Argument = 0x00; SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD; SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; SDIO_SendCommand( & amp;SDIO_CmdInitStructure); errorstatus = CmdResp1Error(SD_CMD_APP_CMD); /*!< If errorstatus is Command TimeOut, it is a MMC card */ /*!< If errorstatus is SD_OK it is a SD card: SD card 2.0 (voltage range mismatch) or SD card 1.x */ if (errorstatus == SD_OK) { /*!< SD CARD */ /*!< Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */ while ((!validvoltage) & amp; & amp; (count < SD_MAX_VOLT_TRIAL)) { /*!< SEND CMD55 APP_CMD with RCA as 0 */ SDIO_CmdInitStructure.SDIO_Argument = 0x00; SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD; SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; SDIO_SendCommand( & amp;SDIO_CmdInitStructure); errorstatus = CmdResp1Error(SD_CMD_APP_CMD); if (errorstatus != SD_OK) { return(errorstatus); } SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDType; SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND; SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; SDIO_SendCommand( & amp;SDIO_CmdInitStructure); errorstatus = CmdResp3Error(); if (errorstatus != SD_OK) { return(errorstatus); } response = SDIO_GetResponse(SDIO_RESP1); validvoltage = (((response >> 31) == 1) ? 1 : 0); count + + ; } if (count >= SD_MAX_VOLT_TRIAL) { errorstatus = SD_INVALID_VOLTRANGE; return(errorstatus); } if (response &= SD_HIGH_CAPACITY) { CardType = SDIO_HIGH_CAPACITY_SD_CARD; } }/*!< else MMC Card */ return(errorstatus); }