这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【STM32F103ZET6】10:使用cubeMX配置一下SD卡的驱动

共4条 1/1 1 跳转至

【STM32F103ZET6】10:使用cubeMX配置一下SD卡的驱动

高工
2025-10-18 16:13:22     打赏

利用周末的时间和大家分享一下使用STM32cube MX软件配置SD卡的过程。

一:SD卡相关知识

SD 卡的规范由 SD 卡协会明确,可以访问 https://www.sdcard.org 查阅更多标准。SD 卡主要有 SD、Mini SD 和 microSD(原名 TF 卡,2004 年正式更名为 Micro SD Card,为方便本文用microSD 表示)三种类型,Mini SD 已经被 microSD 取代,使用得不多,根据最新的 SD 卡规格列出的参数如下所示:

STM32驱动SD卡通常有以下几种方式:

SPI模式:使用SPI总线通信。优点是接口简单,引脚占用少,几乎所有STM32都支持。缺点是速度较慢。

SDIO模式:使用专用的SDIO外设。这是SD卡的标准接口,速度快,效率高,是首选方案。

HAL库与CubeMX:ST提供的HAL库和图形化配置工具极大地简化了驱动开发过程。

2.10-1.png

二: STM32 cube MX 软件配置如下所示:

10-2.png

三:软件代码如下所示:

3.1 SD卡的初始化过程:

void MX_SDIO_SD_Init(void)
{

  /* USER CODE BEGIN SDIO_Init 0 */

  /* USER CODE END SDIO_Init 0 */

  /* USER CODE BEGIN SDIO_Init 1 */

  /* USER CODE END SDIO_Init 1 */
  hsd.Instance = SDIO;
  hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
  hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
  hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
  hsd.Init.BusWide = SDIO_BUS_WIDE_4B;
  hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_ENABLE;
  hsd.Init.ClockDiv = 4;
  if (HAL_SD_Init(&hsd) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
   {
    Error_Handler();
   }
  /* USER CODE BEGIN SDIO_Init 2 */

  /* USER CODE END SDIO_Init 2 */

}

3.2 向SD卡写入数据如下所示:

uint8_t sd_read_disk(uint8_t *pbuf, uint32_t saddr, uint32_t cnt)
{
    uint8_t sta = HAL_OK;
    uint32_t timeout = SD_TIMEOUT;
    long long lsector = saddr;
    
    __disable_irq();                                                                       /* 关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!) */
    sta = HAL_SD_ReadBlocks(&g_sdcard_handler, (uint8_t *)pbuf, lsector, cnt, SD_TIMEOUT); /* 多个sector的读操作 */

    /* 等待SD卡读完 */
    while (get_sd_card_state() != SD_TRANSFER_OK)
    {
        if (timeout-- == 0)
        {
            sta = SD_TRANSFER_BUSY;
        }
    }
    __enable_irq(); /* 开启总中断 */
    return sta;
}

3.3 向SD卡读取数据如下所示:

uint8_t sd_write_disk(uint8_t *pbuf, uint32_t saddr, uint32_t cnt)
{
    uint8_t sta = HAL_OK;
    uint32_t timeout = SD_TIMEOUT;
    long long lsector = saddr;
    __disable_irq();                                                                        /* 关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!) */
    sta = HAL_SD_WriteBlocks(&g_sdcard_handler, (uint8_t *)pbuf, lsector, cnt, SD_TIMEOUT); /* 多个sector的写操作 */

    /* 等待SD卡写完 */
    while (get_sd_card_state() != SD_TRANSFER_OK)
    {
        if (timeout-- == 0)
        {
            sta = SD_TRANSFER_BUSY;
        }
    }
    __enable_irq(); /* 开启总中断 */
    return sta;
}

四:实物测试如下所示:

1102-3.jpg

测试代码如下所示:

    printf("\r\n===== SD Card Read/Write Test Start =====\r\n\r\n");

  
    uint8_t ret = SD_Init();
    if (ret != 0) {
        printf("[ERROR] SD Card Initialization Failed. Error Code: 0x%02X\r\n", ret);
        while(1); // Halt if initialization fails
    }
    printf("[INFO] SD Card Initialized Successfully!\r\n");

   
    uint32_t capacity = SD_GetCapacity();
    printf("[INFO] Total Sectors: %lu (Approx %.2f GB)\r\n", 
           capacity, (float)capacity * 512 / 1000 / 1000 / 1000);

 
    fill_test_pattern(write_buffer);
    const uint32_t test_sector = 1000; // Test sector (avoid overwriting critical data)

    
    printf("[TEST] Writing to Sector %lu...\r\n", test_sector);
    ret = SD_WriteBlock(test_sector, write_buffer);
    if (ret != 0) {
        printf("[ERROR] Sector Write Failed. Error Code: 0x%02X\r\n", ret);
        while(1);
    }
    printf("[TEST] Write Successful. Waiting 1 second...\r\n");
    HAL_Delay(1000); // Ensure data is physically written

    
    printf("[TEST] Reading from Sector %lu...\r\n", test_sector);
    ret = SD_ReadBlock(test_sector, read_buffer);
    if (ret != 0) {
        printf("[ERROR] Sector Read Failed. Error Code: 0x%02X\r\n", ret);
        while(1);
    }

  
    printf("[TEST] Verifying Data...\r\n");
    if (verify_data(write_buffer, read_buffer)) {
        printf("[RESULT] Test Passed! Read/Write Data Matched!\r\n");
    } else {
        printf("[ERROR] Test Failed! Data Mismatch Detected!\r\n");
    }

  printf("\r\n================== Test Completed ===========\r\n");

1102-1.png

调试心得:

一:初始化失败 (HAL_SD_Init返回错误)

1.1时钟问题:确保初始化阶段SDIO_CK ≤ 400kHz。检查CubeMX中的分频系数。

1.2电源问题:确保SD卡供电稳定(3.3V)。

1.3上拉电阻:SDIO的所有数据线和CMD线都需要4.7K-10K的上拉电阻。

二:读写不稳定,偶尔失败

2.1DMA配置:确保DMA已正确配置,并且优先级设置合理。

2.2 时钟频率过高:初始化完成后,虽然可以提高到最高频率(如24MHz, 48MHz),但如果布线质量差,可能会出错。尝试降低频率。

2.3中断冲突:确保SDIO和DMA的中断优先级设置正确,没有被其他高优先级中断长时间阻塞。

2.4 Cache一致性:如果使用了D-Cache,在DMA传输前需要调用 SCB_InvalidateDCache() 和 SCB_CleanDCache() 来保证CPU和DMA看到的内存数据是一致的。

三:FatFS返回 FR_DISK_ERR

3.1 这通常是底层SDIO驱动出错的反映。检查 HAL_SD_GetCardState() 的返回值。

3.2 确保SD卡已被成功初始化 (HAL_SD_Init)。

3.3 检查SD卡是否支持4位总线模式(绝大多数都支持)。




关键词: STM32F103     SD卡    

专家
2025-11-10 15:33:49     打赏
2楼

一直想搞通SD卡的处理,谢谢楼主分享!


高工
2025-11-10 21:46:27     打赏
3楼

有没有可能讲解一下SD卡 的初始化流程?


高工
2025-11-11 10:50:16     打赏
4楼

后续是不是可以基于SD卡适配文件系统了


共4条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]