I have the same problem. I interfaced a SDHC card with a STM32F107VC board.And I succeed in using FatFs.
Actually I never find any clues about this problem.I forwent using SD module and attached SD with Dupont Line.Like this(连接)
It worked then...I also interfaced a mircoSD,also succeed.
My code:
SD_SPI_Mode.c
#include <stdio.h>
#include "SD_SPI_Mode.h"
#include "hdware.h"
SD_INFO G_SDCARD_INFO;
SDErrorType SDInit(void)
{
u16 Response1;
u16 Buff[6] = {0};
u16 Retry;
SPI_SetSpeed(SPI_BaudRatePrescaler_256);
for (Retry = 0; Retry < 10; Retry++) //至少74个时钟的高电平
{
SPI_ReadWriteByte2(DUMMY_BYTE);
}
Retry = 0;
sdEnable();
for (Retry = 0; Retry < 0xFFF; Retry++)
{
Response1 = SDSendCommand(CMD0, 0, 0x95);
if (Response1 == 0x01)
{
Retry = 0;
break;
}
}
if (Retry == 0xFFF)
{
//printf("Reset card into IDLE state failed!\r\n");
return ERROR_NOT_IN_IDLE;
}
Response1 = SDSendCommandHold(CMD8, 0x1AA, 0x87);
if (Response1 == 0x05)
{
G_SDCARD_INFO.CardType = CARDTYPE_SDV1;
sdDisable();
//SPI_ReadWriteByte2(DUMMY_BYTE);
for (Retry = 0; Retry < 0xFFF; Retry++)
{
Response1 = SDSendCommand(CMD55, 0, 0);
if (Response1 != 0x01)
{
return ERROR_CMD55;
}
Response1 = SDSendCommand(ACMD41, 0, 0);
if (Response1 == 0x00)
{
Retry = 0;
break;
}
}
if (Retry == 0xFFF)
{
for (Retry = 0; Retry < 0xFFF; Retry++)
{
Response1 = SDSendCommand(CMD1, 0, 0); /* should be return 0x00 */
if (Response1 == 0x00)
{
Retry = 0;
break;
}
}
if (Retry == 0xFFF)
{
return ERROR_CMD1;
}
G_SDCARD_INFO.CardType = CARDTYPE_MMC;
//printf("Card Type: MMC\r\n");
}
else
{
G_SDCARD_INFO.CardType = CARDTYPE_SDV1;
//printf("Card Type: SD V1\r\n");
}
Response1 = SDSendCommand(CMD16, BLOCKSIZE, 0xFF);
if (Response1 != 0x00)
{
return ERROR_CMD16;
}
}
else if (Response1 == 0x01)
{
Buff[0] = SPI_ReadWriteByte2(DUMMY_BYTE); //0x00
Buff[1] = SPI_ReadWriteByte2(DUMMY_BYTE); //0x00
Buff[2] = SPI_ReadWriteByte2(DUMMY_BYTE); //0x01
Buff[3] = SPI_ReadWriteByte2(DUMMY_BYTE); //0xAA
sdDisable();
if (Buff[2] == 0x01 && Buff[3] == 0xAA) //检查电压范围
{
for (Retry = 0; Retry < 0xFFF; Retry++)
{
Response1 = SDSendCommand(CMD55, 0, 0x01);
sdEnable();
Response1 = SPI_ReadWriteByte2(DUMMY_BYTE);
sdDisable();
Response1 = SDSendCommand(ACMD41, 0x40FF8000, 0xFF);
if (Response1 == 0x00)
{
Retry = 0;
break;
}
}
if (Retry == 0xFFF)
{
return ERROR_ACMD41;
}
Response1 = SDSendCommandHold(CMD58, 0, 0);
if (Response1 != 0x00)
{
return ERROR_CMD58;
}
Buff[0] = SPI_ReadWriteByte2(DUMMY_BYTE);
Buff[1] = SPI_ReadWriteByte2(DUMMY_BYTE);
Buff[2] = SPI_ReadWriteByte2(DUMMY_BYTE);
Buff[3] = SPI_ReadWriteByte2(DUMMY_BYTE);
sdDisable();
if (Buff[0] & 0x40) // OCR -> CCS(bit30) 1: SDV2HC 0: SDV2
{
G_SDCARD_INFO.CardType = CARDTYPE_SDV2HC;
//printf("Card Type: SD V2HC\r\n");
}
else
{
G_SDCARD_INFO.CardType = CARDTYPE_SDV2;
//printf("Card Type: SD V2\r\n");
}
}
}
SPI_SetSpeed(SPI_BaudRatePrescaler_2);
return ERROR_NOP;
}
SDErrorType getCardInfo(SD_INFO *G_SDCARD_INFO)
{
u8 CSD_Tab[16];
u8 CID_Tab[16];
if (SDSendCommand(CMD9, 0, 0x01)) //读CSD
{
return ERROR_CMD9;
}
sdEnable();
if (SDReadToBuffer(CSD_Tab, 16, RELEASE))
{
return ERROR_CSD_READ;
}
sdDisable();
if (SDSendCommand(CMD10, 0, 0xFF)) //读CID
{
return ERROR_CMD10;
}
sdEnable();
if (SDReadToBuffer(CID_Tab, 16, RELEASE))
{
return ERROR_CID_READ;
}
sdDisable();
/* Byte 0 */
G_SDCARD_INFO->CSD.CSDStruct = (CSD_Tab[0] & 0xC0) >> 6;
G_SDCARD_INFO->CSD.SysSpecVersion = (CSD_Tab[0] & 0x3C) >> 2;
G_SDCARD_INFO->CSD.Reserved1 = CSD_Tab[0] & 0x03;
/* Byte 1 */
G_SDCARD_INFO->CSD.TAAC = CSD_Tab[1];
/* Byte 2 */
G_SDCARD_INFO->CSD.NSAC = CSD_Tab[2];
/* Byte 3 */
G_SDCARD_INFO->CSD.MaxBusClkFrec = CSD_Tab[3];
/* Byte 4 */
G_SDCARD_INFO->CSD.CardComdClasses = CSD_Tab[4] << 4;
/* Byte 5 */
G_SDCARD_INFO->CSD.CardComdClasses |= (CSD_Tab[5] & 0xF0) >> 4;
G_SDCARD_INFO->CSD.RdBlockLen = CSD_Tab[5] & 0x0F;
/* Byte 6 */
G_SDCARD_INFO->CSD.PartBlockRead = (CSD_Tab[6] & 0x80) >> 7;
G_SDCARD_INFO->CSD.WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6;
G_SDCARD_INFO->CSD.RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5;
G_SDCARD_INFO->CSD.DSRImpl = (CSD_Tab[6] & 0x10) >> 4;
G_SDCARD_INFO->CSD.Reserved2 = 0; /* Reserved */
G_SDCARD_INFO->CSD.DeviceSize = (CSD_Tab[6] & 0x03) << 10;
/* Byte 7 */
G_SDCARD_INFO->CSD.DeviceSize |= (CSD_Tab[7]) << 2;
/* Byte 8 */
G_SDCARD_INFO->CSD.DeviceSize |= (CSD_Tab[8] & 0xC0) >> 6;
G_SDCARD_INFO->CSD.MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3;
G_SDCARD_INFO->CSD.MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07);
/* Byte 9 */
G_SDCARD_INFO->CSD.MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5;
G_SDCARD_INFO->CSD.MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2;
G_SDCARD_INFO->CSD.DeviceSizeMul = (CSD_Tab[9] & 0x03) << 1;
/* Byte 10 */
G_SDCARD_INFO->CSD.DeviceSizeMul |= (CSD_Tab[10] & 0x80) >> 7;
G_SDCARD_INFO->CSD.EraseGrSize = (CSD_Tab[10] & 0x7C) >> 2;
G_SDCARD_INFO->CSD.EraseGrMul = (CSD_Tab[10] & 0x03) << 3;
/* Byte 11 */
G_SDCARD_INFO->CSD.EraseGrMul |= (CSD_Tab[11] & 0xE0) >> 5;
G_SDCARD_INFO->CSD.WrProtectGrSize = (CSD_Tab[11] & 0x1F);
/* Byte 12 */
G_SDCARD_INFO->CSD.WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7;
G_SDCARD_INFO->CSD.ManDeflECC = (CSD_Tab[12] & 0x60) >> 5;
G_SDCARD_INFO->CSD.WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2;
G_SDCARD_INFO->CSD.MaxWrBlockLen = (CSD_Tab[12] & 0x03) << 2;
/* Byte 13 */
G_SDCARD_INFO->CSD.MaxWrBlockLen |= (CSD_Tab[13] & 0xc0) >> 6;
G_SDCARD_INFO->CSD.WriteBlockPaPartial = (CSD_Tab[13] & 0x20) >> 5;
G_SDCARD_INFO->CSD.Reserved3 = 0;
G_SDCARD_INFO->CSD.ContentProtectAppli = (CSD_Tab[13] & 0x01);
/* Byte 14 */
G_SDCARD_INFO->CSD.FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7;
G_SDCARD_INFO->CSD.CopyFlag = (CSD_Tab[14] & 0x40) >> 6;
G_SDCARD_INFO->CSD.PermWrProtect = (CSD_Tab[14] & 0x20) >> 5;
G_SDCARD_INFO->CSD.TempWrProtect = (CSD_Tab[14] & 0x10) >> 4;
G_SDCARD_INFO->CSD.FileFormat = (CSD_Tab[14] & 0x0C) >> 2;
G_SDCARD_INFO->CSD.ECC = (CSD_Tab[14] & 0x03);
/* Byte 15 */
G_SDCARD_INFO->CSD.CSD_CRC = (CSD_Tab[15] & 0xFE) >> 1;
G_SDCARD_INFO->CSD.Reserved4 = 1;
if (G_SDCARD_INFO->CardType == CARDTYPE_SDV2HC)
{
/* Byte 7 */
G_SDCARD_INFO->CSD.DeviceSize = (u16)(CSD_Tab[8]) * 256;
/* Byte 8 */
G_SDCARD_INFO->CSD.DeviceSize += CSD_Tab[9];
}
G_SDCARD_INFO->Capacity = G_SDCARD_INFO->CSD.DeviceSize * BLOCKSIZE * 1024;
G_SDCARD_INFO->BlockSize = BLOCKSIZE;
/* Byte 0 */
G_SDCARD_INFO->CID.ManufacturerID = CID_Tab[0];
/* Byte 1 */
G_SDCARD_INFO->CID.OEM_AppliID = CID_Tab[1] << 8;
/* Byte 2 */
G_SDCARD_INFO->CID.OEM_AppliID |= CID_Tab[2];
/* Byte 3 */
G_SDCARD_INFO->CID.ProdName1 = CID_Tab[3] << 24;
/* Byte 4 */
G_SDCARD_INFO->CID.ProdName1 |= CID_Tab[4] << 16;
/* Byte 5 */
G_SDCARD_INFO->CID.ProdName1 |= CID_Tab[5] << 8;
/* Byte 6 */
G_SDCARD_INFO->CID.ProdName1 |= CID_Tab[6];
/* Byte 7 */
G_SDCARD_INFO->CID.ProdName2 = CID_Tab[7];
/* Byte 8 */
G_SDCARD_INFO->CID.ProdRev = CID_Tab[8];
/* Byte 9 */
G_SDCARD_INFO->CID.ProdSN = CID_Tab[9] << 24;
/* Byte 10 */
G_SDCARD_INFO->CID.ProdSN |= CID_Tab[10] << 16;
/* Byte 11 */
G_SDCARD_INFO->CID.ProdSN |= CID_Tab[11] << 8;
/* Byte 12 */
G_SDCARD_INFO->CID.ProdSN |= CID_Tab[12];
/* Byte 13 */
G_SDCARD_INFO->CID.Reserved1 |= (CID_Tab[13] & 0xF0) >> 4;
/* Byte 14 */
G_SDCARD_INFO->CID.ManufactDate = (CID_Tab[13] & 0x0F) << 8;
/* Byte 15 */
G_SDCARD_INFO->CID.ManufactDate |= CID_Tab[14];
/* Byte 16 */
G_SDCARD_INFO->CID.CID_CRC = (CID_Tab[15] & 0xFE) >> 1;
G_SDCARD_INFO->CID.Reserved2 = 1;
return ERROR_NOP;
}
SDErrorType SDReadToBuffer(u8 *buff, u16 len, u8 release)
{
u16 Response1;
u16 Retry;
//Start Block
for (Retry = 0; Retry < 2000; Retry++)
{
Response1 = SPI_ReadWriteByte2(DUMMY_BYTE);
if (Response1 == 0xFE)
{
Retry = 0;
break;
}
}
//Time out
if (Retry == 2000)
{
return ERROR_TIME_OUT;
}
//Start Read
for (Retry = 0; Retry < len; Retry++)
{
*(buff + Retry) = SPI_ReadWriteByte2(DUMMY_BYTE);
}
//CRC
SPI_ReadWriteByte2(DUMMY_BYTE);
SPI_ReadWriteByte2(DUMMY_BYTE);
if (release)
{
sdDisable();
SPI_ReadWriteByte2(DUMMY_BYTE);
}
return ERROR_NOP;
}
SDErrorType SDReadSingleBlock(u32 sector, u8 *Buffer)
{
if (G_SDCARD_INFO.CardType != CARDTYPE_SDV2HC)
{
sector = sector << 9;
}
if (SDSendCommand(CMD17, sector, 0x55))
{
return ERROR_CMD17;
}
sdEnable();
if (SDReadToBuffer(Buffer, BLOCKSIZE, RELEASE))
{
return ERROR_DATA_READ;
}
sdDisable();
SPI_ReadWriteByte2(DUMMY_BYTE);
return ERROR_NOP;
}
SDErrorType SDReadMultiBlock(u32 sector, u8 *Buffer, u32 NumOfSector)
{
u32 i;
if (G_SDCARD_INFO.CardType != CARDTYPE_SDV2HC)
{
sector = sector << 9;
}
if (SDSendCommand(CMD18, sector, 0))
{
return ERROR_CMD18;
}
sdEnable();
for (i = 0; i < NumOfSector; i++)
{
if (SDReadToBuffer(Buffer + i * BLOCKSIZE, BLOCKSIZE, HOLD))
{
SDSendCommand(CMD12, 0, 0);
sdDisable();
return ERROR_DATA_READ;
}
}
SDSendCommand(CMD12, 0, 0); //停止位
sdDisable();
SPI_ReadWriteByte2(DUMMY_BYTE);
return ERROR_NOP;
}
SDErrorType SDWriteFromBuffer(u8 *buffer, bool isMultiply)
{
u16 Response1;
u16 i;
if (!isMultiply)
{
SPI_ReadWriteByte2(0xFE);
}
else if (isMultiply)
{
SPI_ReadWriteByte2(0xFC);
}
for (i = 0; i < BLOCKSIZE; i++)
{
SPI_ReadWriteByte2(*buffer++);
}
SPI_ReadWriteByte2(DUMMY_BYTE);
SPI_ReadWriteByte2(DUMMY_BYTE);
Response1 = SPI_ReadWriteByte2(DUMMY_BYTE);
if ((Response1 & 0x1F) != 0x05)
{
return ERROR_DATA_WRITE;
}
return ERROR_NOP;
}
SDErrorType SDWriteSingleBlock(u32 sector, u8 *buffer)
{
if (G_SDCARD_INFO.CardType != CARDTYPE_SDV2HC)
{
sector = sector << 9;
}
if (SDSendCommand(CMD24, sector, 0))
{
return ERROR_CMD24;
}
sdEnable();
SPI_ReadWriteByte2(DUMMY_BYTE);
SPI_ReadWriteByte2(DUMMY_BYTE);
SPI_ReadWriteByte2(DUMMY_BYTE);
SDWriteFromBuffer(buffer, false);
if(SDBusyWait())
{
sdDisable();
return ERROR_DATA_WRITE;
}
sdDisable();
SPI_ReadWriteByte2(DUMMY_BYTE);
return ERROR_NOP;
}
SDErrorType SDWriteMultiBlock(u32 sector, u8 *Buffer, u32 NumOfSector)
{
u32 n;
if (G_SDCARD_INFO.CardType != CARDTYPE_SDV2HC)
{
sector = sector << 9;
}
if (G_SDCARD_INFO.CardType != CARDTYPE_MMC)
{
SDSendCommand(ACMD23, NumOfSector, 0x00);
}
if (SDSendCommand(CMD25, sector, 0))
{
return ERROR_CMD25;
}
SPI_ReadWriteByte2(DUMMY_BYTE);
SPI_ReadWriteByte2(DUMMY_BYTE);
sdEnable();
SPI_ReadWriteByte2(DUMMY_BYTE);
SPI_ReadWriteByte2(DUMMY_BYTE);
SPI_ReadWriteByte2(DUMMY_BYTE);
SPI_ReadWriteByte2(DUMMY_BYTE);
for (n = 0; n < NumOfSector; n++)
{
SDWriteFromBuffer(Buffer, true);
}
if (SPI_ReadWriteByte2(0xFD))
{
return ERROR_DATA_WRITE;
}
if(SDBusyWait())
{
sdDisable();
return ERROR_DATA_WRITE;
}
sdDisable();
SPI_ReadWriteByte2(DUMMY_BYTE);
return ERROR_NOP;
}
SDErrorType SDBusyWait(void)
{
u32 Retry = 0;
while (SPI_ReadWriteByte2(DUMMY_BYTE) == 0x00)
{
/* Timeout return */
if (Retry++ == 0x40000)
{
return ERROR_TIME_OUT;
}
}
return ERROR_NOP;
}
u16 SDSendCommand(u8 cmd, u32 arg, u8 crc)
{
u16 Response1;
u16 Retry;
SPI_ReadWriteByte2(DUMMY_BYTE);
SPI_ReadWriteByte2(DUMMY_BYTE);
sdEnable();
SPI_ReadWriteByte2(cmd | 0x40);
SPI_ReadWriteByte2(arg >> 24);
SPI_ReadWriteByte2(arg >> 16);
SPI_ReadWriteByte2(arg >> 8);
SPI_ReadWriteByte2(arg);
SPI_ReadWriteByte2(crc | 1);
//Busy
for (Retry = 0; Retry < 200; Retry++)
{
Response1 = SPI_ReadWriteByte2(DUMMY_BYTE);
if (Response1 != 0xFF)
{
break;
}
}
sdDisable();
SPI_ReadWriteByte2(DUMMY_BYTE);
return Response1;
}
u16 SDSendCommandHold(u8 cmd, u32 arg, u8 crc)
{
u16 Response1;
u16 Retry;
SPI_ReadWriteByte2(DUMMY_BYTE);
SPI_ReadWriteByte2(DUMMY_BYTE);
sdEnable();
SPI_ReadWriteByte2(cmd | 0x40);
SPI_ReadWriteByte2(arg >> 24);
SPI_ReadWriteByte2(arg >> 16);
SPI_ReadWriteByte2(arg >> 8);
SPI_ReadWriteByte2(arg);
SPI_ReadWriteByte2(crc);
//Busy
for (Retry = 0; Retry < 200; Retry++)
{
Response1 = SPI_ReadWriteByte2(DUMMY_BYTE);
if (Response1 != 0xFF)
{
break;
}
}
return Response1;
}
SD_SPI_Mode.h
#ifndef _SD_SPI_MODE_H_
#define _SD_SPI_MODE_H_
/* Includes ------------------------------------------------------------------*/
#include "DIDO.h"
/* Private define ------------------------------------------------------------*/
#define CARDTYPE_MMC 0x00
#define CARDTYPE_SDV1 0x01
#define CARDTYPE_SDV2 0x02
#define CARDTYPE_SDV2HC 0x04
#define DUMMY_BYTE 0xFF
#define BLOCKSIZE 512
/* SD/MMC command list - SPI mode */
#define CMD0 0 /* Reset */
#define CMD1 1 /* Send Operator Condition - SEND_OP_COND */
#define CMD8 8 /* Send Interface Condition - SEND_IF_COND */
#define CMD9 9 /* Read CSD */
#define CMD10 10 /* Read CID */
#define CMD12 12 /* Stop data transmit */
#define CMD16 16 /* Set block size, should return 0x00 */
#define CMD17 17 /* Read single block */
#define CMD18 18 /* Read multi block */
#define ACMD23 23 /* Prepare erase N-blokcs before multi block write */
#define CMD24 24 /* Write single block */
#define CMD25 25 /* Write multi block */
#define ACMD41 41 /* should return 0x00 */
#define CMD55 55 /* should return 0x01 */
#define CMD58 58 /* Read OCR */
#define CMD59 59 /* CRC disable/enbale, should return 0x00 */
#define sdEnable() GPIO_ResetBits(SD_CS_PORT, SD_CS_PIN)
#define sdDisable() GPIO_SetBits(SD_CS_PORT, SD_CS_PIN)
#define MSD0_card_power_on() ;
#define isCardInsert() 0
enum _CD_HOLD
{
HOLD = 0,
RELEASE = 1,
};
typedef enum
{
ERROR_NOP = 0,
ERROR_NOT_IN_IDLE,
ERROR_TIME_OUT,
ERROR_CSD_READ,
ERROR_CID_READ,
ERROR_DATA_READ,
ERROR_DATA_WRITE,
ERROR_ACMD41,
ERROR_CMD1,
ERROR_CMD9,
ERROR_CMD10,
ERROR_CMD16,
ERROR_CMD17,
ERROR_CMD18,
ERROR_CMD24,
ERROR_CMD25,
ERROR_CMD55,
ERROR_CMD58,
ERROR_CMD59,
} SDErrorType;
typedef struct /* Card Specific Data */
{
vu8 CSDStruct; /* CSD structure */
vu8 SysSpecVersion; /* System specification version */
vu8 Reserved1; /* Reserved */
vu8 TAAC; /* Data read access-time 1 */
vu8 NSAC; /* Data read access-time 2 in CLK cycles */
vu8 MaxBusClkFrec; /* Max. bus clock frequency */
vu16 CardComdClasses; /* Card command classes */
vu8 RdBlockLen; /* Max. read data block length */
vu8 PartBlockRead; /* Partial blocks for read allowed */
vu8 WrBlockMisalign; /* Write block misalignment */
vu8 RdBlockMisalign; /* Read block misalignment */
vu8 DSRImpl; /* DSR implemented */
vu8 Reserved2; /* Reserved */
vu32 DeviceSize; /* Device Size */
vu8 MaxRdCurrentVDDMin; /* Max. read current @ VDD min */
vu8 MaxRdCurrentVDDMax; /* Max. read current @ VDD max */
vu8 MaxWrCurrentVDDMin; /* Max. write current @ VDD min */
vu8 MaxWrCurrentVDDMax; /* Max. write current @ VDD max */
vu8 DeviceSizeMul; /* Device size multiplier */
vu8 EraseGrSize; /* Erase group size */
vu8 EraseGrMul; /* Erase group size multiplier */
vu8 WrProtectGrSize; /* Write protect group size */
vu8 WrProtectGrEnable; /* Write protect group enable */
vu8 ManDeflECC; /* Manufacturer default ECC */
vu8 WrSpeedFact; /* Write speed factor */
vu8 MaxWrBlockLen; /* Max. write data block length */
vu8 WriteBlockPaPartial; /* Partial blocks for write allowed */
vu8 Reserved3; /* Reserded */
vu8 ContentProtectAppli; /* Content protection application */
vu8 FileFormatGrouop; /* File format group */
vu8 CopyFlag; /* Copy flag (OTP) */
vu8 PermWrProtect; /* Permanent write protection */
vu8 TempWrProtect; /* Temporary write protection */
vu8 FileFormat; /* File Format */
vu8 ECC; /* ECC code */
vu8 CSD_CRC; /* CSD CRC */
vu8 Reserved4; /* always 1*/
} MSD_CSD;
typedef struct /*Card Identification Data*/
{
vu8 ManufacturerID; /* ManufacturerID */
vu16 OEM_AppliID; /* OEM/Application ID */
vu32 ProdName1; /* Product Name part1 */
vu8 ProdName2; /* Product Name part2*/
vu8 ProdRev; /* Product Revision */
vu32 ProdSN; /* Product Serial Number */
vu8 Reserved1; /* Reserved1 */
vu16 ManufactDate; /* Manufacturing Date */
vu8 CID_CRC; /* CID CRC */
vu8 Reserved2; /* always 1 */
} MSD_CID;
typedef struct
{
MSD_CSD CSD;
MSD_CID CID;
u32 Capacity; /* Card Capacity */
u32 BlockSize; /* Card Block Size */
u16 RCA;
u8 CardType;
u32 SpaceTotal; /* Total space size in file system */
u32 SpaceFree; /* Free space size in file system */
} SD_INFO;
extern SD_INFO G_SDCARD_INFO;
SDErrorType SDInit(void);
SDErrorType getCardInfo(SD_INFO *G_SDCARD_INFO);
SDErrorType SDReadSingleBlock(u32 sector, u8 *buffer);
SDErrorType SDReadMultiBlock(u32 sector, u8 *buffer, u32 NumOfSector);
SDErrorType SDWriteSingleBlock(u32 sector, u8 *buffer);
SDErrorType SDWriteMultiBlock(u32 sector, u8 *buffer, u32 NumOfSector);
static SDErrorType SDWriteFromBuffer(u8 *buffer,bool isMultiply);
static u16 SDSendCommand(u8 cmd, u32 arg, u8 crc);
static u16 SDSendCommandHold(u8 cmd, u32 arg, u8 crc);
static SDErrorType SDReadToBuffer(u8 *buff, u16 len, u8 release);
static SDErrorType SDBusyWait(void);
#endif
Additionly,my file operation code:
FileOperation.c
#include "stdlib.h"
#include <stdbool.h>
#include "string.h"
#include "FileOperation.h"
static FATFS Fs; //逻辑磁盘工作区.
static FIL File; //文件
static FILINFO FileInfo; //文件信息
static DIR Dir; //目录
static u8 SDBuf; //SD缓存
FRESULT SDMount(u8 device)
{
return f_mount(device, &Fs);
}
FRESULT SDCreateDir(const u8 *pname)
{
return f_mkdir((const TCHAR *)pname);
}
FRESULT SDDirOpen(const u8 *path)
{
return f_opendir(&Dir, (const TCHAR *)path);
}
FRESULT SDDirRead(void)
{
FRESULT res;
char *FileName;
FileInfo.lfsize = _MAX_LFN * 2 + 1;
FileInfo.lfname = malloc(FileInfo.lfsize);
res = f_readdir(&Dir, &FileInfo); //读取一个文件的信息
if (res != FR_OK || FileInfo.fname[0] == 0)
{
free((void *)FileInfo.lfname);
return res; //读完了.
}
FileName = *(FileInfo.lfname) ? FileInfo.lfname : FileInfo.fname;
free((void *)FileInfo.lfname);
return FR_OK;
}
FRESULT SDFileRead(u8 *buf, u16 len)
{
u16 i;
FRESULT res;
UINT ByteCount;
for (i = 0; i < len / 512; i++)
{
res = f_read(&File, buf, 512, &ByteCount);
if (res)
{
break;
}
}
if (len % 512)
{
res = f_read(&File, buf, len % 512, &ByteCount);
}
return res;
}
TCHAR *SDReadString(u16 size)
{
TCHAR *rbuf;
rbuf = f_gets((TCHAR *)&SDBuf, size, &File);
if (*rbuf == 0)
return NULL; //没有数据读到
else
{
return rbuf;
}
}
FRESULT SDFileWrite(const u8 *data, u16 len)
{
UINT ByteCount;
return f_write(&File, data, len, &ByteCount);
}
FRESULT SDScanFiles(const u8 *path, char **FileName)
{
FRESULT res;
u16 FileNum = 0;
FileInfo.lfsize = _MAX_LFN * 2 + 1;
FileInfo.lfname = malloc(FileInfo.lfsize);
res = f_opendir(&Dir, (const TCHAR *)path); //打开一个目录
if (res == FR_OK)
{
while (1)
{
res = f_readdir(&Dir, &FileInfo); //读取目录下的一个文件
if (res != FR_OK || FileInfo.fname[0] == 0)
break; //错误了/到末尾了,退出
FileName[FileNum] = *FileInfo.lfname ? FileInfo.lfname : FileInfo.fname;
FileNum++;
}
}
free(FileInfo.lfname);
return res;
}
FRESULT SDShowFree(const u8 *drv, u32 *FreeSector, u32 *TotalSector)
{
FATFS *fs1;
FRESULT res;
u32 FreeClust = 0;
res = f_getfree((const TCHAR *)drv, (DWORD *)&FreeClust, &fs1);
if (res == FR_OK)
{
*TotalSector = (fs1->n_fatent - 2) * fs1->csize; //总扇区数
*FreeSector = FreeClust * fs1->csize; //空闲扇区数
(*TotalSector) >>= 11;
(*FreeSector) >>= 11;
}
return res;
}
FRESULT SDFormat(u8 device, u8 mode, u16 au)
{
return f_mkfs(device, mode, au); //格式化,drv:盘符;mode:模式;au:簇大小
}
FRESULT SDRemoveFileOrDir(const u8 *pname)
{
return f_unlink((const TCHAR *)pname);
}
FRESULT SDRename(const u8 *oldname, const u8 *newname)
{
return f_rename((const TCHAR *)oldname, (const TCHAR *)newname);
}
FRESULT SDFileOpen(const u8 *path, u8 mode)
{
return f_open(&File, (const TCHAR *)path, mode);
}
FRESULT SDFileClose(void)
{
return f_close(&File);
}
u32 SDFileSize(void)
{
return f_size(&File);
}
FRESULT SDArgumentRead(const u8 *path, ArgumentInfo *argument, UINT *RecordNum)
{
FRESULT res;
u8 *PointToBuff;
UINT ByteCount;
res = SDFileOpen(path, FA_READ);
if (res != FR_OK)
return res;
PointToBuff = malloc(File.fsize);
res = f_read(&File, PointToBuff, File.fsize, &ByteCount);
if (res != FR_OK)
{
return res;
}
SDDataSolve(PointToBuff, argument, ByteCount, RecordNum);
free(PointToBuff);
return SDFileClose();
}
FRESULT SDFileAppend(const u8 *path, const u8 *filename, const u8 *buff)
{
FRESULT res;
u16 len = strlen((const char*)buff);
u8 *FullPath;
res = SDCreateDir(path);
FullPath = malloc(strlen((const char*)path) + strlen((const char*)filename) + 2);
SDComplatePath(path, filename, FullPath);
res = SDFileOpen(FullPath, FA_OPEN_EXISTING | FA_WRITE);
if (res == FR_NO_FILE)
res = SDFileOpen(FullPath, FA_CREATE_ALWAYS | FA_WRITE);
if (res != FR_OK)
return res;
free(FullPath);
SDLseek(File.fsize);
res = SDFileWrite(buff, len);
if (res != FR_OK)
return res;
return SDFileClose();
}
float stringToFloat(u8 *InputString)
{
return atof((const char*)(InputString));
}
int stringToInt(u8 *InputString)
{
return atoi((const char*)(InputString));
}
FRESULT SDLseek(u32 offset)
{
return f_lseek(&File, offset);
}
void SDDataSolve(u8 *buff, ArgumentInfo *argument, UINT ByteCount, UINT *RecordNum)
{
u8 col = 0;
UINT fileRow = 0, CharNum = 0;
u8 *CorChar = buff;
bool isValueRegion = false;
while (CharNum != ByteCount)
{
if (*CorChar == '=')
{
isValueRegion = true;
argument[fileRow].key[col] = '\0';
col = 0;
}
else if (*CorChar == '\r' && *(CorChar + 1) == '\n')
{
CorChar++;
argument[fileRow].value[col] = '\0';
isValueRegion = false;
col = 0;
fileRow++;
}
else
{
if (isValueRegion)
{
argument[fileRow].value[col] = *CorChar;
}
else
{
argument[fileRow].key[col] = *CorChar;
}
col++;
}
CorChar++;
CharNum++;
}
*RecordNum = CharNum;
}
void SDComplatePath(const u8 *Path,const u8 *FileName, u8 *FullPath)
{
u8 TempPath = '/';
strcpy((char*)FullPath, (const char*)Path);
strcat((char*)FullPath, (const char*)&TempPath);
strcat((char*)FullPath, (const char*)FileName);
}
Just for test.May be helpful...
Sorry for my poor English,It’s not my mother tongue.