以下是针对 STM32F303ZET6 驱动 SD NAND(SD卡)的详细指南,涵盖硬件接线、软件代码、注意事项及问题处理。
STM32F303ZET6 引脚分配:
SD卡引脚 | STM32F303ZET6引脚 | 功能 |
---|---|---|
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电容 和 10μF电解电容 以稳定电压。
信号完整性:避免长走线,尽量缩短数据线长度。
STM32F303ZET6 引脚分配:
SD卡引脚 | STM32F303ZET6引脚 | 功能 |
---|---|---|
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引脚初始化为高电平,操作时拉低。
SPI速率:初始化时使用低速(如 100kHz),后续可提升至 25MHz(需SD卡支持)。
#include "stm32f3xx_hal.h"SD_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; // 4位总线模式
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
hsd.Init.ClockDiv = 8; // 时钟分频,确保初始化频率 ≤ 400kHz
if (HAL_SD_Init(&hsd) != HAL_OK) {
Error_Handler(); // 初始化失败处理
}
// 配置4位总线模式
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK) {
Error_Handler();
}
// 初始化完成后,可提升时钟频率(例如 ClockDiv=0,主频 48MHz / (2 + 0) = 24MHz)
HAL_SD_SetBusSpeed(&hsd, SDIO_SPEED_24M);}// 读取单个块(512字节)HAL_StatusTypeDef SD_ReadBlock(uint32_t blockAddr, uint8_t *pData) {
return HAL_SD_ReadBlocks(&hsd, pData, blockAddr, 1, 5000);}// 写入单个块HAL_StatusTypeDef SD_WriteBlock(uint32_t blockAddr, uint8_t *pData) {
return HAL_SD_WriteBlocks(&hsd, pData, blockAddr, 1, 5000);}
#include "stm32f3xx_hal.h"SPI_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; // CPOL=0
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // CPHA=0
hspi1.Init.NSS = SPI_NSS_SOFT; // 软件控制片选
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; // 初始低速
HAL_SPI_Init(&hspi1);}// 发送SD卡命令(CMD格式)uint8_t SD_SPI_SendCommand(uint8_t cmd, uint32_t arg, uint8_t crc) {
uint8_t tx_buf[6] = {0x40 | cmd, (arg >> 24) & 0xFF, (arg >> 16) & 0xFF,
(arg >> 8) & 0xFF, arg & 0xFF, crc};
uint8_t response;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // CS拉低
HAL_SPI_Transmit(&hspi1, tx_buf, 6, 100); // 发送命令
HAL_SPI_Receive(&hspi1, &response, 1, 100); // 接收响应
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // CS拉高
return response;}// 初始化SD卡(SPI模式)uint8_t SD_SPI_Init(void) {
// 发送至少74个时钟脉冲(无片选)
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
uint8_t dummy[10] = {0xFF};
HAL_SPI_Transmit(&hspi1, dummy, 10, 100);
// 发送CMD0(复位卡)
uint8_t res = SD_SPI_SendCommand(0, 0, 0x95);
if (res != 0x01) return 1; // 初始化失败
return 0;}
电源要求:
SD卡必须由 3.3V 供电,电压偏差不超过 ±10%。
避免与电机等大电流设备共用电源,防止电压波动。
信号完整性:
SDIO模式下,D0-D3和CMD线必须上拉。
SPI模式下,MISO线必须上拉。
时钟配置:
SDIO模式初始化时时钟频率需 ≤ 400kHz,初始化后可提升至 24MHz。
SPI模式初始化时使用低速(如 100kHz),后续可提速至 25MHz。
文件系统集成:
若使用FATFS,需正确实现 disk_read
和 disk_write
接口。
参考STM32Cube库中的 FATFS
模块(路径:Middlewares/Third_Party/FatFs
)。
DMA优化:
在SDIO模式下启用DMA传输,提升效率:
hsd.Init.ClockDiv = 0; // 最高速度hsd.hdmatx = &hdma_sdio_tx; // 配置DMA通道hsd.hdmarx = &hdma_sdio_rx;
可能原因:
电源电压不足或未连接。
上拉电阻未焊接。
初始化时钟频率过高。
解决:
用万用表测量VCC是否为3.3V。
检查上拉电阻是否连接。
降低初始化时钟频率(增大 ClockDiv
或 BaudRatePrescaler
)。
可能原因:
数据线接触不良(尤其是D0和CMD)。
文件系统未正确挂载(如FATFS未初始化)。
解决:
检查PCB走线或杜邦线连接。
调用 f_mount
函数挂载文件系统。
调试步骤:
使用逻辑分析仪抓取SPI波形,确认CLK、MOSI、CS信号正常。
检查SD卡是否支持SPI模式(部分工业卡需特殊初始化)。
多次发送CMD0(复位命令)直至返回0x01。
可能原因:
未正确等待SD卡写入完成。
未调用 HAL_SD_CheckWriteOperation
确认写入状态。
解决:
HAL_SD_WriteBlocks(&hsd, pData, blockAddr, 1, 5000);while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER);
STM32CubeF3 SDK:
路径:STM32Cube_FW_F3_Vx.x.x/Projects/STM32F3-Discovery/Applications/SD/SD_ReadWrite
。
SD卡协议文档:
《SD Physical Layer Simplified Specification》Version 8.00。
调试工具:
逻辑分析仪(如Saleae Logic)分析SDIO/SPI时序。
STM32CubeMonitor实时监控SD卡状态。