STM32F4X SDIO(六) 例程讲解-SD_PowerON

STM32F4X SDIO(六) 例程讲解-SD_PowerON

  • 例程讲解-SD_PowerON
    • SDIO引脚初始化和时钟初始化
    • SDIO初始化(单线模式)
    • CMD0:GO_IDLE_STATE
      • 命令发送程序
      • 命令响应程序
    • CMD8:SEND_IF_COND
      • CMD8参数
      • 命令发送程序
      • 命令响应程序
    • CMD55:APP_CMD
      • CMD55命令参数
      • 命令发送
      • 命令响应
    • ACMD41:SD_SEND_OP_COND
      • ACMD41参数
      • 命令发送
      • 命令响应
    • SD卡上电流程
    • 野火电子SD卡上电程序

从本节开始将会结合实际的例程讲解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);
}

在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);

这里需要注意的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; // CMD0SDIO_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(); // 判断错误状态

调用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);
}

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; // 参数,为0x1AASDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND; // 命令编号 CMD8SDIO_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);

在这里插入图片描述

命令响应程序

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);
}

在这里插入图片描述

如何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;}

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; // 命令索引 CMD55SDIO_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);

在这里插入图片描述

命令响应

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);
}

例程中判断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; // 参数 0xC0100000SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND; // 命令索引 ACMD41SDIO_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);

在这里插入图片描述

命令响应

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;}

在这里插入图片描述
至此,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);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/130113.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Acwing170】加成序列(dfs+迭代加深+剪枝)题解和一点感想

本思路来自acwing算法提高课 题目描述 看本文需要准备的知识 1.dfs算法基本思想 2.对剪枝这个词有个简单的认识 迭代加深思想和此题分析 首先&#xff0c;什么是迭代加深呢&#xff1f;当一个问题的解有很大概率出现在递归树很浅的层&#xff0c;但是这个问题的解本身存在…

音视频开发:音频编码原理+采集+编码实战

原理&#xff1a; 消除冗余信息&#xff0c;压缩量最大&#xff0c;也叫有损压缩 剔除人耳听觉范围外的音频信号20Hz以下和20000Hz以上&#xff1b;去除被掩蔽的音频信号&#xff0c;信号的遮蔽可以分为频域遮蔽和时域遮蔽&#xff1b;频域遮蔽效应 屏蔽70分贝以下&#xff0…

汽车标定技术(一):XCP概述

目录 1.汽车标定概述 2.XCP协议由来及版本介绍 3.XCP技术通览 3.1 XCP上下机通信模型 3.2 XCP指令集 3.2.1 XCP帧结构定义 3.2.2 标准指令集 3.2.3 标定指令集 3.2.4 页切换指令集 3.2.5 数据采集指令集 3.2.6 刷写指令集 3.3 ECU描述文件(A2L)概述 3.3.1 标定上位…

C++中何时及如何使用析构函数

C中何时及如何使用析构函数 析构函数不返回任何值&#xff0c;没有返回类型&#xff0c;也没有函数参数。由于没 有函数参数&#xff0c;因此它不能被重载。换言之&#xff0c;一个类可以有多个构造函数&#xff0c;但是只能有一个析构函数。 何时调用析构函数&#xff1a; &…

有方N58 HTTP POST 请求连接 TDengine

串口调试软件&#xff1a;格西调试精灵 第一步先注册网络获取IP地址 建立PPP连接 ATXIIC1\r PPP链路建立成功&#xff0c;查询IP地址 ATXIIC?\r 设置网络APN ATCREG?\r 运行结果&#xff0c;红线处是获…

js:可选链运算符(?.)和空值合并运算符(??)

文档&#xff1a; 可选链运算符&#xff08;?.&#xff09;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Optional_chaining空值合并运算符&#xff08;??&#xff09;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Referenc…

【算法与数据结构】--算法和数据结构的进阶主题--并行算法和分布式数据结构

一、并行算法 1.1 并行计算概述 并行计算是一种计算方法&#xff0c;旨在通过同时执行多个计算任务来提高计算性能和效率。与传统的串行计算不同&#xff0c;其中每个任务按顺序执行&#xff0c;并行计算允许多个任务同时执行。这种并行性通常通过将计算任务分解为较小的子任…

算法:Java构建二叉树并迭代实现二叉树的前序、中序、后序遍历

先自定义一下二叉树的类&#xff1a; // Definition for a binary tree node. public class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val val; }TreeNode(int val, TreeNode left, TreeNode right) {this.val val;this.left…

MongoDB安装及开发系例全教程

一、系列文章目录 一、MongoDB安装教程—官方原版 二、MongoDB 使用教程(配置、管理、监控)_linux mongodb 监控 三、MongoDB 基于角色的访问控制 四、MongoDB用户管理 五、MongoDB基础知识详解 六、MongoDB—Indexs 七、MongoDB事务详解 八、MongoDB分片教程 九、Mo…

ATE新能源汽车充电桩自动负载测试系统

随着新能源汽车的普及&#xff0c;充电桩的需求也在不断增加&#xff0c;为了确保充电桩的性能和安全性&#xff0c;对其进行负载测试是非常重要的。ATE新能源汽车充电桩自动负载测试系统是一种专门用于检测充电桩性能的设备&#xff0c;它可以模拟各种实际使用场景&#xff0c…

6、QtCharts 悬浮曲线效果

文章目录 效果dialog.hdialog.cpp悬浮槽函数 效果 dialog.h #ifndef DIALOG_H #define DIALOG_H#include <QDialog> #include <QtCharts> #include <QLineSeries> #include <QGraphicsScene> #include <QTimer> #include <QSplineSeries>…

《实战:如何搭建一个完整的 Vue2.0 项目》- 7、Vue2.x 项目 webpack 4 升级 5(半自动升级)

1.自动升级 先全局安装升级插件 npm i npm-check npm-check-updates -g检查依赖 npm-check更新检查后的依赖并展示版本号&#xff0c;此时 package.json还没有更新 npm-check-updates升级 package.json&#xff0c;下图显示更新版本&#xff0c;此时 package.json文件已变更…

【JavaScript】变量提升

变量提升&#xff08;Hoisting&#xff09;被认为是&#xff0c;Javascript 中执行上下文&#xff08;特别是创建和执行阶段&#xff09;工作方式的一种认识。 提升&#xff08;Hoisting&#xff09;这个词。不过&#xff0c;需要注意的是&#xff0c;开始时&#xff0c;这个概…

FFmpeg——使用Canvas录制视频尚存问题的解决方案

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

编译正点原子LINUXB报错make: arm-linux-gnueabihf-gcc:命令未找到

编译正点原子LINUX报错make: arm-linux-gnueabihf-gcc&#xff1a;命令未找到 1.报错内容2.解决办法3./bin/sh: 1: lzop: not found4.编译成功 1.报错内容 make: arm-linux-gnueabihf-gcc&#xff1a;命令未找到CHK include/config/kernel.releaseCHK include/generat…

lamba stream处理集合

lamba stream处理集合 带拼接多字段分组List< Object> 转 Map<String,List< Object>> Map<String, List<ProfitAndLossMapping>> collect plMappingList.stream() .collect(Collectors.groupingBy(m -> m.getLosType() ":" m.…

Linux 上的轻量级浏览器

导读大多数 Linux 桌面环境中包含的基本图像查看器可能不足以满足你的需要。如果你想要一些更多的功能&#xff0c;但仍然希望它是轻量级的&#xff0c;那么看看这四个 Linux 桌面中的图像查看器&#xff0c;如果还不能满足你的需要&#xff0c;还有额外的选择。 当你需要的不…

本地部署Jellyfin影音服务器并实现远程访问影音库

文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及&#xff0c;各种各样的使用需求也被开发出来&…

表格冻结第二行

在网上找了一圈也没找到说明白的。 像这样的表格下面会有很多行&#xff0c;往下翻的时候会忘记第二行显示的什么内容。 需求&#xff1a;将第二行进行冻结 实现&#xff1a; 1&#xff0c;选中第一和第二行&#xff0c;下拉&#xff0c;点击冻结 2&#xff0c;会显示冻结至…