参考文章
STM32 + CubeMX + 硬件SPI + SD卡 + FATFS_stm32cubemx fatfs-CSDN博客
例程地址:STM32FatFS: 基于stm32的fatfs例程,配合博客文章
基于野火STM32MINI开发板
STM32配置
系统模式配置
输出串口配置
SPI配置
使用全双工模式,禁用硬件NSS引脚,8位,MSB,256分频因为在协议在 SPI 模式初始化时(如发送 CMD0、CMD8 等命令),必须使用不超过 400kHz 的时钟频率。
NSS的GPIO配置
配置FATFS
使用自定义模式,支持简体中文编码,不建议开启长文件名支持,具体原因详见上一篇。
FREERTOS配置
选用V1版本,FATFS使用了V1版本的函数,选择V2版本编译不通过,增大栈总量,因为我在默认任务中打印了很多东西,所以需要加大栈。
增大默认任务的栈
配置系统时钟,这样可以更快的执行代码,这步完全可以不做。
配置生成独立.h.c文件
代码
创建sd卡的驱动文件,我是图省事直接添加到了Core文件夹中,分别创建sd.h和sd.c
sd.h文件
#ifndef __SD_H
#define __SD_H
#include "main.h"
#include "spi.h"
#include "ff.h"
extern uint8_t SD_TYPE;
//SD卡类型
#define ERR 0x00
#define MMC 0x01
#define V1 0x02
#define V2 0x04
#define V2HC 0x06
#define DUMMY_BYTE 0xFF
#define MSD_BLOCKSIZE 512
//CMD定义
#define CMD0 0 //卡复位
#define CMD1 1
#define CMD8 8 //命令8 ,SEND_IF_COND
#define CMD9 9 //命令9 ,读CSD数据
#define CMD10 10 //命令10,读CID数据
#define CMD12 12 //命令12,停止数据传输
#define CMD16 16 //命令16,设置SectorSize 应返回0x00
#define CMD17 17 //命令17,读sector
#define CMD18 18 //命令18,读Multi sector
#define CMD23 23 //命令23,设置多sector写入前预先擦除N个block
#define CMD24 24 //命令24,写sector
#define CMD25 25 //命令25,写Multi sector
#define CMD41 41 //命令41,应返回0x00
#define CMD55 55 //命令55,应返回0x01
#define CMD58 58 //命令58,读OCR信息
#define CMD59 59 //命令59,使能/禁止CRC,应返回0x00
//数据写入回应字意义
#define MSD_DATA_OK 0x05
#define MSD_DATA_CRC_ERROR 0x0B
#define MSD_DATA_WRITE_ERROR 0x0D
#define MSD_DATA_OTHER_ERROR 0xFF
//SD卡回应标记字
#define MSD_RESPONSE_NO_ERROR 0x00
#define MSD_IN_IDLE_STATE 0x01
#define MSD_ERASE_RESET 0x02
#define MSD_ILLEGAL_COMMAND 0x04
#define MSD_COM_CRC_ERROR 0x08
#define MSD_ERASE_SEQUENCE_ERROR 0x10
#define MSD_ADDRESS_ERROR 0x20
#define MSD_PARAMETER_ERROR 0x40
#define MSD_RESPONSE_FAILURE 0xFF
enum _CD_HOLD
{
HOLD = 0,
RELEASE = 1,
};
typedef struct /* Card Specific Data */
{
uint8_t CSDStruct; /* CSD structure */
uint8_t SysSpecVersion; /* System specification version */
uint8_t Reserved1; /* Reserved */
uint8_t TAAC; /* Data read access-time 1 */
uint8_t NSAC; /* Data read access-time 2 in CLK cycles */
uint8_t MaxBusClkFrec; /* Max. bus clock frequency */
uint16_t CardComdClasses; /* Card command classes */
uint8_t RdBlockLen; /* Max. read data block length */
uint8_t PartBlockRead; /* Partial blocks for read allowed */
uint8_t WrBlockMisalign; /* Write block misalignment */
uint8_t RdBlockMisalign; /* Read block misalignment */
uint8_t DSRImpl; /* DSR implemented */
uint8_t Reserved2; /* Reserved */
uint32_t DeviceSize; /* Device Size */
uint8_t MaxRdCurrentVDDMin; /* Max. read current @ VDD min */
uint8_t MaxRdCurrentVDDMax; /* Max. read current @ VDD max */
uint8_t MaxWrCurrentVDDMin; /* Max. write current @ VDD min */
uint8_t MaxWrCurrentVDDMax; /* Max. write current @ VDD max */
uint8_t DeviceSizeMul; /* Device size multiplier */
uint8_t EraseGrSize; /* Erase group size */
uint8_t EraseGrMul; /* Erase group size multiplier */
uint8_t WrProtectGrSize; /* Write protect group size */
uint8_t WrProtectGrEnable; /* Write protect group enable */
uint8_t ManDeflECC; /* Manufacturer default ECC */
uint8_t WrSpeedFact; /* Write speed factor */
uint8_t MaxWrBlockLen; /* Max. write data block length */
uint8_t WriteBlockPaPartial; /* Partial blocks for write allowed */
uint8_t Reserved3; /* Reserded */
uint8_t ContentProtectAppli; /* Content protection application */
uint8_t FileFormatGrouop; /* File format group */
uint8_t CopyFlag; /* Copy flag (OTP) */
uint8_t PermWrProtect; /* Permanent write protection */
uint8_t TempWrProtect; /* Temporary write protection */
uint8_t FileFormat; /* File Format */
uint8_t ECC; /* ECC code */
uint8_t CSD_CRC; /* CSD CRC */
uint8_t Reserved4; /* always 1*/
}
MSD_CSD;
typedef struct /*Card Identification Data*/
{
uint8_t ManufacturerID; /* ManufacturerID */
uint16_t OEM_AppliID; /* OEM/Application ID */
uint32_t ProdName1; /* Product Name part1 */
uint8_t ProdName2; /* Product Name part2*/
uint8_t ProdRev; /* Product Revision */
uint32_t ProdSN; /* Product Serial Number */
uint8_t Reserved1; /* Reserved1 */
uint16_t ManufactDate; /* Manufacturing Date */
uint8_t CID_CRC; /* CID CRC */
uint8_t Reserved2; /* always 1 */
}
MSD_CID;
typedef struct
{
MSD_CSD CSD;
MSD_CID CID;
uint32_t Capacity; /* Card Capacity */
uint32_t BlockSize; /* Card Block Size */
uint16_t RCA;
uint8_t CardType;
uint32_t SpaceTotal; /* Total space size in file system */
uint32_t SpaceFree; /* Free space size in file system */
}
MSD_CARDINFO, *PMSD_CARDINFO;
extern MSD_CARDINFO SD0_CardInfo;
uint8_t SD_init(void);
void SD_CS(uint8_t p);
uint32_t SD_GetSectorCount(void);
uint8_t SD_GETCID (uint8_t *cid_data);
uint8_t SD_GETCSD(uint8_t *csd_data);
int MSD0_GetCardInfo(PMSD_CARDINFO SD0_CardInfo);
uint8_t SD_ReceiveData(uint8_t *data, uint16_t len);
uint8_t SD_SendBlock(uint8_t*buf,uint8_t cmd);
uint8_t SD_ReadDisk(uint8_t*buf,uint32_t sector,uint8_t cnt);
uint8_t SD_WriteDisk(uint8_t*buf,uint32_t sector,uint8_t cnt);
void SPI_setspeed(uint8_t speed);
uint8_t spi_readwrite(uint8_t Txdata);
void Get_SDCard_Capacity(void);
void WritetoSD(char filename[], BYTE write_buff[], uint8_t bufSize);
#endif
sd.c文件
#include "sd.h"
#include <stdio.h>
#include "fatfs.h"
uint8_t DFF=0xFF;
uint8_t test;
uint8_t SD_TYPE=0x00;
MSD_CARDINFO SD0_CardInfo;
//
//片选
//
void SD_CS(uint8_t p){
if(p==0){
HAL_GPIO_WritePin(SD_CS_GPIO_Port,SD_CS_Pin,GPIO_PIN_SET);
}else{
HAL_GPIO_WritePin(SD_CS_GPIO_Port,SD_CS_Pin,GPIO_PIN_RESET);
}
}
///
//发送命令,发完释放
//
int SD_sendcmd(uint8_t cmd,uint32_t arg,uint8_t crc){
uint8_t r1;
uint8_t retry;
SD_CS(0);
HAL_Delay(20);
SD_CS(1);
do{
retry=spi_readwrite(DFF);
}while(retry!=0xFF);
spi_readwrite(cmd | 0x40);
spi_readwrite(arg >> 24);
spi_readwrite(arg >> 16);
spi_readwrite(arg >> 8);
spi_readwrite(arg);
spi_readwrite(crc);
if(cmd==CMD12)spi_readwrite(DFF);
do
{
r1=spi_readwrite(0xFF);
}while(r1&0X80);
return r1;
}
//SD卡初始化
uint8_t SD_init(void)
{
uint8_t r1;
uint8_t buff[6] = {0};
uint16_t retry;
uint8_t i;
// MX_SPI3_Init();
SPI_setspeed(SPI_BAUDRATEPRESCALER_256);
SD_CS(0);
for(retry=0;retry<10;retry++){
spi_readwrite(0xFF);
}
//SD卡进入IDLE状态
do{
r1 = SD_sendcmd(CMD0 ,0, 0x95);
}while(r1!=0x01);
//查看SD卡的类型
SD_TYPE=0;
r1 = SD_sendcmd(CMD8, 0x1AA, 0x87);
if(r1==0x01){
for(i=0;i<4;i++)buff[i]=spi_readwrite(0xFF); //Get trailing return value of R7 resp
if(buff[2]==0X01&&buff[3]==0XAA)//卡是否支持2.7~3.6V
{
retry=0XFFFE;
do
{
SD_sendcmd(CMD55,0,0X01); //发送CMD55
r1=SD_sendcmd(CMD41,0x40000000,0X01);//发送CMD41
}while(r1&&retry--);
if(retry&&SD_sendcmd(CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始
{
for(i=0;i<4;i++)buff[i]=spi_readwrite(0XFF);//得到OCR值
if(buff[0]&0x40){
SD_TYPE=V2HC;
}else {
SD_TYPE=V2;
}
}
}else{
SD_sendcmd(CMD55,0,0X01); //发送CMD55
r1=SD_sendcmd(CMD41,0,0X01); //发送CMD41
if(r1<=1)
{
SD_TYPE=V1;
retry=0XFFFE;
do //等待退出IDLE模式
{
SD_sendcmd(CMD55,0,0X01); //发送CMD55
r1=SD_sendcmd(CMD41,0,0X01);//发送CMD41
}while(r1&&retry--);
}else//MMC卡不支持CMD55+CMD41识别
{
SD_TYPE=MMC;//MMC V3
retry=0XFFFE;
do //等待退出IDLE模式
{
r1=SD_sendcmd(CMD1,0,0X01);//发送CMD1
}while(r1&&retry--);
}
if(retry==0||SD_sendcmd(CMD16,512,0X01)!=0)SD_TYPE=ERR;//错误的卡
}
}
SD_CS(0);
SPI_setspeed(SPI_BAUDRATEPRESCALER_2);
if(SD_TYPE)return 0;
else return 1;
}
//读取指定长度数据
uint8_t SD_ReceiveData(uint8_t *data, uint16_t len)
{
uint8_t r1;
SD_CS(1);
do
{
r1 = spi_readwrite(0xFF);
HAL_Delay(100);
}while(r1 != 0xFE);
while(len--)
{
*data = spi_readwrite(0xFF);
data++;
}
spi_readwrite(0xFF);
spi_readwrite(0xFF);
return 0;
}
//向sd卡写入一个数据包的内容 512字节
uint8_t SD_SendBlock(uint8_t*buf,uint8_t cmd)
{
uint16_t t;
uint8_t r1;
do{
r1=spi_readwrite(0xFF);
}while(r1!=0xFF);
spi_readwrite(cmd);
if(cmd!=0XFD)//不是结束指令
{
for(t=0;t<512;t++)spi_readwrite(buf[t]);//提高速度,减少函数传参时间
spi_readwrite(0xFF);//忽略crc
spi_readwrite(0xFF);
t=spi_readwrite(0xFF);//接收响应
if((t&0x1F)!=0x05)return 2;//响应错误
}
return 0;//写入成功
}
//获取CID信息
uint8_t SD_GETCID (uint8_t *cid_data)
{
uint8_t r1;
r1=SD_sendcmd(CMD10,0,0x01); //读取CID寄存器
if(r1==0x00){
r1=SD_ReceiveData(cid_data,16);
}
SD_CS(0);
if(r1)return 1;
else return 0;
}
//获取CSD信息
uint8_t SD_GETCSD(uint8_t *csd_data){
uint8_t r1;
r1=SD_sendcmd(CMD9,0,0x01);//发CMD9命令,读CSD寄存器
if(r1==0)
{
r1=SD_ReceiveData(csd_data, 16);//接收16个字节的数据
}
SD_CS(0);//取消片选
if(r1)return 1;
else return 0;
}
//获取SD卡的总扇区数
uint32_t SD_GetSectorCount(void)
{
uint8_t csd[16];
uint32_t Capacity;
uint8_t n;
uint16_t csize;
//取CSD信息,如果期间出错,返回0
if(SD_GETCSD(csd)!=0) return 0;
//如果为SDHC卡,按照下面方式计算
if((csd[0]&0xC0)==0x40) //V2.00的卡
{
csize = csd[9] + ((uint16_t)csd[8] << 8) + 1;
Capacity = (uint32_t)csize << 10;//得到扇区数
}else//V1.XX的卡
{
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1;
Capacity= (uint32_t)csize << (n - 9);//得到扇区数
}
return Capacity;
}
int MSD0_GetCardInfo(PMSD_CARDINFO SD0_CardInfo)
{
uint8_t r1;
uint8_t CSD_Tab[16];
uint8_t CID_Tab[16];
/* Send CMD9, Read CSD */
r1 = SD_sendcmd(CMD9, 0, 0xFF);
if(r1 != 0x00)
{
return r1;
}
if(SD_ReceiveData(CSD_Tab, 16))
{
return 1;
}
/* Send CMD10, Read CID */
r1 = SD_sendcmd(CMD10, 0, 0xFF);
if(r1 != 0x00)
{
return r1;
}
if(SD_ReceiveData(CID_Tab, 16))
{
return 2;
}
/* Byte 0 */
SD0_CardInfo->CSD.CSDStruct = (CSD_Tab[0] & 0xC0) >> 6;
SD0_CardInfo->CSD.SysSpecVersion = (CSD_Tab[0] & 0x3C) >> 2;
SD0_CardInfo->CSD.Reserved1 = CSD_Tab[0] & 0x03;
/* Byte 1 */
SD0_CardInfo->CSD.TAAC = CSD_Tab[1] ;
/* Byte 2 */
SD0_CardInfo->CSD.NSAC = CSD_Tab[2];
/* Byte 3 */
SD0_CardInfo->CSD.MaxBusClkFrec = CSD_Tab[3];
/* Byte 4 */
SD0_CardInfo->CSD.CardComdClasses = CSD_Tab[4] << 4;
/* Byte 5 */
SD0_CardInfo->CSD.CardComdClasses |= (CSD_Tab[5] & 0xF0) >> 4;
SD0_CardInfo->CSD.RdBlockLen = CSD_Tab[5] & 0x0F;
/* Byte 6 */
SD0_CardInfo->CSD.PartBlockRead = (CSD_Tab[6] & 0x80) >> 7;
SD0_CardInfo->CSD.WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6;
SD0_CardInfo->CSD.RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5;
SD0_CardInfo->CSD.DSRImpl = (CSD_Tab[6] & 0x10) >> 4;
SD0_CardInfo->CSD.Reserved2 = 0; /* Reserved */
SD0_CardInfo->CSD.DeviceSize = (CSD_Tab[6] & 0x03) << 10;
/* Byte 7 */
SD0_CardInfo->CSD.DeviceSize |= (CSD_Tab[7]) << 2;
/* Byte 8 */
SD0_CardInfo->CSD.DeviceSize |= (CSD_Tab[8] & 0xC0) >> 6;
SD0_CardInfo->CSD.MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3;
SD0_CardInfo->CSD.MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07);
/* Byte 9 */
SD0_CardInfo->CSD.MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5;
SD0_CardInfo->CSD.MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2;
SD0_CardInfo->CSD.DeviceSizeMul = (CSD_Tab[9] & 0x03) << 1;
/* Byte 10 */
SD0_CardInfo->CSD.DeviceSizeMul |= (CSD_Tab[10] & 0x80) >> 7;
SD0_CardInfo->CSD.EraseGrSize = (CSD_Tab[10] & 0x7C) >> 2;
SD0_CardInfo->CSD.EraseGrMul = (CSD_Tab[10] & 0x03) << 3;
/* Byte 11 */
SD0_CardInfo->CSD.EraseGrMul |= (CSD_Tab[11] & 0xE0) >> 5;
SD0_CardInfo->CSD.WrProtectGrSize = (CSD_Tab[11] & 0x1F);
/* Byte 12 */
SD0_CardInfo->CSD.WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7;
SD0_CardInfo->CSD.ManDeflECC = (CSD_Tab[12] & 0x60) >> 5;
SD0_CardInfo->CSD.WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2;
SD0_CardInfo->CSD.MaxWrBlockLen = (CSD_Tab[12] & 0x03) << 2;
/* Byte 13 */
SD0_CardInfo->CSD.MaxWrBlockLen |= (CSD_Tab[13] & 0xc0) >> 6;
SD0_CardInfo->CSD.WriteBlockPaPartial = (CSD_Tab[13] & 0x20) >> 5;
SD0_CardInfo->CSD.Reserved3 = 0;
SD0_CardInfo->CSD.ContentProtectAppli = (CSD_Tab[13] & 0x01);
/* Byte 14 */
SD0_CardInfo->CSD.FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7;
SD0_CardInfo->CSD.CopyFlag = (CSD_Tab[14] & 0x40) >> 6;
SD0_CardInfo->CSD.PermWrProtect = (CSD_Tab[14] & 0x20) >> 5;
SD0_CardInfo->CSD.TempWrProtect = (CSD_Tab[14] & 0x10) >> 4;
SD0_CardInfo->CSD.FileFormat = (CSD_Tab[14] & 0x0C) >> 2;
SD0_CardInfo->CSD.ECC = (CSD_Tab[14] & 0x03);
/* Byte 15 */
SD0_CardInfo->CSD.CSD_CRC = (CSD_Tab[15] & 0xFE) >> 1;
SD0_CardInfo->CSD.Reserved4 = 1;
if(SD0_CardInfo->CardType == V2HC)
{
/* Byte 7 */
SD0_CardInfo->CSD.DeviceSize = (uint16_t)(CSD_Tab[8]) *256;
/* Byte 8 */
SD0_CardInfo->CSD.DeviceSize += CSD_Tab[9] ;
}
SD0_CardInfo->Capacity = SD0_CardInfo->CSD.DeviceSize * MSD_BLOCKSIZE * 1024;
SD0_CardInfo->BlockSize = MSD_BLOCKSIZE;
/* Byte 0 */
SD0_CardInfo->CID.ManufacturerID = CID_Tab[0];
/* Byte 1 */
SD0_CardInfo->CID.OEM_AppliID = CID_Tab[1] << 8;
/* Byte 2 */
SD0_CardInfo->CID.OEM_AppliID |= CID_Tab[2];
/* Byte 3 */
SD0_CardInfo->CID.ProdName1 = CID_Tab[3] << 24;
/* Byte 4 */
SD0_CardInfo->CID.ProdName1 |= CID_Tab[4] << 16;
/* Byte 5 */
SD0_CardInfo->CID.ProdName1 |= CID_Tab[5] << 8;
/* Byte 6 */
SD0_CardInfo->CID.ProdName1 |= CID_Tab[6];
/* Byte 7 */
SD0_CardInfo->CID.ProdName2 = CID_Tab[7];
/* Byte 8 */
SD0_CardInfo->CID.ProdRev = CID_Tab[8];
/* Byte 9 */
SD0_CardInfo->CID.ProdSN = CID_Tab[9] << 24;
/* Byte 10 */
SD0_CardInfo->CID.ProdSN |= CID_Tab[10] << 16;
/* Byte 11 */
SD0_CardInfo->CID.ProdSN |= CID_Tab[11] << 8;
/* Byte 12 */
SD0_CardInfo->CID.ProdSN |= CID_Tab[12];
/* Byte 13 */
SD0_CardInfo->CID.Reserved1 |= (CID_Tab[13] & 0xF0) >> 4;
/* Byte 14 */
SD0_CardInfo->CID.ManufactDate = (CID_Tab[13] & 0x0F) << 8;
/* Byte 15 */
SD0_CardInfo->CID.ManufactDate |= CID_Tab[14];
/* Byte 16 */
SD0_CardInfo->CID.CID_CRC = (CID_Tab[15] & 0xFE) >> 1;
SD0_CardInfo->CID.Reserved2 = 1;
return 0;
}
//写SD卡
//buf:数据缓存区
//sector:起始扇区
//cnt:扇区数
//返回值:0,ok;其他,失败.
uint8_t SD_WriteDisk(uint8_t*buf,uint32_t sector,uint8_t cnt)
{
uint8_t r1;
if(SD_TYPE!=V2HC)sector *= 512;//转换为字节地址
if(cnt==1)
{
r1=SD_sendcmd(CMD24,sector,0X01);//读命令
if(r1==0)//指令发送成功
{
r1=SD_SendBlock(buf,0xFE);//写512个字节
}
}else
{
if(SD_TYPE!=MMC)
{
SD_sendcmd(CMD55,0,0X01);
SD_sendcmd(CMD23,cnt,0X01);//发送指令
}
r1=SD_sendcmd(CMD25,sector,0X01);//连续读命令
if(r1==0)
{
do
{
r1=SD_SendBlock(buf,0xFC);//接收512个字节
buf+=512;
}while(--cnt && r1==0);
r1=SD_SendBlock(0,0xFD);//接收512个字节
}
}
SD_CS(0);//取消片选
return r1;//
}
//读SD卡
//buf:数据缓存区
//sector:扇区
//cnt:扇区数
//返回值:0,ok;其他,失败.
uint8_t SD_ReadDisk(uint8_t*buf,uint32_t sector,uint8_t cnt)
{
uint8_t r1;
if(SD_TYPE!=V2HC)sector <<= 9;//转换为字节地址
if(cnt==1)
{
r1=SD_sendcmd(CMD17,sector,0X01);//读命令
if(r1==0)//指令发送成功
{
r1=SD_ReceiveData(buf,512);//接收512个字节
}
}else
{
r1=SD_sendcmd(CMD18,sector,0X01);//连续读命令
do
{
r1=SD_ReceiveData(buf,512);//接收512个字节
buf+=512;
}while(--cnt && r1==0);
SD_sendcmd(CMD12,0,0X01); //发送停止命令
}
SD_CS(0);//取消片选
return r1;//
}
uint8_t spi_readwrite(uint8_t Txdata){
uint8_t Rxdata;
HAL_SPI_TransmitReceive(&hspi1,&Txdata,&Rxdata,1,100);
return Rxdata;
}
//SPI1波特率设置
void SPI_setspeed(uint8_t speed){
hspi1.Init.BaudRatePrescaler = speed;
}
void Get_SDCard_Capacity(void)
{
FRESULT result;
FATFS *fs;
DWORD fre_clust,AvailableSize,UsedSize;
uint16_t TotalSpace;
uint8_t res;
printf("SD卡初始化!\r\n");
res = SD_init(); //SD卡初始化
if(res == 1)
{
printf("SD卡初始化失败! \r\n");
}
else
{
printf("SD卡初始化成功! \r\n");
}
/* 挂载 */
result=f_mount(&USERFatFS,USERPath,1); //挂载
if(result == FR_NO_FILESYSTEM) //没有文件系统,格式化
{
// test_sd =1; //用于测试格式化
printf("没有文件系统! \r\n");
result = f_mkfs(USERPath, 0, 0); //格式化sd卡
if(result == FR_OK)
{
printf("格式化成功! \r\n");
result = f_mount(NULL,USERPath,1); //格式化后先取消挂载
result = f_mount(&USERFatFS,USERPath,1); //重新挂载
if(result == FR_OK)
{
printf("SD卡已经成功挂载,可以进进行文件写入测试!\r\n");
}
}
else
{
printf("格式化失败! \r\n");
}
}
else if(res == FR_OK)
{
printf("挂载成功! \r\n");
}
else
{
printf("挂载失败! \r\n");
}
result = f_getfree(USERPath, &fre_clust, &fs); /* 根目录 */
if ( result == FR_OK )
{
TotalSpace=(uint16_t)(((fs->n_fatent - 2) * fs->csize ) / 2 /1024);
AvailableSize=(uint16_t)((fre_clust * fs->csize) / 2 /1024);
UsedSize=TotalSpace-AvailableSize;
/* Print free space in unit of MB (assuming 512 bytes/sector) */
printf("\r\n%d MB total drive space.\r\n""%ld MB available.\r\n""%ld MB used.\r\n",TotalSpace, AvailableSize,UsedSize);
}
else
{
printf("Get SDCard Capacity Failed (%d)\r\n", result);
}
}
void WritetoSD(char filename[], BYTE write_buff[], uint8_t bufSize)
{
FIL file;
uint8_t res = 0;
UINT Bw;
res = f_open(&file, filename, FA_OPEN_ALWAYS | FA_WRITE);
if ((res & FR_DENIED) == FR_DENIED) {
printf("卡存储已满,写入失败!\r\n");
}
f_lseek(&file, f_size(&file)); // 确保写词写入不会覆盖之前的数据
if (res == FR_OK) {
printf("打开成功/创建文件成功! \r\n");
res = f_write(&file, write_buff, bufSize, &Bw); // 写数据到SD卡
if (res == FR_OK) {
printf("文件写入成功! \r\n");
} else {
printf("文件写入失败! \r\n");
}
} else {
printf("打开文件失败!\r\n");
}
f_close(&file); // 关闭文件
}
void UnmountSD(void)
{
f_mount(NULL, USERPath, 1); // 取消挂载
}
///END//
修改FATFS\Target\user_diskio.c文件
添加头文件
//添加头文件
#include "diskio.h" /* Declarations of disk functions */
#include "sd.h"
#include "cmsis_os.h"
修改USER_initialize函数
DSTATUS USER_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
/* USER CODE BEGIN INIT */
uint8_t res;
res = SD_init(); // SD_Initialize()
if (res) // STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常
{
SPI_setspeed(SPI_BAUDRATEPRESCALER_256);
spi_readwrite(0xff); // 提供额外的8个时钟
SPI_setspeed(SPI_BAUDRATEPRESCALER_2);
}
if (res)
return STA_NOINIT;
else
return RES_OK; // 初始化成功
/* USER CODE END INIT */
}
修改USER_status函数
DSTATUS USER_status (
BYTE pdrv /* Physical drive number to identify the drive */
)
{
/* USER CODE BEGIN STATUS */
switch (pdrv) {
case 0:
return RES_OK;
case 1:
return RES_OK;
case 2:
return RES_OK;
default:
return STA_NOINIT;
}
/* USER CODE END STATUS */
}
修改USER_read函数
DRESULT USER_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to read */
)
{
/* USER CODE BEGIN READ */
uint8_t res;
if (!count) {
return RES_PARERR; /* count不能等于0,否则返回参数错误 */
}
switch (pdrv) {
case 0:
res = SD_ReadDisk(buff, sector, count);
if (res == 0) {
return RES_OK;
} else {
return RES_ERROR;
}
default:
return RES_ERROR;
}
/* USER CODE END READ */
}
修改USER_write函数
DRESULT USER_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to write */
)
{
/* USER CODE BEGIN WRITE */
/* USER CODE HERE */
uint8_t res;
if (!count) {
return RES_PARERR; /* count不能等于0,否则返回参数错误 */
}
switch (pdrv) {
case 0:
res = SD_WriteDisk((uint8_t *)buff, sector, count);
if (res == 0) {
return RES_OK;
} else {
return RES_ERROR;
}
default:
return RES_ERROR;
}
/* USER CODE END WRITE */
}
修改USER_ioctl函数
DRESULT USER_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
/* USER CODE BEGIN IOCTL */
DRESULT res;
switch (cmd) {
case CTRL_SYNC:
SD_CS(1);
do {
osDelay(20);
} while (spi_readwrite(0xFF) != 0xFF);
res = RES_OK;
SD_CS(0);
break;
case GET_SECTOR_SIZE:
*(WORD *)buff = 512;
res = RES_OK;
break;
case GET_BLOCK_SIZE:
*(WORD *)buff = 8;
res = RES_OK;
break;
case GET_SECTOR_COUNT:
*(DWORD *)buff = SD_GetSectorCount();
res = RES_OK;
break;
default:
res = RES_PARERR;
break;
}
return res;
/* USER CODE END IOCTL */
}
在mian.c中添加支持printf的函数
/* USER CODE BEGIN 0 */
int __io_putchar(int ch)
{
/* Implementation of __io_putchar */
/* e.g. write a character to the UART1 and Loop until the end of transmission */
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFFFFFF);
return ch;
}
int __io_getchar(void)
{
/* Implementation of __io_getchar */
char rxChar;
// This loops in case of HAL timeout, but if an ok or error occurs, we continue
while (HAL_UART_Receive(&huart1, (uint8_t *)&rxChar, 1, 0xFFFFFFFF) == HAL_TIMEOUT);
return rxChar;
}
/* USER CODE END 0 */
下面编写freertos中的实现功能
修改freertos.c文件
添加头文件
/* USER CODE BEGIN Includes */
/* 添加头文件 */
#include <stdio.h>
#include "sd.h"
/* USER CODE END Includes */
修改默认任务
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
char SD_FileName[] = "hello.txt";
uint8_t WriteBuffer[] = "01 write buff to sd \r\n";
uint8_t write_cnt =0; //写SD卡次数
Get_SDCard_Capacity(); //得到使用内存并选择格式化
osDelay(1000);
WritetoSD(SD_FileName, WriteBuffer,sizeof(WriteBuffer));
osDelay(1000);
WritetoSD(SD_FileName, WriteBuffer,sizeof(WriteBuffer));
UnmountSD();
for(;;)
{
osDelay(1);
}
/* USER CODE END StartDefaultTask */
}
运行结果