You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F411 自定义SPI驱动读取SD卡始终返回0xFF求助

STM32自定义SPI驱动读取SD卡始终返回0xFF排查

问题背景

使用HAL驱动通过SPI读取SD卡功能正常,但速度过慢,因此自行编写裸机SPI驱动。GPIO配置确认无问题,但数据传输环节异常:无论发送什么数据,读取返回值始终为0xFF。已对比数十个STM32裸机SPI实现,未发现代码差异。

自定义SPI驱动代码

void fhSpiInit(u32 pScaler)
{
    fhGpioInitSystemA();

    fhGpioPinSetupA(FH_GPIO_PIN_07, FH_GPIO_MODE_ALTERNATE, FH_GPIO_OTYPE_PUSH_PULL, FH_GPIO_SPEED_HIGH, FH_GPIO_PULL_NONE);
    fhGpioPinSetupA(FH_GPIO_PIN_06, FH_GPIO_MODE_ALTERNATE, FH_GPIO_OTYPE_PUSH_PULL, FH_GPIO_SPEED_HIGH, FH_GPIO_PULL_NONE);
    fhGpioPinSetupA(FH_GPIO_PIN_05, FH_GPIO_MODE_ALTERNATE, FH_GPIO_OTYPE_PUSH_PULL, FH_GPIO_SPEED_HIGH, FH_GPIO_PULL_NONE);
    fhGpioPinSetupA(FH_GPIO_PIN_03, FH_GPIO_MODE_OUTPUT, FH_GPIO_OTYPE_PUSH_PULL, FH_GPIO_SPEED_HIGH, FH_GPIO_PULL_NONE);

    fhGpioAlternateFunctionA(FH_GPIO_PIN_07, 5);
    fhGpioAlternateFunctionA(FH_GPIO_PIN_06, 5);
    fhGpioAlternateFunctionA(FH_GPIO_PIN_05, 5);

    RCC->APB2RSTR &= ~RCC_APB2RSTR_SPI1;
    RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;

    SPI1->CR1 = 0;
    SPI1->CR2 = 0;

    SPI1->CR1 |= pScaler;
    SPI1->CR1 |= SPI_CR1_MSTR;
    SPI1->CR1 |= SPI_CR1_SSM;
    SPI1->CR1 |= SPI_CR1_SSI;
    SPI1->CR1 |= SPI_CR1_SPE;

    fhSpiCsHigh();
}

void fhSpiDeinit()
{
    SPI1->CR1 &= ~SPI_CR1_SPE;
    RCC->APB2ENR &= ~RCC_APB2ENR_SPI1EN;
    RCC->APB2RSTR |= RCC_APB2RSTR_SPI1RST;
}

void fhSpiReInit(u32 pScaler)
{
    fhSpiDeinit();
    fhSpiInit(pScaler);
}

u8 fhSpiTransferByte(u8 pToWrite)
{
    SPI1->DR = pToWrite;

    halt(!(SPI1->SR & SPI_SR_TXE));
    halt(!(SPI1->SR & SPI_SR_RXNE));
    u8 ret = SPI1->DR;

    printf("\tSPI1: %02x <=> %02x\n", pToWrite, ret);

    return ret;
}

void fhSpiCsLow()
{
    fhGpioPinWriteA(FH_GPIO_PIN_03, 0);
}

void fhSpiCsHigh()
{
    fhGpioPinWriteA(FH_GPIO_PIN_03, 1);
}

ulibSD SPI适配代码

/**
    \brief Initialize SPI hardware
 */
void SPI_Init(void)
{
    fhSpiReInit(SPI_BAUDRATEPRESCALER_256);
}

/**
    \brief Read/Write a single byte.
    \param d Byte to send.
    \return Byte that arrived.
 */
BYTE SPI_RW(BYTE d)
{
    return fhSpiTransferByte(d);
}

/**
    \brief Flush of SPI buffer.
 */
void SPI_Release(void)
{
    return;
}

/**
    \brief Selecting function in SPI terms, associated with SPI module.
 */
void SPI_CS_Low(void)
{
    fhSpiCsLow();
}

/**
    \brief Deselecting function in SPI terms, associated with SPI module.
 */
void SPI_CS_High(void)
{
    fhSpiCsHigh();
}

/**
    \brief Setting frequency of SPI's clock to maximun possible.
 */
void SPI_Freq_High(void)
{
    fhSpiReInit(SPI_BAUDRATEPRESCALER_2);
}

/**
    \brief Setting frequency of SPI's clock equal or lower than 400kHz.
 */
void SPI_Freq_Low(void)
{
    fhSpiReInit(SPI_BAUDRATEPRESCALER_256);
}

uint32_t gSpiTimerEnd = 0;

/**
    \brief Start a non-blocking timer.
    \param ms Milliseconds.
 */
void SPI_Timer_On(WORD ms)
{
    gSpiTimerEnd = gSysTick + ms;
}

/**
    \brief Check the status of non-blocking timer.
    \return Status, TRUE if timeout is not reach yet.
 */
BOOL SPI_Timer_Status(void)
{
    if (gSpiTimerEnd == -1)
    {
        return false;
    }

    if (gSysTick >= gSpiTimerEnd)
    {
        SPI_Timer_Off();
        return false;
    }

    return true;
}

/**
    \brief Stop of non-blocking timer. Mandatory.
 */
void SPI_Timer_Off(void)
{
    gSpiTimerEnd = -1;
}

接线与电压检测

  • 接线方式:
    • USB_VCC -> STM_5V
    • USB_GND -> STM_GND
    • SD_GND -> STM_GND
    • SD_VDD -> STM_3V3
    • SD_MOSI -> STM_MOSI1
    • SD_MISO -> STM_MISO1
    • SD_CLK -> STM_CLK1
    • SD_CS -> STM_A3
  • 电压检测:
    • STM32微控制器输入电压:5.06V
    • STM板输出到SD卡的电压:3.44V(略高,判断无影响)

输出日志

SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: 40 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 95 <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: 40 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 95 <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: 40 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 95 <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: 40 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 95 <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: 40 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 95 <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: 40 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 00 <=> ff
        SPI1: 95 <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
        SPI1: ff <=> ff
SD_Init: 1

排查方向

从日志可见,SD卡初始化阶段发送CMD0(0x40开头的指令)后,始终未收到SD卡响应,返回全0xFF,需排查以下点:

  1. SPI配置是否遗漏数据位宽、CPOL/CPHA模式等SD卡要求的参数
  2. MISO引脚的硬件连接或GPIO配置是否存在异常(如浮空未拉、引脚复用错误)
  3. SD卡初始化时序是否符合规范(如CS拉低前的时钟同步、指令发送间隔)
  4. 自定义SPI传输函数的等待逻辑是否存在时序问题(如RXNE等待是否过早)

内容的提问来源于stack exchange,提问作者zlovro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 07:49:51