sdhc 读写 扇区 linux,读写 SD卡 扇区1 操作 (1)

#include "sd_spi.h"

u8 SD_Type=0 ;

/*******************************************************************************

* Function Name : SPI_Configuration

* Description : SPI模块初始化,【包括相关IO口的初始化】

* Input : None

* Output : None

* Return : None

*******************************************************************************/

void SPI1_Configuration(void)

{

SPI_InitTypeDef SPI_InitStructure ;

GPIO_InitTypeDef GPIO_InitStructure ;

//启动SPI时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);

//下面是SPI相关GPIO初始化//

//SPI1模块对应的SCK、MISO、MOSI为AF引脚

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7 ;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz ;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP ;//复用模式

GPIO_Init(GPIOA,&GPIO_InitStructure);

//PA3 pin: CS

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3 ;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz ;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP ;

GPIO_Init(GPIOA,&GPIO_InitStructure);

//SPI模块配置//

//一开始SD初始化阶段,SPI时钟频率必须<400K

SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex ;

SPI_InitStructure.SPI_Mode=SPI_Mode_Master ;

SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b ;

SPI_InitStructure.SPI_CPOL=SPI_CPOL_High ;

SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge ;

SPI_InitStructure.SPI_NSS=SPI_NSS_Soft ; //软件控制

SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_256 ;

SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB ;

SPI_InitStructure.SPI_CRCPolynomial=7 ;

SPI_Init(SPI1,&SPI_InitStructure);

SPI_Cmd(SPI1,ENABLE);

// return 0 ;

}

/*******************************************************************************

* Function Name : SPI_SetSpeed

* Description : SPI设置速度为高速

* Input : u8 SpeedSet

* 如果速度设置输入0,则低速模式,非0则高速模式

* SPI_SPEED_HIGH 1

* SPI_SPEED_LOW 0

* Output : None

* Return : None

*******************************************************************************/

void SPI_SetSpeed(u8 SpeedSet)

{

SPI_InitTypeDef SPI_InitStructure ;

SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex ;

SPI_InitStructure.SPI_Mode=SPI_Mode_Master ;

SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b ;

SPI_InitStructure.SPI_CPOL=SPI_CPOL_High ;

SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge ;

SPI_InitStructure.SPI_NSS=SPI_NSS_Soft ;

//如果速度设置输入0,则低速模式,非0则高速模式

if(SpeedSet==SPI_SPEED_LOW)

{

SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_256 ;

}

else

{

SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_4;

}

//moon.mp3: 4707774 Byte size 目标文件 设为buffer[512]

//speed:实验测试数据,最大速度 392314 Byte/S,

//Prescaler_128, 59592 Byte/S

//Prescaler_64, 104617 Byte/S

//Prescaler_32, 168134 Byte/S 162337 Byte/S

//Prescaler_16, 261543 Byte/S 247777 Byte/S

//Prescaler_8, 313851 Byte/S 336269 Byte/S

//Prescaler_4, 392314 Byte/S 392314 Byte/S

//Prescaler_2, 392314 Byte/S

SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB ;

SPI_InitStructure.SPI_CRCPolynomial=7 ;

SPI_Init(SPI1,&SPI_InitStructure);

return ;

}

/*******************************************************************************

* Function Name : SPI_ReadWriteByte

* Description : SPI读写一个字节(发送完成后返回本次通讯读取的数据)

* Input : u8 TxData 待发送的数

* Output : None

* Return : u8 RxData 收到的数

*******************************************************************************/

u8 SPI_ReadWriteByte(u8 TxData)

{

u8 RxData=0 ;

//GPIO_WriteBit(GPIOC, GPIO_Pin_7, Bit_SET); //读文件闪烁

//等待发送缓冲区空

while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);

//发一个字节

SPI_I2S_SendData(SPI1,TxData);

//等待数据接收

while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET);

//取数据

RxData=SPI_I2S_ReceiveData(SPI1);

//GPIO_WriteBit(GPIOC, GPIO_Pin_7, Bit_RESET);

return RxData ;

}

/*******************************************************************************

* Function Name : SD_WaitReady

* Description : 等待SD卡Ready

* Input : None

* Output : None

* Return : u8

* 0: 成功

* other:失败

*******************************************************************************/

u8 SD_WaitReady(void)

{

u8 r1 ;

u16 retry ;

retry=0 ;

do

{

r1=SPI_ReadWriteByte(0xFF);

if(retry==0xfffe)//????如果卡异常,会死循坏!

{

return 1 ;

}

}

while(r1!=0xFF);

return 0 ;

}

/*******************************************************************************

* Function Name : SD_SendCommand

* Description : 向SD卡发送一个命令

* Input : u8 cmd 命令

* u32 arg 命令参数

* u8 crc crc校验值

* Output : None

* Return : u8 r1 SD卡返回的响应

*******************************************************************************/

u8 SD_SendCommand(u8 cmd,u32 arg,u8 crc)

{

unsigned char r1 ;

unsigned char Retry=0 ;

//????????

SPI_ReadWriteByte(0xff);

//片选端置低,选中SD卡

SD_CS_ENABLE();

//发送

SPI_ReadWriteByte(cmd|0x40);

//分别写入命令

SPI_ReadWriteByte(arg>>24);

SPI_ReadWriteByte(arg>>16);

SPI_ReadWriteByte(arg>>8);

SPI_ReadWriteByte(arg);

SPI_ReadWriteByte(crc);

//等待响应,或超时退出

while((r1=SPI_ReadWriteByte(0xFF))==0xFF)

{

Retry++;

if(Retry>200)

{

break ;

}

}

//关闭片选

SD_CS_DISABLE();

//在总线上额外增加8个时钟,让SD卡完成剩下的工作

SPI_ReadWriteByte(0xFF);

//返回状态值

return r1 ;

}

/*******************************************************************************

* Function Name : SD_SendCommand_NoDeassert

* Description : 向SD卡发送一个命令(结束是不失能片选,还有后续数据传来)

* Input : u8 cmd 命令

* u32 arg 命令参数

* u8 crc crc校验值

* Output : None

* Return : u8 r1 SD卡返回的响应

*******************************************************************************/

u8 SD_SendCommand_NoDeassert(u8 cmd,u32 arg,u8 crc)

{

unsigned char r1 ;

unsigned char Retry=0 ;

//????????

SPI_ReadWriteByte(0xff);

//片选端置低,选中SD卡

SD_CS_ENABLE();

//发送

SPI_ReadWriteByte(cmd|0x40);

//分别写入命令

SPI_ReadWriteByte(arg>>24);

SPI_ReadWriteByte(arg>>16);

SPI_ReadWriteByte(arg>>8);

SPI_ReadWriteByte(arg);

SPI_ReadWriteByte(crc);

//等待响应,或超时退出

while((r1=SPI_ReadWriteByte(0xFF))==0xFF)

{

Retry++;

if(Retry>200)

{

break ;

}

}

//返回响应值

return r1 ;

}

/*******************************************************************************

* Function Name : SD_Init

* Description : 初始化SD卡

* Input : None

* Output : None

* Return : u8

* 0:NO_ERR

* 1:TIME_OUT

* 99:NO_CARD

*******************************************************************************/

u8 SD_Init(void)

{

u16 i ;

// 用来循环计数

u8 r1 ;

// 存放SD卡的返回值

u16 retry ;

// 用来进行超时计数

u8 buff[6];

//如果没有检测到卡插入,直接退出,返回错误标志

#if 0

if(!SD_DET())

{

//return 99;

return STA_NODISK ;

// FatFS错误标志:没有插入磁盘

}

//SD卡上电

SD_PWR_ON();

// 纯延时,等待SD卡上电完成

for(i=0;i<0xf00;i++);

#endif

//先产生>74个脉冲,让SD卡自己初始化完成

for(i=0;i<10;i++)

{

SPI_ReadWriteByte(0xFF);

}

//-----------------SD卡复位到idle开始-----------------

//循环连续发送CMD0,直到SD卡返回0x01,进入IDLE状态

//超时则直接退出

retry=0 ;

do

{

//发送CMD0,让SD卡进入IDLE状态

r1=SD_SendCommand(CMD0,0,0x95);

retry++;

}

while((r1!=0x01)&&(retry<200));

//跳出循环后,检查原因:初始化成功?or 重试超时?

if(retry==200)

{

return 1 ;

//超时返回1

}

//-----------------SD卡复位到idle结束-----------------

//获取卡片的SD版本信息

r1=SD_SendCommand_NoDeassert(8,0x1aa,0x87);

//如果卡片版本信息是v1.0版本的,即r1=0x05,则进行以下初始化

if(r1==0x05)

{

//设置卡类型为SDV1.0,如果后面检测到为MMC卡,再修改为MMC

SD_Type=SD_TYPE_V1 ;

//如果是V1.0卡,CMD8指令后没有后续数据

//片选置高,结束本次命令

SD_CS_DISABLE();

//多发8个CLK,让SD结束后续操作

SPI_ReadWriteByte(0xFF);

//-----------------SD卡、MMC卡初始化开始-----------------

//发卡初始化指令CMD55+ACMD41

// 如果有应答,说明是SD卡,且初始化完成

// 没有回应,说明是MMC卡,额外进行相应初始化

retry=0 ;

do

{

//先发CMD55,应返回0x01;否则出错

r1=SD_SendCommand(CMD55,0,0);

if(r1!=0x01)

{

return r1 ;

}

//得到正确响应后,发ACMD41,应得到返回值0x00,否则重试200次

r1=SD_SendCommand(ACMD41,0,0);

retry++;

}

while((r1!=0x00)&&(retry<400));

// 判断是超时还是得到正确回应

// 若有回应:是SD卡;没有回应:是MMC卡

//----------MMC卡额外初始化操作开始------------

if(retry==400)

{

retry=0 ;

//发送MMC卡初始化命令(没有测试)

do

{

r1=SD_SendCommand(1,0,0);

retry++;

}

while((r1!=0x00)&&(retry<400));

if(retry==400)

{

return 1 ;

//MMC卡初始化超时

}

//写入卡类型

SD_Type=SD_TYPE_MMC ;

}

//----------MMC卡额外初始化操作结束------------

//设置SPI为高速模式

SPI_SetSpeed(1);

SPI_ReadWriteByte(0xFF);

//禁止CRC校验

/*

r1 = SD_SendCommand(CMD59, 0, 0x01);

if(r1 != 0x00)

{

return r1; //命令错误,返回r1

}

*/

//设置Sector Size

r1=SD_SendCommand(CMD16,512,0xff);

if(r1!=0x00)

{

return r1 ;

//命令错误,返回r1

}

//-----------------SD卡、MMC卡初始化结束-----------------

}

//SD卡为V1.0版本的初始化结束

//下面是V2.0卡的初始化

//其中需要读取OCR数据,判断是SD2.0还是SD2.0HC卡

else if(r1==0x01)

{

//V2.0的卡,CMD8命令后会传回4字节的数据,要跳过再结束本命令

buff[0]=SPI_ReadWriteByte(0xFF);

//should be 0x00

buff[1]=SPI_ReadWriteByte(0xFF);

//should be 0x00

buff[2]=SPI_ReadWriteByte(0xFF);

//should be 0x01

buff[3]=SPI_ReadWriteByte(0xFF);

//should be 0xAA

SD_CS_DISABLE();

//the next 8 clocks

SPI_ReadWriteByte(0xFF);

//判断该卡是否支持2.7V-3.6V的电压范围

if(buff[2]==0x01&&buff[3]==0xAA)

{

//支持电压范围,可以操作

retry=0 ;

//发卡初始化指令CMD55+ACMD41

do

{

r1=SD_SendCommand(CMD55,0,0);

if(r1!=0x01)

{

return r1 ;

}

r1=SD_SendCommand(ACMD41,0x40000000,0);

if(retry>200)

{

return r1 ;

//超时则返回r1状态

}

}

while(r1!=0);

//初始化指令发送完成,接下来获取OCR信息

//-----------鉴别SD2.0卡版本开始-----------

r1=SD_SendCommand_NoDeassert(CMD58,0,0);

if(r1!=0x00)

{

return r1 ;

//如果命令没有返回正确应答,直接退出,返回应答

}

//读OCR指令发出后,紧接着是4字节的OCR信息

buff[0]=SPI_ReadWriteByte(0xFF);

buff[1]=SPI_ReadWriteByte(0xFF);

buff[2]=SPI_ReadWriteByte(0xFF);

buff[3]=SPI_ReadWriteByte(0xFF);

//OCR接收完成,片选置高

SD_CS_DISABLE();

SPI_ReadWriteByte(0xFF);

//检查接收到的OCR中的bit30位(CCS),确定其为SD2.0还是SDHC

//如果CCS=1:SDHC CCS=0:SD2.0

//检查CCS

if(buff[0]&0x40)

{

SD_Type=SD_TYPE_V2HC ;

}

else

{

SD_Type=SD_TYPE_V2 ;

}

//-----------鉴别SD2.0卡版本结束-----------

//设置SPI为高速模式

SPI_SetSpeed(1);

}

}

return r1 ;

}

/*******************************************************************************

* Function Name : SD_ReceiveData

* Description : 从SD卡中读回指定长度的数据,放置在给定位置

* Input : u8 *data(存放读回数据的内存>len)

* u16 len(数据长度)

* u8 release(传输完成后是否释放总线CS置高 0:不释放 1:释放)

* Output : None

* Return : u8

* 0:NO_ERR

* other:错误信息

*******************************************************************************/

u8 SD_ReceiveData(u8*data,u16 len,u8 release)

{

u16 retry ;

u8 r1 ;

// 启动一次传输

SD_CS_ENABLE();

//等待SD卡发回数据起始令牌0xFE

retry=0 ;

do

{

r1=SPI_ReadWriteByte(0xFF);

retry++;

//2000次等待后没有应答,退出报错

if(retry>2000)

{

SD_CS_DISABLE();

return 1 ;

}

}

while(r1!=0xFE);

//开始接收数据

while(len--)

{

*data=SPI_ReadWriteByte(0xFF);

data++;

}

//下面是2个伪CRC(dummy CRC)

SPI_ReadWriteByte(0xFF);

SPI_ReadWriteByte(0xFF);

//按需释放总线,将CS置高

if(release==RELEASE)

{

//传输结束

SD_CS_DISABLE();

SPI_ReadWriteByte(0xFF);

}

return 0 ;

}

/*******************************************************************************

* Function Name : SD_GetCID

* Description : 获取SD卡的CID信息,包括制造商信息

* Input : u8 *cid_data(存放CID的内存,至少16Byte)

* Output : None

* Return : u8

* 0:NO_ERR

* 1:TIME_OUT

* other:错误信息

*******************************************************************************/

u8 SD_GetCID(u8*cid_data)

{

u8 r1 ;

//发CMD10命令,读CID

r1=SD_SendCommand(CMD10,0,0xFF);

if(r1!=0x00)

{

return r1 ;

//没返回正确应答,则退出,报错

}

//接收16个字节的数据

SD_ReceiveData(cid_data,16,RELEASE);

return 0 ;

}

/*******************************************************************************

* Function Name : SD_GetCSD

* Description : 获取SD卡的CSD信息,包括容量和速度信息

* Input : u8 *cid_data(存放CID的内存,至少16Byte)

* Output : None

* Return : u8

* 0:NO_ERR

* 1:TIME_OUT

* other:错误信息

*******************************************************************************/

u8 SD_GetCSD(u8 *csd_data)

{

u8 r1 ;

//发CMD9命令,读CSD

r1=SD_SendCommand(CMD9,0,0xFF);

if(r1!=0x00)

{

return r1 ;

//没返回正确应答,则退出,报错

}

//接收16个字节的数据

SD_ReceiveData(csd_data,16,RELEASE);

return 0 ;

}

/*******************************************************************************

* Function Name : SD_GetCapacity

* Description : 获取SD卡的容量

* Input : None

* Output : None

* Return : u32 capacity

* 0: 取容量出错

*******************************************************************************/

u32 SD_GetCapacity(void)

{

u8 csd[16];

u32 Capacity ;

u8 r1 ;

u16 i ;

u16 temp ;

//取CSD信息,如果期间出错,返回0

if(SD_GetCSD(csd)!=0)

{

return 0 ;

}

//如果为SDHC卡,按照下面方式计算

if((csd[0]&0xC0)==0x40)

{

Capacity=(((u32)csd[8])<<8+(u32)csd[9]+1)*(u32)1024 ;

}

else

{

//下面代码为网上版本

formula of the capacity///

//

// memory capacity = BLOCKNR * BLOCK_LEN

//

//    BLOCKNR = (C_SIZE + 1)* MULT

//

// C_SIZE_MULT+2

//    MULT = 2

//

// READ_BL_LEN

//    BLOCK_LEN = 2

/**********************************************/

//C_SIZE

i=csd[6]&0x03 ;

i<<=8 ;

i+=csd[7];

i<<=2 ;

i+=((csd[8]&0xc0)>>6);

//C_SIZE_MULT

r1=csd[9]&0x03 ;

r1<<=1 ;

r1+=((csd[10]&0x80)>>7);

//BLOCKNR

r1+=2 ;

temp=1 ;

while(r1)

{

temp*=2 ;

r1--;

}

Capacity=((u32)(i+1))*((u32)temp);

// READ_BL_LEN

i=csd[5]&0x0f ;

//BLOCK_LEN

temp=1 ;

while(i)

{

temp*=2 ;

i--;

}

//The final result

Capacity*=(u32)temp ;

//Capacity /= 512;

}

return (u32)Capacity ;

}

/*******************************************************************************

* Function Name : SD_ReadSingleBlock

* Description : 读SD卡的一个block

* Input : u32 sector 取地址(sector值,非物理地址)

* u8 *buffer 数据存储地址(大小至少512byte)

* Output : None

* Return : u8 r1

* 0: 成功

* other:失败

*******************************************************************************/

u8 SD_ReadSingleBlock(u32 sector,u8*buffer)

{

u8 r1 ;

//设置为高速模式

SPI_SetSpeed(SPI_SPEED_HIGH);

//如果不是SDHC,将sector地址转成byte地址

sector=sector<<9 ;

r1=SD_SendCommand(CMD17,sector,0);

//读命令

if(r1!=0x00)

{

return r1 ;

}

r1=SD_ReceiveData(buffer,512,RELEASE);

if(r1!=0)

{

return r1 ;

//读数据出错!

}

else

{

return 0 ;

}

}

/*******************************************************************************

* Function Name : SD_WriteSingleBlock

* Description : 写入SD卡的一个block

* Input : u32 sector 扇区地址(sector值,非物理地址)

* u8 *buffer 数据存储地址(大小至少512byte)

* Output : None

* Return : u8 r1

* 0: 成功

* other:失败

*******************************************************************************/

u8 SD_WriteSingleBlock(u32 sector,const u8 *data)

{

u8 r1 ;

u16 i ;

u16 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个Byte的dummy CRC

SPI_ReadWriteByte(0xff);

SPI_ReadWriteByte(0xff);

//等待SD卡应答

r1=SPI_ReadWriteByte(0xff);

if((r1&0x1F)!=0x05)

{

SD_CS_DISABLE();

return r1 ;

}

//等待操作完成

retry=0 ;

while(!SPI_ReadWriteByte(0xff))

{

retry++;

//如果长时间写入没有完成,报错退出

if(retry>0xfffe)

{

SD_CS_DISABLE();

return 1 ;

//写入超时返回1

}

}

//写入完成,片选置1

SD_CS_DISABLE();

SPI_ReadWriteByte(0xff);

return 0 ;

}

/*******************************************************************************

* Function Name : SD_ReadMultiBlock

* Description : 读SD卡的多个block

* Input : u32 sector 取地址(sector值,非物理地址)

* u8 *buffer 数据存储地址(大小至少512byte)

* u8 count 连续读count个block

* Output : None

* Return : u8 r1

* 0: 成功

* other:失败

*******************************************************************************/

u8 SD_ReadMultiBlock(u32 sector,u8 *buffer,u8 count)

{

u8 r1 ;

//设置为高速模式

SPI_SetSpeed(SPI_SPEED_HIGH);

//如果不是SDHC,将sector地址转成byte地址

sector=sector<<9 ;

//SD_WaitReady();

//发读多块命令

r1=SD_SendCommand(CMD18,sector,0);

//读命令

if(r1!=0x00)

{

return r1 ;

}

//开始接收数据

do

{

if(SD_ReceiveData(buffer,512,NO_RELEASE)!=0x00)

{

break ;

}

buffer+=512 ;

}

while(--count);

//全部传输完毕,发送停止命令

SD_SendCommand(CMD12,0,0);

//释放总线

SD_CS_DISABLE();

SPI_ReadWriteByte(0xFF);

if(count!=0)

{

return count ;

//如果没有传完,返回剩余个数

}

else

{

return 0 ;

}

}

/*******************************************************************************

* Function Name : SD_WriteMultiBlock

* Description : 写入SD卡的N个block

* Input : u32 sector 扇区地址(sector值,非物理地址)

* u8 *buffer 数据存储地址(大小至少512byte)

* u8 count 写入的block数目

* Output : None

* Return : u8 r1

* 0: 成功

* other:失败

*******************************************************************************/

u8 SD_WriteMultiBlock(u32 sector,const u8*data,u8 count)

{

u8 r1 ;

u16 i ;

//设置为高速模式

SPI_SetSpeed(SPI_SPEED_HIGH);

//如果不是SDHC,给定的是sector地址,将其转换成byte地址

if(SD_Type!=SD_TYPE_V2HC)

{

sector=sector<<9 ;

}

//如果目标卡不是MMC卡,启用ACMD23指令使能预擦除

if(SD_Type!=SD_TYPE_MMC)

{

r1=SD_SendCommand(ACMD23,count,0x00);

}

//发多块写入指令

r1=SD_SendCommand(CMD25,sector,0x00);

if(r1!=0x00)

{

return r1 ;

//应答不正确,直接返回

}

//开始准备数据传输

SD_CS_ENABLE();

//先放3个空数据,等待SD卡准备好

SPI_ReadWriteByte(0xff);

SPI_ReadWriteByte(0xff);

//--------下面是N个sector写入的循环部分

do

{

//放起始令牌0xFC 表明是多块写入

SPI_ReadWriteByte(0xFC);

//放一个sector的数据

for(i=0;i<512;i++)

{

SPI_ReadWriteByte(*data++);

}

//发2个Byte的dummy CRC

SPI_ReadWriteByte(0xff);

SPI_ReadWriteByte(0xff);

//等待SD卡应答

r1=SPI_ReadWriteByte(0xff);

if((r1&0x1F)!=0x05)

{

SD_CS_DISABLE();

//如果应答为报错,则带错误代码直接退出

return r1 ;

}

//等待SD卡写入完成

if(SD_WaitReady()==1)

{

SD_CS_DISABLE();

//等待SD卡写入完成超时,直接退出报错

return 1 ;

}

//本sector数据传输完成

}

while(--count);

//发结束传输令牌0xFD

r1=SPI_ReadWriteByte(0xFD);

if(r1==0x00)

{

count=0xfe ;

}

if(SD_WaitReady())

{

while(1){}

}

//写入完成,片选置1

SD_CS_DISABLE();

SPI_ReadWriteByte(0xff);

return count ;

//返回count值,如果写完则count=0,否则count=1

}

#if 0

u8 SD_GPIO_SPI_Init(void)

{

u16 i = 0;

u8 response = 0;

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//SPI1 管脚

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); //时钟使能

//设置 SCK MOSI 模式

GPIO_InitStructure.GPIO_Pin = SPI1_PIN_SCK | SPI1_PIN_MOSI;    // SCK MOSI 输出模式

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用功能

GPIO_Init(SPI1_GPIO, &GPIO_InitStructure);    //初始化 SCK MOSI 管脚

GPIO_InitStructure.GPIO_Pin = SPI1_PIN_MISO;//MISO 输入模式

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入

GPIO_Init(SPI1_GPIO, &GPIO_InitStructure); //初始化 MISO 管脚

GPIO_InitStructure.GPIO_Pin = SD_CS_Pin;//CS输出模式

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推拉输出

GPIO_Init(SD_CS_GPIO, &GPIO_InitStructure); //初始化 SD_CS 管脚

//

SD_SPI_Low_Speed();//低速启动

for(i = 0; i < 10; ++i)    //需要74个周期, 我们提供了80个周期

{

SD_SPI_Write_Byte(0xff);

}

SD_SPI_SELECT();/* address card 片选 SD*/

for(i = 0; ; ++i)//复位SD卡

{

response = SD_Send_Command(CMD_GO_IDLE_STATE, 0 );

if(response == 0x01)

break;

if(i == 0x1ff) //复位次数到,返回1

{

SD_SPI_DESELECT();

return 1;

}

}

for(i = 0; ; ++i) //等待SD准备好

{

response = SD_Send_Command(CMD_SEND_OP_COND, 0);

if(!(response & (1 << R1_IDLE_STATE)))

break;

if(i == 0x7fff)

{

SD_SPI_DESELECT();

return 1;

}

}

if(SD_Send_Command(CMD_SET_BLOCKLEN, 512))//设置块大小512字节

{

SD_SPI_DESELECT();

return 1;

}

SD_SPI_DESELECT(); //片选 取消

// SD_MMC_High_Speed();//转换到高速模式

SD_SPI_High_Speed();

return 0;

}

void SD_SPI_Low_Speed(void)

{

SPI_InitTypeDef SPI_InitStructure;

/* SPI1 configuration */

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //全双工模式

SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //配置为主机

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8位数据帧

SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;    //空闲时 为低电平

SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //数据在第二个边沿捕获

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //内部NSS信号由SSI控制

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//预分频256

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //高位在前

SPI_InitStructure.SPI_CRCPolynomial = 7; //用于计算CRC

SPI_Init(SPI1, &SPI_InitStructure);    //初始化 SPI1

/* SPI1 enable */

SPI_Cmd(SPI1, ENABLE);

}

void SD_SPI_High_Speed(void)

{

SPI_InitTypeDef SPI_InitStructure;

/* SPI1 configuration */

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;

SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;//预分频

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

SPI_InitStructure.SPI_CRCPolynomial = 7;

SPI_Init(SPI1, &SPI_InitStructure);

/* SPI1 enable */

SPI_Cmd(SPI1, ENABLE);

}

void SD_SPI_Write_Byte(u8 byte)//主设备 写数据到 从设备

{

while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(SPI1, byte);

//每次发送数据时,收到的数据时没有用的话要舍弃,但是要清除RXNE位

while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);

SPI_I2S_ReceiveData(SPI1);

}

//主设备 读取数据 from 从设备

u8 SD_SPI_Read_Byte(void)

{

//每次要收取数据时,先要发送一个字节,主要是输出时钟

while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(SPI1, 0xff);

while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);

return SPI_I2S_ReceiveData(SPI1);

}

/* 读写一起

u8 SPI_Send_Byte(u8 byte)

{

while(SPI_GetFlagStatus(SPI2, SPI_FLAG_TXE) == RESET);

SPI_SendData(SPI2, byte);

while(SPI_GetFlagStatus(SPI2, SPI_FLAG_RXNE) == RESET);

return SPI_ReceiveData(SPI2);

}

*/

u8 SD_Send_Command(u8 cmd, u32 arg)

{

u8 Response;

u8 Retry = 0;

SD_SPI_Write_Byte(0xff);

SD_SPI_SELECT();

//分别写入命令

SD_SPI_Write_Byte(cmd | 0x40);

SD_SPI_Write_Byte(arg >> 24);

SD_SPI_Write_Byte(arg >> 16);

SD_SPI_Write_Byte(arg >> 8);

SD_SPI_Write_Byte(arg);

SD_SPI_Write_Byte(0x95);

do{

// 等待响应,响应的开始位为0

Response = SD_SPI_Read_Byte();

Retry++;

}while( ((Response&0x80)!=0) && (Retry < 200) );

SD_SPI_DESELECT();

return Response; //返回状态值

}

u8 SD_Read_Single_Block(u32 sector, u8* buffer)

{

u8 Response;

u16 i;

u16 Retry = 0;

//读命令 send read command

Response = SD_Send_Command(CMD_READ_SINGLE_BLOCK, sector<<9);

if(Response != 0x00)

return Response;

SD_SPI_SELECT();

// start byte 0xfe

while(SD_SPI_Read_Byte() != 0xfe)

{

if(++Retry > 0xfffe)

{

SD_SPI_DESELECT();

return 1; //timeout

}

}

for(i = 0; i < 512; ++i)

{

//读512个数据

*buffer++ = SD_SPI_Read_Byte();

}

// SD_MMC_ReadWrite_Byte(0xff); //伪crc

// SD_MMC_ReadWrite_Byte(0xff); //伪crc

SD_SPI_Write_Byte(0xff);

SD_SPI_Write_Byte(0xff);

SD_SPI_DESELECT();

// SD_MMC_ReadWrite_Byte(0xff); // extra 8 CLK

SD_SPI_Write_Byte(0xff);

return 0;

}

u8 SD_Write_Single_Block(u32 sector, u8* buffer)

{

u8 Response;

u16 i;

u16 retry=0;

//写命令 send write command

Response = SD_Send_Command(CMD_WRITE_SINGLE_BLOCK, sector<<9);

if(Response != 0x00)

return Response;

SD_SPI_SELECT();

SD_SPI_Write_Byte(0xff);

SD_SPI_Write_Byte(0xff);

SD_SPI_Write_Byte(0xff);

//发开始符    start byte 0xfe

SD_SPI_Write_Byte(0xfe);

//送512字节数据    send 512 bytes data

for(i=0; i<512; i++)

{

SD_SPI_Write_Byte(*buffer++);

}

SD_SPI_Write_Byte(0xff); //dummy crc

SD_SPI_Write_Byte(0xff); //dummy crc

Response = SD_SPI_Read_Byte();

//等待是否成功    judge if it successful

if( (Response&0x1f) != 0x05)

{

SD_SPI_DESELECT();

return Response;

}

//等待操作完 wait no busy

while(SD_SPI_Read_Byte() != 0x00)

{

if(retry++ > 0xfffe)

{

SD_SPI_DESELECT();

return 1;

}

}

SD_SPI_DESELECT();

SD_SPI_Write_Byte(0xff);// extra 8 CLK

return 0;

}

#endif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于计算机专业的学生而言,参加各类比赛能够带来多方面的益处,具体包括但不限于以下几点: 技能提升: 参与比赛促使学生深入学习和掌握计算机领域的专业知识与技能,如编程语言、算法设计、软件工程、网络安全等。 比赛通常涉及实际问题的解决,有助于将理论知识应用于实践中,增强问题解决能力。 实践经验: 大多数比赛都要求参赛者设计并实现解决方案,这提供了宝贵的动手操作机会,有助于积累项目经验。 实践经验对于计算机专业的学生尤为重要,因为雇主往往更青睐有实际项目背景的候选人。 团队合作: 许多比赛鼓励团队协作,这有助于培养学生的团队精神、沟通技巧和领导能力。 团队合作还能促进学生之间的知识共享和思维碰撞,有助于形成更全面的解决方案。 职业发展: 获奖经历可以显著增强简历的吸引力,为求职或继续深造提供有力支持。 某些比赛可能直接与企业合作,提供实习、工作机会或奖学金,为学生的职业生涯打开更多门路。 网络拓展: 比赛是结识同行业人才的好机会,可以帮助学生建立行业联系,这对于未来的职业发展非常重要。 奖金与荣誉: 许多比赛提供奖金或奖品,这不仅能给予学生经济上的奖励,还能增强其成就感和自信心。 荣誉证书或奖状可以证明学生的成就,对个人品牌建设有积极作用。 创新与研究: 参加比赛可以激发学生的创新思维,推动科研项目的开展,有时甚至能促成学术论文的发表。 个人成长: 在准备和参加比赛的过程中,学生将面临压力与挑战,这有助于培养良好的心理素质和抗压能力。 自我挑战和克服困难的经历对个人成长有着深远的影响。 综上所述,参加计算机领域的比赛对于学生来说是一个全面发展的平台,不仅可以提升专业技能,还能增强团队协作、沟通、解决问题的能力,并为未来的职业生涯奠定坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值