我尝试使用SPI将microSD卡与 STM32L152-DISCOVERY 板(STM32L152RCT6 ARM Cortex-M3)连接。最终目标是使用 FatFs (http://elm-chan.org/fsw/ff/00index_e.html)将传感器数据存储在SD卡上,该SD卡也可以在Decktop PC上读取。在Chan的网站上有一个非常有用的流程图描述了初始化过程(http://elm-chan.org/docs/mmc/im/sdinit.png)。
不幸的是,我的代码中存在一个问题,导致SDCard无法初始化。具体来说,当我发送命令ACMD41(CMD55 + CMD41)时,SD卡总是返回 0x01 。
我已多次修改我的代码,此处有关于堆栈溢出的帖子,特别是SDHC microSD card and SPI initialization,但问题仍然存在。
以下是我系统的硬件和软件设置:
硬件设置
软件设置 - SPI初始化
SPI频率最初设置在125 KHz之间(I读数必须在100 KHz - 400 KHz范围内)。
/* SPI2 init function */
void MX_SPI2_Init(void)
{
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(spiHandle->Instance==SPI2)
{
/* SPI2 clock enable */
__HAL_RCC_SPI2_CLK_ENABLE();
/**SPI2 GPIO Configuration
PB13 ------> SPI2_SCK
PB14 ------> SPI2_MISO
PB15 ------> SPI2_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
}
软件设置 - SDCARD初始化
#include <string.h>
#include "ff_gen_drv.h"
#define CS_HIGH() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
#define CS_LOW() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
#define DEFAULT_TIMEOUT 10
uint8_t dummy_clocks[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
/* Definitions for MMC/SDC command */
#define CMD0 (0) /* GO_IDLE_STATE */
#define CMD1 (1) /* SEND_OP_COND (MMC) */
#define ACMD41 (41) /* SEND_OP_COND (SDC) */
#define CMD8 (8) /* SEND_IF_COND */
#define CMD9 (9) /* SEND_CSD */
#define CMD10 (10) /* SEND_CID */
#define CMD12 (12) /* STOP_TRANSMISSION */
#define ACMD13 (13) /* SD_STATUS (SDC) */
#define CMD16 (16) /* SET_BLOCKLEN */
#define CMD17 (17) /* READ_SINGLE_BLOCK */
#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */
#define ACMD23 (23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24 (24) /* WRITE_BLOCK */
#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
#define CMD55 (55) /* APP_CMD */
#define CMD58 (58) /* READ_OCR */
static volatile DSTATUS Stat = STA_NOINIT;
extern SPI_HandleTypeDef hspi2;
DSTATUS USER_initialize (BYTE pdrv);
DSTATUS USER_status (BYTE pdrv);
DRESULT USER_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count);
#if _USE_WRITE == 1
DRESULT USER_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count);
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1
DRESULT USER_ioctl (BYTE pdrv, BYTE cmd, void *buff);
#endif /* _USE_IOCTL == 1 */
Diskio_drvTypeDef USER_Driver =
{
USER_initialize,
USER_status,
USER_read,
#if _USE_WRITE
USER_write,
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1
USER_ioctl,
#endif /* _USE_IOCTL == 1 */
};
void spi_init(void);
uint8_t send_cmd(BYTE cmd, DWORD arg);
DSTATUS USER_initialize (BYTE pdrv)
{
/* USER CODE BEGIN INIT */
Stat = STA_NOINIT;
enum initialization_state
{
SD_POWER_CYCLE = 0,
SD_SEND_CMD0,
SD_WAIT_CMD0_ANSWER,
SD_SEND_CMD8,
SD_SEND_CMD55,
SD_SEND_ACMD41,
SD_SEND_CMD1,
SD_SEND_CMD58,
SD_SEND_CMD16,
SD_SUCCESS,
SD_ERROR,
} init_phase;
uint8_t response = 0x00;
DWORD arg = 0;
init_phase = SD_POWER_CYCLE;
spi_init();
while(init_phase < SD_SUCCESS)
{
switch(init_phase)
{
case SD_POWER_CYCLE:
// Wait 1 ms
HAL_Delay(1);
HAL_SPI_Transmit(&hspi2, dummy_clocks, sizeof(dummy_clocks), 10);
init_phase = SD_SEND_CMD0;
break;
case SD_SEND_CMD0:
CS_LOW();
response = send_cmd(CMD0,arg);
if(response == 0x01)
init_phase = SD_SEND_CMD8;
else
init_phase = SD_ERROR;
break;
case SD_SEND_CMD8:
arg = 0x000001AA;
response = send_cmd(CMD8,arg);
if(response == 0x01)
init_phase = SD_SEND_CMD55;
else
init_phase = SD_ERROR;
break;
case SD_SEND_CMD55:
arg = 0x00000000;
response = send_cmd(CMD55,arg);
if(response == 0x01)
init_phase = SD_SEND_ACMD41;
else
init_phase = SD_ERROR;
break;
case SD_SEND_ACMD41:
arg = 0x40000000;
response = send_cmd(ACMD41,arg);
if(response == 0x00)
init_phase = SD_SEND_CMD58;
else
{
// HAL_Delay(1000);
init_phase = SD_SEND_CMD55;
}
break;
case SD_SEND_CMD58:
arg = 0x00000000;
response = send_cmd(CMD58,arg);
break;
case SD_ERROR:
CS_HIGH();
Stat = STA_NODISK;
break;
default:
// Something went wrong - Try to re-init
init_phase = SD_POWER_CYCLE;
spi_init();
break;
}
}
return Stat;
/* USER CODE END INIT */
}
...
...
void spi_init(void)
{
CS_HIGH();
HAL_Delay(10);
}
uint8_t send_cmd(BYTE cmd, DWORD arg)
{
// cmd packet is of fixed lenght
uint8_t cmd_packet[6] = {0};
// Response
uint8_t cmd_response = 0xFF;
// R1 is 1 byte only and it is used for most commands
uint8_t r1 = 0xFF;
// Commands R3 and R7 are 5 bytes long, (R1 + trailing 32-bit data)
uint8_t r3_7[5] = {0};
// First byte is the command
// The cmd_packet must start with 01, therefore we add 0x40 to the cmd byte
cmd_packet[0] = 0x40 | cmd;
// Four bytes for the argument
for(uint8_t i = 1; i<=4; i++)
cmd_packet[i] = (uint8_t)(arg >> (4-i)*8);
// Add crc: it must be correct for CMD0 and CMD 8 only; for other commands, we use a dummy crc (0x01)
if(cmd == CMD0)
cmd_packet[5] = 0x95;
else if(cmd == CMD8)
cmd_packet[5] = 0x87;
else if(cmd == ACMD41)
cmd_packet[5] = 0x95;
else
cmd_packet[5] = 0x01;
// Send the command
HAL_SPI_Transmit(&hspi2, cmd_packet, sizeof(cmd_packet), DEFAULT_TIMEOUT);
// Receive the answer from SDcard
switch(cmd)
{
case CMD0:
// Try 3 times to get the answer
for(uint8_t j = 0; j<3; j++)
{
HAL_SPI_Transmit(&hspi2, (uint8_t*)&cmd_response, sizeof(cmd_response), DEFAULT_TIMEOUT);
HAL_SPI_Receive(&hspi2,&r1,sizeof(r1),DEFAULT_TIMEOUT);
if(r1 != 0xFF)
return r1;
}
break;
case CMD8:
HAL_SPI_Transmit(&hspi2, (uint8_t*)&cmd_response, sizeof(cmd_response), DEFAULT_TIMEOUT);
HAL_SPI_Receive(&hspi2,r3_7,sizeof(r3_7),DEFAULT_TIMEOUT);
if( r3_7[3] == 0x01 && r3_7[4] == 0xAA)
return 0x01;
break;
case CMD55:
HAL_SPI_Transmit(&hspi2, (uint8_t*)&cmd_response, sizeof(cmd_response), DEFAULT_TIMEOUT);
HAL_SPI_Receive(&hspi2,&r1,sizeof(r1),DEFAULT_TIMEOUT);
if(r1 != 0xFF)
return r1;
break;
case ACMD41:
for(int i = 0; i<150; i++)
{
HAL_SPI_Transmit(&hspi2, (uint8_t*)&cmd_response, sizeof(cmd_response), DEFAULT_TIMEOUT);
HAL_SPI_Receive(&hspi2,&r1,sizeof(r1),DEFAULT_TIMEOUT);
if(r1 == 0x00)
return r1;
else
HAL_Delay(10);
}
return 0xFF;
break;
case CMD58:
HAL_SPI_Transmit(&hspi2, (uint8_t*)&cmd_response, sizeof(cmd_response), DEFAULT_TIMEOUT);
HAL_SPI_Receive(&hspi2,r3_7,sizeof(r3_7),DEFAULT_TIMEOUT);
if( r3_7[1] & (1<<7))
return 0x01;
else
return 0x00;
break;
}
}
答案 0 :(得分:1)
我有同样的问题。我将SDHC卡与STM32F107VC接口连接起来。我成功使用了FatFs。 实际上我从来没有找到任何关于这个问题的线索。我使用SD模块和附加SD与Dupont Line。就像这个(连接)
然后它工作了......我还连接了一个mircoSD,也成功了。
我的代码:
#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;
}
#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
另外,我的文件操作码:
#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);
}
只是为了测试。可能会有所帮助......
抱歉我的英语不好,这不是我的母语。