硬件要点:
时钟线串联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座