• STM32F4X SDIO(六) 例程讲解-SD_PowerON


    从本节开始将会结合实际的例程讲解SD卡使用,包括SDIO控制器初始化,SD卡初始化,SD卡擦除、SD卡读写等。本例程将会使用野火电子的STM32F407的SD卡读写例程进行讲解。

    例程讲解-SD_PowerON

    SD_PowerON函数主要是配置SDIO的引脚询问SD卡的工作电压配置SD卡时钟

    SDIO引脚初始化和时钟初始化

    在使用STM32F4X的SDIO控制器前,需要先初始化SDIO的GPIO引脚。
    在这里插入图片描述
    STM32F4X的SDIO需要用到6个引脚

    • PC8:SDIO的数据线0引脚
    • PC9:SDIO的数据线1引脚
    • PC10:SDIO的数据线2引脚
    • PC11:SDIO的数据线3引脚
    • PC12:SDIO的时钟引脚
    • PD12:SDIO的命令引脚
    void SD_LowLevel_Init(void)
    {
      GPIO_InitTypeDef  GPIO_InitStructure;
    
      /* 使能GPIOC和GPIOD时钟 */
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD, ENABLE);
      /* 将GPIOC8、GPIOC9、GPIOC10、GPIOC11、GPIOC12和GPIOD2 复用为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);
    
      /*  配置GPIOC8、GPIOC9、GPIOC10、GPIOC11、GPIOC12和GPIOD2引脚属性  */
      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, &GPIO_InitStructure);
    
    
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
      GPIO_Init(GPIOD, &GPIO_InitStructure);
    
    
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
      GPIO_Init(GPIOC, &GPIO_InitStructure);
    
      /* 使能SDIO时钟 */
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);
    
      /*使能DMA时钟 */
      RCC_AHB1PeriphClockCmd(SD_SDIO_DMA_CLK, ENABLE);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    在SD_LowLevel_Init函数中做了SDIO引脚和时钟的初始化操作。

    SDIO初始化(单线模式)

    在SD卡刚上电的初始化的时候,默认的总线宽度为1位总线宽度,其通信频率在400KHz左右,所以在SD卡上电的时候,也需要配置SDIO的总线宽度和工作频率。

    
    SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV; // SDIOCLK分频系数
    SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising; // SDIO_CK的采样模式
    SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;// SDIO_CK的使能
    SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;// SDIO_CK是否使用节能模式
    SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;// SDIO总线宽度
    SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable; // 是否使用硬件流控
    SDIO_Init(&SDIO_InitStructure);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这里需要注意的SDIO_CK的频率计算

    在这里插入图片描述
    根据数据手册可以知道SDIO_CK的计算公式。STM32F4X的SDIOCLK的时钟频率是48MHz,SDIO_INIT_CLK_DIV值为0x76,那么SDIO_CK频率计算如下
    SDIO_CK = SDIOCLK / (0x76 + 2) = 400KHz
    刚好满足SD卡上电时的频率要求。

    CMD0:GO_IDLE_STATE

    SD卡初始化的第一步是发送CMD0命令复位SD卡,让SD卡进入IDLE状态。
    在这里插入图片描述

    命令发送程序

      SDIO_CmdInitStructure.SDIO_Argument = 0x0; // 没有参数
      SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_GO_IDLE_STATE; // CMD0
      SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No; // 没有响应
      SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; // 不等待
      SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; // 使能CPSM状态机
      SDIO_SendCommand(&SDIO_CmdInitStructure);
      errorstatus = CmdError(); // 判断错误状态
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    调用SDIO_SendCommand函数发送CMD0命令到SD卡

    在这里插入图片描述

    命令响应程序

    发送完CMD0之后需要判断发送是否有误,由于CMD0没有响应数据,所以只需判断SDIO控制器状态即可

    static SD_Error CmdError(void)
    {
      SD_Error errorstatus = SD_OK;
      uint32_t timeout;
    
      timeout = SDIO_CMD0TIMEOUT; /*!< 10000 */
    
      while ((timeout > 0) && (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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    CMD8:SEND_IF_COND

    CMD8命令的作用有两个,分别是电压校验扩展现有的命令和响应
    在SD卡进入IDLE模式后,下一步就是通过CMD8给SD卡发送电压校验命令。
    在这里插入图片描述

    CMD8参数

    在这里插入图片描述
    在这里插入图片描述

    bit[39:8]是CMD8的参数。

    • bit[39:20]:保留位,为0
    • bit[19:16]:支持的电压范围,从表中可以知道这里我们写1
    • bit[15:8]:根据手册,bit[15:8]要为0xAA
      所以CMD8的参数的输入参数就为0x1AA

    命令发送程序

      SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN; // 参数,为0x1AA
      SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND; // 命令编号 CMD8
      SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; // 短响应
      SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;  // 不等待
      SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;  // 使用CPSM状态机
      SDIO_SendCommand(&SDIO_CmdInitStructure);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    命令响应程序

    CMD8的响应类型是R7,如果SD卡接受提供的电压范围就会返回R7响应,否则不会返回R7响应。
    在这里插入图片描述

    /* 检查R7响应 */
    static SD_Error CmdResp7Error(void)
    {
      SD_Error errorstatus = SD_OK;
      uint32_t status;
      uint32_t timeout = SDIO_CMD0TIMEOUT;
    
      status = SDIO->STA;
    
      while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) && (timeout > 0))
      {
        timeout--;
        status = SDIO->STA;
      }
    
      if ((timeout == 0) || (status & SDIO_FLAG_CTIMEOUT))
      {
        /*!< Card is not V2.0 complient 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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    如何SD卡响应CMD8命令,则代表该SD卡为SD2.0以上的卡

    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(&SDIO_CmdInitStructure);
    
      errorstatus = CmdResp7Error();
    
      if (errorstatus == SD_OK)
      {
        CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0; /*!< SD Card 2.0 */
        SDType = SD_HIGH_CAPACITY;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    CMD55:APP_CMD

    在主机发完CMD8命令后,如果SD卡响应CMD8命令,那么接下来主机就需要发送CMD55命令,告诉SD卡在CMD55命令后的是特殊应用命令
    在这里插入图片描述

    CMD55命令参数

    • bit[31:16]:RCA,SD卡的地址,这里因为还没有获取到SD卡地址,所以设为0
    • bit[15:0]:一般为0

    命令发送

        SDIO_CmdInitStructure.SDIO_Argument = 0x00; // CMD55参数
        SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD; // 命令索引 CMD55
        SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; // 短响应
        SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; // 不等待
        SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; // CPSM状态机使能
        SDIO_SendCommand(&SDIO_CmdInitStructure);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    命令响应

    CMD55的命令响应是R1,R1命令会返回SD卡的状态,所以在判断R1响应时需要判断SD卡的状态是否正常。
    在这里插入图片描述

    R1响应返回的卡状态如下
    在这里插入图片描述
    在这里插入图片描述

    static SD_Error CmdResp1Error(uint8_t cmd)
    {
      SD_Error errorstatus = SD_OK;
      uint32_t status;
      uint32_t response_r1;
    
      status = SDIO->STA;
    
     /* 判断SDIO控制器状态 */
      while (!(status & (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);
      }
    
      /*!< 命令号是否为发送的命令号 */
      if (SDIO_GetCommandResponse() != cmd)
      {
        errorstatus = SD_ILLEGAL_CMD;
        return(errorstatus);
      }
    
      /*!< Clear all the static flags */
      SDIO_ClearFlag(SDIO_STATIC_FLAGS);
    
      /*!< 依次判断SD卡状态位  */
      response_r1 = SDIO_GetResponse(SDIO_RESP1);
    
      if ((response_r1 & 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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141

    例程中判断R1响应的步骤如下

    • 先判断SDIO控制的状态是否有错
    • 判断R1响应的命令号是否为CMD55
    • 最后再根据R1响应的SD卡状态位依次进行判断
      在这里插入图片描述
      根据波形图可知,返回的SD卡状态位0x120,也就是bit5和bit8置1
      在这里插入图片描述

    ACMD41:SD_SEND_OP_COND

    发送ACMD41的作用是告诉SD卡,主机是否支持大容量卡,并且判断SD卡是否上电完成。
    在这里插入图片描述

    ACMD41参数

    ACMD41参数是根据SD卡的OCR寄存器进行定义,以下为OCR寄存器的定义表

    在这里插入图片描述

    在这里我们需要注意以下几个bit

    • bit[30]:卡容量位,如果是高容量卡,设置为 1,如果是标准卡,设置为 0。
    • bit[31]:卡上电状态位,这个状态位在卡的上电流程完成后设置
      在程序中,我们需要将bit30和bit31都设置为1,卡的电压设置为3.2-3.3,也就是bit20为1,则AMCD41的输入参数就为0xC0100000

    命令发送

          SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDType; // 参数 0xC0100000
          SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND; // 命令索引 ACMD41
          SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; // 短响应
          SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; // 不等待
          SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; // CPSM状态机使能
          SDIO_SendCommand(&SDIO_CmdInitStructure);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    命令响应

    ACMD41的响应是R3响应
    在这里插入图片描述
    例程中需要判断R3响应的OCR寄存器中的bit[31]是否为1,如果不为1,则需要循环发送CMD55和ACMD41,一直等到OCR寄存器总bit31为1

    while ((!validvoltage) && (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(&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(&SDIO_CmdInitStructure);
    
          errorstatus = CmdResp3Error();
          if (errorstatus != SD_OK)
          {
            return(errorstatus);
          }
    
          response = SDIO_GetResponse(SDIO_RESP1);
          validvoltage = (((response >> 31) == 1) ? 1 : 0); // 判断bit31是否为1,如果为1则代表SD卡上电完成
          count++;
        }
        if (count >= SD_MAX_VOLT_TRIAL)
        {
          errorstatus = SD_INVALID_VOLTRANGE;
          return(errorstatus);
        }
    
        if (response &= SD_HIGH_CAPACITY)
        {
          CardType = SDIO_HIGH_CAPACITY_SD_CARD;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在这里插入图片描述
    至此,SD卡上电部分就完成了,下面来简介梳理一下SD卡上电的流程

    SD卡上电流程

    1. 初始化SDIO引脚和时钟
    2. 初始化SDIO控制器,设置总线宽度为1,SDIO_CK频率不高于400KHz
    3. 发生CMD0命令,让SD卡进入IDLE模式
    4. 发生CMD8命令,判断SD卡是否支持设置的电压范围
    5. 发送CMD55命令
    6. 发送ACMD41命令,并判断SD卡是否上电完成,如果没有上电完成就重复5和6步骤
    7. SD卡上电完成

    野火电子SD卡上电程序

    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(&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(&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(&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(&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) && (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(&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(&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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
  • 相关阅读:
    大数据平台测试-高级架构师语录(偷笑)
    共赴开源路,共筑新丰碑!2022云栖大会龙蜥操作系统峰会圆满落幕!
    全国大学生数学竞赛(非数学专业)习题精讲等相关资源
    如何用MFI确定波浪理论第一浪,anzo capital实操演示
    LVS+Keepalived高可用群集
    在SOUI里使用真窗口时使用SOUI的滚动条
    linux之iptables防火墙
    Unittest套件与运行器
    决策树分析及其在项目管理中的应用
    喜讯!爱创科技荣获腾讯智慧零售“产品力先锋奖”
  • 原文地址:https://blog.csdn.net/hwx1546/article/details/134185656