/**
- 本代码案例将演示如何通过STM32读写SD卡。我们将使用SDIO接口和FATFS文件系统库来实现这一功能。
- 步骤概述:
-
- 初始化SD卡接口(SDIO)
-
- 挂载文件系统
-
- 创建、写入和读取文件
- 硬件要求:
-
- 一个STM32单片机开发板(例如:STM32F4Discovery)
-
- 一个带有SD卡插槽的SD卡模块
- 软件要求:
-
- STM32CubeMX:用于生成STM32项目的初始化代码
-
- STM32CubeIDE:用于编写和调试STM32代码
-
- FATFS库:用于支持SD卡的文件系统操作
- 注意事项:
-
- 在运行此代码之前,请确保已将SD卡正确连接到STM32开发板,并使用正确的引脚和电压级别。
-
- 在STM32CubeMX中配置SD卡初始化,并将相关代码复制到main.c文件中。
-
- 在STM32CubeIDE中添加FATFS库,并将相关代码复制到main.c文件中。
-
- 在FATFS库的diskio.c文件中,根据SD卡的初始化配置修改SD卡的片选引脚。 */
#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;
/**
- 初始化SD卡接口 */ void SD_Init() { // 根据SD卡的初始化配置进行相应的初始化操作 // 这部分由STM32CubeMX生成的代码负责 MX_SDIO_SD_Init(); }
/**
- SD卡选中 */ void SD_Select() { HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_RESET); }
/**
- SD卡取消选中 */ void SD_Deselect() { HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_SET); }
/**
-
通过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