栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

SD卡驱动

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SD卡驱动

SD卡驱动介绍
  • 一、介绍
    • 1.SD 卡
    • 2. SD的通讯模式
    • 3.SD引脚定义
  • 二、SD卡驱动介绍
    • 1.SD寄存器介绍
    • 2、SD卡识别流程
      • 初始化过程
    • 3、读写SD卡
      • SD卡读取数据(CMD17):
      • SD卡写数据(CMD24):
  • 三、SD卡驱动源码
    • 源文件
    • 头文件
  • 使用指南
      • 在不同的平台下实现以下函数

一、介绍 1.SD 卡

安全数码卡, 它是在 MMC 的基础上发展而来, 是一种基于半导体快闪记忆器的新一代记忆设备。按容量分类,可以将SD 卡分为 3 类: SD 卡、 SDHC 卡、 SDXC 卡。SD卡(SDSC):0~2G SDHC卡:2~32G SDXC卡:32G~2T

2. SD的通讯模式
  • SD 卡模式(通过 SD 总线通信):允许 4 线的高速数据传输,只能使用 3.3V 的 IO 电平,所以, MCU 一定要能够支持 3.3V 的 IO 端口输出。
  • SPI 模式:同 SD 卡模式相比就是丧失了速度,在 SPI 模式下, CS/MOSI/MISO/CLK 都需要加 10~100K 左右的上拉电阻。
3.SD引脚定义

二、SD卡驱动介绍 1.SD寄存器介绍
名称宽度描述
CID128卡识别寄存器
CSD128卡描述数据寄存器:卡操作条件相关的信息数据。
OCR32操作条件寄存器
RCA16相对卡地址寄存器:本地系统中卡的地址,动态变化,在卡的初始化时确定。(SPI模式中没有)
SCR64SD配置寄存器:SD卡特定信息数据
2、SD卡识别流程

初始化过程
  1. 初始化与 SD 卡连接的硬件条件(MCU 的 SPI 配置, IO 口配置;
  2. 上电延时(>74 个 CLK)(因为 SD 卡内部有个供电电压上升时间,大概为 64 个 CLK,剩下的 10 个 CLK 用于 SD 卡同步,之后才能开始 CMD0 的操作);
  3. 复位卡(CMD0),进入 IDLE 状态;
  4. 发送 CMD8,检查是否支持 2.0 协议;
  5. 根据不同协议检查 SD 卡(命令包括: CMD55、 CMD41、 CMD58 和 CMD1 等);
  6. 取消片选,发多 8 个 CLK(提供 SD 卡额外的时钟,完成某些操作),结束初始化;
3、读写SD卡

SD卡读取数据(CMD17):
  • 发送 CMD17;
  • 接收卡响应 R1;
  • 接收数据起始令牌 0xFE;
  • 接收数据;
  • 接收 2 个字节的 CRC,如果不使用 CRC,这两个字节在读取后可以丢掉。
  • 禁止片选之后,发多 8 个 CLK;
SD卡写数据(CMD24):
  • 发送 CMD24;
  • 接收卡响应 R1;
  • 发送写数据起始令牌 0xFE;
  • 发送数据;
  • 发送 2 字节的伪 CRC;
  • 禁止片选之后,发多 8 个 CLK;
三、SD卡驱动源码 源文件
#include "mmc_sd.h"

uint8_t  SD_Type = 0;//SD卡的类型
uint32_t Capacity = 0; //可用扇区数

移植修改区///
//SPI初始化
void hal_spi_init(void)
{

}


uint8_t SD_SPI_ReadWriteByte(uint8_t Dat)
{
	
}

//取消选择,释放SPI总线
void SD_DisSelect(void)
{
    SD_CS_HIGH_HRS();
    SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
}

//选择sd卡,并且等待卡准备OK
//返回值:0,成功;1,失败;
uint8_t SD_Select(void)
{
    SD_CS_LOW_HRS();
    if(SD_WaitReady()==0)return 0;//等待成功
    SD_DisSelect();
    return 1;//等待失败
}
///

//等待卡准备好
//返回值:0,准备好了;其他,错误代码
uint8_t SD_WaitReady(void)
{
    uint32_t t=0;
    do
    {
        if(SD_SPI_ReadWriteByte(0xFF)==0xFF)return 0;//OK
        t++;
    }
    while(t<0xFFFFFF); //等待
    return 1;
}
//等待SD卡回应
//Response:要得到的回应值
//返回值:0,成功得到了该回应值
//    其他,得到回应值失败
uint8_t SD_GetResponse(uint8_t Response)
{
    uint16_t Count=0xFFF;//等待次数
    while ((SD_SPI_ReadWriteByte(0xFF)!=Response)&&Count)Count--;//等待得到准确的回应
    if (Count==0)return MSD_RESPONSE_FAILURE;//得到回应失败
    else return MSD_RESPONSE_NO_ERROR;//正确回应
}
//从sd卡读取一个数据包的内容
//buf:数据缓存区
//len:要读取的数据长度.
//返回值:0,成功;其他,失败;
uint8_t SD_RecvData(uint8_t*buf,uint16_t len)
{
    if(SD_GetResponse(0xFE))return 1;//等待SD卡发回数据起始令牌0xFE
    while(len--)//开始接收数据
    {
        *buf=SD_SPI_ReadWriteByte(0xFF);
        buf++;
    }
    //下面是2个伪CRC(dummy CRC)
    SD_SPI_ReadWriteByte(0xFF);
    SD_SPI_ReadWriteByte(0xFF);
    return 0;//读取成功
}
//向sd卡写入一个数据包的内容 512字节
//buf:数据缓存区
//cmd:指令
//返回值:0,成功;其他,失败;
uint8_t SD_SendBlock(uint8_t*buf,uint8_t cmd)
{
    uint16_t t;
    if(SD_WaitReady())return 1;//等待准备失效
    SD_SPI_ReadWriteByte(cmd);
    if(cmd!=0xFD)//不是结束指令
    {
        for(t=0; t<512; t++)SD_SPI_ReadWriteByte(buf[t]); //提高速度,减少函数传参时间
        SD_SPI_ReadWriteByte(0xFF);//忽略crc
        SD_SPI_ReadWriteByte(0xFF);
        t=SD_SPI_ReadWriteByte(0xFF);//接收响应
        if((t&0x1F)!=0x05)return 2;//响应错误
    }
    return 0;//写入成功
}

//向SD卡发送一个命令
//输入: uint8_t cmd   命令
//      uint32_t arg  命令参数
//      uint8_t crc   crc校验值
//返回值:SD卡返回的响应
uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg, uint8_t crc)
{
    uint8_t r1;
    uint8_t Retry=0;
    SD_DisSelect();//取消上次片选
    if(SD_Select())return 0xFF;//片选失效
    //发送
    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--);
    //返回状态值
    return r1;
}
//获取SD卡的CID信息,包括制造商信息
//输入: uint8_t *cid_data(存放CID的内存,至少16Byte)
//返回值:0:NO_ERR
//		 1:错误
uint8_t SD_GetCID(uint8_t *cid_data)
{
    uint8_t r1;
    //发CMD10命令,读CID
    r1=SD_SendCmd(CMD10,0,0x01);
    if(r1==0x00)
    {
        r1=SD_RecvData(cid_data,16);//接收16个字节的数据
    }
    SD_DisSelect();//取消片选
    if(r1)return 1;
    else return 0;
}
//获取SD卡的CSD信息,包括容量和速度信息
//输入:uint8_t *cid_data(存放CID的内存,至少16Byte)
//返回值:0:NO_ERR
//		 1:错误
uint8_t SD_GetCSD(uint8_t *csd_data)
{
    uint8_t r1;
    r1=SD_SendCmd(CMD9,0,0x01);//发CMD9命令,读CSD
    if(r1==0)
    {
        r1=SD_RecvData(csd_data, 16);//接收16个字节的数据
    }
    SD_DisSelect();//取消片选
    if(r1)return 1;
    else return 0;
}
//获取SD卡的总扇区数(扇区数)
//返回值:0: 取容量出错
//       其他:SD卡的容量(扇区数/512字节)
//每扇区的字节数必为512,因为如果不是512,则初始化不能通过.
uint32_t SD_GetSectorCount(void)
{
    uint8_t csd[16];
    uint32_t Capacity;
    uint8_t n;
    uint16_t csize;
    //取CSD信息,如果期间出错,返回0
    if(SD_GetCSD(csd)!=0) return 0;
    //如果为SDHC卡,按照下面方式计算
    if((csd[0]&0xC0)==0x40)	 //V2.00的卡
    {
        csize = csd[9] + ((uint16_t)csd[8] << 8) + 1;
        Capacity = (uint32_t)csize << 10;//得到扇区数
    }
    else //V1.XX的卡
    {
        n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
        csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1;
        Capacity= (uint32_t)csize << (n - 9);//得到扇区数
    }
    return Capacity;
}
uint8_t SD_Idle_Sta(void)
{
    uint16_t i;
    uint8_t retry;
    for(i=0; i<0xf00; i++); //纯延时,等待SD卡上电完成
    //先产生>74个脉冲,让SD卡自己初始化完成
    for(i=0; i<10; i++)SD_SPI_ReadWriteByte(0xFF);
    //-----------------SD卡复位到idle开始-----------------
    //循环连续发送CMD0,直到SD卡返回0x01,进入IDLE状态
    //超时则直接退出
    retry = 0;
    do
    {
        //发送CMD0,让SD卡进入IDLE状态
        i = SD_SendCmd(CMD0, 0, 0x95);
        retry++;
    }
    while((i!=0x01)&&(retry<200));
    //跳出循环后,检查原因:初始化成功?or 重试超时?
    if(retry==200)return 1; //失败
    return 0;//成功
}
//初始化SD卡
uint8_t SD_Initialize(void)
{
    uint8_t r1;      // 存放SD卡的返回值
    uint16_t retry;  // 用来进行超时计数
    uint8_t buf[4];
    uint16_t i;
    
     while(SD_Idle_Sta());
    
    SD_Type=0;//默认无卡
    if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
    {
        for(i=0; i<4; i++)buf[i]=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,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/ MMC	V3
    {
        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
        {
            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_GetSectorCount();
    SD_DisSelect();//取消片选
    if(SD_Type)return 0;
    else if(r1)return r1;
    return 0xaa;//其他错误
}

//读SD卡
//buf:数据缓存区
//sector:扇区
//cnt:扇区数
//返回值:0,ok;其他,失败.
uint8_t SD_ReadDisk(uint8_t*buf,uint32_t sector,uint8_t cnt)
{
    uint8_t 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;//
}
//写SD卡
//buf:数据缓存区
//sector:起始扇区
//cnt:扇区数
//返回值:0,ok;其他,失败.
uint8_t SD_WriteDisk(uint8_t*buf,uint32_t sector,uint8_t cnt)
{
    uint8_t r1;
    if(SD_Type!=SD_TYPE_V2HC)sector *= 512;//转换为字节地址
    if(cnt==1)
    {
        r1=SD_SendCmd(CMD24,sector,0x01);//读命令
        if(r1==0)//指令发送成功
        {
            r1=SD_SendBlock(buf,0xFE);//写512个字节
        }
    }
    else
    {
        if(SD_Type!=SD_TYPE_MMC)
        {
            SD_SendCmd(CMD55,0,0x01);
            SD_SendCmd(CMD23,cnt,0x01);//发送指令
        }
        r1=SD_SendCmd(CMD25,sector,0x01);//连续读命令
        if(r1==0)
        {
            do
            {
                r1=SD_SendBlock(buf,0xFC);//接收512个字节
                buf+=512;
            }
            while(--cnt && r1==0);
            r1=SD_SendBlock(0,0xFD);//接收512个字节
        }
    }
    SD_DisSelect();//取消片选
    return r1;//
}





uint8_t SD_disk_status(void)
{
    return 1;
}




uint8_t SD_disk_initialize(void)
{
    if(SD_Initialize() == 0)
        return 1;
    else
        return 0;
}
头文件
#ifndef _MMC_SD_H_
#define _MMC_SD_H_
移植修改区///
#include 
#include "nrf_drv_common.h"
#include "nrf_drv_spi.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "nrf_gpio.h"
#include "boards.h"
#include "nrf_delay.h"
#include "ds1302.h"

#define SPI_INSTANCE  0 

#define SPI_SS_PIN     28
#define SPI_SCK_PIN     29
#define SPI_MOSI_PIN     30
#define SPI_MISO_PIN     31

#define SD_CS_STANDARD0_NODRIVE_HRS() do { 
NRF_GPIO->PIN_CNF[SPI_SS_PIN] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos) 
|(GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos)    
|(GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)  
|(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) 
|(GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);  
} while (0)     

#define SD_CS_OUTPUT_HRS() do { NRF_GPIO->DIRSET = (1UL << SPI_SS_PIN);  } while(0) 

#define SD_CS_HIGH_HRS()   do { NRF_GPIO->OUTSET = (1UL << SPI_SS_PIN);  } while(0)   
#define SD_CS_LOW_HRS()    do { NRF_GPIO->OUTCLR = (1UL << SPI_SS_PIN);  } while(0)       

///
// SD卡类型定义
#define SD_TYPE_ERR     0x00
#define SD_TYPE_MMC     0x01
#define SD_TYPE_V1      0x02
#define SD_TYPE_V2      0x04
#define SD_TYPE_V2HC    0x06
// SD卡指令表
#define CMD0    0       //卡复位
#define CMD1    1
#define CMD8    8       //命令8 ,SEND_IF_COND
#define CMD9    9       //命令9 ,读CSD数据
#define CMD10   10      //命令10,读CID数据
#define CMD12   12      //命令12,停止数据传输
#define CMD16   16      //命令16,设置SectorSize 应返回0x00
#define CMD17   17      //命令17,读sector
#define CMD18   18      //命令18,读Multi sector
#define CMD23   23      //命令23,设置多sector写入前预先擦除N个block
#define CMD24   24      //命令24,写sector
#define CMD25   25      //命令25,写Multi sector
#define CMD41   41      //命令41,应返回0x00
#define CMD55   55      //命令55,应返回0x01
#define CMD58   58      //命令58,读OCR信息
#define CMD59   59      //命令59,使能/禁止CRC,应返回0x00
//数据写入回应字意义
#define MSD_DATA_OK                0x05
#define MSD_DATA_CRC_ERROR         0x0B
#define MSD_DATA_WRITE_ERROR       0x0D
#define MSD_DATA_OTHER_ERROR       0xFF
//SD卡回应标记字
#define MSD_RESPONSE_NO_ERROR      0x00
#define MSD_IN_IDLE_STATE          0x01
#define MSD_ERASE_RESET            0x02
#define MSD_ILLEGAL_COMMAND        0x04
#define MSD_COM_CRC_ERROR          0x08
#define MSD_ERASE_SEQUENCE_ERROR   0x10
#define MSD_ADDRESS_ERROR          0x20
#define MSD_PARAMETER_ERROR        0x40
#define MSD_RESPONSE_FAILURE       0xFF
		    	               
extern uint8_t  SD_Type;//SD卡的类型
extern uint32_t Capacity;



#define SECTOR_SIZE     512 //扇区大小
#define BLOCK_SIZE      1   //块大小
uint8_t SD_disk_status(void);
uint8_t SD_disk_initialize(void);
uint8_t SD_ReadDisk(uint8_t*buf,uint32_t sector,uint8_t cnt);		//读块
uint8_t SD_WriteDisk(uint8_t*buf,uint32_t sector,uint8_t cnt);		//写块

//函数申明区
uint8_t SD_WaitReady(void);							//等待SD卡准备
uint8_t SD_GetResponse(uint8_t Response);					//获得相应
uint8_t SD_Initialize(void);							//初始化
uint32_t SD_GetSectorCount(void);   					//读扇区数
uint8_t SD_GetCID(uint8_t *cid_data);                     //读SD卡CID
uint8_t SD_GetCSD(uint8_t *csd_data);                     //读SD卡CSD
void hal_spi_init(void);
void Set_spi_speed(void);

#endif
使用指南 在不同的平台下实现以下函数
  • 初始化SPI函数:**void hal_spi_init(void);**
  • 实现SPI的传输数据函数: **uint8_t SD_SPI_ReadWriteByte(uint8_t Dat)**
  • 实现对片选(CS)脚的控制:void SD_DisSelect(void)uint8_t SD_Select(void)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/385056.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号