STM32 SD卡读写学习指南
/**
- 初始化SD卡接口(SDIO)
- 挂载文件系统
- 创建、写入和读取文件
#include "stm32f4xx_hal.h" #include "ff.h" #include "string.h"
// 定义SD卡的片选引脚 #define SD_CS_GPIO_Port GPIOB #define SD_CS_Pin GPIO_PIN_0
// 定义文件名和缓冲区 #define FILENAME "test.txt" #define BUFFER_SIZE 512 uint8_t buffer[BUFFER_SIZE];
// FATFS和文件句柄 FATFS fs; FIL fil;
// SD卡错误标志 volatile DSTATUS sdCardStatus = STA_NOINIT;
/**
/**
/**
/**
通过SDIO接口向SD卡发送命令
@param cmd 命令宏定义
@param arg 命令参数
@param response 得到的响应
@return 成功或失败标志 */ int SD_SendCommand(uint8_t cmd, uint32_t arg, uint8_t *response) { SDIO_CmdInitTypeDef cmdInit; uint32_t responseVal = 0;
// 初始化命令结构体 cmdInit.Argument = arg; cmdInit.CmdIndex = cmd; cmdInit.Response = SDIO_RESPONSE_SHORT; cmdInit.WaitForInterrupt = SDIO_WAIT_NO; cmdInit.CPSM = SDIO_CPSM_Enable; SDIO_SendCommand(&cmdInit);
// 如果是命令7,8,12,那么需要等待一段时间来接收完响应 if (cmd == SD_CMD_SEND_IF_COND || cmd == SD_CMD_APP_CMD || cmd == SD_CMD_SD_SEND_OP_COND) { for (uint32_t i = 0; i < 0xFFFF; ++i); // 等待一段时间 }
// 根据命令获取响应结果 if (cmdInit.Response != SDIO_RESPONSE_NO) { while (!(__HAL_SDIO_GET_FLAG(&hsdio, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT))); if (__HAL_SDIO_GET_FLAG(&hsdio, SDIO_FLAG_CTIMEOUT)) { __HAL_SDIO_CLEAR_FLAG(&hsdio, SDIO_FLAG_CTIMEOUT); return 0; } if (__HAL_SDIO_GET_FLAG(&hsdio, SDIO_FLAG_CMDREND)) { __HAL_SDIO_CLEAR_FLAG(&hsdio, SDIO_FLAG_CMDREND); responseVal = SDIO_GetResponse(SDIO_RESP1); if (response != NULL) { response[3] = (responseVal & 0xFF000000) >> 24; response[2] = (responseVal & 0x00FF0000) >> 16; response[1] = (responseVal & 0x0000FF00) >> 8; response[0] = (responseVal & 0x000000FF); } } }
return 1; }
/**
等待SD卡准备就绪
@return 成功或失败标志 */ int SD_WaitReady() { uint32_t response; uint64_t timeout = HAL_GetTick() + 500; // 等待500毫秒
// 等待SD卡准备就绪 do { if (!SD_SendCommand(SD_CMD_SEND_STATUS, 0, (uint8_t *) &response)) { return 0; } } while ((response & 0xFF) != 0x00 && HAL_GetTick() < timeout);
return 1; }
/**
读取SD卡的块数据
@param blockNumber 要读取的块号
@param buffer 数据缓冲区
@return 成功或失败标志 */ int SD_ReadBlock(uint32_t blockNumber, uint8_t *buffer) { if (!SD_WaitReady()) { return 0; }
// 配置SD卡数据传输配置 SDIO_DataInitTypeDef dataInit; dataInit.DataTimeOut = SD_DATATIMEOUT; dataInit.DataLength = 512; dataInit.DataBlockSize = SDIO_DATABLOCK_SIZE_512B; dataInit.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO; dataInit.TransferMode = SDIO_TRANSFER_MODE_BLOCK; dataInit.DPSM = SDIO_DPSM_Enable; SDIO_DataConfig(&dataInit);
// 发送读取块命令 if (!SD_SendCommand(SD_CMD_READ_SINGLE_BLOCK, blockNumber * 512, NULL)) { return 0; }
// 接收数据 HAL_SD_IO_ReadBlocks((uint32_t *) buffer, 512, 1);
// 等待数据传输完成 while (!(__HAL_SDIO_GET_FLAG(&hsdio, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR))); if (__HAL_SDIO_GET_FLAG(&hsdio, SDIO_FLAG_DTIMEOUT)) { __HAL_SDIO_CLEAR_FLAG(&hsdio, SDIO_FLAG_DTIMEOUT); return 0; } if (__HAL_SDIO_GET_FLAG(&hsdio, SDIO_FLAG_DCRCFAIL)) { __HAL_SDIO_CLEAR_FLAG(&hsdio, SDIO_FLAG_DCRCFAIL); return 0; } if (__HAL_SDIO_GET_FLAG(&hsdio, SDIO_FLAG_RXOVERR)) { __HAL_SDIO_CLEAR_FLAG(&hsdio, SDIO_FLAG_RXOVERR); return 0; } if (__HAL_SDIO_GET_FLAG(&hsdio, SDIO_FLAG_STBITERR)) { __HAL_SDIO_CLEAR_FLAG(&hsdio, SDIO_FLAG_STBITERR); return 0; }
return 1; }
/**
写入SD卡的块数据
@param blockNumber 要写入的块号
@param buffer 数据缓冲区
@return 成功或失败标志 */ int SD_WriteBlock(uint32_t blockNumber, uint8_t *buffer) { if (!SD_WaitReady()) { return 0; }
// 配置SD卡数据传输配置 SDIO_DataInitTypeDef dataInit; dataInit.DataTimeOut = SD_DATATIMEOUT; dataInit.DataLength = 512; dataInit.DataBlockSize = SDIO_DATABLOCK_SIZE_512B; dataInit.TransferDir = SDIO_TRANSFER_DIR_TO_CARD; dataInit.TransferMode = SDIO_TRANSFER_MODE_BLOCK; dataInit.DPSM = SDIO_DPSM_Enable; SDIO_DataConfig(&dataInit);
// 发送写入块命令 if (!SD_SendCommand(SD_CMD_WRITE_SINGLE_BLOCK, blockNumber * 512, NULL)) { return 0; }
// 发送数据 HAL_SD_IO_WriteBlocks((uint32_t *) buffer, 512, 1);
// 等待数据传输完成 while (!(__HAL_SDIO_GET_FLAG(&hsdio, SDIO_FLAG_TXUNDERR
作者:xiaoalla