SD卡基本函数
SPI_InitTypeDef结构体 SPI 初始化结构体
1.SD_Lowlevel_Init( );
该函数初始化SPI相关外围时钟,配置GPIO引脚,调用SPI_Init( )初始化SPI_InitStructre结构体-->SPI_Init(SD_SPI, &SPI_InitStructure);
SPI_Cmd(SD_SPI, ENABLE)使能SPI功能
2.SD_SPI_SetSpeedLow( );
里面调用SD_SPI_SetSpeed(SPI_BaudRatePrescaler_256)降低SPI的时钟,初始化时需要使用低速模式
3.SD卡初始化的时候, SD_CS_HIGH( );挂起SD卡.延时至少74个时钟,等待SD卡完成内部操作,MMC协议中说明
/*!< Send dummy byte 0xFF, 10 times with CS high */
/*!< Rise CS and MOSI for 80 clocks cycles */
for (i = 0; i <= 9; i++)
{
/*!< Send dummy byte 0xFF */
SD_WriteByte(SD_DUMMY_BYTE);
}
4.SD_GoIdleState( ); 将SD卡设置在空闲状态
之前SD_CS_HIGH( ),在这一步需要将CS_Low,在SD_GoIdleState( )函数中,
SD_Error SD_GoIdleState(void)
{
SD_CS_LOW(); //设置CS_LOW
/*!< Send CMD0 (SD_CMD_GO_IDLE_STATE) to put SD in SPI mode */
SD_SendCmd(SD_CMD_GO_IDLE_STATE, 0, 0x95); //发送CMD0,等待应答为0x01发送CMD0,收到的应答是0x01
/*!< Wait for In Idle State Response (R1 Format) equal to 0x01 */
if (SD_GetResponse(SD_IN_IDLE_STATE)) //SD_GetResponse()返回值: SD_RESPONSE_FAILURE,SD_RESPONSE_NO_ERROR
{
/*!< No Idle State Response: return response failue */
return SD_RESPONSE_FAILURE;
}
/*----------Activates the card initialization process-----------*/ //激活卡的初始化进程
do
{
/*!< SD chip select high */
SD_CS_HIGH();
/*!< Send Dummy byte 0xFF */
SD_WriteByte(SD_DUMMY_BYTE);
/*!< SD chip select low */
SD_CS_LOW();
/*!< Send CMD1 (Activates the card process) until response equal to 0x0 */ //接着发送CMD1,收到的应答应该是0x00接着发送CMD1=0x41,收到的应答应该是0x00
SD_SendCmd(SD_CMD_SEND_OP_COND, 0, 0xFF);
/*!< Wait for no error Response (R1 Format) equal to 0x00 */
}
while (SD_GetResponse(SD_RESPONSE_NO_ERROR)); //SD_RESPONSE_NO_ERROR = (0x00),初始化成功后返回0x00,跳出while循环
/*!< SD chip select high */ SD_CS_HIGH(); //最后拉高 /*!< Send dummy byte 0xFF */ SD_WriteByte(SD_DUMMY_BYTE); return SD_RESPONSE_NO_ERROR;}
5.获取SD卡信息SD_GetCardInfo(SD_CardInfo *cardinfo),定义了SD卡信息结构体,SD_CardInfo,
typedef struct
{
SD_CSD SD_csd; //csd 128位宽度 卡的工作条件的相关信息
SD_CID SD_cid; //cid 128位宽度 卡的识别码,用于识别单个卡的编号
uint32_t CardCapacity; /*!< Card Capacity */ //卡的大小
uint32_t CardBlockSize; /*!< Card Block Size */ //块大小
} SD_CardInfo;
SD/MMC内部寄存器见
http://www.cnblogs.com/Efronc/archive/2010/03/27/1698474.html
SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo)
{
SD_Error status = SD_RESPONSE_FAILURE;
status = SD_GetCSDRegister(&(cardinfo->SD_csd));
status = SD_GetCIDRegister(&(cardinfo->SD_cid));
cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) ;
cardinfo->CardCapacity *= (1 << (cardinfo->SD_csd.DeviceSizeMul + 2));
cardinfo->CardBlockSize = 1 << (cardinfo->SD_csd.RdBlockLen);
cardinfo->CardCapacity *= cardinfo->CardBlockSize;
/*!< Returns the reponse */
return status;
}
6.STM SPI数据发送接收过程,移位寄存器,状态位
SPI_DR在发送和接收时用作数据缓冲器使用。在发送时,当数据从SPI_DR传送到移位寄存器时,TXE发送缓冲空标志置位,此时表示SPI_DR可以再次接收一个数据。所以在发送新的数据前,软件必须确认TXE标志位为'1',否则新的数据会覆盖已经写入SPI_DR里面的数据。
/*!< Wait until the transmit buffer is empty */
while(SPI_I2S_GetFlagStatus(SD_SPI, SPI_I2S_FLAG_TXE) == RESET) //当TXE置位时即=SET时,跳出循环。表示可以像SPI_DR写入新的数据
{
}
FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG)
{
FlagStatus bitstatus = RESET;
/* Check the parameters */
assert_param(IS_SPI_ALL_PERIPH(SPIx));
assert_param(IS_SPI_I2S_GET_FLAG(SPI_I2S_FLAG));
/* Check the status of the specified SPI/I2S flag */
if ((SPIx->SR & SPI_I2S_FLAG) != (uint16_t)RESET)
{
/* SPI_I2S_FLAG is set */
bitstatus = SET;
}
else
{
/* SPI_I2S_FLAG is reset */
bitstatus = RESET;
}
/* Return the SPI_I2S_FLAG status */
return bitstatus;
}
接收时,当数据被从移位寄存器传送到SPI_DR寄存器中时,设置RXNE标志位,此时可以从SPI_DR中读取数据,读出SPI_DR即可清除RXNE标志位
while (SPI_I2S_GetFlagStatus(SD_SPI, SPI_I2S_FLAG_RXNE) == RESET)
{
}
7.SPI_SendData( )其实就是往SPI_DR里写数据
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data)
{
/* Check the parameters */
assert_param(IS_SPI_ALL_PERIPH(SPIx));
/* Write in the DR register the data to be sent */
SPIx->DR = Data;
}
8.读一个单块的过程
1. CS_LOW-->8个clk-->发送CMD17(单块)或CMD18(多块)读命令,返回0x00
2. 接收数据开始令牌0xfe -->正式接收数据512Bytes --> 接收CRC 校验2Bytes-->8个clk-->CS_HIGH
SD_Error SD_ReadBlock(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t BlockSize)
pBuffer是一个指针,指向接收到SD卡数据的地址。
ReadAddr指向要读取的SD卡内部数据的起始地址
BlockSize SD卡块大小
SD_Error SD_ReadBlock(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t BlockSize)
{
uint32_t i = 0;
SD_Error rvalue = SD_RESPONSE_FAILURE;
SD_CS_LOW();
if(flag_SDHC == 1)
{
ReadAddr = ReadAddr/512;
}
SD_SendCmd(SD_CMD_READ_SINGLE_BLOCK, ReadAddr, 0xFF); //发送CMD17
if (!SD_GetResponse(SD_RESPONSE_NO_ERROR)) //SD_RESPONSE_NO_ERROR=0x00,返回0x00,执行下面的if语句
{
if (!SD_GetResponse(SD_START_DATA_SINGLE_BLOCK_READ)) //获取接收数据开始令牌0XFE,Data token start byte,Start single Block Read
{
for (i = 0; i < BlockSize; i++) //循环写入,pBuffer-->data[512]
{
*pBuffer = SD_ReadByte();
pBuffer++;
}
/*!< Get CRC bytes (not really needed by us, but required by SD) */
SD_ReadByte(); //CRC校验
SD_ReadByte();
rvalue = SD_RESPONSE_NO_ERROR;
}
}
SD_CS_HIGH(); //拉高
/*!< Send dummy byte: 8 Clock pulses of delay */
SD_WriteByte(SD_DUMMY_BYTE); //8个clk
return rvalue;
}
9.写一个单块的过程写入单块数据流程:CS_LOW‐‐>8个clk‐‐>发送CMD24‐‐>接收响应R1‐‐>写入读数据起始令牌0xFE‐‐>写入数据‐‐>接收CRC‐‐>8个clk‐‐>CS_HIGH
SD_Error SD_WriteBlock(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t BlockSize)
{
uint32_t i = 0;
SD_Error rvalue = SD_RESPONSE_FAILURE;
/*!< SD chip select low */
SD_CS_LOW();
if(flag_SDHC == 1)
{
WriteAddr = WriteAddr/512;
}
/*!< Send CMD24 (SD_CMD_WRITE_SINGLE_BLOCK) to write multiple block */
SD_SendCmd(SD_CMD_WRITE_SINGLE_BLOCK, WriteAddr, 0xFF);
/*!< Check if the SD acknowledged the write block command: R1 response (0x00: no errors) */
if (!SD_GetResponse(SD_RESPONSE_NO_ERROR))
{
/*!< Send a dummy byte */
SD_WriteByte(SD_DUMMY_BYTE);
/*!< Send the data token to signify the start of the data */
SD_WriteByte(0xFE);
/*!< Write the block data to SD : write count data by block */
for (i = 0; i < BlockSize; i++)
{
/*!< Send the pointed byte */
SD_WriteByte(*pBuffer);
/*!< Point to the next location where the byte read will be saved */
pBuffer++;
}
/*!< Put CRC bytes (not really needed by us, but required by SD) */
SD_ReadByte();
SD_ReadByte();
/*!< Read data response */
if (SD_GetDataResponse() == SD_DATA_OK)
{
rvalue = SD_RESPONSE_NO_ERROR;
}
}
/*!< SD chip select high */
SD_CS_HIGH();
/*!< Send dummy byte: 8 Clock pulses of delay */
SD_WriteByte(SD_DUMMY_BYTE);
/*!< Returns the reponse */
return rvalue;
}