ST意法半导体
直播中

李桂英

8年用户 1454经验值
私信 关注
[问答]

SD卡初始化第一次初始化后再次初始化时会失败,是什么原因?怎么解决?

使用的是STM32F407驱动一个32G的tf卡,使用的SPI模式。第一次上电时,卡识别初始化能通过,但是再keil调试时复位,再运行到初始化这里。卡识别初始化一直过不了。这个时候拔插一次tf卡,再次初始化就能通过。这是什么原因?怎么解决?
初始化代码部分:uint8_t SD_Initialize(void){
uint8_t r1;      // 存放SD卡的返回值uint16_t retry;  // 用来进行超时计数
uint8_t buf[4];
SD_Type = 0; //默认无卡
if (r1 == 0X01){
if (SD_SendCmd(CMD8, 0x1AA, 0x87) == 1) //SD V2.0{
for (i = 0; i < 4; i++)buf[i] = SD_SPI_ReadWriteByte(0XFF);        //Get trailing return value of R7 resp
if (buf[2] == 0X01 && buf[3] == 0XAA) //卡是否支持2.7~3.6V{
retry = 0XFFFE;do
{r1=SD_SendCmd(CMD55, 0, 0X01);        //发送CMD55
r1 = SD_SendCmd(CMD41, 0x40000000, 0X01); //发送CMD41}
while (r1 && retry--);
if (retry && SD_SendCmd(CMD58, 0, 0X01) == 0) //鉴别SD2.0卡版本开始{
for (i = 0; i < 4; i++)buf[i] = SD_SPI_ReadWriteByte(0XFF); //得到OCR值if (buf[0] & 0x40)SD_Type = SD_TYPE_V2HC; //检查CCS
else SD_Type = SD_TYPE_V2;}
}
}
else //SD V1.x/ MMC        V3{
SD_SendCmd(CMD55, 0, 0X01);                //发送CMD55r1 = SD_SendCmd(CMD41, 0, 0X01);        //发送CMD41
if (r1 <= 1){
SD_Type = SD_TYPE_V1;retry = 0XFFFE;
do //等待退出IDLE模式{
SD_SendCmd(CMD55, 0, 0X01);        //发送CMD55r1 = SD_SendCmd(CMD41, 0, 0X01); //发送CMD41
}
while (r1 && retry--);}
else{
SD_Type = SD_TYPE_MMC; //MMC V3retry = 0XFFFE;
do //等待退出IDLE模式{
r1 = SD_SendCmd(CMD1, 0, 0X01); //发送CMD1}
while (r1 && retry--);}
if (retry == 0 || SD_SendCmd(CMD16, 512, 0X01) != 0)SD_Type = SD_TYPE_ERR; //错误的卡}
}SD_DisSelect();//取消片选
if (SD_Type)return 0;else if (r1)return r1;
return 0xaa;//其他错误
}发送CMD8时,响应值正常。CMD55也正常响应。ACMD41返回值一直是0x01(r1 = SD_SendCmd(CMD41, 0x40000000, 0X01); //发送CMD41)。if (buf[2] == 0X01 && buf[3] == 0XAA) //卡是否支持2.7~3.6V
{
retry = 0XFFFE;do
{SD_SendCmd(CMD55, 0, 0X01);        //发送CMD55
r1 = SD_SendCmd(CMD41, 0x40000000, 0X01); //发送CMD41}while (r1 && retry--);



回帖(1)

发财树

2025-6-24 17:57:01

针对STM32F407在SPI模式下初始化32G TF卡时,第一次上电成功但复位后初始化失败的问题,原因和解决方案如下:




原因分析




  1. TF卡未完全复位



    • MCU复位时TF卡仍处于数据传输状态,未被正确复位到空闲状态(IDLE)。

    • 拔插卡相当于物理复位,强制卡回到初始状态。




  2. 初始化时序缺失



    • 复位后未重新进行必要的SPI时钟同步(74+个时钟脉冲),导致卡状态未同步。




  3. SPI外设状态残留



    • MCU复位后SPI外设可能残留错误状态,未重新初始化SPI外设。






解决方案


修改初始化代码逻辑,确保每次初始化前执行完整复位流程:


1. 添加SPI总线同步


void SD_SPI_Sync(void) {
    SD_CS_HIGH();          // 释放片选
    for (uint8_t i = 0; i < 10; i++) { // 发送80个时钟(10字节 * 8位)
        SD_SPI_ReadWriteByte(0xFF);
    }
}

2. 确保SPI外设复位后初始化


SD_Initialize()开头添加:


// 复位后重新初始化SPI
SPI_Init();              // 重新配置SPI时钟和模式
SD_SPI_Sync();           // 同步时钟

3. 强化CMD0复位逻辑


uint8_t SD_GoIdleState(void) {
    uint8_t r1;
    uint16_t retry = 0;
    do {
        SD_CS_LOW();                 // 片选拉低
        r1 = SD_SendCmd(CMD0, 0, 0x95); // 发送CMD0
        SD_WaitResponse();           // 等待响应完成
        SD_CS_HIGH();                // 释放片选
        SD_SPI_ReadWriteByte(0xFF);  // 额外8个时钟
        if (r1 == 0x01) return 0;    // 成功返回0
        retry++;
    } while (retry < 100);           // 重试100次
    return 1; // 超时失败
}

4. 完整的初始化流程修正


uint8_t SD_Initialize(void) {
    // 关键修复:每次初始化前同步总线和SPI外设
    SPI_Init();          // 确保SPI配置正确
    SD_SPI_Sync();       // 发送74+时钟同步卡

    if (SD_GoIdleState() != 0) {
        return SD_ERR;   // CMD0复位失败
    }

    // 后续流程(CMD8, ACMD41等)
    if (SD_SendCmd(CMD8, 0x1AA, 0x87) == 1) { // SD V2.0
        // ... 原有代码
    }
    // ... 其他初始化步骤
}



关键点说明




  1. SPI同步时钟



    • 每次初始化前必须通过SD_SPI_Sync()发送至少74个时钟脉冲(10字节0xFF),确保卡退出遗留状态。




  2. SPI外设初始化



    • MCU复位后需重新调用SPI_Init(),配置SPI时钟分频(初始化阶段≤400kHz)、CPOL/CPHA模式。




  3. 片选信号(CS)时序



    • CMD0发送期间片选必须保持低电平,结束后拉高并额外提供8个时钟。




  4. 硬件检查



    • 确保TF卡供电稳定(复位时电压不掉落)。

    • 检查PCB连接:CLK/MOSI/MISO/CS信号是否接触不良(可尝试降低SPI速率排查干扰)。






流程图解复位流程


MCU上电/复位 → SPI外设初始化(低速模式)
              → 释放片选(CS=1) + 发送80个时钟
              → 拉低片选(CS=0) + 发送CMD0
              → 等待卡返回0x01(空闲状态)
              → 释放片选(CS=1) + 额外8时钟
              → 继续后续初始化(CMD8/ACMD41等)

通过上述修改,TF卡会在每次MCU复位后被强制同步到空闲状态,解决软件复位初始化失败的问题。无需用户手动拔插卡。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分