
硬件要点:
时钟线串联22Ω电阻抑制反射
所有信号线加3.3V上拉电阻(10kΩ)
电源走线宽度≥20mil,VCC与GND间并联10μF+100nF电容

硬件要点:
MISO需加10kΩ上拉电阻
SCK频率初始≤400kHz(初始化后可达25MHz)
CS引脚建议串联100Ω电阻
// 1. 配置SDIO时钟RCC_PeriphCLKInitTypeDef sdcfg = {0};sdcfg.PeriphClockSelection = RCC_PERIPHCLK_SDIO;sdcfg.SdioClockSelection = RCC_SDIOCLKSOURCE_PLLPCLK;HAL_RCCEx_PeriphCLKConfig(&sdcfg);// 2. 初始化SDIO外设SD_HandleTypeDef hsd;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_1B; // 初始为1-bit模式hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_ENABLE;hsd.Init.ClockDiv = SDIO_INIT_CLK_DIV; // 通常为0x76(400kHz)HAL_SD_Init(&hsd);// 3. 发送初始化序列HAL_SD_InitCard(&hsd);// 4. 切换至4-bit模式HAL_SD_WideBusOperation_Config(&hsd, SDIO_BUS_WIDE_4B);// 5. 设置高速模式(24MHz)hsd.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV; // 如0x00(24MHz)HAL_SD_Init(&hsd);// 6. 验证初始化成功if(HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_TRANSFER)
printf("SDIO Init Success!
");// 1. 配置SPI外设SPI_HandleTypeDef hspi;hspi.Instance = SPI1;hspi.Init.Mode = SPI_MODE_MASTER;hspi.Init.Direction = SPI_DIRECTION_2LINES;hspi.Init.DataSize = SPI_DATASIZE_8BIT;hspi.Init.CLKPolarity = SPI_POLARITY_LOW; // CPOL=0hspi.Init.CLKPhase = SPI_PHASE_1EDGE; // CPHA=0hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; // 400kHzHAL_SPI_Init(&hspi);// 2. 发送74+个时钟脉冲(唤醒SD NAND)CS_LOW();uint8_t dummy[10] = {0xFF};HAL_SPI_Transmit(&hspi, dummy, 10, 100);CS_HIGH();// 3. CMD0(软复位)sd_cmd(0x40, 0, 0x95); // 参数: CMD0+0x40, arg=0, CRC7=0x95// 4. CMD8(电压检查)do {
response = sd_cmd(0x48, 0x1AA, 0x87); // CMD8+0x40, arg=0x1AA, CRC=0x87} while(response != 0x01); // 等待退出空闲状态// 5. ACMD41(初始化)do {
sd_cmd(0x77, 0, 0); // CMD55(APP_CMD)
response = sd_cmd(0x69, 0x40000000, 0); // ACMD41(带HCS位)} while(response != 0x00);// 6. 切换高速模式hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // 25MHzHAL_SPI_Init(&hspi);// 单块读取HAL_SD_ReadBlocks(&hsd, buffer, sector, 1, 1000);// 多块写入(启用DMA)HAL_SD_WriteBlocks_DMA(&hsd, buffer, sector, num_blocks);// 回调函数(DMA完成中断)void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) {
printf("Write Complete!
");}// SPI发送命令(返回R1响应)uint8_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc) {
uint8_t frame[6] = {
cmd,
(uint8_t)(arg >> 24),
(uint8_t)(arg >> 16),
(uint8_t)(arg >> 8),
(uint8_t)arg,
crc };
CS_LOW();
HAL_SPI_Transmit(&hspi, frame, 6, 100);
// 等待响应(最多重试8次)
uint8_t response;
for(int i=0; i<8; i++) {
HAL_SPI_Receive(&hspi, &response, 1, 10);
if(!(response & 0x80)) break;
}
return response;}// 读取数据块void sd_read_block(uint32_t sector, uint8_t *buffer) {
sd_cmd(0x51, sector << 9, 0); // CMD17 (地址按字节计算)
// 等待数据令牌0xFE
uint8_t token;
do {
HAL_SPI_Receive(&hspi, &token, 1, 100);
} while(token != 0xFE);
// 读取512字节数据
HAL_SPI_Receive(&hspi, buffer, 512, 1000);
// 跳过2字节CRC
HAL_SPI_Receive(&hspi, buffer, 2, 10);}SDIO 常见问题:
初始化失败 → 检查D0上拉电阻
数据传输CRC错误 → 降低时钟频率
DMA超时 → 检查4-bit模式是否配置成功
SPI 调试工具:
# 使用pyftdi检测SPI通信from pyftdi.spi import SpiController
spi = SpiController()spi.configure('ftdi://::/1')slave = spi.get_port(cs=0, freq=1E6)data = slave.exchange([0x40,0,0,0,0,0x95], 6) # CMD0print(f"Response: {hex(data[0])}")逻辑分析仪抓包:
SDIO模式:关注CMD线初始化序列
SPI模式:检查CMD0返回的0x01响应

关键代码优化:
// SDIO开启D-Cache(STM32H7)SCB_EnableDCache();// SPI使用内存对齐缓冲区__attribute__((aligned(32))) uint8_t buffer[512];
完整工程建议:
实现FATFS文件系统集成
添加异常处理(拔出检测、写保护)
设计磨损均衡算法(针对NAND特性)
参考文档:
SD Physical Layer Specification v7.0
JESD84-B51(eMMC标准)
STM32 SDIO应用笔记AN5348
本指南覆盖从硬件设计到软件驱动的全流程,可根据具体芯片手册调整电压参数和时序要求。
上一篇:sd nand 初始化
电话:176-6539-0767
Q Q:135-0379-986
邮箱:1350379986@qq.com
地址:深圳市南山区后海大道1021号C座