利用周末的时间和大家分享一下使用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.
二: STM32 cube MX 软件配置如下所示:

三:软件代码如下所示:
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;
}四:实物测试如下所示:

测试代码如下所示:
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");
调试心得:
一:初始化失败 (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位总线模式(绝大多数都支持)。
我要赚赏金
