{
u8 r1;
//高速模式
SPI_SetSpeed(SPI_SPEED_HIGH);
if(SD_Type!=SD_TYPE_V2HC) //如果不是SDHC卡
{
sector = sector<<9; //512*sector即物理扇区的边界对其地址
}
r1 = SD_SendCommand(CMD17, sector, 1); //发送CMD17 读命令
if(r1 != 0x00) return r1;
r1 = SD_ReceiveData(buffer, 512, RELEASE); //一个扇区为512字节
if(r1 != 0)
return r1; //读数据出错
else
return 0; //读取正确,返回0
} 读多块:u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count)
{
u8 r1;
SPI_SetSpeed(SPI_SPEED_HIGH);
if(SD_Type != SD_TYPE_V2HC)
{
sector = sector<<9;
}
r1 = SD_SendCommand(CMD18, sector, 1); //读多块命令
if(r1 != 0x00) return r1;
do //开始接收数据
{
if(SD_ReceiveData(buffer, 512, NO_RELEASE) != 0x00)
{
break;
}
buffer += 512;
} while(--count);
SD_SendCommand(CMD12, 0, 1); //全部传输完成,发送停止命令
SD_CS_DISABLE(); //释放总线
SPI_ReadWriteByte(0xFF);
if(count != 0)
return count; //如果没有传完,返回剩余个数
else
return 0;
} 写单块和写多块
SD卡用CMD24和CMD25来写单块和多块,参数的定义和读操作是一样的。 忙检测:
SD卡写入数据并自编程时,数据线上读到0x00表示SD卡正忙,当读到0xff表示写操作完成。 u8 SD_WaitReady(void)
{
u8 r1;
u16 retry=0;
do
{
r1 = SPI_ReadWriteByte(0xFF);
retry++;
if(retry==0xfffe)
return 1;
}while(r1!=0xFF);
return 0;
} 写单块流程:
1.发送CMD24,收到0x00表示成功
2.发送若干时钟
3.发送写单块开始字节0xFE
4.发送512个字节数据
5.发送2字节CRC(可以均为0xff)
6.连续读直到读到XXX00101表示数据写入成功
7.继续读进行忙检测(读到0x00表示SD卡正忙),当读到0xff表示写操作完成 u8 SD_WriteSingleBlock(u32 sector, const u8 *data)
{
u8 r1;
u16 i;
16 retry;
//高速模式
SPI_SetSpeed(SPI_SPEED_HIGH);
//如果不是SDHC卡,将sector地址转为byte地址
if(SD_Type!=SD_TYPE_V2HC)
{
sector = sector<<9;
}
//写扇区指令
r1 = SD_SendCommand(CMD24, sector, 0x00);
if(r1 != 0x00)
{
//应答错误,直接返回
return r1;
}
//开始准备数据传输
SD_CS_ENABLE();
//先发3个空数据,等待SD卡准备好
SPI_ReadWriteByte(0xff);
SPI_ReadWriteByte(0xff);
SPI_ReadWriteByte(0xff);
//放起始令牌0xFE
SPI_ReadWriteByte(0xFE);
//发一个sector数据
for(i=0;i<512;i++)
{
SPI_ReadWriteByte(*data++);
}
//发送2个伪CRC校验
SPI_ReadWriteByte(0xff);
SPI_ReadWriteByte(0xff);
//等待SD卡应答
r1 = SPI_ReadWriteByte(0xff);
//如果为0x05说明数据写入成功
if((r1&0x1F)!=0x05)
{
SD_CS_DISABLE();
return r1;
}
//等待操作完成
retry = 0;
//卡自编程时,数据线被拉低
while(!SPI_ReadWriteByte(0xff))
{
retry++;
if(retry>65534) //如果长时间没有写入完成,退出报错
{
SD_CS_DISABLE();
return 1; //写入超时,返回1
}
}
//写入完成,片选置1
SD_CS_DISABLE();
SPI_ReadWriteByte(0xff);
return 0;
} 写多块流程:
1.发送CMD25,收到0x00表示成功
2.发送若干时钟
3.发送写多块开始字节0xFC
4.发送512字节数据
5.发送两个CRC(可以均为0xff)
6.连续读直到读到XXX00101表示数据写入成功
7.继续读进行忙检测,直到读到0xFF表示写操作完成
8.如果想读下一扇区重复2-7步骤
9.发送写多块停止字节0xFD来停止写操作
10.进行忙检测直到读到0xFF u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count)
{
u8 r1;
u16 i;
SPI_SetSpeed(SPI_SPEED_HIGH);
if(SD_Type != SD_TYPE_V2HC)
{
sector = sector<<9;
}
if(SD_Type != SD_TYPE_MMC)
{
//启用ACMD23指令使能预擦除
r1 = SD_SendCommand(ACMD23, count, 0x01);
}
//写多块指令CMD25
r1 = SD_SendCommand(CMD25, sector, 0x01);
//应答不正确,直接返回
if(r1 != 0x00) return r1;
//开始准备数据传输
SD_CS_ENABLE();
//放3个空数据让SD卡准备好
SPI_ReadWriteByte(0xff);
SPI_ReadWriteByte(0xff);
SPI_ReadWriteByte(0xff);
//下面是N个sector循环写入的部分
do
{
//放起始令牌0xFC,表明是多块写入
SPI_ReadWriteByte(0xFC);
//发1个sector的数据
for(i=0;i<512;i++)
{
SPI_ReadWriteByte(*data++);
}
//发2个伪CRC
SPI_ReadWriteByte(0xff);
SPI_ReadWriteByte(0xff);
//等待SD卡回应
r1 = SPI_ReadWriteByte(0xff);
//0x05表示数据写入成功
if((r1&0x1F)!=0x05)
{
SD_CS_DISABLE();
return r1;
}
//检测SD卡忙信号
if(SD_WaitReady()==1)
{
SD_CS_DISABLE(); //长时间写入未完成,退出
return 1;
}
}
while(--count);
//发送传输结束令牌0xFD
SPI_ReadWriteByte(0xFD);
//等待准备好
if(SD_WaitReady())
{
SD_CS_DISABLE();
return 1;
}
//写入完成,片选置1
SD_CS_DISABLE();
SPI_ReadWriteByte(0xff);
//返回count值,如果写完,则count=0,否则count=未写完的sector数
return count;
} SD卡的基本读写程序就是这些,编写的思路就是由最底层的SPI 读写一字节数据的程序作为基本程序,然后根据SD卡不同时序进行相应的组合。
想细致研究STM32的SPI在这个例程中的配置还是需要下载源码仔细阅读的。掌握了这个例程的读写SD卡的函数原理,下一步就可以着手运用到FATFS文件系统了。
请问在哪里可以下载呢?
页:
1
[2]