OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 6340|回复: 13

求帮看代码,SPI驱动SD卡,调了两天了。。

[复制链接]

10

主题

68

帖子

0

精华

初级会员

Rank: 2

积分
96
金钱
96
注册时间
2015-5-13
在线时间
21 小时
发表于 2016-4-15 12:32:40 | 显示全部楼层 |阅读模式
10金钱
    找了很多F4的例程,都是SDIO驱动SD卡的,手上这块板又做成了SPI驱动的,找到战舰107的SPI驱动SD卡例程,移植过来,却不成功,不知道哪错了,感觉片选这部分有问题,自己试着改了,还是不行。。求帮忙看看代码
QQ截图20160415122637.jpg
QQ截图20160415122708.jpg

PROJECT.rar

4.27 MB, 下载次数: 218

最佳答案

付出总有回报
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

10

主题

68

帖子

0

精华

初级会员

Rank: 2

积分
96
金钱
96
注册时间
2015-5-13
在线时间
21 小时
 楼主| 发表于 2016-4-15 12:32:41 | 显示全部楼层
回复

使用道具 举报

10

主题

68

帖子

0

精华

初级会员

Rank: 2

积分
96
金钱
96
注册时间
2015-5-13
在线时间
21 小时
 楼主| 发表于 2016-4-15 12:39:48 | 显示全部楼层
调了两天了,烦死了,求大神支援啊~~
付出总有回报
回复

使用道具 举报

10

主题

68

帖子

0

精华

初级会员

Rank: 2

积分
96
金钱
96
注册时间
2015-5-13
在线时间
21 小时
 楼主| 发表于 2016-4-15 13:02:51 | 显示全部楼层
@正点原子 原子哥,求支援啊!
付出总有回报
回复

使用道具 举报

25

主题

683

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1351
金钱
1351
注册时间
2012-4-25
在线时间
195 小时
发表于 2016-4-15 13:45:47 | 显示全部楼层
要想有进步就自己调试出来,动不动找这个源码找那个代码,你自己问题根源没找到。下次还来做这个,你还是要蒙。
先从硬件上排除,这个简单就不说了。
然后再软件上,把连接SD的 IO都同时拉高,拉低,看有没动作,然后继续 调试,设置断点,看看哪个地方错误。
1-1
回复

使用道具 举报

3

主题

548

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1383
金钱
1383
注册时间
2015-2-3
在线时间
197 小时
发表于 2016-4-15 16:12:20 | 显示全部楼层
本帖最后由 yyx112358 于 2016-4-15 16:14 编辑

发一个我改写的吧。基于F429的SPI。
原子说SD卡不需要注意CRC是不对的,我发现有些SD卡还是必须要有CRC。之前被坑了很长时间
不知道为什么发不了附件,我直接发代码吧
头文件:
[mw_shl_code=c,true]#ifndef _MMC_SD_H_
#define _MMC_SD_H_                 
#include "sys.h"         
//暂缺:多卡、SDIO、错误回调及复位、CRC

//这部分应根据具体的连线来修改!
#define        SD_CS  PFout(6)         //SD卡片选引脚        

#define DUMMYBYTE        (0xFF)        //伪字节
// SD卡类型定义  
typedef enum
{
        SD_TYPE_ERR                =0X00,
        SD_TYPE_MMC                =0X01,
        SD_TYPE_V1                =0X02,
        SD_TYPE_V2                =0X04,
        SD_TYPE_V2HC        =0X06
}SD_TypeDef;
// SD卡指令表
enum
{
        CMD0    =0,       //卡复位
        CMD1    =1,
        CMD8    =8,              //命令8 ,SEND_IF_COND
        CMD9    =9,       //命令9 ,读CSD数据
        CMD10   =10,      //命令10,读CID数据
        CMD12   =12,      //命令12,停止数据传输
        CMD16   =16,      //命令16,设置SectorSize 应返回0x00
        CMD17   =17,      //命令17,读sector
        CMD18   =18,      //命令18,读Multi sector
        CMD23   =23,      //命令23,设置多sector写入前预先擦除N个block
        CMD24   =24,      //命令24,写sector
        CMD25   =25,      //命令25,写Multi sector
        CMD32                =32,                        //命令32,设置要擦除的第一个写数据块地址
        CMD33                =33,                        //命令33,设置要擦除的最后一个写数据块地址
        CMD38                =38,                        //命令38,擦除所有选中的写数据块
        CMD41   =41,      //命令41,应返回0x00
        CMD55   =55,      //命令55,应返回0x01
        CMD58   =58,      //命令58,读OCR信息
        CMD59   =59              //命令59,使能/禁止CRC,应返回0x00
};
//数据写入回应字意义
enum
{
        SD_DATA_OK                =0x05,
        SD_DATA_CRC_ERROR         =0x0B,
        SD_DATA_WRITE_ERROR       =0x0D,
        SD_DATA_OTHER_ERROR       =0xFF,
};
//SD卡回应标记字
typedef enum
{
        SD_RESPONSE_NO_ERROR      =0x00,
        SD_IN_IDLE_STATE          =0x01,
        SD_ERASE_RESET            =0x02,
        SD_ILLEGAL_COMMAND        =0x04,
        SD_COM_CRC_ERROR          =0x08,
        SD_ERASE_SEQUENCE_ERROR   =0x10,
        SD_ADDRESS_ERROR          =0x20,
        SD_PARAMETER_ERROR        =0x40,
        SD_RESPONSE_FAILURE       =0xFF,
}SD_ERRSTATE;
//SD卡CSD寄存器数据                  
typedef struct
{
        u8  CSDStruct;            /*!< CSD structure */
        u8  SysSpecVersion;       /*!< System specification version */
        u8  Reserved1;            /*!< Reserved */
        u8  TAAC;                 /*!< Data read access-time 1 */
        u8  NSAC;                 /*!< Data read access-time 2 in CLK cycles */
        u8  MaxBusClkFrec;        /*!< Max. bus clock frequency */
        u16 CardComdClasses;      /*!< Card command classes */
        u8  RdBlockLen;           /*!< Max. read data block length */
        u8  PartBlockRead;        /*!< Partial blocks for read allowed */
        u8  WrBlockMisalign;      /*!< Write block misalignment */
        u8  RdBlockMisalign;      /*!< Read block misalignment */
        u8  DSRImpl;              /*!< DSR implemented */
        u8  Reserved2;            /*!< Reserved */
        u32 DeviceSize;           /*!< Device Size */
        u8  MaxRdCurrentVDDMin;   /*!< Max. read current @ VDD min */
        u8  MaxRdCurrentVDDMax;   /*!< Max. read current @ VDD max */
        u8  MaxWrCurrentVDDMin;   /*!< Max. write current @ VDD min */
        u8  MaxWrCurrentVDDMax;   /*!< Max. write current @ VDD max */
        u8  DeviceSizeMul;        /*!< Device size multiplier */
        u8  EraseGrSize;          /*!< Erase group size */
        u8  EraseGrMul;           /*!< Erase group size multiplier */
        u8  WrProtectGrSize;      /*!< Write protect group size */
        u8  WrProtectGrEnable;    /*!< Write protect group enable */
        u8  ManDeflECC;           /*!< Manufacturer default ECC */
        u8  WrSpeedFact;          /*!< Write speed factor */
        u8  MaxWrBlockLen;        /*!< Max. write data block length */
        u8  WriteBlockPaPartial;  /*!< Partial blocks for write allowed */
        u8  Reserved3;            /*!< Reserded */
        u8  ContentProtectAppli;  /*!< Content protection application */
        u8  FileFormatGrouop;     /*!< File format group */
        u8  CopyFlag;             /*!< Copy flag (OTP) */
        u8  PermWrProtect;        /*!< Permanent write protection */
        u8  TempWrProtect;        /*!< Temporary write protection */
        u8  FileFormat;           /*!< File Format */
        u8  ECC;                  /*!< ECC code */
        u8  CSD_CRC;              /*!< CSD CRC */
        u8  Reserved4;            /*!< always 1*/
} SD_CSD;   

//SD卡CID寄存器数据
typedef struct
{
        u8  ManufacturerID;       /*!< ManufacturerID */
        u16 OEM_AppliID;          /*!< OEM/Application ID */
        u32 ProdName1;            /*!< Product Name part1 */
        u8  ProdName2;            /*!< Product Name part2*/
        u8  ProdRev;              /*!< Product Revision */
        u32 ProdSN;               /*!< Product Serial Number */
        u8  Reserved1;            /*!< Reserved1 */
        u16 ManufactDate;         /*!< Manufacturing Date */
        u8  CID_CRC;              /*!< CID CRC */
        u8  Reserved2;            /*!< always 1 */
} SD_CID;         

//SD卡信息,包括CSD,CID等数据
typedef struct
{
  SD_CSD SD_csd;
  SD_CID SD_cid;
  uint64_t CardCapacity;          //SD卡容量,单位:字节,最大支持2^64字节大小的卡.
  u32 CardBlockSize;                 //SD卡块大小        
  u16 RCA;                                        //卡相对地址
  u8 CardType;                                //卡类型
} SD_CardInfo;
extern SD_CardInfo SDCardInfo;//SD卡信息               

extern u8  SD_Type;//SD卡的类型
//函数申明区
u8 SD_SPI_ReadWriteByte(u8 data);
void SD_SPI_SpeedLow(void);
void SD_SPI_SpeedHigh(void);
u8 SD_Select(void);
void SD_DisSelect(void);
u32 SD_UserCallBack(void);                                                        //错误回调
u8 SD_Deinit(void);

u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc);
u8 SD_WaitReady(void);                                                        //等待SD卡准备
u8 SD_GetResponse(u8 Response);                                        //获得相应
u8 SD_Initialize(void);                                                        //初始化
u8 SD_Init(void);                                                                                //初始化并获得卡信息
u8 SD_ReadDisk(u8*buf,u32 sector,u32 cnt);                //读块
u8 SD_WriteDisk(u8*buf,u32 sector,u32 cnt);                //写块
u8 SD_EraseDisk(u32 startsector,u32 endsector);//擦除块
u32 SD_GetSectorCount(void);                                           //读扇区数
u8 SD_GetCID(u32 *cid_data);                     //读SD卡CID
u8 SD_GetCSD(u32 *csd_data);                     //读SD卡CSD
SD_ERRSTATE SD_GetCardInfo(SD_CardInfo *cardinfo);

#endif




[/mw_shl_code]

回复

使用道具 举报

3

主题

548

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1383
金钱
1383
注册时间
2015-2-3
在线时间
197 小时
发表于 2016-4-15 16:13:09 | 显示全部楼层
C源文件[mw_shl_code=c,true]#include "sys.h"
#include "spi.h"
#include "mmc_sd.h"                          

#include "usart.h"       
                                                                             
u8  SD_Type=0;//SD卡的类型
static u32 CSD_Tab[4],CID_Tab[4];                                        //SD卡CSD,CID以及相对地址(RCA)数据
SD_CardInfo SDCardInfo;                                                                        //SD卡信息
//static DMA_InitTypeDef SD_DMAInitStructure;
////////////////////////////////////移植修改区///////////////////////////////////
//移植时候的接口
//data:要写入的数据
//返回值:读到的数据
u8 SD_SPI_ReadWriteByte(u8 data)
{
        return SPI5_ReadWriteByte(data);
}          
//SD卡初始化的时候,需要低速
void SD_SPI_SpeedLow(void)
{
        SPI5_SetSpeed(SPI_BaudRatePrescaler_256);
}
//SD卡正常工作的时候,可以高速了
void SD_SPI_SpeedHigh(void)
{
        SPI5_SetSpeed(SPI_BaudRatePrescaler_4);//【如果出现错误应改为16分频】
}
//SPI硬件层初始化
void SD_SPI_Init(void)
{
          GPIO_InitTypeDef  GPIO_InitStructure;

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF|RCC_AHB1Periph_GPIOC, ENABLE);//使能GPIOA时钟

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOF, &GPIO_InitStructure);
        SD_CS=1;

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
        GPIO_Init(GPIOC, &GPIO_InitStructure);
        L3GD20_CS=1;//其件片选引脚置为高以免影响
       
        SPI5_Init();
}

u8 SD_Deinit(void)
{
        SPI_DeInit(SPI5);
        return 1;
}

u32 SD_UserCallBack(void)
{
        SD_Deinit();
       
        return SD_Init();
}
///////////////////////////////////////////////////////////////////////////////////
//取消选择,释放SPI总线
void SD_DisSelect(void)
{
        SD_CS=1;
        SD_SPI_ReadWriteByte(DUMMYBYTE);//提供额外的8个时钟
}
//选择sd卡,并且等待卡准备OK
//返回值:0,成功;1,失败;
u8 SD_Select(void)
{
        SD_CS=0;
        if(SD_WaitReady()==0)return 0;//等待成功
        SD_DisSelect();
        return 1;//等待失败
}
//等待卡准备好
//返回值:0,准备好了;其他,错误代码
u8 SD_WaitReady(void)
{
        u32 t=0;
        do
        {
                if(SD_SPI_ReadWriteByte(0XFF)==0XFF)return 0;//OK
                t++;                         
        }while(t<0XFFFFF);//等待
        return SD_UserCallBack();
}
//等待SD卡回应
//Response:要得到的回应值
//返回值:0,成功得到了该回应值
//    其他,得到回应值失败
u8 SD_GetResponse(u8 Response)
{
        u16 Count=0x1000  ;//等待次数                                                             
        while ((SD_SPI_ReadWriteByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应            
        if (Count==0)return SD_RESPONSE_FAILURE;//得到回应失败   
        else return SD_RESPONSE_NO_ERROR;//正确回应
}
//向SD卡发送一个命令
//输入: u8 cmd   命令
//      u32 arg  命令参数
//      u8 crc   crc校验值          
//返回值:SD卡返回的响应                                                                                                                          
u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc)
{
  u8 r1;       
        u8 Retry=0;
#if SD_SPI_USE_CRC///SD卡SPI模式下是否使用CRC
        //SPI模式下,一般只需要初始化时用于进入SPI模式的CMD0需要CRC,除非使用CMD59打开SPI的CRC
        do
        {
                SD_DisSelect();//取消上次片选
                if(SD_Select())return SD_RESPONSE_FAILURE;//片选失效
                //发送
                        SD_SPI_ReadWriteByte(cmd | 0x40);//分别写入命令
                        SD_SPI_ReadWriteByte(arg >> 24);
                        SD_SPI_ReadWriteByte(arg >> 16);
                        SD_SPI_ReadWriteByte(arg >> 8);
                        SD_SPI_ReadWriteByte(arg);          
                        SD_SPI_ReadWriteByte(crc);
                if(cmd==CMD12)SD_SPI_ReadWriteByte(0xff);//Skip a stuff byte when stop reading
                        //等待响应,或超时退出
                Retry=0X1F;
                do
                {
                        r1=SD_SPI_ReadWriteByte(0xFF);
                }while((r1&0X80) && Retry--);         
                crc++;
        }while(r1&SD_COM_CRC_ERROR);
        #if        MY_DEBUG
        printf("cmd:%d,arg:%x,crc:%x\r\n",cmd,arg,crc-1);
        #endif
#else //不使用CRC
        SD_DisSelect();//取消上次片选
        if(SD_Select())return SD_RESPONSE_FAILURE;//片选失效
        //发送
                SD_SPI_ReadWriteByte(cmd | 0x40);//分别写入命令
                SD_SPI_ReadWriteByte(arg >> 24);
                SD_SPI_ReadWriteByte(arg >> 16);
                SD_SPI_ReadWriteByte(arg >> 8);
                SD_SPI_ReadWriteByte(arg);          
                SD_SPI_ReadWriteByte(crc);
        if(cmd==CMD12)SD_SPI_ReadWriteByte(0xff);//Skip a stuff byte when stop reading
                //等待响应,或超时退出
        Retry=0X1F;
        do
        {
                r1=SD_SPI_ReadWriteByte(0xFF);
        }while((r1&0X80) && Retry--);         
#endif
        //返回状态值
  return r1;
}
//初始化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);////低电平时发送CMD0进入SPI模式
        }while((r1!=SD_IN_IDLE_STATE) && retry--);
        SD_Type=0;//默认无卡
       
        if(r1!=SD_ILLEGAL_COMMAND)//R1未返回非法命令,说明支持SD2.0标准
        {
                if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
                {
                        for(i=0;i<4;i++)
                                buf=SD_SPI_ReadWriteByte(0XFF);        //Get trailing return value of R7 resp
                       
                        if(buf[2]==0X01&&buf[3]==0XAA)//卡是否支持2.7~3.6V
                        {
                                retry=0XFFFE;
                                do
                                {
                                        SD_SendCmd(CMD55,0,0X64);        //发送CMD55
                                        r1=SD_SendCmd(CMD41,0x40000000,0X77);//发送CMD41
                                }while(r1&&retry--);
                                if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始
                                {
                                        for(i=0;i<4;i++)buf=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/ MMC        V3
                {
                        SD_SendCmd(CMD55,0,0X64);                //发送CMD55
                        r1=SD_SendCmd(CMD55,0,0X77);        //发送CMD41
                        if(r1<=1)
                        {               
                                SD_Type=SD_TYPE_V1;
                                retry=0XFFFE;
                                do //等待退出IDLE模式
                                {
                                        SD_SendCmd(CMD55,0,0X64);        //发送CMD55
                                        r1=SD_SendCmd(CMD55,0,0X77);//发送CMD41
                                }while(r1&&retry--);
                        }else
                        {
                                SD_Type=SD_TYPE_MMC;//MMC V3
                                retry=0X1000;
                                do //等待退出IDLE模式
                                {                                                                                            
                                        r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1
                                }while(r1&&retry--);  
                        }
                        if(retry==-1||SD_SendCmd(CMD16,512,0X14)!=0)SD_Type=SD_TYPE_ERR;//错误的卡
                }
                r1=SD_SendCmd(CMD59,0,0x95);
        }
        SD_DisSelect();//取消片选
        SD_SPI_SpeedHigh();//高速
        if(SD_Type)return SD_RESPONSE_NO_ERROR;
        else if(r1)return r1;
       
        return 0xaa;//其他错误
}
u8 SD_Init(void)
{
        u8 r1=SD_RESPONSE_NO_ERROR;
       
        SD_Deinit();
        SD_SPI_Init();
        r1=SD_Initialize();
        if(r1!=SD_RESPONSE_NO_ERROR)
                return r1;
       
        r1=SD_GetCID(CID_Tab);
        if(r1!=SD_RESPONSE_NO_ERROR)
                return r1;
       
        r1=SD_GetCSD(CSD_Tab);
        if(r1!=SD_RESPONSE_NO_ERROR)
                return r1;
       
        SD_GetCardInfo(&SDCardInfo);
        return SD_RESPONSE_NO_ERROR;
}

//从sd卡读取一个数据包的内容
//buf:数据缓存区
//len:要读取的数据长度.
//返回值:0,成功;其他,失败;       
u8 SD_RecvData(u8 buf[],u16 len)
{                                    
        if(SD_GetResponse(0xFE))return SD_RESPONSE_FAILURE;//等待SD卡发回数据起始令牌0xFE
       
  while(len--)//开始接收数据
        {
                        *buf=SPI5_ReadWriteByte(DUMMYBYTE);
                        buf++;
        }
        //下面是2个伪CRC(dummy CRC)
        SD_SPI_ReadWriteByte(DUMMYBYTE);
        SD_SPI_ReadWriteByte(DUMMYBYTE);                                                                                                                      
        return 0;//读取成功
}
//向sd卡写入一个数据包的内容 512字节
//buf:数据缓存区
//cmd:指令
//返回值:0,成功;其他,失败;       
u8 SD_SendBlock(u8*buf,u8 cmd)
{       
        u16 t;                            
        if(SD_WaitReady())
                return SD_RESPONSE_FAILURE;//等待准备失效
       
        SD_SPI_ReadWriteByte(cmd);
        if(cmd!=0XFD)//不是结束指令
        {
                for(t=0;t<512;t++)SPI5_ReadWriteByte(buf[t]);//提高速度,减少函数传参时间
               
          SD_SPI_ReadWriteByte(DUMMYBYTE);//忽略crc
          SD_SPI_ReadWriteByte(DUMMYBYTE);
                t=SD_SPI_ReadWriteByte(DUMMYBYTE);//接收响应
                if((t&0x1F)!=0x05)return 2;//响应错误                                                                                                                      
        }                                                                                                                                                                       
  return 0;//写入成功
}

                                                                                                                                                                              
//获取SD卡的CID信息,包括制造商信息
//输入: u8 *cid_data(存放CID的内存,至少16Byte)          
//返回值:0:NO_ERR
//                 1:错误                                                                                                                  
u8 SD_GetCID(u32 *cid_data)
{
  u8 r1,temp[16],i=0;          
    //发CMD10命令,读CID
  r1=SD_SendCmd(CMD10,0,0x01);
  if(r1==0||r1==SD_COM_CRC_ERROR)
        {
                r1=SD_RecvData(temp,16);//接收16个字节的数据
  }
        for(i=0;i<4;i++)//小端模式转化为大端
        {
                cid_data=(temp[4*i]<<24)+(temp[4*i+1]<<16)+(temp[4*i+2]<<8)+(temp[4*i+3]);
        }
       
        SD_DisSelect();//取消片选
        if(r1)return r1;
        else return 0;
}                                                                                                                                                                  
//获取SD卡的CSD信息,包括容量和速度信息
//输入:u8 *cid_data(存放CID的内存,至少16Byte)            
//返回值:0:NO_ERR
//                 1:错误                                                                                                                  
u8 SD_GetCSD(u32 *csd_data)
{
  u8 r1,temp[16],i=0;         
       
  r1=SD_SendCmd(CMD9,0,0xAF);//发CMD9命令,读CSD
  if(r1==0||r1==SD_COM_CRC_ERROR)
        {
            r1=SD_RecvData(temp, 16);//接收16个字节的数据
  }
        for(i=0;i<4;i++)//小端模式转化为大端
        {
                csd_data=(temp[4*i]<<24)+(temp[4*i+1]<<16)+(temp[4*i+2]<<8)+(temp[4*i+3]);
        }
        SD_DisSelect();//取消片选
        if(r1)return r1;
        else return 0;
}  
////获取SD卡的总扇区数(扇区数)   
////返回值:0: 取容量出错
////       其他:SD卡的容量(扇区数/512字节)
////每扇区的字节数必为512,因为如果不是512,则初始化不能通过.                                                                                                                  
//u32 SD_GetSectorCount(void)
//{
//        u8 csd[16];
//        u32 Capacity;  
//        u8 n;
//        u16 csize;                                              
//        //取CSD信息,如果期间出错,返回0
//        if(SD_GetCSD(csd)!=0) return 0;            
//        //如果为SDHC卡,按照下面方式计算
//        if((csd[0]&0xC0)==0x40)         //V2.00的卡
//        {       
//                csize = csd[9] + ((u16)csd[8] << 8) + 1;
//                Capacity = (u32)csize << 10;//得到扇区数                           
//        }
//        else//V1.XX的卡
//        {       
//                n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
//                csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;
//                Capacity= (u32)csize << (n - 9);//得到扇区数   
//        }
//        return Capacity;
//}
//得到卡信息
//cardinfo:卡信息存储区
//返回值:错误状态
SD_ERRSTATE SD_GetCardInfo(SD_CardInfo *cardinfo)//这个函数是按照
{
        SD_ERRSTATE errorstatus=SD_RESPONSE_NO_ERROR;
        u8 tmp=0;          
        cardinfo->CardType=(u8)SD_Type;                                 //卡类型
        cardinfo->RCA=(u16)0x01;                                                        //卡RCA值
        tmp=(u8)((CSD_Tab[0]&0xFF000000)>>24);
        cardinfo->SD_csd.CSDStruct=(tmp&0xC0)>>6;                //CSD结构
        cardinfo->SD_csd.SysSpecVersion=(tmp&0x3C)>>2;        //2.0协议还没定义这部分(为保留),应该是后续协议定义的
        cardinfo->SD_csd.Reserved1=tmp&0x03;                        //2个保留位  
        tmp=(u8)((CSD_Tab[0]&0x00FF0000)>>16);                        //第1个字节
        cardinfo->SD_csd.TAAC=tmp;                                                   //数据读时间1
        tmp=(u8)((CSD_Tab[0]&0x0000FF00)>>8);                          //第2个字节
        cardinfo->SD_csd.NSAC=tmp;                                                  //数据读时间2
        tmp=(u8)(CSD_Tab[0]&0x000000FF);                                //第3个字节
        cardinfo->SD_csd.MaxBusClkFrec=tmp;                                  //传输速度          
        tmp=(u8)((CSD_Tab[1]&0xFF000000)>>24);                        //第4个字节
        cardinfo->SD_csd.CardComdClasses=tmp<<4;            //卡指令类高四位
        tmp=(u8)((CSD_Tab[1]&0x00FF0000)>>16);                         //第5个字节
        cardinfo->SD_csd.CardComdClasses|=(tmp&0xF0)>>4;//卡指令类低四位
        cardinfo->SD_csd.RdBlockLen=tmp&0x0F;                    //最大读取数据长度
        tmp=(u8)((CSD_Tab[1]&0x0000FF00)>>8);                        //第6个字节
        cardinfo->SD_csd.PartBlockRead=(tmp&0x80)>>7;        //允许分块读
        cardinfo->SD_csd.WrBlockMisalign=(tmp&0x40)>>6;        //写块错位
        cardinfo->SD_csd.RdBlockMisalign=(tmp&0x20)>>5;        //读块错位
        cardinfo->SD_csd.DSRImpl=(tmp&0x10)>>4;
        cardinfo->SD_csd.Reserved2=0;                                         //保留
        if((cardinfo->CardType==SD_TYPE_V1)||(cardinfo->CardType==SD_TYPE_V2)||(cardinfo->CardType==SD_TYPE_MMC))//标准1.1/2.0卡/MMC卡
        {
                cardinfo->SD_csd.DeviceSize=(tmp&0x03)<<10;        //C_SIZE(12位)
                 tmp=(u8)(CSD_Tab[1]&0x000000FF);                         //第7个字节       
                cardinfo->SD_csd.DeviceSize|=(tmp)<<2;
                tmp=(u8)((CSD_Tab[2]&0xFF000000)>>24);                //第8个字节       
                cardinfo->SD_csd.DeviceSize|=(tmp&0xC0)>>6;
                cardinfo->SD_csd.MaxRdCurrentVDDMin=(tmp&0x38)>>3;
                cardinfo->SD_csd.MaxRdCurrentVDDMax=(tmp&0x07);
                tmp=(u8)((CSD_Tab[2]&0x00FF0000)>>16);                //第9个字节       
                cardinfo->SD_csd.MaxWrCurrentVDDMin=(tmp&0xE0)>>5;
                cardinfo->SD_csd.MaxWrCurrentVDDMax=(tmp&0x1C)>>2;
                cardinfo->SD_csd.DeviceSizeMul=(tmp&0x03)<<1;//C_SIZE_MULT
                tmp=(u8)((CSD_Tab[2]&0x0000FF00)>>8);                  //第10个字节       
                cardinfo->SD_csd.DeviceSizeMul|=(tmp&0x80)>>7;
                cardinfo->CardCapacity=(cardinfo->SD_csd.DeviceSize+1);//计算卡容量
                cardinfo->CardCapacity*=(1<<(cardinfo->SD_csd.DeviceSizeMul+2));
                cardinfo->CardBlockSize=1<<(cardinfo->SD_csd.RdBlockLen);//块大小
                cardinfo->CardCapacity*=cardinfo->CardBlockSize;
        }
        else if(cardinfo->CardType==SD_TYPE_V2HC)        //高容量卡
        {
                tmp=(u8)(CSD_Tab[1]&0x000000FF);                 //第7个字节       
                cardinfo->SD_csd.DeviceSize=(tmp&0x3F)<<16;//C_SIZE
                tmp=(u8)((CSD_Tab[2]&0xFF000000)>>24);         //第8个字节       
                cardinfo->SD_csd.DeviceSize|=(tmp<<8);
                tmp=(u8)((CSD_Tab[2]&0x00FF0000)>>16);        //第9个字节       
                cardinfo->SD_csd.DeviceSize|=(tmp);
                tmp=(u8)((CSD_Tab[2]&0x0000FF00)>>8);         //第10个字节       
                cardinfo->CardCapacity=(long long)(cardinfo->SD_csd.DeviceSize+1)*512*1024;//计算卡容量
                cardinfo->CardBlockSize=512;                         //块大小固定为512字节
        }          
        cardinfo->SD_csd.EraseGrSize=(tmp&0x40)>>6;
        cardinfo->SD_csd.EraseGrMul=(tmp&0x3F)<<1;          
        tmp=(u8)(CSD_Tab[2]&0x000000FF);                        //第11个字节       
        cardinfo->SD_csd.EraseGrMul|=(tmp&0x80)>>7;
        cardinfo->SD_csd.WrProtectGrSize=(tmp&0x7F);
        tmp=(u8)((CSD_Tab[3]&0xFF000000)>>24);                //第12个字节       
        cardinfo->SD_csd.WrProtectGrEnable=(tmp&0x80)>>7;
        cardinfo->SD_csd.ManDeflECC=(tmp&0x60)>>5;
        cardinfo->SD_csd.WrSpeedFact=(tmp&0x1C)>>2;
        cardinfo->SD_csd.MaxWrBlockLen=(tmp&0x03)<<2;         
        tmp=(u8)((CSD_Tab[3]&0x00FF0000)>>16);                //第13个字节
        cardinfo->SD_csd.MaxWrBlockLen|=(tmp&0xC0)>>6;
        cardinfo->SD_csd.WriteBlockPaPartial=(tmp&0x20)>>5;
        cardinfo->SD_csd.Reserved3=0;
        cardinfo->SD_csd.ContentProtectAppli=(tmp&0x01);  
        tmp=(u8)((CSD_Tab[3]&0x0000FF00)>>8);                //第14个字节
        cardinfo->SD_csd.FileFormatGrouop=(tmp&0x80)>>7;
        cardinfo->SD_csd.CopyFlag=(tmp&0x40)>>6;
        cardinfo->SD_csd.PermWrProtect=(tmp&0x20)>>5;
        cardinfo->SD_csd.TempWrProtect=(tmp&0x10)>>4;
        cardinfo->SD_csd.FileFormat=(tmp&0x0C)>>2;
        cardinfo->SD_csd.ECC=(tmp&0x03);  
        tmp=(u8)(CSD_Tab[3]&0x000000FF);                        //第15个字节
        cardinfo->SD_csd.CSD_CRC=(tmp&0xFE)>>1;
        cardinfo->SD_csd.Reserved4=1;                 
        tmp=(u8)((CID_Tab[0]&0xFF000000)>>24);                //第0个字节
        cardinfo->SD_cid.ManufacturerID=tmp;                    
        tmp=(u8)((CID_Tab[0]&0x00FF0000)>>16);                //第1个字节
        cardinfo->SD_cid.OEM_AppliID=tmp<<8;          
        tmp=(u8)((CID_Tab[0]&0x000000FF00)>>8);                //第2个字节
        cardinfo->SD_cid.OEM_AppliID|=tmp;            
        tmp=(u8)(CID_Tab[0]&0x000000FF);                        //第3个字节       
        cardinfo->SD_cid.ProdName1=tmp<<24;                                  
        tmp=(u8)((CID_Tab[1]&0xFF000000)>>24);                 //第4个字节
        cardinfo->SD_cid.ProdName1|=tmp<<16;          
        tmp=(u8)((CID_Tab[1]&0x00FF0000)>>16);                   //第5个字节
        cardinfo->SD_cid.ProdName1|=tmp<<8;                 
        tmp=(u8)((CID_Tab[1]&0x0000FF00)>>8);                //第6个字节
        cardinfo->SD_cid.ProdName1|=tmp;                  
        tmp=(u8)(CID_Tab[1]&0x000000FF);                          //第7个字节
        cardinfo->SD_cid.ProdName2=tmp;                          
        tmp=(u8)((CID_Tab[2]&0xFF000000)>>24);                 //第8个字节
        cardinfo->SD_cid.ProdRev=tmp;                 
        tmp=(u8)((CID_Tab[2]&0x00FF0000)>>16);                //第9个字节
        cardinfo->SD_cid.ProdSN=tmp<<24;          
        tmp=(u8)((CID_Tab[2]&0x0000FF00)>>8);                 //第10个字节
        cardinfo->SD_cid.ProdSN|=tmp<<16;          
        tmp=(u8)(CID_Tab[2]&0x000000FF);                           //第11个字节
        cardinfo->SD_cid.ProdSN|=tmp<<8;                  
        tmp=(u8)((CID_Tab[3]&0xFF000000)>>24);                 //第12个字节
        cardinfo->SD_cid.ProdSN|=tmp;                             
        tmp=(u8)((CID_Tab[3]&0x00FF0000)>>16);                 //第13个字节
        cardinfo->SD_cid.Reserved1|=(tmp&0xF0)>>4;
        cardinfo->SD_cid.ManufactDate=(tmp&0x0F)<<8;   
        tmp=(u8)((CID_Tab[3]&0x0000FF00)>>8);                //第14个字节
        cardinfo->SD_cid.ManufactDate|=tmp;                           
        tmp=(u8)(CID_Tab[3]&0x000000FF);                        //第15个字节
        cardinfo->SD_cid.CID_CRC=(tmp&0xFE)>>1;
        cardinfo->SD_cid.Reserved2=1;         
        return errorstatus;
}
//读SD卡
//buf:数据缓存区
//sector:扇区
//cnt:扇区数
//返回值:0,ok;其他,失败.
//SPI无DMA下                多块读:约1047K/S                单块读:约623K/S
u8 SD_ReadDisk(u8*buf,u32 sector,u32 cnt)
{
        u8 r1;
        if((sector+cnt)>(SDCardInfo.SD_csd.DeviceSize+1)*1024)        return SD_PARAMETER_ERROR;//超出最大扇区数
        if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;//转换为字节地址(每扇区512B)
       
        if(cnt==1)
        {
                r1=SD_SendCmd(CMD17,sector,0X01);//读命令
                if(r1==0||r1==SD_COM_CRC_ERROR)//指令发送成功【由于未进行CRC计算,故R1可能为SD_COM_CRC_ERROR】
                {
                        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||r1==SD_COM_CRC_ERROR));        
                SD_SendCmd(CMD12,0,0X60);        //发送停止命令
        }
        SD_DisSelect();//取消片选
        return r1;//
}
//写SD卡
//buf:数据缓存区
//sector:起始扇区
//cnt:扇区数
//返回值:0,ok;其他,失败.
u8 SD_WriteDisk(u8*buf,u32 sector,u32 cnt)
{
        u8 r1;
        if(buf==NULL)        return SD_PARAMETER_ERROR;//空指针
        if((sector+cnt)>(SDCardInfo.SD_csd.DeviceSize+1)*1024)        return SD_PARAMETER_ERROR;//超出最大扇区数
       
        if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;//转换为字节地址
        if(cnt==1)
        {
                r1=SD_SendCmd(CMD24,sector,0X01);//写命令
                if(r1==0||r1==SD_COM_CRC_ERROR)//指令发送成功【由于未进行CRC计算,故R1可能为SD_COM_CRC_ERROR】
                {
                        r1=SD_SendBlock(buf,0xFE);//写512个字节          
                }
        }else
        {
                if(SD_Type!=SD_TYPE_MMC)
                {
                        SD_SendCmd(CMD55,0,0X64);       
                        SD_SendCmd(CMD23,cnt,0X01);//发送指令       
                }
                r1=SD_SendCmd(CMD25,sector,0X01);//连续写命令
                if(r1==0||r1==SD_COM_CRC_ERROR)
                {
                        do
                        {
                                r1=SD_SendBlock(buf,0xFC);//接收512个字节         
                                buf+=512;  
                        }while(--cnt && (r1==0||r1==SD_COM_CRC_ERROR));
                        r1=SD_SendBlock(0,0xFD);//接收512个字节
                }
        }   
        SD_DisSelect();//取消片选
        return r1;//
}          
//擦除指定区间的块
//写之前预先擦除会加快写SD卡速度
u8 SD_EraseDisk(u32 startsector,u32 endsector)
{
        u8 r1;
        if(SD_Type!=SD_TYPE_V2HC)
        {
                startsector <<= 9;//转换为字节地址(每扇区512B)
                endsector                <<=9;
        }
       
        r1=SD_SendCmd(CMD32,startsector,0x01);
        if(r1!=0&&r1!=SD_COM_CRC_ERROR)
                return r1;
       
        r1=SD_SendCmd(CMD33,endsector,0x01);
        if(r1!=0&&r1!=SD_COM_CRC_ERROR)
                return r1;
       
        r1=SD_SendCmd(CMD33,endsector,0x01);
        if(r1!=0&&r1!=SD_COM_CRC_ERROR)
                return r1;
       
        return r1;
}


[/mw_shl_code]
回复

使用道具 举报

10

主题

68

帖子

0

精华

初级会员

Rank: 2

积分
96
金钱
96
注册时间
2015-5-13
在线时间
21 小时
 楼主| 发表于 2016-4-15 16:48:39 | 显示全部楼层
yyx112358 发表于 2016-4-15 16:13
C源文件[mw_shl_code=c,true]#include "sys.h"
#include "spi.h"
#include "mmc_sd.h"                          

谢谢了,发现初始化函数里跟原子的代码 发送的命令不一样,主要是发的命令跟注释不一样,是注释没修改吗?
        else//SD V1.x/ MMC  V3
        {
            SD_SendCmd(CMD55,0,0X64);       //发送CMD55
            r1=SD_SendCmd(CMD55,0,0X77);    //发送CMD41
            if(r1<=1)
            {      
                SD_Type=SD_TYPE_V1;
                retry=0XFFFE;
                do //等待退出IDLE模式
                {
                    SD_SendCmd(CMD55,0,0X64);   //发送CMD55
                    r1=SD_SendCmd(CMD55,0,0X77);//发送CMD41
                }while(r1&&retry--);
            }else
            {
                SD_Type=SD_TYPE_MMC;//MMC V3
                retry=0X1000;
                do //等待退出IDLE模式
                {                                               
                    r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1
                }while(r1&&retry--);  
            }
            if(retry==-1||SD_SendCmd(CMD16,512,0X14)!=0)SD_Type=SD_TYPE_ERR;//错误的卡
        }
        r1=SD_SendCmd(CMD59,0,0x95);
    }
付出总有回报
回复

使用道具 举报

10

主题

68

帖子

0

精华

初级会员

Rank: 2

积分
96
金钱
96
注册时间
2015-5-13
在线时间
21 小时
 楼主| 发表于 2016-4-15 16:56:06 | 显示全部楼层
yyx112358 发表于 2016-4-15 16:13
C源文件[mw_shl_code=c,true]#include "sys.h"
#include "spi.h"
#include "mmc_sd.h"                          

        do
        {
                r1=SD_SendCmd(CMD0,0,0x95);//&#189;&#248;è&#235;IDLE×′ì&#172;
        }while((r1!=0X01) && retry--);
        SD_Type=0;//&#196;&#172;è&#207;&#206;T&#191;¨
        if(r1==0X01)
        {
DEBUG发现这个if进不去。。
付出总有回报
回复

使用道具 举报

3

主题

548

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1383
金钱
1383
注册时间
2015-2-3
在线时间
197 小时
发表于 2016-4-16 11:42:49 | 显示全部楼层
JAMES 发表于 2016-4-15 16:48
谢谢了,发现初始化函数里跟原子的代码 发送的命令不一样,主要是发的命令跟注释不一样,是注释没修改吗 ...

我用的不是SD1.X的卡所以没注意,最好还是去翻SD卡协议,我当时就是照着SD卡协议改的

SD卡初始化流程

SD卡初始化流程
回复

使用道具 举报

10

主题

68

帖子

0

精华

初级会员

Rank: 2

积分
96
金钱
96
注册时间
2015-5-13
在线时间
21 小时
 楼主| 发表于 2016-4-18 08:51:13 | 显示全部楼层
yyx112358 发表于 2016-4-16 11:42
我用的不是SD1.X的卡所以没注意,最好还是去翻SD卡协议,我当时就是照着SD卡协议改的

嗯,谢谢了
付出总有回报
回复

使用道具 举报

10

主题

68

帖子

0

精华

初级会员

Rank: 2

积分
96
金钱
96
注册时间
2015-5-13
在线时间
21 小时
 楼主| 发表于 2016-4-18 13:12:42 | 显示全部楼层
mygod 发表于 2016-4-15 13:45
要想有进步就自己调试出来,动不动找这个源码找那个代码,你自己问题根源没找到。下次还来做这个, ...

都拉高或拉低能有什么现象?看不出来的吧
付出总有回报
回复

使用道具 举报

13

主题

101

帖子

0

精华

高级会员

Rank: 4

积分
509
金钱
509
注册时间
2016-1-4
在线时间
87 小时
发表于 2016-8-29 21:57:54 | 显示全部楼层
顶一个
回复

使用道具 举报

4

主题

57

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
269
金钱
269
注册时间
2016-1-25
在线时间
75 小时
发表于 2016-11-23 16:59:31 | 显示全部楼层

你好,我现在也在做SD卡,用SPI1驱动,碰到两个问题,请教一下。
1. SD卡初始化有时能通过,有时不能通过,当不能通过的时候,用手碰一下MISO引脚,立马就可以了;
2. SD卡通过了,但在打开文件时,返回错误FR_DISK_ERR,

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-17 18:11

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表