新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > STM32之SD卡驱动

STM32之SD卡驱动

作者: 时间:2016-11-26 来源:网络 收藏
44.3软件设计
打开上一章的工程,首先在HARDWARE文件夹下新建一个SD的文件夹。然后新建一个MMC_SD.C和MMC_SD.H的文件保存在SD文件夹下,并将这个文件夹加入头文件包含路径。
打开MMC_SD.C文件,在该文件里面,我们输入与SD卡相关的操作代码,这里由于篇幅限制,我们不贴出所有代码,仅介绍两个最重要的函数,第一个是SD_Initialize函数,该函数源码如下:
//初始化SD卡
u8 SD_Initialize(void)
{
u8 r1;//存放SD卡的返回值
u16 retry;//用来进行超时计数
u8 buf[4];
u16 i;
SD_SPI_Init();//初始化IO
SD_SPI_SpeedLow();//设置到低速模式
for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XFF);//发送最少74个脉冲
retry=20;
do
{
r1=SD_SendCmd(CMD0,0,0x95);//进入IDLE状态
}while((r1!=0X01) && retry--);
SD_Type=0;//默认无卡
if(r1==0X01)
{
if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
{
for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//得到R7相应值
if(buf[2]==0X01&&buf[3]==0XAA)//卡是否支持2.7~3.6V
{
retry=0XFFFE;
do
{
SD_SendCmd(CMD55,0,0X01);//发送CMD55
r1=SD_SendCmd(CMD41,0x40000000,0X01);//发送CMD41
}while(r1&&retry--);
if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始
{
for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//得到OCR值
if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;//检查CCS
else SD_Type=SD_TYPE_V2;
}
}
}else//SD V1.x/ MMCV3
{
SD_SendCmd(CMD55,0,0X01);//发送CMD55
r1=SD_SendCmd(CMD41,0,0X01);//发送CMD41
if(r1<=1)
{
SD_Type=SD_TYPE_V1;
retry=0XFFFE;
do //等待退出IDLE模式
{
SD_SendCmd(CMD55,0,0X01);//发送CMD55
r1=SD_SendCmd(CMD41,0,0X01);//发送CMD41
}while(r1&&retry--);
}else//MMC卡不支持CMD55+CMD41识别
{
SD_Type=SD_TYPE_MMC;//MMC V3
retry=0XFFFE;
do //等待退出IDLE模式
{
r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1
}while(r1&&retry--);
}
if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;
//错误的卡
}
}
SD_DisSelect();//取消片选
SD_SPI_SpeedHigh();//高速
if(SD_Type)return 0;
else if(r1)return r1;
return 0xaa;//其他错误
}
该函数先设置与SD相关的IO口及SPI初始化,然后发送CMD0,进入IDLE状态,并设置SD卡为SPI模式通信,然后判断SD卡类型,完成SD卡的初始化,注意该函数调用的SD_SPI_Init等函数,实际是对SPI2的相关函数进行了一层封装,方便移植。另外一个要介绍的函数是SD_ReadDisk,该函数用于从SD卡读取一个扇区的数据(这里一般为512字节),该函数代码如下:
//读SD卡
//buf:数据缓存区
//sector:扇区
//cnt:扇区数
//返回值:0,ok;其他,失败.
u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
{
u8 r1;
if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;//转换为字节地址
if(cnt==1)
{
r1=SD_SendCmd(CMD17,sector,0X01);//读命令
if(r1==0) r1=SD_RecvData(buf,512);//命令发送成功,接收512个字节
}else
{
r1=SD_SendCmd(CMD18,sector,0X01);//连续读命令
do
{
r1=SD_RecvData(buf,512);//接收512个字节
buf+=512;
}while(--cnt && r1==0);
SD_SendCmd(CMD12,0,0X01);//发送停止命令
}
SD_DisSelect();//取消片选
return r1;//
}
此函数先发送CMD17命令,然后读取一个扇区的数据,详细见代码,这里我们就不多介绍了。保存MMC_SD.C文件,并加入到HARDWARE组下,然后打开MMC_SD.H,在该文件里面输入如下代码:
#ifndef _MMC_SD_H_
#define _MMC_SD_H_
#include "sys.h"
#include
// SD卡类型定义
#define SD_TYPE_ERR0X00
#define SD_TYPE_MMC0X01
#define SD_TYPE_V10X02
#define SD_TYPE_V20X04
#define SD_TYPE_V2HC0X06
// SD卡指令表
#define CMD00//卡复位
#define CMD11
#define CMD88//命令8,SEND_IF_COND
#define CMD99//命令9,读CSD数据
#define CMD1010//命令10,读CID数据
#define CMD1212//命令12,停止数据传输
#define CMD1616//命令16,设置SectorSize应返回0x00
#define CMD1717//命令17,读sector
#define CMD1818//命令18,读Multi sector
#define CMD2323//命令23,设置多sector写入前预先擦除N个block
#define CMD2424//命令24,写sector
#define CMD2525//命令25,写Multi sector
#define CMD4141//命令41,应返回0x00
#define CMD5555//命令55,应返回0x01
#define CMD5858//命令58,读OCR信息
#define CMD5959//命令59,使能/禁止CRC,应返回0x00
//数据写入回应字意义
#define MSD_DATA_OK0x05
#define MSD_DATA_CRC_ERROR0x0B
#define MSD_DATA_WRITE_ERROR0x0D
#define MSD_DATA_OTHER_ERROR0xFF
//SD卡回应标记字
#define MSD_RESPONSE_NO_ERROR0x00
#define MSD_IN_IDLE_STATE0x01
#define MSD_ERASE_RESET0x02
#define MSD_ILLEGAL_COMMAND0x04
#define MSD_COM_CRC_ERROR0x08
#define MSD_ERASE_SEQUENCE_ERROR0x10
#define MSD_ADDRESS_ERROR0x20
#define MSD_PARAMETER_ERROR0x40
#define MSD_RESPONSE_FAILURE0xFF
//这部分应根据具体的连线来修改!
//战舰STM32开发板使用的是PD2作为SD卡的CS脚.
#defineSD_CSPDout(2) //SD卡片选引脚extern u8SD_Type;//SD卡的类型
//函数申明区
u8 SD_SPI_ReadWriteByte(u8 data);
void SD_SPI_SpeedLow(void);
void SD_SPI_SpeedHigh(void);
u8 SD_WaitReady(void);//等待SD卡准备
u8 SD_GetResponse(u8 Response);//获得相应
u8 SD_Initialize(void);//初始化
u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt);//读块
u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt);//写块
u32 SD_GetSectorCount(void);//读扇区数
u8 SD_GetCID(u8 *cid_data);//读SD卡CID
u8 SD_GetCSD(u8 *csd_data);//读SD卡CSD
#endif
该部分代码主要是一些命令的宏定义以及函数声明,在这里我们设定了SD卡的CS管脚为PD2。保存MMC_SD.H,就可以在主函数里面编写我们的应用代码了,打开test.c文件,在该文件中修改main函数如下:
int main(void)
{
u8 key; u8 t=0; u8 *buf;
u32 sd_size;
Stm32_Clock_Init(9);//系统时钟设置
uart_init(72,9600); //串口初始化为9600
delay_init(72);//延时初始化
LED_Init();//初始化与LED连接的硬件接口
LCD_Init();//初始化LCD
usmart_dev.init(72);//初始化USMART
KEY_Init();//按键初始化
FSMC_SRAM_Init();//初始化外部SRAM
mem_init(SRAMIN);//初始化内部内存池
POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(60,50,200,16,16,"WarShip STM32");
LCD_ShowString(60,70,200,16,16,"SD CARD TEST");
LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(60,110,200,16,16,"2012/9/17");
LCD_ShowString(60,130,200,16,16,"KEY0:Read Sector 0");
while(SD_Initialize())//检测不到SD卡
{
LCD_ShowString(60,150,200,16,16,"SD Card Error!");
delay_ms(500);
LCD_ShowString(60,150,200,16,16,"Please Check! ");
delay_ms(500);
LED0=!LED0;//DS0闪烁
}
POINT_COLOR=BLUE;//设置字体为蓝色
//检测SD卡成功
LCD_ShowString(60,150,200,16,16,"SD Card OK");
LCD_ShowString(60,170,200,16,16,"SD Card Size:MB");
sd_size=SD_GetSectorCount();//得到扇区数
LCD_ShowNum(164,170,sd_size>>11,5,16);//显示SD卡容量(MB)
while(1)
{
key=KEY_Scan(0);
if(key==KEY_RIGHT)//KEY0按下了
{
buf=mymalloc(0,512);//在内部内存池,申请512字节内存
if(SD_ReadDisk(buf,0,1)==0)//读取0扇区的内容
{
LCD_ShowString(60,190,200,16,16,"USART1 Sending Data...");
printf("SECTOR 0 DATA:");
for(sd_size=0;sd_size<512;sd_size++)printf("%x ",buf[sd_size]);
//打印0扇区数据
printf("DATA ENDED");
LCD_ShowString(60,190,200,16,16,"USART1 Send Data Over!");
}
myfree(0,buf);//释放内存
}
t++;
delay_ms(10);
if(t==20)
{
LED0=!LED0;
t=0;
}
}
}

上一页 1 2 下一页

关键词: STM32SD卡驱

评论


技术专区

关闭