|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2011-11-22 00:31:24
|
显示全部楼层
终于搞定!关键还是先要搞清SPI通信过程,写读同时进行,读也是通过写操作。特别是几种类型,马老师书11章说的很清楚。对于M051,时序和时钟类型属于M051的SPI类型5:下降传输,上升采样/锁定以及时钟高:空闲
经硬件运行通过的SPI初始化SD/MMC卡程序如下:
/////////////////////////////////////////////////////
//SPI初始化
void Sd_spi_on(void)
{
DrvGPIO_InitFunction (E_FUNC_SPI0);//指定SPI功能,相关几个引脚就不要再GPIO设定
DrvSPI_Open(eDRVSPI_PORT0, eDRVSPI_MASTER, eDRVSPI_TYPE5, 32);//开启SPI,注意SD卡对应模式5
DrvSPI_SetEndian(eDRVSPI_PORT0, eDRVSPI_MSB_FIRST);//大头朝前
DrvSPI_DisableAutoSS(eDRVSPI_PORT0);//不用自动SS选择
DrvSPI_SetSlaveSelectActiveLevel(eDRVSPI_PORT0, eDRVSPI_ACTIVE_LOW_FALLING);//选SD是下降沿低电平有效
}
//按字节读SD
uint8_t Sd_spi_read() //读就是一边发送0XFF一边把数据从SD卡逼出来
{
uint32_t rxbuff=0; //接收缓冲器
uint32_t txdata=0xff; //发送器
uint8_t reback; //8bit读出数据
DrvSPI_SetBitLength(eDRVSPI_PORT0, 8);//每次发送8bit
DrvSPI_SingleWrite(eDRVSPI_PORT0, &txdata);//发0XFF
while (DrvSPI_IsBusy(eDRVSPI_PORT0)); //等待发完
DrvSPI_DumpRxRegister(eDRVSPI_PORT0, &rxbuff, 1);//收到的数据存入缓冲
reback=rxbuff; //取最低8位
return reback;
}
//读SD卡应答:初始化过程需要反复读卡,直到应答0X01或0X00
uint8_t Sd_spi_response()
{
uint8_t i=0;
uint8_t response;
while(i<10) //一般在10次以内连续读,可以得到应答
{
response=Sd_spi_read();
if(response==0)
break;
if(response==1)
break;
i++;
}
return response;
}
//SD卡命令:是6字节命令,8位命令码,32位参数,8位校验码,8位单片机一次只能传8位,M051一次32位就很方便啦
void Sd_spi_command(uint8_t command, uint32_t argument, uint8_t CRC)
{
uint32_t tmp1=command|0x40; //命令号和0X40位或得到命令码
uint32_t tmp2=argument; //存放32位参数
uint32_t tmp3=CRC; //校验码
DrvSPI_SetBitLength(eDRVSPI_PORT0, 8);
DrvSPI_SingleWrite(eDRVSPI_PORT0, &tmp1); //发送8位命令码
while(DrvSPI_IsBusy(eDRVSPI_PORT0) );
DrvSPI_SetBitLength(eDRVSPI_PORT0, 32);
DrvSPI_SingleWrite(eDRVSPI_PORT0, &tmp2); //发送32位参数
while(DrvSPI_IsBusy(eDRVSPI_PORT0) );
DrvSPI_SetBitLength(eDRVSPI_PORT0, 8);
DrvSPI_SingleWrite(eDRVSPI_PORT0, &tmp3); //发送8位校验码
while(DrvSPI_IsBusy(eDRVSPI_PORT0) );
}
//SD初始化,和MMC卡兼容需要先在SS失能时连续发74个时钟,然后SS使能发送命令0,等返回0X01后发送命令1,等返回0X00完成初始化
void Sd_spi_Init(void)
{
uint32_t i ,u32tmp,u32tmp1=0xff;
uint8_t response;
Sd_spi_on(); //设置SPI
DrvSPI_ClrSS(eDRVSPI_PORT0);//SS失能(高)
DrvSPI_SetBitLength(eDRVSPI_PORT0, 32);//一次发送32位,
DrvSPI_SetClockFreq(eDRVSPI_PORT0, 400000, 0);//初始化SPI频率取低
u32tmp=0xffffffff;
for(i=0;i<3;i++)
{
DrvSPI_SingleWrite(eDRVSPI_PORT0, &u32tmp);//发送
while(DrvSPI_IsBusy(eDRVSPI_PORT0) ); //
}
DrvSPI_SetSS(eDRVSPI_PORT0); //SS使能
do{
Sd_spi_command(0, 0, 0X95); //命令0
response=Sd_spi_response();
}while(response!=0x01); //返回01复位成功如无返回0X01就多发几次命令0
DrvSPI_ClrSS(eDRVSPI_PORT0);
DrvSPI_SingleWrite(eDRVSPI_PORT0, &u32tmp1); //SS失能时加发8个时钟
while(DrvSPI_IsBusy(eDRVSPI_PORT0)); //
DrvSPI_SetSS(eDRVSPI_PORT0); //SS使能
do{
Sd_spi_command(1, 0, 0Xff); //命令1
response=Sd_spi_response();
}while(response !=0x00); //返回0,SD卡已经初始化成功
DrvSPI_ClrSS(eDRVSPI_PORT0);
DrvSPI_SingleWrite(eDRVSPI_PORT0, &u32tmp1); //SS失能时加发8个时钟,巩固战果
while(DrvSPI_IsBusy(eDRVSPI_PORT0));
DrvSPI_SetClockFreq(eDRVSPI_PORT0, 10000000, 0); //SPI频率提高到10MHZ
}
这样,初始化就完成了。全部使用M051的标准库函数 |
|