您的位置:首页 > 其它

STM32开发板入门教程(十三) - SPI模式读写SD卡

2012-04-25 00:00 681 查看
功能介绍 :使用SPI模式 读写SD卡block数据 可通过串口发送到PC机查看
SD卡是Secure Digital Card卡的简称,直译成汉语就是“安全数字卡”,是由日本松下公司、东芝公司和美国SANDISK公司共同开发研制的全新的存储卡产品。SD存储卡是一个完全开放的标准(系统),多用于MP3、数码摄像机、数码相机、电子图书、AV器材等等,尤其是被广泛应用在超薄数码相机上。呵呵 现在偶们做东西也喜欢用sd卡了 为啥? 容量大啊 价格便宜啊 读写次数100000次以上(也有资料说是300000次 呵呵) 这个次数够猛了啊
读写的速度也很快 现在高速的SD卡写速度可以达到20M/S 呵呵 如果你买的SD卡达不到这个速度 就应该考虑一下是不是买到假货了 呵呵 现在SD卡都是白菜价了啊 貌似4G的也就50块钱一个啦

嗯 不扯远了 继续正题 SD卡读写有2种方式 一种是SD模式 一种是SPI模式 SD模式操作时序复杂 使用的IO口也多 呵呵 常用的一般是SPI模式 我们今天介绍的也是SPI模式 接口简单 移植也方便 速度也不慢了啊 使用高速的SPI模式 1M/S应该是很容易达到的 刚刚把STM32下的SD卡读写移植好 也没测试读写速度 呵呵 下回有时间把读写速度测试了发上来 呵呵

SD卡初始化过程:

1. 初始化STM32的SPI接口 使用低速模式

2. 延时至少74clock

3. 发送CMD0,需要返回0x01,进入Idle状态

4. 循环发送CMD55+ACMD41,直到返回0x00,进入Ready状态

5. 设置读写block大小为512byte

5. 把STM32的SPI设置为高速模式

读一个block块的过程

1. 发送CMD17(单块)或CMD18(多块)读命令,返回0x00

2. 接收数据开始令牌0xfe + 正式数据512Bytes + CRC 校验2Bytes

写一个block块的过程

1. 发送CMD24(单块)或CMD25(多块)写命令,返回0x00

2. 发送数据开始令牌0xfe + 正式数据512Bytes + CRC校验2Bytes

附上一个datasheet上的标准 spi mode initialization flow



初始化函数

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

* Function Name : SD_MMC_SPI_Init

* Description : SD_MMC_SPI_Init

* Input : None

* Output : None

* Return : zero init success, non-zero init error

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

u8 SD_MMC_SPI_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

/* Enable SPI1 and GPIO clocks */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA |

RCC_APB2Periph_SD_MMC_SPI_CS, ENABLE);

/* Configure SPI1 pins: SCK, MISO and MOSI */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Configure SD_MMC_SPI_CS */

GPIO_InitStructure.GPIO_Pin = SD_MMC_SPI_CS_Pin_CS;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(SD_MMC_SPI_CS, &GPIO_InitStructure);

////////////////////////////////////////////////////////////////////////////////////////////////

/* initialize SPI with lowest frequency */

SD_MMC_Low_Speed();

/* card needs 74 cycles minimum to start up */

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

{

/* wait 8 clock cycles */

SD_MMC_ReadWrite_Byte(0x00);

}

/* address card */

SD_MMC_SPI_SELECT();

/* reset card */

u8 response;

for(u16 i = 0; ; ++i)

{

response = SD_MMC_Send_Command(CMD_GO_IDLE_STATE , 0 );

if( response == 0x01 )

break;

if(i == 0x1ff)

{

SD_MMC_SPI_DESELECT();

return 1;

}

}

/* wait for card to get ready */

for(u16 i = 0; ; ++i)

{

response = SD_MMC_Send_Command(CMD_SEND_OP_COND, 0);

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

break;

if(i == 0x7fff)

{

SD_MMC_SPI_DESELECT();

return 1;

}

}

/* set block size to 512 bytes */

if(SD_MMC_Send_Command(CMD_SET_BLOCKLEN, 512))

{

SD_MMC_SPI_DESELECT();

return 1;

}

/* deaddress card */

SD_MMC_SPI_DESELECT();

/* switch to highest SPI frequency possible */

SD_MMC_High_Speed();

return 0;

}
发送一个命令

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

* Function Name : SD_MMC_Send_Command

* Description : SD_MMC_Send_Command

* Input : None

* Output : None

* Return : None

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

u8 SD_MMC_Send_Command(u8 cmd, u32 arg)

{

u8 Response;

u8 Retry = 0;

SD_MMC_ReadWrite_Byte(0xff);

SD_MMC_SPI_SELECT();

//分别写入命令

SD_MMC_ReadWrite_Byte(cmd | 0x40);

SD_MMC_ReadWrite_Byte(arg >> 24);

SD_MMC_ReadWrite_Byte(arg >> 16);

SD_MMC_ReadWrite_Byte(arg >> 8);

SD_MMC_ReadWrite_Byte(arg);

SD_MMC_ReadWrite_Byte(0x95);

do{

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

Response = SD_MMC_ReadWrite_Byte(0xff);

Retry++;

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

SD_MMC_SPI_DESELECT();

return Response; //返回状态值

}

读一个block块 读取成功返回0 非0 则读取失败

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

* Function Name : SD_MMC_Read_Single_Block

* Description : SD_MMC_Read_Single_Block

* Input : sector number and buffer data point

* Output : None

* Return : zero success, non-zero error

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

u8 SD_MMC_Read_Single_Block(u32 sector, u8* buffer)

{

u8 Response;

u16 i;

u16 Retry = 0;

//读命令 send read command

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

if(Response != 0x00)

return Response;

SD_MMC_SPI_SELECT();

// start byte 0xfe

while(SD_MMC_ReadWrite_Byte(0xff) != 0xfe)

{

if(++Retry > 0xfffe)

{

SD_MMC_SPI_DESELECT();

return 1; //timeout

}

}

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

{

//读512个数据

*buffer++ = SD_MMC_ReadWrite_Byte(0xff);

}

SD_MMC_ReadWrite_Byte(0xff); //伪crc

SD_MMC_ReadWrite_Byte(0xff); //伪crc

SD_MMC_SPI_DESELECT();

SD_MMC_ReadWrite_Byte(0xff); // extra 8 CLK

return 0;

}

写一个block块 成功返回0 非0 则写入失败

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

* Function Name : SD_MMC_Write_Single_Block

* Description : SD_MMC_Write_Single_Block

* Input : sector number and buffer data point

* Output : None

* Return : zero success, non-zero error.

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

u8 SD_MMC_Write_Single_Block(u32 sector, u8* buffer)

{

u8 Response;

u16 i;

u16 retry=0;

//写命令 send write command

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

if(Response != 0x00)

return Response;

SD_MMC_SPI_SELECT();

SD_MMC_ReadWrite_Byte(0xff);

SD_MMC_ReadWrite_Byte(0xff);

SD_MMC_ReadWrite_Byte(0xff);

//发开始符 start byte 0xfe

SD_MMC_ReadWrite_Byte(0xfe);

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

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

{

SD_MMC_ReadWrite_Byte(*buffer++);

}

SD_MMC_ReadWrite_Byte(0xff); //dummy crc

SD_MMC_ReadWrite_Byte(0xff); //dummy crc

Response = SD_MMC_ReadWrite_Byte(0xff);

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

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

{

SD_MMC_SPI_DESELECT();

return Response;

}

//等待操作完 wait no busy

while(SD_MMC_ReadWrite_Byte(0xff) != 0x00)

{

if(retry++ > 0xfffe)

{

SD_MMC_SPI_DESELECT();

return 1;

}

}

SD_MMC_SPI_DESELECT();

SD_MMC_ReadWrite_Byte(0xff);// extra 8 CLK

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: