|
|
/**************************************************************************//**
|
|
|
* @file SPI_SD.c
|
|
|
* @brief SPI Driver for SD Card
|
|
|
* @author Laputa
|
|
|
* @version V2.0
|
|
|
* @date 2023-02-13
|
|
|
******************************************************************************/
|
|
|
|
|
|
#include "SPI_SD.h"
|
|
|
#include "uart.h"
|
|
|
#include "delay.h"
|
|
|
#include "sys.h"
|
|
|
#include "spi_drv.h"
|
|
|
#include "eport_drv.h"
|
|
|
#include "dmac_drv.h"
|
|
|
#include "edma_drv.h"
|
|
|
|
|
|
|
|
|
u8 SD_Type=0;//SD卡的类型
|
|
|
|
|
|
#define Speed_High SPI_BaudRatePrescaler_2
|
|
|
|
|
|
#define SD_DMA 1
|
|
|
|
|
|
SPI_InitTypeDef SPI_InitStruct ;
|
|
|
|
|
|
|
|
|
u16 SPIX_ReadWriteByte(u16 TxData)
|
|
|
{
|
|
|
u16 retry=0;
|
|
|
while((SPI3->SPISRHW)&(SPISR_TXFFULL_MASK)) //等待发送区空
|
|
|
{
|
|
|
retry++;
|
|
|
if(retry>=0XFFFE)return 0; //超时退出
|
|
|
}
|
|
|
SPI3->SPIDR=TxData; //发送一个byte
|
|
|
retry=0;
|
|
|
while((SPI3->SPISRHW) & (SPISR_RXFEMP_MASK)) //等待接收完一个byte
|
|
|
{
|
|
|
retry++;
|
|
|
if(retry>=0XFFFE)return 0; //超时退出
|
|
|
}
|
|
|
return SPI3->SPIDR; //返回收到的数据
|
|
|
}
|
|
|
|
|
|
void SPIX_Init(void)
|
|
|
{
|
|
|
|
|
|
SPI_Cmd(SPI3,DISABLE);
|
|
|
//////SPI模块配置//////
|
|
|
|
|
|
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
|
|
|
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
|
|
|
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
|
|
|
SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
|
|
|
SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
|
|
|
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
|
|
|
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
|
|
|
SPI_InitStruct.SPI_CRCPolynomial = 7;
|
|
|
|
|
|
SPI_Init(SPI3, &SPI_InitStruct); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
|
|
|
|
|
|
SPI_Cmd(SPI3,ENABLE);
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
}
|
|
|
|
|
|
void SPIX_SetSpeed(u16 speed)
|
|
|
{
|
|
|
SPI_Cmd(SPI3,DISABLE);
|
|
|
SPI3->SPIBR = speed;
|
|
|
SPI_Cmd(SPI3,ENABLE);
|
|
|
}
|
|
|
|
|
|
|
|
|
void SPI3_DMA_Rx_Init(void)
|
|
|
{
|
|
|
DMA_Init(DMA2_BASE_ADDR);
|
|
|
m_dma_control->DMA_CONFIG = 1;
|
|
|
//rx配置
|
|
|
m_dma_channel[0]->DMA_SADDR = (UINT32)&SPI3->SPIDR;
|
|
|
m_dma_channel[0]->DMA_CTRL = SNOCHG|DIEC|P2M_DMA|DWIDTH_B|SWIDTH_B;
|
|
|
m_dma_channel[0]->DMA_CFG = (HS_SEL_SRC_HARD);
|
|
|
m_dma_channel[0]->DMA_CFG_HIGH = SRC_PER4;
|
|
|
m_dma_control->DMA_MASKTFR = CHANNEL_UMASK(0);
|
|
|
|
|
|
//tx
|
|
|
m_dma_channel[1]->DMA_DADDR = (UINT32)&SPI3->SPIDR;
|
|
|
m_dma_channel[1]->DMA_CTRL = SNOCHG|DNOCHG|M2P_DMA|DWIDTH_B|SWIDTH_B;
|
|
|
m_dma_channel[1]->DMA_CFG = (HS_SEL_DST_HARD);
|
|
|
m_dma_channel[1]->DMA_CFG_HIGH = DST_PER5;
|
|
|
m_dma_control->DMA_MASKTFR = CHANNEL_UMASK(1);
|
|
|
|
|
|
SPI3->SPIDMATHR = (7<<4)|(0<<0);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SPI3_DMA(UINT8* Rx_Addr, UINT32 length)
|
|
|
{
|
|
|
uint8_t Tx_buff[1] = {0xFF};
|
|
|
|
|
|
m_dma_channel[0]->DMA_DADDR = (UINT32)Rx_Addr;
|
|
|
m_dma_channel[0]->DMA_CTRL_HIGH = length ;
|
|
|
m_dma_control->DMA_CHEN |= CHANNEL_WRITE_ENABLE(0)|CHANNEL_ENABLE(0);
|
|
|
|
|
|
m_dma_channel[1]->DMA_SADDR = (UINT32)Tx_buff;
|
|
|
m_dma_channel[1]->DMA_CTRL_HIGH = length ;
|
|
|
m_dma_control->DMA_CHEN |= CHANNEL_WRITE_ENABLE(1)|CHANNEL_ENABLE(1);
|
|
|
|
|
|
SPI3->SPIDMACR |= 0x03; //使能SPI3 RX的DMA
|
|
|
|
|
|
|
|
|
while((m_dma_control->DMA_RAWTFR & CHANNEL_STAT(0)) != CHANNEL_STAT(0)){__nop();}
|
|
|
m_dma_control->DMA_CLRTFR = CHANNEL_STAT(0);
|
|
|
while((m_dma_control->DMA_RAWTFR & CHANNEL_STAT(1)) != CHANNEL_STAT(1)){__nop();}
|
|
|
m_dma_control->DMA_CLRTFR = CHANNEL_STAT(1);
|
|
|
while((SPI3->SPISR & 0x20) == 0x00){__nop();} //确保SPI传送完成
|
|
|
SPI3->SPIDMACR = 0; //禁止SPI RX的DMA
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//@brief: SD卡初始化
|
|
|
//@param :
|
|
|
//@retval: 1:错误 r1:命令响应
|
|
|
u8 SD_Init(void)
|
|
|
{
|
|
|
u16 i;
|
|
|
u8 r1;
|
|
|
u16 retry;
|
|
|
u8 buff[6];
|
|
|
|
|
|
SPIX_Init(); //初始化SPI1
|
|
|
|
|
|
SPIX_SetSpeed(SPI_BaudRatePrescaler_256); //SD卡初始化时钟不能超过400KHz
|
|
|
|
|
|
SD_CS = 1; //打开SD卡片选引脚
|
|
|
|
|
|
DelayMS(5); //等待SD卡上电稳定,完成初始化
|
|
|
|
|
|
for(i=0;i<10;i++)
|
|
|
{
|
|
|
SPIX_ReadWriteByte(0xff); //产生80个时钟脉冲
|
|
|
}
|
|
|
|
|
|
//将SD卡复位至idle状态
|
|
|
|
|
|
SD_CS = 0;
|
|
|
|
|
|
retry = 0;
|
|
|
do
|
|
|
{
|
|
|
r1 = SD_SendCommand(CMD0,0,0X95); //发送CMD0
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
retry++;
|
|
|
}while((r1!=0x01)&&(retry<200)); //收到正确响应或超时后退出
|
|
|
|
|
|
if(retry==200) //如果退出原因为超时
|
|
|
{
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
r1= SD_SendCommand(CMD8,0x01aa,0x87); //如果退出原因为SD卡复位至idle并收到正确响应,继续发送CMD8获取SD卡版本信息
|
|
|
//如果是v2.0版本的SD卡
|
|
|
if(r1==0x01) //接收到CMD8的正确响应接收CMD8响应后续传送的4字节数据
|
|
|
{
|
|
|
buff[0] = SPIX_ReadWriteByte(0xff); //接收CMD8响应后续传送的4字节数据
|
|
|
buff[1] = SPIX_ReadWriteByte(0xff);
|
|
|
buff[2] = SPIX_ReadWriteByte(0xff);
|
|
|
buff[3] = SPIX_ReadWriteByte(0xff);
|
|
|
|
|
|
////// SD_CS = 1;
|
|
|
|
|
|
////// SPIX_ReadWriteByte(0xff); //多发送8个时钟信号
|
|
|
|
|
|
//// //开始初始化SD卡
|
|
|
|
|
|
SD_CS = 0;
|
|
|
|
|
|
retry = 0;
|
|
|
|
|
|
do
|
|
|
{
|
|
|
r1 = SD_SendCommand(CMD55,0,0xff); //发送CMD55,通知SD卡下一条命令为应用相关命令而非通用命令
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
if(r1!=0x01) //如果主机未接收到CMD55的正确响应
|
|
|
return r1;
|
|
|
r1 = SD_SendCommand(ACMD41,0x40000000,1); //否则继续发送ACMD41
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
retry++;
|
|
|
if(retry>200)
|
|
|
return r1; //超时退出
|
|
|
}while(r1!=0); //接收到ACMD41的正确响应退出
|
|
|
|
|
|
SD_CS = 1;
|
|
|
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
|
|
|
SD_CS = 0;
|
|
|
|
|
|
//初始化指令发送完成,继续获取OCR信息
|
|
|
//识别SD2.00版本的SD卡类型
|
|
|
|
|
|
r1 = SD_SendCommand_NoDeassert(CMD58,0,0); //发送CMD58
|
|
|
|
|
|
if(r1!=0x00)
|
|
|
return r1; //未接收到CMD58的正确响应退出
|
|
|
buff[0] = SPIX_ReadWriteByte(0xff); //否则接收CMD58响应后续传回的4字节COR信息
|
|
|
buff[1] = SPIX_ReadWriteByte(0xff);
|
|
|
buff[2] = SPIX_ReadWriteByte(0xff);
|
|
|
buff[3] = SPIX_ReadWriteByte(0xff);
|
|
|
|
|
|
SD_CS =1;
|
|
|
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
|
|
|
//分析OCR信息中的bit30(CCS)判断卡的类型
|
|
|
//CCS=1,SDHC;CCS=0;SD2.0;
|
|
|
|
|
|
|
|
|
if(buff[0]&0x40)
|
|
|
{
|
|
|
SD_Type = SD_TYPE_V2HC; //类型为SDHC
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
SD_Type = SD_TYPE_V2; //类型为SD2.0
|
|
|
}
|
|
|
SPIX_SetSpeed(Speed_High); //SPI4时钟频率配置为45MHz
|
|
|
|
|
|
}
|
|
|
printf("SD_Type:%d\r\n",SD_Type);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
//@brief:向SD卡发送命令(发送结束后关闭片选信号)
|
|
|
//@param:cmd start bit+transmission bit+command index
|
|
|
//@param:arg
|
|
|
//@param :crc CRC7+end bit
|
|
|
//@retval: r1:命令响应
|
|
|
u8 SD_SendCommand(u8 cmd,u32 arg,u8 crc)
|
|
|
{
|
|
|
unsigned char r1;
|
|
|
unsigned int Retry = 0;
|
|
|
|
|
|
SD_CS = 1;
|
|
|
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
|
|
|
SD_CS = 0;
|
|
|
|
|
|
SPIX_ReadWriteByte(cmd|0x40); //将CMD命令中的传输位设置为1
|
|
|
SPIX_ReadWriteByte((u8)(arg>>24)); //写入CMD命令的32位参数
|
|
|
SPIX_ReadWriteByte((u8)(arg>>16));
|
|
|
SPIX_ReadWriteByte((u8)(arg>>8));
|
|
|
SPIX_ReadWriteByte((u8)(arg));
|
|
|
SPIX_ReadWriteByte(crc); //写入CRC校验和
|
|
|
|
|
|
while((r1 = SPIX_ReadWriteByte(0xff))==0xff) //接收到相关命令的正确响应后退出
|
|
|
{
|
|
|
Retry++;
|
|
|
if(Retry>800) break; //超时退出
|
|
|
}
|
|
|
|
|
|
SD_CS = 1;
|
|
|
|
|
|
SPIX_ReadWriteByte(0xff); //额外发送8个时钟信号,使SD卡完成剩余工作
|
|
|
|
|
|
return r1;
|
|
|
}
|
|
|
|
|
|
//@brief:向SD卡发送命令(发送结束后持续打开片选信号)
|
|
|
//@param:cmd start bit+transmission bit+command index
|
|
|
//@param:arg
|
|
|
//@param :crc CRC7+end bit
|
|
|
//@retval:r1:命令响应
|
|
|
u8 SD_SendCommand_NoDeassert(u8 cmd,u32 arg,u8 crc)
|
|
|
{
|
|
|
unsigned char r1;
|
|
|
unsigned int Retry = 0;
|
|
|
|
|
|
SD_CS = 1;
|
|
|
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
|
|
|
SD_CS = 0;
|
|
|
|
|
|
SPIX_ReadWriteByte(cmd|0x40);
|
|
|
SPIX_ReadWriteByte((u8)(arg>>24));
|
|
|
SPIX_ReadWriteByte((u8)(arg>>16));
|
|
|
SPIX_ReadWriteByte((u8)(arg>>8));
|
|
|
SPIX_ReadWriteByte((u8)(arg));
|
|
|
SPIX_ReadWriteByte(crc);
|
|
|
|
|
|
while((r1 = SPIX_ReadWriteByte(0xff))==0xff)
|
|
|
{
|
|
|
Retry++;
|
|
|
if(Retry >800) break;
|
|
|
}
|
|
|
return r1;
|
|
|
}
|
|
|
//@brief:从SD卡中读取指定长度的数据
|
|
|
//@param:*data 指向存储读回数据的缓冲区的指针
|
|
|
//@param:len 数据长度
|
|
|
//@param:release 读取结束后是否释放总线
|
|
|
//@retval:1:错误 0:正确
|
|
|
u8 SD_ReceiveData(u8 *data,u16 len,u8 release)
|
|
|
{
|
|
|
u16 retry;
|
|
|
u8 r1;
|
|
|
|
|
|
|
|
|
SD_CS = 0;
|
|
|
|
|
|
retry = 0;
|
|
|
do
|
|
|
{
|
|
|
r1 = SPIX_ReadWriteByte(0xff);
|
|
|
retry++;
|
|
|
if(retry>4000)
|
|
|
{
|
|
|
SD_CS = 1;
|
|
|
|
|
|
return 1; //超时退出
|
|
|
}
|
|
|
}while(r1!=0xfe); //主机收到SD卡传回的正确数据读取响应退出
|
|
|
|
|
|
#if !SD_DMA
|
|
|
/*****************************正常模式*************************************/
|
|
|
//接收到正确响应后,开始接收数据
|
|
|
|
|
|
while(len--)
|
|
|
{
|
|
|
*data = SPIX_ReadWriteByte(0xff);
|
|
|
data++;
|
|
|
}
|
|
|
/*****************************正常模式*************************************/
|
|
|
#else
|
|
|
/*****************************DMA模式*************************************/
|
|
|
|
|
|
SPI3_DMA_Rx_Init();
|
|
|
SPI3_DMA(data,len);
|
|
|
|
|
|
/*****************************DMA模式*************************************/
|
|
|
#endif
|
|
|
|
|
|
|
|
|
SPIX_ReadWriteByte(0xff); //发送2个无效CRC
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
|
|
|
if(release == RELEASE) //是否需要释放总线
|
|
|
{
|
|
|
SD_CS = 1;
|
|
|
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
}
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
//@brief:获取CID寄存器数据
|
|
|
//@param:*cid_data 指向存储CID寄存器数据的缓冲区的指针
|
|
|
//@retval:0:正确 r1:命令响应
|
|
|
u8 SD_GetCID(u8 *cid_data)
|
|
|
{
|
|
|
u8 r1;
|
|
|
|
|
|
|
|
|
r1 = SD_SendCommand(CMD10,0,0xff); //发送CMD10命令以获取CID寄存器数据
|
|
|
if(r1!=0x00)
|
|
|
return r1; //主机未接收到正确响应退出
|
|
|
|
|
|
SD_ReceiveData(cid_data,16,RELEASE); //接收CID寄存器数据并释放总线
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
//@brief:获取CSD寄存器数据
|
|
|
//@param:*csd_data 指向存储CSD寄存器数据的缓冲区的指针
|
|
|
//@retval:0:正确 r1:命令响应
|
|
|
u8 SD_GetCSD(u8 *csd_data)
|
|
|
{
|
|
|
u8 r1;
|
|
|
|
|
|
|
|
|
r1 = SD_SendCommand(CMD9,0,0xff); //发送CMD9命令以获取CSD寄存器数据
|
|
|
if(r1!=0x00)
|
|
|
return r1; //主机未接收到正确响应退出
|
|
|
|
|
|
SD_ReceiveData(csd_data,16,RELEASE); //接收CSD寄存器数据并释放总线
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
//@brief:获取SD卡容量信息
|
|
|
//@param:
|
|
|
//@retval:Capacity:SD卡容量
|
|
|
u32 SD_GetCapacity(void)
|
|
|
{
|
|
|
u8 csd[16];
|
|
|
u32 Capacity;
|
|
|
u8 r1;
|
|
|
u16 i;
|
|
|
u16 temp;
|
|
|
|
|
|
if(SD_GetCSD(csd)!=0)
|
|
|
return 0; //未成功获取CSD寄存器数据退出
|
|
|
|
|
|
if((csd[0]&0xC0)==0x40) //如果CSD寄存器版本为v2.0
|
|
|
{
|
|
|
Capacity=((u32)csd[8])<<8;
|
|
|
Capacity+=(u32)csd[9]+1;
|
|
|
Capacity = ((u32)Capacity)/2;
|
|
|
//Capacity = (Capacity)*1024; //得到扇区数
|
|
|
//Capacity*=512; //得到字节数
|
|
|
|
|
|
}
|
|
|
else //如果CSD寄存器版本是v1.0
|
|
|
{
|
|
|
i = csd[6]&0x03;
|
|
|
i<<=8;
|
|
|
i += csd[7];
|
|
|
i<<=2;
|
|
|
i += ((csd[8]&0xc0)>>6);
|
|
|
r1 = csd[9]&0x03;
|
|
|
r1<<=1;
|
|
|
r1 += ((csd[10]&0x80)>>7);
|
|
|
r1+=2;
|
|
|
temp = 1;
|
|
|
while(r1)
|
|
|
{
|
|
|
temp*=2;
|
|
|
r1--;
|
|
|
}
|
|
|
Capacity = ((u32)(i+1))*((u32)temp);
|
|
|
i = csd[5]&0x0f;
|
|
|
temp = 1;
|
|
|
while(i)
|
|
|
{
|
|
|
temp*=2;
|
|
|
i--;
|
|
|
}
|
|
|
|
|
|
Capacity *= (u32)temp; //得到字节数
|
|
|
}
|
|
|
return (u32)Capacity; //返回SD卡容量(字节)
|
|
|
}
|
|
|
|
|
|
//@brief:singleblock读取
|
|
|
//@param:sector 数据地址(扇区地址)
|
|
|
//@param:*buffer 指向存储读回数据的缓冲的指针
|
|
|
//@retval:0:正确 r1:命令响应
|
|
|
u8 SD_ReadSingleBlock(u32 sector, u8 *buffer)
|
|
|
{
|
|
|
u8 r1;
|
|
|
|
|
|
|
|
|
SPIX_SetSpeed(Speed_High); //SPI4时钟频率配置为45MHz
|
|
|
|
|
|
if(SD_Type!=SD_TYPE_V2HC) //如果不是SDHC卡
|
|
|
{
|
|
|
sector = sector<<9; //512*sector即物理扇区的边界对齐地址
|
|
|
}
|
|
|
r1 = SD_SendCommand(CMD17,sector, 1); //发送CMD17 读单块命令
|
|
|
if(r1 != 0x00) return r1; //未接收到CMD17的正确响应退出
|
|
|
r1 = SD_ReceiveData(buffer, 512, RELEASE); //一个扇区为512字节 读取数据并释放总线
|
|
|
if(r1 != 0)
|
|
|
return r1; //读取数据失败退出
|
|
|
else
|
|
|
return 0; //读取数据成功
|
|
|
}
|
|
|
|
|
|
//@brief:multiblock读取
|
|
|
//@param:sector 数据地址(扇区地址)
|
|
|
//@param:*buff 指向存储读回数据的缓冲的指针
|
|
|
//@param:count 要读取的扇区数量
|
|
|
//@retval:0:正确 count:未处理完扇区数 r1:命令响应
|
|
|
u8 SD_ReadMultiBlock(u8 *buff, u32 sector, u32 count)
|
|
|
{
|
|
|
u8 r1;
|
|
|
|
|
|
SPIX_SetSpeed(Speed_High); //SPI1时钟频率配置为45MHz
|
|
|
|
|
|
if(SD_Type != SD_TYPE_V2HC)
|
|
|
{
|
|
|
sector = sector<<9;
|
|
|
}
|
|
|
r1 = SD_SendCommand(CMD18, sector, 1); //发送CMD18 读多块命令
|
|
|
if(r1 != 0x00) return r1;
|
|
|
do //开始接收数据
|
|
|
{
|
|
|
if(SD_ReceiveData((u8 *)buff, 512, NO_RELEASE) != 0x00) //读取数据完成后不释放总线
|
|
|
{
|
|
|
break; //读取数据失败退出
|
|
|
}
|
|
|
buff += 512;
|
|
|
}while(--count); //数据接收全部完成
|
|
|
|
|
|
SD_SendCommand(CMD12, 0, 1); //全部传输完成,发送停止命令
|
|
|
SD_CS=1; //释放总线
|
|
|
|
|
|
|
|
|
SPIX_ReadWriteByte(0xFF);
|
|
|
if(count != 0)
|
|
|
return count; //如果数据传输中途因错误退出,返回剩余扇区个数
|
|
|
else
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
//@brief:SD卡繁忙检测
|
|
|
//@param:
|
|
|
//@retval:0:空闲 1:繁忙
|
|
|
u8 SD_WaitReady(void)
|
|
|
{
|
|
|
u8 r1;
|
|
|
u16 retry=0;
|
|
|
do
|
|
|
{
|
|
|
r1 = SPIX_ReadWriteByte(0xFF); //当SD卡繁忙,数据线会被拉低;当SD卡结束繁忙后,数据线会被拉高
|
|
|
retry++;
|
|
|
if(retry==0xfffe)
|
|
|
return 1;
|
|
|
}while(r1!=0xFF);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
//@brief:singleblock写入
|
|
|
//@param:sector 数据地址(扇区地址)
|
|
|
//@param:*data 指向存储要写入SD卡的数据的缓冲区的指针
|
|
|
//@retval:0:正确 1:超时 r1:命令响应
|
|
|
u8 SD_WriteSingleBlock(u32 sector, const u8 *data)
|
|
|
{
|
|
|
u8 r1;
|
|
|
u16 i;
|
|
|
u16 retry;
|
|
|
|
|
|
SPIX_SetSpeed(SPI_BaudRatePrescaler_256); //SPI4时钟频率配置为45MHz
|
|
|
|
|
|
if(SD_Type!=SD_TYPE_V2HC) //如果不是SDHC卡,将sector地址转为byte地址
|
|
|
{
|
|
|
sector = sector<<9;
|
|
|
}
|
|
|
|
|
|
r1 = SD_SendCommand(CMD24, sector, 0x00); //发送CMD24 写扇区命令
|
|
|
if(r1 != 0x00)
|
|
|
{
|
|
|
return r1;
|
|
|
}
|
|
|
|
|
|
SD_CS = 0; //开始准备写入数据
|
|
|
|
|
|
SPIX_ReadWriteByte(0xff); //先发3个空数据,等待SD卡准备好
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
|
|
|
SPIX_ReadWriteByte(0xFE); //发送数据发送起始符号
|
|
|
|
|
|
for(i=0;i<512;i++) //发送一个sector的数据
|
|
|
{
|
|
|
SPIX_ReadWriteByte(*data++);
|
|
|
}
|
|
|
|
|
|
SPIX_ReadWriteByte(0xff); //发送2个无效CRC校验
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
|
|
|
r1 = SPIX_ReadWriteByte(0xff); //等待SD卡的数据响应符号
|
|
|
|
|
|
if((r1&0x1F)!=0x05) //如果为r1=0x05则数据写入成功
|
|
|
{
|
|
|
SD_CS = 1;
|
|
|
|
|
|
return r1; //否则释放总线并退出
|
|
|
}
|
|
|
|
|
|
retry = 0; //等待操作完成
|
|
|
|
|
|
while(!SPIX_ReadWriteByte(0xff)) //SD卡自编程时,数据线被拉低
|
|
|
{
|
|
|
retry++;
|
|
|
if(retry>65534) //如果超时写入未完成,退出报错
|
|
|
{
|
|
|
SD_CS = 1;
|
|
|
|
|
|
return 1; //写入超时,返回1
|
|
|
}
|
|
|
}
|
|
|
|
|
|
SD_CS = 1; //写入完成,片选置1
|
|
|
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
//@brief:multiblock写入
|
|
|
//@param:sector 数据地址(扇区地址)
|
|
|
//@param:*data 指向存储要写入SD卡的数据的缓冲区的指针
|
|
|
//@param:count 要写入的扇区数量
|
|
|
//@retval:0:正确 1:超时 count:未处理完扇区数 r1:命令响应
|
|
|
u8 SD_WriteMultiBlock(const u8 *data, u32 sector, u8 count)
|
|
|
{
|
|
|
u8 r1;
|
|
|
u16 i;
|
|
|
|
|
|
SPIX_SetSpeed(SPI_BaudRatePrescaler_256); //SPI4时钟频率配置为45MHz
|
|
|
|
|
|
if(SD_Type != SD_TYPE_V2HC)
|
|
|
{
|
|
|
sector = sector<<9;
|
|
|
}
|
|
|
/*if(SD_Type != SD_TYPE_MMC)
|
|
|
{
|
|
|
r1 = SD_SendCommand(ACMD23, count, 0x01); //启用ACMD23指令使能预擦除
|
|
|
}*/
|
|
|
|
|
|
r1 = SD_SendCommand(CMD25, sector, 0x01); //发送CMD25 写多块命令
|
|
|
|
|
|
if(r1 != 0x00) return r1;
|
|
|
|
|
|
SD_CS = 0; //开始准备数据传输
|
|
|
|
|
|
|
|
|
SPIX_ReadWriteByte(0xff); //发送3个空数据让SD卡准备好
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
|
|
|
do //下面是N个sector循环写入的部分
|
|
|
{
|
|
|
|
|
|
SPIX_ReadWriteByte(0xFC); //发送数据传输起始符号0xFC,表明是多块写入
|
|
|
|
|
|
for(i=0;i<512;i++) //发1个sector的数据
|
|
|
{
|
|
|
SPIX_ReadWriteByte(*data++);
|
|
|
}
|
|
|
|
|
|
SPIX_ReadWriteByte(0xff); //发2个伪CRC
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
|
|
|
r1 = SPIX_ReadWriteByte(0xff); //等待SD卡回应
|
|
|
|
|
|
if((r1&0x1F)!=0x05) //如果r1=0x05则表示数据写入成功
|
|
|
{
|
|
|
SD_CS = 1; //写入失败则释放总线退出
|
|
|
|
|
|
return r1;
|
|
|
}
|
|
|
|
|
|
if(SD_WaitReady()==1) //检测SD卡忙信号
|
|
|
{
|
|
|
SD_CS = 1; //如果长时间写入未完成,释放总线并退出
|
|
|
|
|
|
return 1;
|
|
|
}
|
|
|
}while(--count);
|
|
|
|
|
|
SPIX_ReadWriteByte(0xFD); //发送数据传输结束符号0xFD
|
|
|
|
|
|
if(SD_WaitReady()) //等待准备好
|
|
|
{
|
|
|
SD_CS = 1; //超时未退出繁忙则释放总线并退出
|
|
|
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
SD_CS = 1; //写入完成,片选置1
|
|
|
|
|
|
SPIX_ReadWriteByte(0xff);
|
|
|
|
|
|
return count; //返回count值,如果写完,则count=0,否则count=未写完的sector数
|
|
|
}
|