以下是针对 STM32F405RGT6 和 STM32L476RGT6 驱动 SD NAND(SD卡)的详细指南,涵盖硬件接线、软件代码、注意事项及问题处理。
STM32F405RGT6 引脚分配:
SD卡引脚 | STM32F405引脚 | 功能 |
---|---|---|
CLK | PC12 (SDIO_CK) | 时钟信号 |
CMD | PD2 (SDIO_CMD) | 命令/响应线 |
D0 | PC8 (SDIO_D0) | 数据线0 |
D1 | PC9 (SDIO_D1) | 数据线1 |
D2 | PC10 (SDIO_D2) | 数据线2 |
D3 | PC11 (SDIO_D3) | 数据线3 |
VCC | 3.3V | 电源 |
GND | GND | 地线 |
STM32L476RGT6 引脚分配:
SD卡引脚 | STM32L476引脚 | 功能 |
---|---|---|
CLK | PC12 (SDIO_CK) | 时钟信号 |
CMD | PD2 (SDIO_CMD) | 命令/响应线 |
D0 | PC8 (SDIO_D0) | 数据线0 |
D1 | PC9 (SDIO_D1) | 数据线1 |
D2 | PC10 (SDIO_D2) | 数据线2 |
D3 | PC11 (SDIO_D3) | 数据线3 |
VCC | 3.3V | 电源 |
GND | GND | 地线 |
注意事项:
数据线(D0-D3)和CMD线需接10kΩ上拉电阻。
电源需稳定(建议加100nF电容滤波)。
STM32F405RGT6 引脚分配:
SD卡引脚 | STM32F405引脚 | 功能 |
---|---|---|
CLK | PA5 (SPI1_SCK) | 时钟信号 |
DI (MOSI) | PA7 (SPI1_MOSI) | 主机输出从机输入 |
DO (MISO) | PA6 (SPI1_MISO) | 主机输入从机输出 |
CS | PA4 (自定义GPIO) | 片选信号 |
VCC | 3.3V | 电源 |
GND | GND | 地线 |
STM32L476RGT6 引脚分配:
SD卡引脚 | STM32L476引脚 | 功能 |
---|---|---|
CLK | PA5 (SPI1_SCK) | 时钟信号 |
DI (MOSI) | PA7 (SPI1_MOSI) | 主机输出从机输入 |
DO (MISO) | PA6 (SPI1_MISO) | 主机输入从机输出 |
CS | PA4 (自定义GPIO) | 片选信号 |
VCC | 3.3V | 电源 |
GND | GND | 地线 |
注意事项:
MISO需接10kΩ上拉电阻。
片选(CS)通过GPIO控制,建议初始化为高电平。
// STM32F405RGT6 / STM32L476RGT6 通用代码#include "stm32f4xx_hal.h" // F405使用f4xx,L476使用l4xxSD_HandleTypeDef hsd;void SDIO_Init(void) {
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_DISABLE;
// F405主频较高,分频需更大(例如 ClockDiv=8)
// L476主频较低,分频可更小(例如 ClockDiv=4)
hsd.Init.ClockDiv = 8;
if (HAL_SD_Init(&hsd) != HAL_OK) {
Error_Handler();
}
// 配置4位总线模式
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK) {
Error_Handler();
}}
// STM32F405RGT6 / STM32L476RGT6 通用代码#include "stm32f4xx_hal.h" // L476使用l4xxSPI_HandleTypeDef hspi1;void SPI_Init(void) {
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; // 初始低速
HAL_SPI_Init(&hspi1);}// 发送CMD0(复位卡)uint8_t SD_SPI_GoIdle(void) {
uint8_t cmd[6] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95}; // CMD0 + CRC
uint8_t response;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1, cmd, 6, 100);
HAL_SPI_Receive(&hspi1, &response, 1, 100);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
return response; // 期望返回0x01(空闲状态)}
电源管理:
STM32L476 是低功耗芯片,需关闭低功耗模式(如调高系统时钟或禁用睡眠模式)。
STM32F405 需确保SDIO时钟源(如PLL48CLK)正确配置。
信号完整性:
数据线长度尽量短,避免干扰。
在高速模式(SDIO)下,建议使用屏蔽线或PCB走线优化。
文件系统适配:
若使用FATFS,需正确实现 disk_read
和 disk_write
函数。
示例代码参考STM32Cube库中的 FATFS
模块。
SD卡初始化:
SPI模式下需多次发送CMD0(复位)直到返回0x01。
SDIO模式下需检查卡状态:HAL_SD_GetCardState(&hsd)
.
可能原因:
时钟配置错误(检查 hsd.Init.ClockDiv
分频值)。
未正确配置4位总线模式(调用 HAL_SD_ConfigWideBusOperation
)。
解决:
使用STM32CubeMX生成SDIO初始化代码,验证分频参数。
调试步骤:
用逻辑分析仪检查CLK、MOSI、MISO信号。
确认CS信号在传输期间保持低电平。
检查SD卡是否支持SPI模式(部分工业级SD卡需要特殊初始化)。
硬件问题:
检查电源电压(3.3V±10%)。
增加数据线上拉电阻(10kΩ~50kΩ)。
软件问题:
降低时钟频率(例如SPI预分频设为SPI_BAUDRATEPRESCALER_64
)。
启用SDIO的CRC校验功能。
现象:
进入睡眠模式后SD卡无法唤醒。
解决:
在进入低功耗前卸载SD卡。
使用HAL_SD_DeInit()
释放资源,唤醒后重新初始化。
STM32Cube库:
F405参考:STM32Cube_FW_F4_Vx.x.x/Projects/STM32F4-Discovery/Applications
L476参考:STM32Cube_FW_L4_Vx.x.x/Projects/NUCLEO-L476RG/Examples
SD卡协议文档:
《SD Specifications Part 1 Physical Layer Simplified Specification》
调试工具:
逻辑分析仪(Saleae/PulseView)抓取SDIO/SPI波形。
STM32CubeMonitor实时监控SD卡状态。