SD卡已经看了两天了,主要是因为测试出来的卡容量不对,所以一直找原因,最终还是发现了,总比不过是单位上面出现了问题,或许是之前没有接触到SD的缘故吧,所以对其中的一些寄存器很不了解,一切都是重新开始,对照这寄存器手册,理解程序,修改程序。一步步还是总结一下!

首先关于SD卡的协议是有必要了解的,我今天花了一上午的课堂时间来理解这个SD卡的协议,就是基于这个文档的,这个文档很适合入门SD协议的(个人认为)。http://download.csdn.net/detail/king_bingge/5218183

初识SD之后,就可以开始正式学习SD卡了!

一、要使用SD卡,那么首先肯定得对SD卡进行初始化,那么如何进行初始化呢?(命令的参数暂且不提)

1、这里涉及到很多指令了。协议规定了在给SD卡上电之后需要给出至少74个时钟脉冲后,才能进行相关的SD初始化工作,虽然是这么说,但是我不给74个时钟,他照样能初始化,看看。

;i<;i++)SD_SPI_ReadWriteByte(0XF);

但是,或许为了能够更加成功的初始化吧,所以有这个规定所以,我们还是规规矩矩的好,给它74个时钟,没关系的嘛!

2、然后就是协议中说到当我们复位或者上电的时候,SD卡的SD控制寄存器处于卡识别模式中的空闲模式的,暂且这样称吧。本来我们是不需要发送复位命令了的,但是我们不知道我们的SD所支持的电压范围。所以,我们最好还是先给出一条复位指令,然后紧接着一条获取工作电压的指令,这样也是比较保险,如果多SD卡工作电压有疑问的,那么就得去看芯片手册了。有了这个知识,那下面的代码就不成问题了

retry=;
    do
    {
        r1=SD_SendCmd(CMD0,,0x95);//进入IDLE状态
    }while((r1!=0X01) && retry--);
     SD_Type=;    //默认无卡
    if(r1==0X01)
    {
        )  //SD V2.0
        {
            ;i<;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);    //Get trailing return value of R7 resp
            ]==]==0XAA)              //卡是否支持2.7~3.6V

3、协议上还提到ACMD41命令的目的是给予 SD卡控制器一个识别 SD卡是否可以在所给Vdd 范围下工作的机制,如果 SD 卡无法在指定 Vdd 范围内工作,则它会进入非活动状态(Inactive state ),所以我们接下来需要发送这个命令,但是在发送这个命令之前,要知道这是一个应用型的命令,所以要加上CMD55命令,所以有了下面的代码。

]==]==0XAA)//卡是否支持2.7~3.6V
    {
        retry=0XFFFE;
        do
        {
            SD_SendCmd(CMD55,,0X01);    //发送CMD55
            r1=SD_SendCmd(CMD41,0x40000000,0X01);//发送CMD41
        }while(r1&&retry--);
        ,)//鉴别SD2.0卡版本开始        //获取供电状态
        {
            ;i<;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//得到OCR值
            ]&0x40)SD_Type=SD_TYPE_V2HC;    //检查CCS
            else SD_Type=SD_TYPE_V2;
        }

这样就获取了卡的类型了,至此卡的初始化基本完成,当然根据协议上,我们还可以在这里修改相对地址之类的。如果有必要的话,可以这样做!

二、初始化完SD卡,接下来如果你想查看我们SD的容量,可以这样做!

之前就是因为卡容量的问题,所以郁闷了好久,理解了个大概!注意这里函数名是读取扇区数,实际上返回的值是我们卡的容量,这里得注意了。

1、首先看代码

u32 SD_GetSectorCount(void)
{
    u8 csd[];
    u32 Capacity_KB,Capacity_MB ;
    u8 n;
        u16 csize;
    //取CSD信息,如果期间出错,返回0
    ) ;
        n = (csd[] & ) + ((csd[] & ) >> ) + ((csd[] & ) << ) + ;
        csize = (csd[] >> ) + ((u16)csd[] << ) + ((u16)(csd[] & ) << ) + ;

        Capacity_KB= (u32)csize << (n - );//得到扇区数 ,这里的单位是KB
        Capacity_MB = Capacity_KB/;
    return Capacity_MB;
}

这个计算的问题必须得看SD卡的手册,也就是128位的CSD寄存器。这里我把我分析的过程贴出来,我不得不说比较乱,或许只有我自己能看懂了,懒得整理了,仅供参考!

//My SD_Card
//CSD寄存器中的值如下:
 7f ff     bit(-)            csd0 - csd3
5f   cb    bit(--)            csd4 - csd7
 db df ff    bit(--)            csd8 - csd11
       bit(---)            csd12 -csd15

csize  {,}
csize_muti{,}
read {,}
csize =    =
csize_muti =  =
read =  =
//计算公式:
//blocknr = (csize+1)*mult    =
//mult = (csize_muti < 8)*(2^(csize_muti + 2))
//block_len = (read < 12)*(2^(read))
//capacity = blocknr * block_len = 13*4*3516*98304
//依据下面代码来计算我的容量:
        n = (csd[] & ) + ((csd[] & ) >> ) + ((csd[] & ) << ) + ;
        csize = (csd[] >> ) + ((u16)csd[] << ) + ((u16)(csd[] & ) << ) + ;

        Capacity_KB= (u32)csize << (n - );//得到扇区数 ,这里的单位是KB  // 00 7f ff 32 5f 59 83 cb  76 db df ff 96 40 00 97
        Capacity_MB = Capacity_KB/;

        //1、(csd[8] >> 6) 得到的是 bit62和bit63的值                去掉2位
        //2、((u16)csd[7] << 2)得到的是bit64--bit69的值            去掉6位
        //3、((u16)(csd[6] & 3) << 10)得到的是bit70--bit73的值    
 

其实我的问题还是出现在单位上面!

这样我们就能看到显示的容量值了,我的是1G的。打印出来是971M,和windows下面的是一致的。其实我们可以通过读SD卡的引导扇区,从而把相关的信息读取出来,而不需要使用那些个寄存器。那么现在我们的计算公式就是(这只是我自己信手写的,如果想要理解,你必须得看扇区的内容咯,我就是对照着那个MBR来写的)

  x=(((buf_read[])**+(buf_read[])*+(buf_read[])))*//;    //打印大小
  printf("\n SD Sector Size:%d  Mb\n",x);

虽然不怎么雅观,但是能用就是了。

2、接下来看如何用SPI读一个扇区吧,先看代码

u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
{
    u8 r1;
    ;//转换为字节地址
    )
    {
        r1=SD_SendCmd(CMD17,sector,0X01);//读命令
        )//指令发送成功
        {
            r1=SD_RecvData(buf,);//接收512个字节
        }
    }else
    {
        r1=SD_SendCmd(CMD18,sector,0X01);//连续读命令
        do
        {
            r1=SD_RecvData(buf,);//接收512个字节
            buf+=;
        });
        SD_SendCmd(CMD12,,0X01);    //发送停止命令
    }
    SD_DisSelect();//取消片选
    return r1;//
}

这几行代码能实现单个和多个扇区的读写,跟踪进去可以能够看到这个函数

//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8 SPIx_ReadWriteByte(u8 TxData)
{
    u8 retry=;
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
        {
        retry++;
        );
        }
    SPI_I2S_SendData(SPI1, TxData);                                                              //通过外设SPIx发送一个数据
    retry=;

    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); //检查指定的SPI标志位设置与否:接受缓存非空标志位
        {
        retry++;
        );
        }
    return SPI_I2S_ReceiveData(SPI1);                                                                 //返回通过SPIx最近接收的数据
}

这个函数的功能实现了既可以进行发送又可以进行读取数据,现在来总结一下!

读一个扇区的过程

1、先发命令r1=SD_SendCmd(CMD17,sector,0X01);//读单个扇区的命令

2、然后将接收到得数据存在临时数组里面

u8 SD_RecvData(u8*buf,u16 len)
{
    ;//等待SD卡发回数据起始令牌0xFE
    while(len--)//开始接收数据
    {
        *buf=SPIx_ReadWriteByte(0xFF);
        buf++;
    }
    //下面是2个伪CRC(dummy CRC)
    SD_SPI_ReadWriteByte(0xFF);
    SD_SPI_ReadWriteByte(0xFF);
    ;//读取成功
}

那么对应的写扇区也类似的

1、先发写单个扇区的命令 r1=SD_SendCmd(CMD24,sector,0X01);//写命令

2、将Buffer里面的内容写到对应的扇区里面去

u8 SD_SendBlock(u8*buf,u8 cmd)
{
    u16 t;
    ;//等待准备失效
    SD_SPI_ReadWriteByte(cmd);
    if(cmd!=0XFD)//不是结束指令
    {
        ;t<;t++)SPIx_ReadWriteByte(buf[t]);//提高速度,减少函数传参时间
        SD_SPI_ReadWriteByte(0xFF);//忽略crc
        SD_SPI_ReadWriteByte(0xFF);
        t=SD_SPI_ReadWriteByte(0xFF);//接收响应
        ;//响应错误
    }
    ;//写入成功
}

到这里,读写扇区就完成了,下一步就是,使用文件系统来进行操作了。

基于stm32f103zet6的FAT16文件系统学习0(读SD卡扇区)的更多相关文章

  1. 基于stm32f103zet6的FAT16文件系统学习1(初识FAT16)

    有了之前读写block的基础之后,准备弄个文件系统,之前没有接触过这东西,所以有很多都晕晕的,但是看到fat的源代码之后还是挺有信心的,因为之前一直过uboot,所以这个文件当然是小巫见大巫了.首先来 ...

  2. Android中向SD卡读写数据,读SD卡和手机内存

    package com.example.sdoperation; import java.io.BufferedReader; import java.io.File; import java.io. ...

  3. uboot里读sd卡内容

    1. sd卡升级命令 mmcinit 0 fatload mmc 0:1 0 uzImage.bin 80000 fatload mmc 0:1 1000000 initrd.gz 580000 bo ...

  4. FPGA之SPI SD卡读操作

    这几天在FPGA调试与SD通信,读SD卡里的图片,之前接触32时没有去研究过SD卡,不太熟悉操作流程,在网上找了很多资料,也看了几个32开发板的资料,但大多数都讲得不是特别清楚,只能瞎操作了一番,在别 ...

  5. 第37章 基于SD卡的FatFs文件系统—零死角玩转STM32-F429系列

    第37章     基于SD卡的FatFs文件系统 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.co ...

  6. Keil MDK STM32系列(九) 基于HAL和FatFs的FAT格式SD卡TF卡读写

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  7. 玩转X-CTR100 l STM32F4 l SD卡FatFs文件系统

    我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ] X-CTR100控制器具有SD卡接口,本教程使用免费 ...

  8. sd 卡驱动--基于高通平台

    点击打开链接 内容来自以下博客: http://blog.csdn.net/qianjin0703/article/details/5918041 Linux设备驱动子系统第二弹 - SD卡 (有介绍 ...

  9. SD卡与FAT32系统学习

    2011-06-06 23:04 前2天,我了解了一下SD卡驱动的原理及FAT32文件系统的结构.接着准备主要已移植为主.通过LCD显示SD卡中的图片.但我需要分步进行. 0,使sd卡能读写数据.1, ...

随机推荐

  1. EF 一对一,一对多,多对多 Flunt API 配置

       一对一 就拿后台用户权限相关的实体来说明吧,用户表,用户详细表,是一对一的关系: /// <summary> /// 用户信息类 /// </summary> publi ...

  2. Powershell变量的幕后管理

    Powershell变量的幕后管理 513 12月, 2011  在 Powershell  tagged 变量 / 类型 by Mooser Lee本文索引[隐藏]1修改变量的选项设置2激活变量的写 ...

  3. UML--核心元素之参与者Actor

    参与者(actor):在系统之外与系统交互的某人或某事物.例如,管理员,用户等等. 参与者位于边界之外,边界之内的都不叫参与者.用一个词来形容更准确,主角.也就是只有主动启动了这个业务的人,才是参与者 ...

  4. 利用jquery表格添加一行并在每行第一列大写字母显示实现方法

    表格添加一行并在每行第一列大写字母显示jquery实现方法 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN& ...

  5. mysql----用户root被删除或忘记root密码的解决方案

    修改文件my.cnf,可用VIM打开,如:sudo vim /etc/my.cnf 在[mysqld]下加上一行: skip-grant-tables 保存文件,然后重启mysqld程序:sudo s ...

  6. 异步化DAO的设计和实践

    目前,公司技术规划要求未来所有的服务要全面实现异步化接口,使得每个服务能达到1万/秒的单机性能.我们知道,在一个服务请求中,可能会调用其他服务,还会使用memcache.kv以及mysql等.目前,大 ...

  7. python list 中找连续的数字(由网友处学习)

    # -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' #学习这个要求的:http://wsky.org/archives/ ...

  8. AngularJs登录

    AngularJs 登录的简单实现 多数AngularJs应用离不开登录操作,最近阅读了一篇关于AngularJs登录的博客,博客中实现的登录系统demo能够应用于多数小型AngularJs应用,实现 ...

  9. Linux 内核开发 - 进程空间

    1.1 虚拟内存 Linux 的系统.假设每一个任务都独立的占用内存,则实际的物理内存将非常快消耗殆尽.实际上对于前台正在执行的任务来说,所须要要的内存并不多,非常多任务基本不须要执行,也就没有必要一 ...

  10. map的类型映射

    以下是使用STL中map类型,对类型的转换示例,主要可以解决的问题,也就是一般的类型之间的相互转换,可以较好的解决相关的问题. 以下是C++源码,比较简短,容易理解的. #include " ...