STM32F4X SDIO(6) routine explanation-SD_PowerON

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

  1. Initialize SDIO pins and clock
  2. Initialize the SDIO controller, set the bus width to 1, and the SDIO_CK frequency is not higher than 400KHz
  3. The CMD0 command occurs to put the SD card into IDLE mode.
  4. The CMD8 command occurs to determine whether the SD card supports the set voltage range.
  5. SendCMD55 command
  6. Send the ACMD41 command and determine whether the SD card is powered on. If not, repeat steps 5 and 6.
  7. 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);
}