使用新唐的SDIO例子修改为SDH1始终驱动不了SD卡,所以使用模拟的方式驱动SD卡

头文件:

#ifndef __SD_H
#define __SD_H#include "NuMicro.h"#define SD_CLK PG14#define SD_CMD PA5
#define SD_D0 PG12
#define SD_D1 PA9
#define SD_D2 PG10
#define SD_D3 PG9
#define SD_NCD PE14#define SD_CS SD_D3
#define SD_DI SD_CMD
#define SD_DO SD_D0// 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#define GPIO_NSS    GPIO_Pin_12
#define GPIO_SCK    GPIO_Pin_13
#define GPIO_MISO   GPIO_Pin_14
#define GPIO_MOSI   GPIO_Pin_15
#define CS_H        GPIO_SetBits(GPIOB,GPIO_NSS);
#define CS_L        GPIO_ResetBits(GPIOB,GPIO_NSS);uint8_t SD_Initialize(void);
//uint8_t SPI_ReadWrite_Byte(u8 TxData);
//uint8_t SPI_Read_Byte(u8 txdata);
//uint8_t SD_SPI_ReadWriteByte(u8 data);
//void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler);
uint8_t SD_WaitReady(void);
//uint8_t SD_GetResponse(u8 Response);
//uint8_t SD_Init_Config(void);
//uint8_t SD_ReadDisk2(u8*buf,u32 sector,u8 cnt);
//uint8_t SD_WriteDisk2(u8*buf,u32 sector,u8 cnt);
//uint32_t SD_GetSectorCount(void);
//uint8_t SD_GetCID(u8 *cid_data);
//uint8_t SD_GetCSD(u8 *csd_data);
// void SD_GPIO_init(void);#endif

.c文件

#include "sd.h"static void delay_us(uint32_t us)
{uint32_t i=0xFF*us;while(i>0)i--;
}void SD_GPIO_init(void)
{GPIO_SetMode(PG, BIT14, GPIO_MODE_OUTPUT);GPIO_SetMode(PE, BIT14, GPIO_MODE_INPUT);GPIO_SetMode(PA, BIT5, GPIO_MODE_QUASI);GPIO_SetMode(PA, BIT9, GPIO_MODE_QUASI);GPIO_SetMode(PG, BIT12, GPIO_MODE_QUASI);GPIO_SetMode(PG, BIT10, GPIO_MODE_QUASI);GPIO_SetMode(PG, BIT9, GPIO_MODE_QUASI);PA9=PA5=PE14=PG14=PG9=PG10=PG12 = 1;
//  SD_CLK = SD_CMD = SD_D0 = SD_D1 =SD_D2=SD_D3=SD_NCD =1;
}/// 移植修改区函数 ///*** SD卡SPI接口读写一个字节* @param  TxData 待写入的字节* @return        来自SPI的接收*/
uint8_t SD_SPI_ReadWriteByte(uint8_t TxData)
{int i = 0;uint8_t RxData = 0;SD_CS =0;for(i = 7; i >= 0; i--){SD_CLK = 0;if(TxData & (1 << i)){SD_DI = 1;}else{SD_DI = 0;}delay_us(1);SD_CLK = 1;RxData <<= 1;if(SD_DO){RxData |= 1;}delay_us(1);}SD_CS =1;return RxData;
}/// SPI硬件层初始化
void SD_SPI_Init(void)
{SD_CLK = 0;    /* 时钟空闲为低电平 */SD_SPI_ReadWriteByte(0xFF);SD_CS =1;
}//取消选择,释放SPI总线
void SD_DisSelect(void)
{SD_CS =1;SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
}/*** 选中SD卡并等待卡准备好* @return  0:成功  1:失败*/
uint8_t SD_Select(void)
{SD_CS =0;if (SD_WaitReady() == 0)return 0; //等待成功SD_DisSelect();return 1;//等待失败
}/*** 等待SD卡准备好* @return  0:成功  other:失败*/
uint8_t SD_WaitReady(void)
{uint32_t t = 0;do{if (SD_SPI_ReadWriteByte(0XFF) == 0XFF)return 0; //OKt++;}while (t < 0XFFFFFF); //等待return 1;
}/*** 等待SD卡回应* @param  Response 要得到的回应值* @return          0:成功  other:失败*/
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卡的一包数据* @param  buf 存放接收的数据* @param  len 接收的数据长度* @return     0:成功  other:失败*/
uint8_t SD_RecvData(uint8_t*buf, uint16_t len)
{if (SD_GetResponse(0xFE))return 1; //等待SD卡发回数据起始令牌0xFEwhile (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,成功;其他,失败;/*** 向SD卡写入一扇区数据* @param  buf 待写入的数据,size=512* @param  cmd 指令* @return     0:成功  other:失败*/
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);//忽略crcSD_SPI_ReadWriteByte(0xFF);t = SD_SPI_ReadWriteByte(0xFF); //接收响应if ((t & 0x1F) != 0x05)return 2; //响应错误}return 0;//写入成功
}/*** 向SD卡发送命令* @param  cmd 待发送的命令* @param  arg 参数* @param  crc crc校验值* @return     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信息,包括制造商信息* @param  cid_data 存放CID数据,至少16字节* @return          0:成功  1:失败*/
uint8_t SD_GetCID(uint8_t *cid_data)
{uint8_t r1;//发CMD10命令,读CIDr1 = 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卡CID信息,包括制造商信息* @param  csd_data 存放CID信息,至少16字节* @return          0:成功  1:失败*/
uint8_t SD_GetCSD(uint8_t *csd_data)
{uint8_t r1;r1 = SD_SendCmd(CMD9, 0, 0x01); //发CMD9命令,读CSDif (r1 == 0){r1 = SD_RecvData(csd_data, 16); //接收16个字节的数据}SD_DisSelect();//取消片选if (r1)return 1;else return 0;
}
/*** 获取SD卡扇区数* @return  0:获取出错  other:SD卡扇区数*/
uint32_t SD_GetSectorCount(void)
{uint8_t csd[16];uint32_t Capacity;uint8_t n;uint16_t csize;//取CSD信息,如果期间出错,返回0if (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;
}/// SD卡进入闲置状态
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;//成功
}
uint8_t SD_Type;
/// 初始化SD卡
uint8_t SD_Initialize(void)
{uint8_t r1;      // 存放SD卡的返回值uint16_t retry;  // 用来进行超时计数uint8_t buf[4];uint16_t i;SD_SPI_Init();      //初始化IOfor (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);    //Get trailing return value of R7 respif (buf[2] == 0X01 && buf[3] == 0XAA) //卡是否支持2.7~3.6V{retry = 0XFFFE;do{SD_SendCmd(CMD55, 0, 0X01);  //发送CMD55r1 = 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; //检查CCSelse SD_Type = SD_TYPE_V2;}}}else //SD V1.x/ MMC   V3{SD_SendCmd(CMD55, 0, 0X01);      //发送CMD55r1 = SD_SendCmd(CMD41, 0, 0X01);  //发送CMD41if (r1 <= 1){SD_Type = SD_TYPE_V1;retry = 0XFFFE;do //等待退出IDLE模式{SD_SendCmd(CMD55, 0, 0X01); //发送CMD55r1 = SD_SendCmd(CMD41, 0, 0X01); //发送CMD41}while (r1 && retry--);}else{SD_Type = SD_TYPE_MMC; //MMC V3retry = 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();//取消片选if (SD_Type)return 0;else if (r1)return r1;return 0xaa;//其他错误
}/*** 读取SD卡一个扇区* @param  buf    存放读取的数据* @param  sector 扇区编号* @param  cnt    要读取的扇区个数* @return        0:成功  other:失败*/
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卡写一个扇区的数据* @param  buf    存放待写入的数据* @param  sector 扇区编号* @param  cnt    要写入的扇区个数* @return        0:成功  other:失败*/
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;//
}

SD卡SPI驱动时序讲解:

STM32开发_利用SPI协议读写SD卡、介绍SD卡SPI时序_DS小龙哥的博客-CSDN博客

收集的一些SD卡资料:

https://download.csdn.net/download/klp1358484518/87238010

模拟SPI驱动SD卡相关推荐

  1. STM32——SPI驱动SD卡

    文末有工程链接(FATFS文件系统也移植了) VCC:5V GND:GND MISO:PA6 MOSI:PA7 SCK:PA5 CS:PA4 /*外设驱动*/ /*.c*/ /*以下是SPI1口初始化 ...

  2. 模拟SPI进行TF卡操作+Fatfs文件系统移植

    FATFS版本:FATFS R0.13b SD卡容量:16G 概述 本文的重点是进行Fatfs文件系统的移植和初步的使用.TF卡的操作实际上是指令操作,即你想它发送固定的CMD指令,它接收到指令给你返 ...

  3. RT-Thread Studio驱动SD卡

    RT-Thread Studio驱动SD卡 前言 一.创建基本工程 1.创建Bootloader 2.创建项目工程 二.配置RT-Thread Settings 三.代码分析 四.效果验证 总结 前言 ...

  4. MSP430杂谈--AD7793硬件SPI驱动与模拟SPI驱动

    最近项目中用到了AD7793读取铂电阻值来得到相应的温度,编写了基于MSP430的硬件驱动程序和模拟驱动程序,并且能成功运行,现在记录一下分享给大家. AD7793硬件IIC驱动完整版下载链接:htt ...

  5. 鸿蒙开发板Hi3861模拟SPI驱动JLX12864_LCD(UC1701X)_基于code-2.0

    鸿蒙开发板驱动晶联讯LCDjlx12864_lcd_hi3861源码-C文档类资源-CSDN下载鸿蒙开发板驱动晶联讯LCDjlx12864_lcd_hi3861源码博文介绍https://t更多下载资 ...

  6. 【全志T113-S3_100ask】15-2 linux系统gpio模拟spi驱动屏幕——ILI9341

    [全志T113-S3_100ask]15-2 linux系统gpio模拟spi驱动屏幕--ILI9341 背景 (一)查阅参考文档 (二)使能内核模块 (三)修改设备树 (四)测试 (五)后语 背景 ...

  7. STM32利用SPI读写SD卡的程序详解

    STM32利用SPI读写SD卡的一些程序详解 关于SD卡的基础知识这里不做过多陈述,如果有对这方面感兴趣的朋友可以直接百度一下,有很多讲SD卡的文章,这里主要是针对SD卡的读写程序实现做一些详细说明. ...

  8. stm32驱动sd卡(1)

    Stm32驱动sd卡知识总结(1) 1.Stm32支持SDIO接口,可以用来接入一张不超过32G的SD卡 2.CID寄存器长度为128bit,用来标记SD卡的全球唯一身份识别号 3.支持单线和四线传输 ...

  9. 鸿蒙开发板Hi3861模拟SPI驱动12864LCD_ST7920_基于code-2.0-CANARY

    鸿蒙开发板Hi3861模拟SPI驱动12864LCD_ST7920源码.rar-C文档类资源-CSDN下载鸿蒙开发板Hi3861模拟SPI驱动12864LCD_ST7920源码.rar博文链接:htt ...

最新文章

  1. Java打造一款SSH客户端,而且已开源
  2. 轻松精通数据库管理之道——运维巡检系列
  3. 《皇帝:中国的崛起》从入门到精通
  4. 博客园上海俱乐部第二次活动全程图片报道(多图)
  5. mysql in 按顺序排序_mysql in 排序 也可以按in里面的顺序来排序
  6. W3C近期要闻:W3C战略重点报告新版发布
  7. FreeMarker_模板引擎_代码自动生成器_源码下载
  8. 浏览器与WEB服务器交互
  9. SpringMvc-HandlerMethodArgumentResolver
  10. SCCM 2012安装部署三:客户端管理
  11. 带孩子们做环球旅行的读后感_孩子少言寡语、不爱说话怎么办?家长们可以这样做...
  12. 关于java 中 的 null。
  13. 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0...
  14. JAVA并发:深入分析volatile
  15. 在mac上制作PDF的基础教程
  16. pycharm2020版本以上中文版教程
  17. 通过分析词性进行人名、地名、组织的替换,生成新的狗屁不通文章
  18. Java校园二手交易平台【计算机毕业设计】
  19. 扩展欧几里得算法(求逆元)总结
  20. html5 3d gallery,使用jQuery制作3d画廊房间

热门文章

  1. vmware 恢复快照时出错
  2. Golang panic:WaitGroup is reused before previous Wait has returned
  3. ValueError: Classification metrics can‘t handle a mix of continuous-multioutput and multiclass targe
  4. jQuery背景墙聚光灯效果
  5. Java架构师成长之路
  6. 不完全免疫算法简介HEIA--AIS学习笔记2
  7. 树莓派csi摄像头和usb摄像头_一、树莓派CSI摄像头
  8. 一个登录页面的测试用例
  9. Druid Monitor监控
  10. 华擎计算机主板型号,华擎科技 新闻中心