战舰精英版的SD卡SDIO程序请问如何将SD卡烧录成软盘到普通战舰版本的开发版中出现错误

MCU | Layout | DIY
SD卡升级——SDIO_IAP实验
在嵌入式项目中,经常会用到SD卡升级这一方式来进行产品的软件升级。刚好最近做的项目也需要这一功能,由于之前未接触过IAP开发,刚好在这个时候可以学习一下,于是先到各大网站去搜索相关资料,两天下来,基本对于IAP的概念和编程步骤有了大致的了解。本人手里有块正点原子的开发板,前期的实验都是在这块开发板上实现的。在实现了SD卡IAP功能以后,立马将工程移植到项目中去,很快就把这个功能添加进去了,甚是高兴,对于以前的SD卡升级功能也不再那么神秘了。
本人是先看正点原子的超级战舰手册,先看的《第三十九章 FLASH模拟EEPROM实验》,了解了STM32片内FLASH编程的步骤,然后再看的《第五十三章 串口IAP实验》,学习IAP编程的思想,最后到阿莫电子论坛上搜索相关的资料,最终完成了SD卡IAP编程的学习,并解决了实际问题。
学习总结:
1.STM32片内FLASH编程步骤4步曲:解锁、擦除、编程、上锁;
2.设置IAP程序在FLASH的起始地址,设置用户程序的起始地址为IAP后面的地址,并修改ROM空间大小;
3.在用户程序中,设置中断向量偏移地址为用户程序的起始地址;
4.STM32大容量存储器的页大小为2K,起初总以为是512字节;
5.页擦除的时候,所有的页地址都是实际的字节地址,而并非常说的“第几页第几页”中的页编号;
6.页擦除的时候,如果指定的页地址没有和页边界对齐的话,擦除操作仍然有效,只是擦除的范围是指定地址所在的整页大小;
原子哥的IAP实验是基于串口的,由于串口的数据发送是不可调的,只能一次性将整个用户程序的BIN文件发送给bootloader,而且bootloader是将接收到的用户文件暂存在片内SRAM的,这就限值了用户程序的大小,不能大于SRAM的大小64K。而SD卡设计则不受用户程序大小限值,只要FLASH装得下就行。由于原子哥的代码很多都是寄存器版本的,而文件系统又是他自己独门的FAT32驱动,再加上他的开发板SD卡例程都基于SPI驱动的(只有一个扩展例程是SDIO的),而我的项目时间比较急,要求用最高的效率完成这项功能,于是就产生了以ST官方库函数为主导,以网上开源文件系统Fatfs作为SD卡文件系统驱动,以SDIO4位总线的DMA访问模式为SD卡驱动这样一个方案,一切都只为了开发的效率,同时,也将源代码与大家分享,相信也有很多人使用这样一种方案的。
本工程试验平台:
1.硬件:正点原子超级战舰开发板,由于购买时配套的3.5寸触摸屏,对于3.5以下的屏为测试过,但应该没问题,因为LCD驱动用的还是原子哥的驱动,是兼容2.4到3.5的。SanDisk 1G SD卡, MicroSD 2G。注意:要使用超级战舰开发板上的SDIO功能,必须将开发板上的P10跳线帽接到P11上,因为原子的SD卡驱动默认使用SPI接口的,所以这里必须要设置!
2.软件:ST官方库V3.0的,比较老了。
FatFs文件系统,注意:本人在ff.h配置中将宏_FS_READONLY配置为1,即只生成读操作的代码,不编译写操作的代码,目的是为了减小
bootloader的代码量,包括原子哥的LCD.C中的代码也删减了很多。
下面就将主要的源代码贴出,供大家参考。
/*****************************************************************************************************
文件描述:程序执行的主要文件,不用说也明白
博客:http://blog.csdn.net/hexiaolong2009
创建时间:
更改历史:
*****************************************************************************************************/
#include "stm32f10x.h"
#include "delay.h"
#include "LED.h"
#include "diskio.h"
#include "ff.h"
#include "lcd.h"
#define FLASH_APP_ADDR
//第一个应用程序起始地址(存放在FLASH)
#define STM_PAGE_SIZE
//注意:STM32F103ZET6的FLASH页大小为2K
//****************************************************************************************************
//全局变量声明
BYTE buffer[STM_PAGE_SIZE];
void (*fun)(void);
//定义一个函数类型的参数.
/*****************************************************************************************************
:Jump2App
能:从Bootloader跳转到用户APP程序地址空间
入口参数:Addr,用户APP的起始执行地址
出口参数:无
*****************************************************************************************************/
void Jump2App(u32 Addr)
if(((*(vu32*)Addr)&0x2FFE0000) == 0x)
//检查栈顶地址是否合法.
AppStart = (fun)(*(vu32*)(Addr+4));
//用户代码区第二个字为程序开始地址(复位地址)
AppStart();
//跳转到APP.
/*****************************************************************************************************
:FirmwareUpdate
能:固件升级函数
入口参数:无
出口参数:无
*****************************************************************************************************/
void FirmwareUpdate(void)
int PageOffest = 0;
//页偏移,从APP的基地址到当前页起始位置的字节总数
//当前页内的字节偏移,从当前操作页的起始位置到正在写入位置的字节偏移
/*首先初始化SD卡*/
if(0 != disk_initialize(0))
/*接着挂载文件系统对象*/
f_mount(0, &Fs);
/*查找是否存在要升级的BIN文件*/
res = f_open(&file, "RTC.bin", FA_OPEN_EXISTING | FA_READ);
if(FR_OK != res)
/*绘制进度条边框*/
LCD_DrawRectangle(50, 225, 250, 255);
/*初始化临时变量*/
a = file.fsize / 100;
//100表示将进度条平均分成100份,由于进度条长度为200个像素,所以1份占用2个像素
//将文件平均分成100份,所以a表示一份文件所占的字节数,为确保该字节数为偶数,故做此转换
//b表示当前已经更新了多少字节
/*执行主要的IAP功能*/
/*每次读取一个页的数据到内存缓冲区,注意:STM32F103ZE的页大小为2K*/
res = f_read(&file, buffer, STM_PAGE_SIZE, &br);
if (res || br == 0)
/*然后就是永恒的4步骤:解锁、擦除、更新、上锁*/
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
FLASH_ErasePage(FLASH_APP_ADDR + PageOffest);
for(ByteOffest = 0; ByteOffest & STM_PAGE_SIZE; ByteOffest += 2)
/*更新FLASH,注意当前操作的实际位置:APP基地址FLASH_APP_ADDR+页偏移字节PageOffest+当前页内的字节偏移ByteOffest*/
FLASH_ProgramHalfWord(FLASH_APP_ADDR + PageOffest + ByteOffest, *(u16*)(buffer + ByteOffest));
/*更新显示进度条,(b % a == 0)的目的是确保当前正好写完1份文件*/
if(b % a == 0)
LCD_Fill(50, 225, 50 + 2 * (b / a), 255, 0x7e0); //(b / a)表示已经写了几份文件
FLASH_Lock();
PageOffest += STM_PAGE_SIZE;
/*每更新完1页,让LED状态翻转一次*/
GPIO_SetBits(GPIOB, GPIO_Pin_5);
GPIO_ResetBits(GPIOB, GPIO_Pin_5);
/*关闭文件,卸载文件系统*/
f_close(&file);
f_mount(0, 0);
/*****************************************************************************************************
能:主程序入口函数
入口参数:无
出口参数:无
*****************************************************************************************************/
int main(void)
SystemInit();
delay_init(72);
LED_Init();
LCD_Init();
FirmwareUpdate();
Jump2App(FLASH_APP_ADDR);
工程源码:
KB, 下载次数: 286)
还要注意的地方:用户程序是放在FLASH地址0x的位置的,而且该代码只识别SD卡根目录下的RTC.bin文件,如果要更改文件名,则只需将FirmwareUpdate函数中的“RTC.bin”文件改成你要升级的文件即可。
以下是运行效果:
IMAG1541.jpg (202.74 KB, 下载次数: 0)
18:54 上传
希望对大家有帮助。
没有更多推荐了,拒绝访问 | www.broadon.net | 百度云加速
请打开cookies.
此网站 (www.broadon.net) 的管理员禁止了您的访问。原因是您的访问包含了非浏览器特征(439bb2afd1dc44e5-ua98).
重新安装浏览器,或使用别的浏览器阿里巴巴中国站和淘宝网会员帐号体系、《阿里巴巴服务条款》升级,完成登录后两边同时登录成功。
奋斗版stm32
阿里巴巴找货神器为您推荐
奋斗版stm32
同款货源、相似货源。
让千万商家找到您
感兴趣的产品
感兴趣的产品
感兴趣的产品
感兴趣的产品战舰V3_IO引脚分配表_图文_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&10W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
战舰V3_IO引脚分配表
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩3页未读,
定制HR最喜欢的简历
你可能喜欢记录学习嵌入式的点点滴滴
S3C6410裸机SD卡驱动(SDIO模式)
花了几天写了SD卡裸机驱动,现在还不完善,只支持4G以内的卡,以后再加上;现在经过修改可以写入数据了,亲测没问题.
S3C6410_SDIO.C
#include "s3c6410_system.h"
#include "s3c6410_sdio.h"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//块大小寄存器(0通道)BLKSIZE0
#define BLKSIZE0_BLKSIZE
//块大小为512字节
//传输模式寄存器(0通道)TRNMOD0
#define TRNMOD0_CCSCON
//正常模式
#define TRNMOD0_MUL1SIN0
(0 && 5) //默认为单区段操作模式
#define TRNMOD0_RD1WT0
(1 && 4) //默认为读操作模式
#define TRNMOD0_ENACMD12
(0 && 2) //自动CMD12禁止,多区段操作完成后主机自动发出停止命令
#define TRNMOD0_ENBLKCNT
(0 && 1) //块计数器无效
#define TRNMOD0_ENDMA
(0 && 0) //DMA无效
//主机控制寄存器(0通道)HOSTCTL0
#define HOSTCTL0_WIDE8
(0 && 5) //这个为宽度被位1指定 (数据传输宽度)
#define HOSTCTL0_DMASEL
(0 && 3) //SDMA
#define HOSTCTL0_OUTEDGEINV
(0 && 2) //时钟上升沿沿数据有效
//这个寄存器有歧义,不知道到底是干啥用的
#define HOSTCTL0_WIDE4
(0 && 4) //数据传输宽度。1BIT模式
//电源控制寄存器(0通道)PWRCON0
#define PWRCON0_SELPWRLVL
(7 && 1) //3.3V电源模式
#define PWRCON0_PWRON
(1 && 0) //电源打开
//容限寄存器(0 通道)CAPAREG0
#define CAPAREG0_V18
(1 && 26) //电压支持1.8V
#define CAPAREG0_V30
(0 && 25) //电压不支持3v
#define CAPAREG0_V33
(1 && 24) //电压支持3.3V
#define CAPAREG0_SUSRES
(1 && 23) //支持暂停/恢复操作
#define CAPAREG0_DMA
(1 && 22) //支持DMA
#define CAPAREG0_HSPD
(1 && 21) //支持高速模式
#define CAPAREG0_ADMA2
(0 && 19) //不支持DMA2
#define CAPAREG0_MAXBLKLEN
(0 && 16) //最大块大小为512B
#define CAPAREG0_BASECLK
(25 && 8) //SD基础始终25MHz
#define CAPAREG0_TOUTUNIT
(0 && 7) //超时时钟单位KHZ
#define CAPAREG0_TOUTCLK
(10 && 0) //超时时钟频率为10KHZ
//最大电流容限寄存器(0 通道)MAXCURR0
#define MAXCURR0_MAXCURR18
(10 && 16) //对于1.8V,最大电流为40MA
#define MAXCURR0_MAXCURR30
(10 && 8) //对于3.0V,最大电流为40MA
#define MAXCURR0_MAXCURR33
(10 && 0) //对于3.3V,最大电流为40MA
//控制寄存器2 CONTROL2_0
#define CONTROL2_0_ENSTAASYNCCLR (0 && 31) //该位可以使正常和错误中断的异步明确启用状态位
#define CONTROL2_0_ENCMDCNFMSK
(0 && 30) //不屏蔽指令冲突
#define CONTROL2_0_CDINVRXD3
(0 && 29) //卡检测信号倒置对于RX_DAT[3]。禁止
#define CONTROL2_0_SELCARDOUT
(0 && 28) //卡移除条件是“无卡插入” 状态。
#define CONTROL2_0_FLTCLKSEL
(8 && 24) //滤波器时钟 (iFLTCLK) 选择。
#define CONTROL2_0_ENFBCLKTX
(0 && 15) //反馈时钟禁止,对于发送数据时钟
#define CONTROL2_0_ENFBCLKRX
(0 && 14) //反馈时钟禁止,对于接收数据时钟
#define CONTROL2_0_SDCDSEL
(0 && 13) //nSDCD 用于SD 卡检测信号
#define CONTROL2_0_SDSIGPC
(0 && 12) //同步控制输出有效信号
#define CONTROL2_0_ENBUSYCHKTXSTART (0 && 11) //发送数据启动状态前忙碌状态检测。
#define CONTROL2_0_DFCNT
(0 && 9) //反跳滤波器计数16 iSDCLK
#define CONTROL2_0_ENCLKOUTHOLD
(1 && 8) //SDCLK 操作有效。
#define CONTROL2_0_RWAITMODE
(0 && 7) //主机控制器释放读等待状态(自动)
#define CONTROL2_0_DISBUFRD
(0 && 6) //正常模式,用0x20 寄存器使用者可以读缓冲区(FIFO)数据
//HCLK = 128MHZ
EPLL = 24MHZ
#define CONTROL2_0_SELBASECLK
(2 && 4) //基础时钟源选择。00 或01 = HCLK,10 = EPLL 输出时钟(来自系统)11 = 外部时钟源(XTI 或XEXTCLk)
#define CONTROL2_0_PWRSYNC
(0 && 3) //不同步,控制输入有效信号(指令,数据)
#define CONTROL2_0_ENCLKOUTMSKCON (0 && 1) //当卡插入被清除时,SDCLK 输出时钟屏蔽。当处于无卡状态时,设置该区域为高位来停止SDCLK。
#define CONTROL2_0_HWINITFIN
(1 && 0) //SD 主机控制器硬件初始化完成。
//时钟控制寄存器(0 通道)CLKCON0
#define CLKCON0_SELFREQ
(0x80 && 8) //SDCLK频率最低
#define CLKCON0_ENSDCLK
(1 && 2) //SD 时钟启动。
#define CLKCON0_ENINTCLK
(1 && 0) //中断时钟启动。
//超时控制寄存器(0 通道)TIMEOUTCON0
/*******************************************************************************
* Function Name
: SDIO_DeInit
* Description
: Deinitializes the SDIO peripheral registers to their default
reset values.
*******************************************************************************/
void SDIO_DeInit(void)
//初始化硬件IO
rGPGCON = 0x2222222; //初始化IO为SDIO模式
rGPGPUD = 0;
//禁止上下拉
//时钟控制寄存器配置
SDIO0-&CLKCON = CLKCON0_SELFREQ + CLKCON0_ENSDCLK + CLKCON0_ENINTCLK;
//主机控制寄存器配置
SDIO0-&HOSTCTL = HOSTCTL0_WIDE8 + HOSTCTL0_DMASEL + HOSTCTL0_OUTEDGEINV + HOSTCTL0_WIDE4;
//容限寄存器配置
SDIO0-&CAPAREG = CAPAREG0_V18 + CAPAREG0_V30 + CAPAREG0_V33 + CAPAREG0_SUSRES + CAPAREG0_DMA + CAPAREG0_HSPD + CAPAREG0_ADMA2 +\
CAPAREG0_MAXBLKLEN + CAPAREG0_BASECLK + CAPAREG0_TOUTUNIT + CAPAREG0_TOUTCLK;
//控制寄存器2配置
SDIO0-&CONTROL2 = CONTROL2_0_ENSTAASYNCCLR + CONTROL2_0_ENCMDCNFMSK + CONTROL2_0_CDINVRXD3 + CONTROL2_0_SELCARDOUT + CONTROL2_0_FLTCLKSEL + \
CONTROL2_0_ENFBCLKTX + CONTROL2_0_ENFBCLKRX + CONTROL2_0_SDCDSEL + CONTROL2_0_SDSIGPC + CONTROL2_0_ENBUSYCHKTXSTART + \
CONTROL2_0_DFCNT + CONTROL2_0_ENCLKOUTHOLD + CONTROL2_0_RWAITMODE + CONTROL2_0_DISBUFRD + CONTROL2_0_SELBASECLK + \
CONTROL2_0_PWRSYNC + CONTROL2_0_ENCLKOUTMSKCON + CONTROL2_0_HWINITFIN;
//传输模式寄存器配置
SDIO0-&TRNMOD = TRNMOD0_CCSCON + TRNMOD0_MUL1SIN0 + TRNMOD0_RD1WT0 + TRNMOD0_ENACMD12 + TRNMOD0_ENBLKCNT + TRNMOD0_ENDMA;
//超时控制寄存器(0 通道)
SDIO0-&TIMEOUTCON = 0x0e;
//超时设置最大
//电源控制寄存器配置
SDIO0-&PWRCON = PWRCON0_SELPWRLVL + PWRCON0_PWRON;
//块间隔寄存器
SDIO0-&BLKGAP = 0;
//开启卡插入+卡移除+传输完成+指令完成中断状态+数据超时错误+命令索引错误+指令最后位错误+指令超时错误+指令CRC + 缓冲区读就绪 + 写缓冲区就绪
SDIO_FlagConfig(SDIO_FLAG_CARDREMOVAL | SDIO_FLAG_CARDINSERTION | SDIO_FLAG_TRANSFER | SDIO_FLAG_COMMANDEND | SDIO_FLAG_DATACRC |
SDIO_FLAG_DATATIMEOUT | SDIO_FLAG_COMMANDINDEX | SDIO_FLAG_COMMANDCRC | SDIO_FLAG_COMMANDTIMEOUT | SDIO_FLAG_BUFFREAD | SDIO_FLAG_BUFFWRITE,Enable);
//使能卡插入拔出中断
SDIO_FlagITConfig(SDIO_FLAG_CARDREMOVAL | SDIO_FLAG_CARDINSERTION,Enable);
SDIO_ClearFlag(SDIO_FLAG_ALL); //清除所有中断标志
void SDIO_FlagITConfig(u32 SDIO_FLAG, u8 EN)
if(EN) //中断使能
SDIO0-&INTSEGEN |= SDIO_FLAG;
SDIO0-&INTSEGEN &= ~SDIO_FLAG;
void SDIO_FlagConfig(u32 SDIO_FLAG, u8 EN)
if(EN) //状态使能
SDIO0-&INTSTSEN |= SDIO_FLAG;
SDIO0-&INTSTSEN &= ~SDIO_FLAG;
/*************************************************************************************************************************
: void SD_SendCommand(vu8 CmdIdx,vu32 CmdArg,vu8 CmdTyp,vu8 Misc)
: 向SD卡发送一个命令
: CmdIdx:指令索引;CmdArg:命令参数;CmdMisc:其它杂项设置,详见说明
底层宏定义
*最后修改时间:
: 写SD命令寄存器;
指令索引:这些位设置为SD存储卡物理层规范中指令格式的第40到45位和SDIO卡规范中指定的指令数(CMD0-63, ACMD0-63)。
杂项: SDIO_Type_Default 一般为0
SDIO_Type_Pend
写总线暂停
SDIO_Type_FS
SDIO_Type_IT
SDIO_CMDIndexEn
SDIO指令索引使能
SDIO_CMDCrcEn
SDIO指令CRC校验使能
SDIO_Response_No
SDIO_Response_Short
SDIO_Response_Long
长应答 136
SDIO_Response_ShortBusy
短应答+检测繁忙情况
*************************************************************************************************************************/
void SDIO_SendCommand(vu8 CmdIdx,vu32 CmdArg,vu8 CmdMisc)
{&span style="white-space:pre"& &/span&
&span style="white-space:pre"& &/span&u16 temreg = 0;
&span style="white-space:pre"& &/span&SDIO_ClearFlag(SDIO_FLAG_ALL);&span style="white-space:pre"& &/span&//清除所有状态寄存
&span style="white-space:pre"& &/span&temreg = CmdI
&span style="white-space:pre"& &/span&temreg &&= 8;
&span style="white-space:pre"& &/span&temreg |= CmdM
&span style="white-space:pre"& &/span&SDIO0-&ARGUMENT = CmdA&span style="white-space:pre"& &/span&//先写入命令参数
&span style="white-space:pre"& &/span&SDIO0-&CMDREG =&span style="white-space:pre"&
&/span&//再写入命令索引以及类型等参数
&span style="white-space:pre"& &/span&while(!(SDIO0-&PRNSTS & BIT0));&span style="white-space:pre"& &/span&//等待命令线空忙,也就是开始执行命令
&span style="white-space:pre"& &/span&while(SDIO0-&PRNSTS & BIT0);&span style="white-space:pre"& &/span&//等待命令线空闲,也就是命令执行完毕
/*************************************************************************************************************************
: u32 SD_GetResponse(u8 SDIO_RESP)
: 获取SD卡的应答
: Rep:应答数据存放的位置
SDIO_RESP1: Response Register 1
SDIO_RESP2: Response Register 2
SDIO_RESP3: Response Register 3
SDIO_RESP4: Response Register 4
: 返回应答
底层宏定义
*最后修改时间:
: 存放应答数据的缓冲区为128BIT;4个32
指令应答。下表27-4为每一个应答描述了从SD总线到寄存器的指令映射。在这个表中,在表中 R[]指出在SD总线上传输的应答数据的范围,
REP[]指出应答寄存器中位的范围。128位应答位的顺序: {RSPREG3, RSPREG2, RSPREG1, RSPREG0}
*************************************************************************************************************************/
u32 SDIO_GetResponse(u8 SDIO_RESP)
return (SDIO0-&RSPREG[SDIO_RESP]);
u32 SDIO_ReadData(void)
return SDIO0-&BDATA;
//从缓冲区读数据
void SDIO_WriteData(u32 Data)
SDIO0-&BDATA = D
u8 SDIO_GetFlagStatus(u32 SDIO_FLAG)
return ((SDIO_STATUS & SDIO_FLAG) ? 1 : 0);
void SDIO_ClearFlag(u32 SDIO_FLAG)
SDIO_STATUS |= SDIO_FLAG;
/*************************************************************************************************************************
* 函数 : void SDIO_SetFIFOInterruptAddress(u8 FIFOxAdd,u8 WordAdd)
* 功能 : 设置FIFO中断触发位置
* 参数 : FIFOxAdd:FIFO地址选择
WordAdd:触发位置选择,单位为字,共512B,也就是1-128字
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
*************************************************************************************************************************/
void SDIO_SetFIFOInterruptAddress(u8 FIFOxAdd,u8 WordAdd)
if(WordAdd & 128)
WordAdd = 128;
switch (FIFOxAdd)
case FIFO_A0:
SDIO0-&CONTROL3 &= ~(0x1f);
SDIO0-&CONTROL3 |= WordA
case FIFO_A1:
SDIO0-&CONTROL3 &= ~(0x1f && 8);
SDIO0-&CONTROL3 |= WordAdd && 8;
case FIFO_A2:
SDIO0-&CONTROL3 &= ~(0x1f && 16);
SDIO0-&CONTROL3 |= WordAdd && 16;
case FIFO_A3:
SDIO0-&CONTROL3 &= ~(0x1f && 24);
SDIO0-&CONTROL3 |= WordAdd && 24;
/*************************************************************************************************************************
* 函数 : void SDIO_CLKFrequencySelect(u8 SDCLK)
* 功能 : 设置SDIO时钟分频系数
* 参数 : SDCLK:设置SDIO时钟分频系数
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
高速基础时钟为50MHz
低速基础时钟为25MHz
*************************************************************************************************************************/
void SDIO_CLKFrequencySelect(u8 SDCLK)
SDIO_SDClkDisable();
//时钟停止
SDIO0-&CAPAREG &= ~(0x3f && 8); //清除设置
SDIO0-&CAPAREG |= (50 && 8); //这一位设置其实没作用
SDIO0-&CLKCON &= ~(0xff && 8); //清除
SDIO0-&CLKCON |= (SDCLK && 8); //设置基础时钟分频系数
SDIO_SDClkEnable();
//时钟使能
while(!(SDIO0-&CLKCON & BIT0)); //等待时钟稳定
/*************************************************************************************************************************
* 函数 : void SDIO_SoftwareReset(u32 SDIO_RST)
* 功能 : 设置SDIO软件复位
* 参数 : SDIO_RST:
SDIO_RSTDAT //复位DAT线
SDIO_RSTCMD //复位CMD线
SDIO_RSTALL //复位所有
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
*************************************************************************************************************************/
void SDIO_SoftwareReset(u32 SDIO_RST)
SDIO0-&SWRST |= SDIO_RST;
while(SDIO0-&SWRST & SDIO_RST);
//等待复位完成
/*************************************************************************************************************************
: void SDIO_SetTimeOutClock(u8 Unit,u8 Frequency)
: 超时时钟设置
: Unit:超时时钟单位选择
TIME_OUT_UNIT_KHZ(0):超时时钟单位为KHZ
TIME_OUT_UNIT_MHZ(1):超时时钟单位为MHZ
Frequency:时钟频率:1~63
: 返回应答
底层宏定义
*最后修改时间:
: 配置指令超时时间
*************************************************************************************************************************/
void SDIO_SetTimeOutClock(u8 Unit,u8 Frequency)
SDIO0-&CAPAREG &= ~(0xff); //清除原先设置
//配置超时时钟单位:MHZ
SDIO0-&CAPAREG |= (1 && 7);
if(Frequency & 63)
//最大只能设置为63
Frequency = 63;
SDIO0-&CAPAREG |= F
s3c6410_sdio.h#ifndef _S3C6410_SDIO_H_
#define _S3C6410_SDIO_H_
#include "s3c6410_system.h"
#define FIFO_A0 0 //FIFO中断地址0
#define FIFO_A1 1 //FIFO中断地址1
#define FIFO_A2 2 //FIFO中断地址2
#define FIFO_A3 3 //FIFO中断地址3
//SDIO总线宽度设置
#define SDIO_BusWide_1b
#define SDIO_BusWide_4b
#define SDIO_BusWide_8b
//SDIO 命令杂项设置
//SDIO响应类型
#define SDIO_Response_No
((u8)0) //无应答
#define SDIO_Response_Long
((u8)1) //长应答 136
#define SDIO_Response_Short
((u8)2) //短应答 48
#define SDIO_Response_ShortBusy
((u8)3) //短应答+检测繁忙情况
//其它设置
#define SDIO_CMDIndexEn
((u8)1 && 4)//SDIO指令索引使能
#define SDIO_CMDCrcEn
((u8)1 && 3)//SDIO指令CRC校验使能
#define SDIO_DataSelect
((u8)1 && 5)//SDIO当前数据选择
//SDIO指令类型CmdTyp
#define SDIO_Type_Default
((u8)0 && 6)//一般为0
#define SDIO_Type_Pend
((u8)1 && 6)//写总线暂停
#define SDIO_Type_FS
((u8)2 && 6)//功能选择
#define SDIO_Type_IT
((u8)3 && 6)//中断模式
//SDIO响应寄存器选择
#define SDIO_RESP1
#define SDIO_RESP2
#define SDIO_RESP3
#define SDIO_RESP4
/* SDIO Data Block Size ------------------------------------------------------*/
#define SDIO_DataBlockSize_1b
#define SDIO_DataBlockSize_2b
#define SDIO_DataBlockSize_4b
#define SDIO_DataBlockSize_8b
#define SDIO_DataBlockSize_16b
#define SDIO_DataBlockSize_32b
#define SDIO_DataBlockSize_64b
#define SDIO_DataBlockSize_128b
((u16)128)
#define SDIO_DataBlockSize_256b
((u16)256)
#define SDIO_DataBlockSize_512b
((u16)512)
#define SDIO_DataBlockSize_1024b
((u16)1024)
#define SDIO_DataBlockSize_2048b
((u16)2048)
#define SDIO_DataBlockSize_4096b
((u16)4096)
#define SDIO_DataBlockSize_8192b
((u16)8192)
#define SDIO_DataBlockSize_16384b
((u16)16384)
/* SDIO Flags ----------------------------------------------------------------*/
//SDIO中断状态
#define SDIO_STATUS
(SDIO0-&INTSTS)
#define SDIO_FLAG_FIFOADDERR3
((u32)1 && 14)
//FIFO SD 地址指示器中断3 状态 (RW1C)
#define SDIO_FLAG_FIFOADDERR2
((u32)1 && 13)
//FIFO SD 地址指示器中断2 状态 (RW1C)
#define SDIO_FLAG_FIFOADDERR1
((u32)1 && 12)
//FIFO SD 地址指示器中断1 状态 (RW1C)
#define SDIO_FLAG_FIFOADDERR0
((u32)1 && 11)
//FIFO SD 地址指示器中断0 状态 (RW1C)
#define SDIO_FLAG_READWAIT
((u32)1 && 10)
//读等待中断状态 (RW1C)。
#define SDIO_FLAG_CCS
((u32)1 && 9)
//CCS 中断状态 (RW1C)。
#define SDIO_FLAG_CARD
((u32)1 && 8)
//卡 中断。
#define SDIO_FLAG_CARDREMOVAL
((u32)1 && 7)
#define SDIO_FLAG_CARDINSERTION
((u32)1 && 6)
#define SDIO_FLAG_BUFFREAD
((u32)1 && 5)
//读缓冲区就绪
#define SDIO_FLAG_BUFFWRITE
((u32)1 && 4)
//写缓冲区就绪
#define SDIO_FLAG_DMA
((u32)1 && 3)
#define SDIO_FLAG_BLOCKGAP
((u32)1 && 2)
//块间隔事件。
#define SDIO_FLAG_TRANSFER
((u32)1 && 1)
//传输完成。超时错误优先
#define SDIO_FLAG_COMMANDEND
((u32)1 && 0)
//指令完成。超时错误优先
#define SDIO_FLAG_ADMA
((u32)1 && 25)
#define SDIO_FLAG_AUTOCMD12
((u32)1 && 24)
//自动CMD12错误
#define SDIO_FLAG_DATAENDBIT
((u32)1 && 22)
//数据最后位错误
#define SDIO_FLAG_DATACRC
((u32)1 && 21)
//数据CRC错误
#define SDIO_FLAG_DATATIMEOUT
((u32)1 && 20)
//数据超时错误
#define SDIO_FLAG_COMMANDINDEX
((u32)1 && 19)
//命令索引错误
#define SDIO_FLAG_COMMANDENDBIT
((u32)1 && 18)
//指令最后位错误
#define SDIO_FLAG_COMMANDCRC
((u32)1 && 17)
//指令CRC错误
#define SDIO_FLAG_COMMANDTIMEOUT
((u32)1 && 16)
//指令超时错误
#define SDIO_FLAG_ALL
((u32)0xffffffff) //所有标志
void SDIO_DeInit(void);
void SDIO_ClockCmd(u8 EN);
void SDIO_SetPowerState(u32 SDIO_PowerState);
void SDIO_FlagITConfig(u32 SDIO_FLAG, u8 EN);
void SDIO_FlagConfig(u32 SDIO_FLAG, u8 EN);
void SDIO_SendCommand(vu8 CmdIdx,vu32 CmdArg,vu8 CmdMisc);
u32 SDIO_GetResponse(u8 SDIO_RESP);
u32 SDIO_ReadData(void);
void SDIO_WriteData(u32 Data);
u8 SDIO_GetFlagStatus(u32 SDIO_FLAG);
void SDIO_ClearFlag(u32 SDIO_FLAG);
void SDIO_SetFIFOInterruptAddress(u8 FIFOxAdd,u8 WordAdd);
void SDIO_SetTimeOutClock(u8 Unit,u8 Frequency);
void SDIO_CLKFrequencySelect(u8 SDCLK);
void SDIO_SoftwareReset(u32 SDIO_RST);//软件复位
//设置需要传输的块数量
#define SDIO_SetTransferBlockCnt(x)
(SDIO0-&BLKCNT = x)
//获取剩余传输的块的数量
#define SDIO_GetTransferBlockCnt()
(SDIO0-&BLKCNT)
//设置单次传输的块的大小
#define SDIO_SetTransferBlockSize(x)
(SDIO0-&BLKSIZE = (x & 0xfff))
//设置为单块传输模式
#define SDIO_SingleBlockMode()
(SDIO0-&TRNMOD &= ~(BIT5))
//设置为多区段传输模式
#define SDIO_MultipleBlockMode()
(SDIO0-&TRNMOD |= BIT5)
//自动CMD12命令启动
#define SDIO_AutoCMD12Enable()
(SDIO0-&TRNMOD |= BIT2)
//自动CMD12命令禁止
#define SDIO_AuotCMD12Disable()
(SDIO0-&TRNMOD &= ~(BIT2))
//设置SDIO为写数据模式
#define SDIO_WriteMode()
(SDIO0-&TRNMOD &= ~(BIT4))
//设置SDIO为读数据模式
#define SDIO_ReadMode()
(SDIO0-&TRNMOD |= BIT4)
//块计数器启动
#define SDIO_BlockCountEnable()
(SDIO0-&TRNMOD |= BIT1)
//禁止块计数器启动
#define SDIO_BlockCountDisable()
(SDIO0-&TRNMOD &= ~(BIT1))
#define SDIO_DMAEnable()
(SDIO0-&TRNMOD |= BIT0)
#define SDIO_DMADisable()
(SDIO0-&TRNMOD &= ~(BIT0))
//数据线忙
#define SDIO_DATLineActive()
(SDIO0-&PRNSTS & BIT2)
//指令禁止
#define SDIO_CommandInhibit()
(SDIO0-&PRNSTS & BIT0)
//高速时钟模式使能
#define SDIO_HighSpeedEnable()
(SDIO0-&CAPAREG |= BIT21)
//取消高速时钟模式
#define SDIO_HighSpeedDisable()
(SDIO0-&CAPAREG &= ~BIT21)
//数据线宽度设置为4bit
#define SDIO_SetDataDataWidth_4b()
(SDIO0-&HOSTCTL |= BIT1)
//数据线宽设置为1bit
#define SDIO_SetDataDataWidth_1b()
(SDIO0-&HOSTCTL &= ~BIT1)
//总线电压选择3.3V
#define SDIO_SetBusVoltage_3_3V()
(SDIO0-&PWRCON &= ~(0x7 && 1); SDIO0-&PWRCON |= (7 && 1))
//总线电源开启
#define SDIO_BusPowerON()
(SDIO0-&PWRCON |= BIT0)
//总线电压关闭
#define SDIO_BusPowerOFF()
(SDIO0-&PWRCON &= ~BIT0)
//唤醒发生在SD卡插入
#define SDIO_WakeupOnSDInsertion()
(SDIO0-&WAKCON |= BIT1
//使能SD时钟
#define SDIO_SDClkEnable()
(SDIO0-&CLKCON |= BIT2)
//SD时钟停止
#define SDIO_SDClkDisable()
(SDIO0-&CLKCON &= ~BIT2)
//超时时钟单位设置
#define TIME_OUT_UNIT_KHZ 0 //超时时钟单位为KHZ
#define TIME_OUT_UNIT_MHZ 1 //超时时钟单位为MHZ
//时钟分频系数
#define SDCLK_1_256
((u8)0x80) //基础时钟256分频
#define SDCLK_1_128
((u8)0x40) //基础时钟128分频
#define SDCLK_1_64
((u8)0x20) //基础时钟64分频
#define SDCLK_1_32 ((u8)0x10) //基础时钟32分频
#define SDCLK_1_16
((u8)0x08) //基础时钟16分频
#define SDCLK_1_8
((u8)0x04) //基础时钟8分频
#define SDCLK_1_4
((u8)0x02) //基础时钟4分频
#define SDCLK_1_2
((u8)0x01) //基础时钟2分频
#define SDCLK_1_1
((u8)0x00) //基础时钟1分频
//软件复位选择
#define SDIO_RSTDAT
BIT2 //复位DAT线
#define SDIO_RSTCMD
BIT1 //复位CMD线
#define SDIO_RSTALL
BIT0 //复位所有
sdcard_sdio.c,
/*******************************************************************************
//功能:SDCARD 驱动,SDIO 模式
//作者:陈鹏
//创建时间: 10:32
//修改时间: 10:32
//修订说明:
//声明:源程序借鉴了意法STM32F103X库函数
********************************************************************************/
#include "sdcard_sdio.h"
#include "s3c6410_sdio.h"
#include "s3c6410_system.h"
u8 SDMMC0_MOV_Flag = 0;
//sdmmc0卡移除信号有
1.3 寄存器
名称 宽度 描述
CID 128 卡标识号
RCA 16 相对卡地址(Relative card address):本地系统中卡的地
址,动态变化,在主机初始化的时候确定
*SPI 模式中没有
CSD 128 卡描述数据:卡操作条件相关的信息数据
SCR 64 SD 配置寄存器:SD 卡特定信息数据
OCR 32 操作条件寄存器*/
//容量 = BLOCKNR * BLOCK_LEN = (C_SIZE+1)*2^(C_SIZE_MULT+2)*2^(READ_BL_LEN)
#define SD_BlockSize
//SD卡块大小
#define SDIO_CMD0TIMEOUT
1000000 //超时计数器大小
#define SDIO_READTIMEOUT
1000000 //读等待超时
#define SDIO_WRITETIMEOUT
2000000 //写等待超时
// SD卡指令表
#define CMD0
#define CMD1
#define CMD9
//命令9 ,读CSD数据
#define CMD10
//命令10,读CID数据
#define CMD12
//命令12,停止数据传输
#define CMD16
//命令16,设置SectorSize 应返回0x00
#define CMD17
//命令17,读sector
#define CMD18
//命令18,读Multi sector
#define ACMD23
//命令23,设置多sector写入前预先擦除N个block
#define CMD24
//命令24,写sector
#define CMD25
//命令25,写Multi sector
#define ACMD41
//命令41,应返回0x00
#define CMD55
//命令55,应返回0x01
#define CMD58
//命令58,读OCR信息
#define CMD59
//命令59,使能/禁止CRC,应返回0x0
/* Mask for errors Card Status R1 (OCR Register) */
#define SD_OCR_ADDR_OUT_OF_RANGE
#define SD_OCR_ADDR_MISALIGNED
#define SD_OCR_BLOCK_LEN_ERR
#define SD_OCR_ERASE_SEQ_ERR
#define SD_OCR_BAD_ERASE_PARAM
#define SD_OCR_WRITE_PROT_VIOLATION
#define SD_OCR_LOCK_UNLOCK_FAILED
#define SD_OCR_COM_CRC_FAILED
#define SD_OCR_ILLEGAL_CMD
#define SD_OCR_CARD_ECC_FAILED
#define SD_OCR_CC_ERROR
#define SD_OCR_GENERAL_UNKNOWN_ERROR
#define SD_OCR_STREAM_READ_UNDERRUN
#define SD_OCR_STREAM_WRITE_OVERRUN
#define SD_OCR_CID_CSD_OVERWRIETE
#define SD_OCR_WP_ERASE_SKIP
#define SD_OCR_CARD_ECC_DISABLED
#define SD_OCR_ERASE_RESET
#define SD_OCR_AKE_SEQ_ERROR
#define SD_OCR_ERRORBITS
((u32)0xFDFFE008)
/* Masks for R6 Response */
#define SD_R6_GENERAL_UNKNOWN_ERROR
#define SD_R6_ILLEGAL_CMD
#define SD_R6_COM_CRC_FAILED
#define SD_VOLTAGE_WINDOW_SD
#define SD_HIGH_CAPACITY
#define SD_STD_CAPACITY
#define SD_CHECK_PATTERN
((u32)0x000001AA)
#define SD_MAX_VOLT_TRIAL
((u32)0x0000FFFF)
#define SD_ALLZERO
#define SD_WIDE_BUS_SUPPORT
#define SD_SINGLE_BUS_SUPPORT
#define SD_CARD_LOCKED
#define SD_CARD_PROGRAMMING
#define SD_CARD_RECEIVING
#define SD_DATATIMEOUT
((u32)0x000FFFFF)
#define SD_0TO7BITS
((u32)0x000000FF)
#define SD_8TO15BITS
((u32)0x0000FF00)
#define SD_16TO23BITS
((u32)0x00FF0000)
#define SD_24TO31BITS
((u32)0xFF000000)
#define SD_MAX_DATA_LENGTH
((u32)0x01FFFFFF)
#define SD_HALFFIFO
#define SD_HALFFIFOBYTES
/* Command Class Supported */
#define SD_CCCC_LOCK_UNLOCK
#define SD_CCCC_WRITE_PROT
#define SD_CCCC_ERASE
/* Following commands are SD Card Specific commands.
SDIO_APP_CMD should be sent before sending these commands. */
#define SDIO_SEND_IF_COND
//#define SDIO_MULTIMEDIA_CARD
((u32)0x0)
#define SDIO_SECURE_DIGITAL_CARD
((u32)0x1)
//#define SDIO_SECURE_DIGITAL_IO_CARD
((u32)0x2)
//#define SDIO_HIGH_SPEED_MULTIMEDIA_CARD
((u32)0x3)
//#define SDIO_SECURE_DIGITAL_IO_COMBO_CARD
((u32)0x4)
//#define SDIO_HIGH_CAPACITY_SD_CARD
((u32)0x5)
//#define SDIO_HIGH_CAPACITY_MMC_CARD
((u32)0x6)
#define SDIO_INIT_CLK_DIV
((u8)0xB2)
#define SDIO_TRANSFER_CLK_DIV
((u8)0x01)
//时钟分频
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static u32 CardType =
SDIO_SECURE_DIGITAL_CARD;
static u32 CSD_Tab[4], CID_Tab[4], RCA = 0;
//static u32 DeviceMode = SD_POLLING_MODE;
//static u32 TotalNumberOfBytes = 0, StopCondition = 0;
u32 *SrcBuffer, *DestB
volatile SD_Error TransferError = SD_OK;
vu32 TransferEnd = 0;
vu32 NumberOfBytes = 0;
//SD卡中断服务程序,用来检测卡的插入与移除的
static void __irq Isr_SDMMC_Card(void);
/* Private function prototypes -----------------------------------------------*/
static SD_Error CmdError(void);
static SD_Error CmdResp1Error(void);
static SD_Error CmdResp7Error(void);
static SD_Error CmdResp3Error(void);
static SD_Error CmdResp2Error(void);
static SD_Error CmdResp6Error(u16 *prca);
static SD_Error SDEnWideBus(u8 EN);
static SD_Error IsCardProgramming(u8 *pstatus);
static SD_Error FindSCR(u16 rca, u32 *pscr);
#define DebugPrintf printf
/*************************************************************************************************************************
* 函数 : SD_Error SD_Init(void)
* 功能 : SD卡初始化
* 参数 : 无
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
初始化SD卡
*************************************************************************************************************************/
SD_Error SD_Init(void)
SD_Error errorstatus = SD_OK;
SDIO_SoftwareReset(SDIO_RSTALL); //软件复位所有寄存器
SDIO_DeInit(); //初始化SDIO硬件
SDIO_FlagITConfig(SDIO_FLAG_CARDREMOVAL | SDIO_FLAG_CARDINSERTION,Enable);//使能卡插入拔出中断
Set_IsrAddr(INT_HSMMC0,(vu32)Isr_SDMMC_Card); //设置中断矢量入口
Set_IntEnable(INT_HSMMC0,Enable); //开启SDMMC0中断
errorstatus = SD_SetIdleSta(); //SD卡上电
if (errorstatus != SD_OK)
//卡上电发送错误
DebugPrintf("SD power up error:(%d)!\n",errorstatus); //调试,打印错误
return(errorstatus); //返回错误
errorstatus = SD_InitializeCards();
if (errorstatus != SD_OK)
DebugPrintf("SD initialize error(%d)!\n",errorstatus); //调试,打印错误
return(errorstatus);
return(errorstatus);
/*************************************************************************************************************************
* 函数 : SD_Error SD_SetIdleSta(void)
* 功能 : SD卡上电进入空闲模式,并识别卡
* 参数 : 无
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
SD卡上电进入空闲模式
*************************************************************************************************************************/
SD_Error SD_SetIdleSta(void)
SD_Error errorstatus = SD_OK;
u32 response = 0, count = 0;
bool validvoltage = FALSE;
u32 SDType = SD_STD_CAPACITY;
SDIO_CLKFrequencySelect(SDCLK_1_64);
//设置时钟400KHZ
SDIO_SetTimeOutClock(TIME_OUT_UNIT_KHZ,1); //设置超时时钟频率最低
//发送至少74个时钟,等待SD卡上电成功并同步
for(response = 0;response & 1000;response ++);
//循环发生发送CMD0,无响应,无返回,让SD卡进入空闲模式
for(i = 0;i & 50;i ++)
SDIO_SendCommand(CMD0,0,0);
errorstatus = CmdError();
//判断命令是否执行成功,此命令只要初始化了SDIO就会执行成功
if(errorstatus == SD_OK)
if(errorstatus != SD_OK)
DEBUG("error!(%d)\n",errorstatus); //调试,打印信息
return(errorstatus);
//发送CMD8:SEND_IF_COND;短响应,命令参数:SD_CHECK_PATTERN;返回响应R7
//识别卡版本
SDIO_SendCommand(SDIO_SEND_IF_COND,SD_CHECK_PATTERN,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp7Error();
if (errorstatus == SD_OK)
//返回成功;说明卡为SD Card 2.0 V2.0
CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0; /* SD Card 2.0 */
SDType = SD_HIGH_CAPACITY;
DEBUG("SDIO_STD_CAPACITY_SD_CARD_V2_0!\n"); //调试,打印错误信息
else //V1.0 V1.1
DEBUG("SD Card V1.1!\n"); //调试,打印信息
CardType = SDIO_STD_CAPACITY_SD_CARD_V1_1;
//V1.0 V1.1
SDIO_SendCommand(CMD55,0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
CmdResp1Error();
//发送CMD55 SDIO_APP_CMD;命令参数:0;返回响应R1,设置RCA为0,短响应
SDIO_SendCommand(SDIO_APP_CMD,0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
if (errorstatus != SD_OK)
DEBUG("CMD55 error(%d)!\n",errorstatus); //调试,打印错误信息
return(errorstatus);
//发送ACM41命令;命令参数:SD_APP_OP_COND(0x);短响应.响应为R3,返回操作条件寄存器RCA
SDIO_SendCommand(SDIO_SD_APP_OP_COND,SD_VOLTAGE_WINDOW_SD | SDType,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp3Error();
if (errorstatus != SD_OK)
DEBUG("ACM41 error(%d)!\n",errorstatus); //调试,打印错误信息
return(errorstatus);
response = SDIO_GetResponse(SDIO_RESP1); //获取响应,RESE1
validvoltage = (bool) (((response && 31) == 1) ? 1 : 0);
while((!validvoltage) && (count & SD_MAX_VOLT_TRIAL));//循环初始化,直到返回成功或者超时
if (count &= SD_MAX_VOLT_TRIAL) //重试次数超出
errorstatus = SD_INVALID_VOLTRANGE;
return(errorstatus);
if (response &= SD_HIGH_CAPACITY)
CardType = SDIO_HIGH_CAPACITY_SD_CARD;
return(errorstatus);
/*************************************************************************************************************************
* 函数 : SD_Error SD_PowerOFF(void)
* 功能 : SD卡掉电
* 参数 : 无
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
*************************************************************************************************************************/
SD_Error SD_PowerOFF(void)
SD_Error errorstatus = SD_OK;
SDIO_BusPowerOFF(); //关闭总线电源
return(errorstatus);
/*************************************************************************************************************************
* 函数 : SD_Error SD_PowerON(void)
* 功能 : SD卡电源开启
* 参数 : 无
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
SD卡电源开启
*************************************************************************************************************************/
SD_Error SD_PowerON(void)
SD_Error errorstatus = SD_OK;
SDIO_BusPowerON(); //打开总线电源
return(errorstatus);
/*************************************************************************************************************************
* 函数 : SD_Error SD_InitializeCards(void)
* 功能 : 将所有的卡进行初始化配置
* 参数 : 无
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
将所有的卡进行初始化配置
*************************************************************************************************************************/
SD_Error SD_InitializeCards(void)
SD_Error errorstatus = SD_OK;
u16 rca = 0x01;
//发送CMD2 SDIO_ALL_SEND_CID命令,命令参数:0;长回复,R2
//发送CMD用来获取CID信息的
SDIO_SendCommand(SDIO_ALL_SEND_CID,0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Long);
errorstatus = CmdResp2Error();
//获取响应R2
if (errorstatus != SD_OK)
DEBUG("error!(%d)\n",errorstatus);
//调试,打印错误信息
return(errorstatus);
//到每个卡以获取每个卡的唯一标识CID
CID_Tab[0] = SDIO_GetResponse(SDIO_RESP1);
CID_Tab[1] = SDIO_GetResponse(SDIO_RESP2);
CID_Tab[2] = SDIO_GetResponse(SDIO_RESP3);
CID_Tab[3] = SDIO_GetResponse(SDIO_RESP4);
//发送CMD3,SET_REL_ADDR命令,参数0,响应,短响应,R6
//用来获取卡地址
//主机发送CMD3(SEND_RELATIVE_ADDR)要求卡发布一个新的相对卡地址RCA,地址比CID短,在以后的数据传输模式中用来寻址卡。一旦获得RCA后,卡状态变成就绪状态(Stand-by state)
SDIO_SendCommand(SDIO_SET_REL_ADDR,0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp6Error(&rca); //获取卡地址
if (errorstatus != SD_OK)
DEBUG("error!(%d)!\n",errorstatus);
//调试,打印错误信息
return(errorstatus);
RCA =//存储卡地址
//发送CMD9 SDIO_SEND_CSD命令,参数:rca地址;长响应,R2;
//给卡发送一个新的RCA,主要是用来设置卡地址的
SDIO_SendCommand(SDIO_SEND_CSD,(u32)rca && 16,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Long);
errorstatus = CmdResp2Error();
if (errorstatus != SD_OK)
DEBUG("error!(%d)!\n",errorstatus);
//调试,打印错误信息
return(errorstatus);
CSD_Tab[0] = SDIO_GetResponse(SDIO_RESP1);
CSD_Tab[1] = SDIO_GetResponse(SDIO_RESP2);
CSD_Tab[2] = SDIO_GetResponse(SDIO_RESP3);
CSD_Tab[3] = SDIO_GetResponse(SDIO_RESP4);
//选中卡,并激活
errorstatus = SD_SelectDeselect((u32)RCA && 16);
if(errorstatus != SD_OK)
DEBUG("SelectDeselect error!(%d)!\n",errorstatus);
//调试,打印错误信息
return(errorstatus);
errorstatus = SD_OK; /* All cards get intialized */
SDIO_CLKFrequencySelect(SDCLK_1_2); //设置时钟
SDIO_SetTimeOutClock(TIME_OUT_UNIT_KHZ,63); //设置超时时钟频率最高
errorstatus = SD_EnableWideBusMode(Enable);
if(errorstatus == SD_OK) //配置SD卡为4线模式
DEBUG("SD SDIO 4BIT OK\n");
errorstatus = SD_EnableWideBusMode(Disable);
DEBUG("SD SDIO 4BIT ERROR (%d)\n",errorstatus);
SDIO_SetTransferBlockSize(SD_BlockSize);//设置传输块大小为512字节
errorstatus = SD_SetBlockSize(SD_BlockSize);//配置SD卡块大小
if (errorstatus != SD_OK)
DEBUG("SD SetBlockSize error(%d)!\n",errorstatus);
return(errorstatus);
return(errorstatus);
/*************************************************************************************************************************
* 函数 : SD_Error SD_SelectDeselect(u32 addr)
* 功能 : 选中一个卡,并处于传输状态
* 参数 : addr:卡地址
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
选择一个卡并将它置于传输状态(Transfer state)
*************************************************************************************************************************/
SD_Error SD_SelectDeselect(u32 addr)
SD_Error errorstatus = SD_OK;
//CMD7用来选择一个卡并将它置于传输状态(Transfer state),在任何时间只能有一个卡处于传输状态
SDIO_SendCommand(SDIO_SEL_DESEL_CARD,addr,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
return(errorstatus);
/*************************************************************************************************************************
* 函数 : SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo)
* 功能 : 获取卡的细节信息
* 参数 : cardinfo:卡信息结构指针,指向信息存放缓冲区地址
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
获取卡的信息,通过CSD信息得到
*************************************************************************************************************************/
SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo)
SD_Error errorstatus = SD_OK;
u8 tmp = 0;
cardinfo-&CardType = (u8)CardT
cardinfo-&RCA = (u16)RCA;
/* Byte 0 */
tmp = (u8)((CSD_Tab[0] & 0xFF000000) && 24);
cardinfo-&SD_csd.CSDStruct = (tmp & 0xC0) && 6;
cardinfo-&SD_csd.SysSpecVersion = (tmp & 0x3C) && 2;
cardinfo-&SD_csd.Reserved1 = tmp & 0x03;
/* Byte 1 */
tmp = (u8)((CSD_Tab[0] & 0x00FF0000) && 16);
cardinfo-&SD_csd.TAAC =
/* Byte 2 */
tmp = (u8)((CSD_Tab[0] & 0x0000FF00) && 8);
cardinfo-&SD_csd.NSAC =
/* Byte 3 */
tmp = (u8)(CSD_Tab[0] & 0x000000FF);
cardinfo-&SD_csd.MaxBusClkFrec =
/* Byte 4 */
tmp = (u8)((CSD_Tab[1] & 0xFF000000) && 24);
cardinfo-&SD_csd.CardComdClasses = tmp && 4;
/* Byte 5 */
tmp = (u8)((CSD_Tab[1] & 0x00FF0000) && 16);
cardinfo-&SD_csd.CardComdClasses |= (tmp & 0xF0) && 4;
cardinfo-&SD_csd.RdBlockLen = tmp & 0x0F;
/* Byte 6 */
tmp = (u8)((CSD_Tab[1] & 0x0000FF00) && 8);
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; /* Reserved */
cardinfo-&SD_csd.DeviceSize = (tmp & 0x03) && 10;
/* Byte 7 */
tmp = (u8)(CSD_Tab[1] & 0x000000FF);
cardinfo-&SD_csd.DeviceSize |= (tmp) && 2;
/* Byte 8 */
tmp = (u8)((CSD_Tab[2] & 0xFF000000) && 24);
cardinfo-&SD_csd.DeviceSize |= (tmp & 0xC0) && 6;
cardinfo-&SD_csd.MaxRdCurrentVDDMin = (tmp & 0x38) && 3;
cardinfo-&SD_csd.MaxRdCurrentVDDMax = (tmp & 0x07);
/* Byte 9 */
tmp = (u8)((CSD_Tab[2] & 0x00FF0000) && 16);
cardinfo-&SD_csd.MaxWrCurrentVDDMin = (tmp & 0xE0) && 5;
cardinfo-&SD_csd.MaxWrCurrentVDDMax = (tmp & 0x1C) && 2;
cardinfo-&SD_csd.DeviceSizeMul = (tmp & 0x03) && 1;
/* Byte 10 */
tmp = (u8)((CSD_Tab[2] & 0x0000FF00) && 8);
cardinfo-&SD_csd.DeviceSizeMul |= (tmp & 0x80) && 7;
cardinfo-&SD_csd.EraseGrSize = (tmp & 0x40) && 6;
cardinfo-&SD_csd.EraseGrMul = (tmp & 0x3F) && 1;
/* Byte 11 */
tmp = (u8)(CSD_Tab[2] & 0x000000FF);
cardinfo-&SD_csd.EraseGrMul |= (tmp & 0x80) && 7;
cardinfo-&SD_csd.WrProtectGrSize = (tmp & 0x7F);
/* Byte 12 */
tmp = (u8)((CSD_Tab[3] & 0xFF000000) && 24);
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;
/* Byte 13 */
tmp = (u8)((CSD_Tab[3] & 0x00FF0000) && 16);
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);
/* Byte 14 */
tmp = (u8)((CSD_Tab[3] & 0x0000FF00) && 8);
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);
/* Byte 15 */
tmp = (u8)(CSD_Tab[3] & 0x000000FF);
cardinfo-&SD_csd.CSD_CRC = (tmp & 0xFE) && 1;
cardinfo-&SD_csd.Reserved4 = 1;
/* Byte 0 */
tmp = (u8)((CID_Tab[0] & 0xFF000000) && 24);
cardinfo-&SD_cid.ManufacturerID =
/* Byte 1 */
tmp = (u8)((CID_Tab[0] & 0x00FF0000) && 16);
cardinfo-&SD_cid.OEM_AppliID = tmp && 8;
/* Byte 2 */
tmp = (u8)((CID_Tab[0] & 0x) && 8);
cardinfo-&SD_cid.OEM_AppliID |=
/* Byte 3 */
tmp = (u8)(CID_Tab[0] & 0x000000FF);
cardinfo-&SD_cid.ProdName1 = tmp && 24;
/* Byte 4 */
tmp = (u8)((CID_Tab[1] & 0xFF000000) && 24);
cardinfo-&SD_cid.ProdName1 |= tmp && 16;
/* Byte 5 */
tmp = (u8)((CID_Tab[1] & 0x00FF0000) && 16);
cardinfo-&SD_cid.ProdName1 |= tmp && 8;
/* Byte 6 */
tmp = (u8)((CID_Tab[1] & 0x0000FF00) && 8);
cardinfo-&SD_cid.ProdName1 |=
/* Byte 7 */
tmp = (u8)(CID_Tab[1] & 0x000000FF);
cardinfo-&SD_cid.ProdName2 =
/* Byte 8 */
tmp = (u8)((CID_Tab[2] & 0xFF000000) && 24);
cardinfo-&SD_cid.ProdRev =
/* Byte 9 */
tmp = (u8)((CID_Tab[2] & 0x00FF0000) && 16);
cardinfo-&SD_cid.ProdSN = tmp && 24;
/* Byte 10 */
tmp = (u8)((CID_Tab[2] & 0x0000FF00) && 8);
cardinfo-&SD_cid.ProdSN |= tmp && 16;
/* Byte 11 */
tmp = (u8)(CID_Tab[2] & 0x000000FF);
cardinfo-&SD_cid.ProdSN |= tmp && 8;
/* Byte 12 */
tmp = (u8)((CID_Tab[3] & 0xFF000000) && 24);
cardinfo-&SD_cid.ProdSN |=
/* Byte 13 */
tmp = (u8)((CID_Tab[3] & 0x00FF0000) && 16);
cardinfo-&SD_cid.Reserved1 |= (tmp & 0xF0) && 4;
cardinfo-&SD_cid.ManufactDate = (tmp & 0x0F) && 8;
/* Byte 14 */
tmp = (u8)((CID_Tab[3] & 0x0000FF00) && 8);
cardinfo-&SD_cid.ManufactDate |=
/* Byte 15 */
tmp = (u8)(CID_Tab[3] & 0x000000FF);
cardinfo-&SD_cid.CID_CRC = (tmp & 0xFE) && 1;
cardinfo-&SD_cid.Reserved2 = 1;
return(errorstatus);
/*************************************************************************************************************************
* 函数 : SD_Error SD_EnableWideBusMode(u8 EN)
* 功能 : 使能4bit DAT线模式,如果失败将保持原来模式
* 参数 : Enable:4bit模式;Disable:1bit模式
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
设置卡和控制器为4bit总线模式
*************************************************************************************************************************/
SD_Error SD_EnableWideBusMode(u8 EN)
SD_Error errorstatus = SD_OK;
//SD卡不支持设置
if (CardType == SDIO_MULTIMEDIA_CARD)
errorstatus = SD_UNSUPPORTED_FEATURE;
return(errorstatus);
else if ((CardType == SDIO_SECURE_DIGITAL_CARD) || (CardType == SDIO_HIGH_CAPACITY_SD_CARD)) //SD卡
if (EN) //4BIT模式
errorstatus = SDEnWideBus(Enable); //设置SD卡为4bit总线模式
if (errorstatus == SD_OK) //设置SD卡成功
IntFlag = Get_IntEnable(INT_HSMMC0);
if(IntFlag) //如果开启了卡全局中断
Set_IntEnable(INT_HSMMC0,Disable); //先关闭中断,防止误触发
SDIO_SetDataDataWidth_4b(); //设置SDIO为4bit模式
SDIO_ClearFlag(SDIO_FLAG_ALL); //清除所有标志
if(IntFlag) //如果开启了卡全局中断
Set_IntEnable(INT_HSMMC0,Enable); //开启
errorstatus = SDEnWideBus(Disable); //设置SD卡为1bit总线模式
if (errorstatus == SD_OK) //设置SD卡成功
IntFlag = Get_IntEnable(INT_HSMMC0);
if(IntFlag) //如果开启了卡全局中断
Set_IntEnable(INT_HSMMC0,Disable); //先关闭中断,防止误触发
SDIO_SetDataDataWidth_1b(); //设置SDIO为1bit模式
SDIO_ClearFlag(SDIO_FLAG_ALL); //清除所有标志
if(IntFlag) //如果开启了卡全局中断
Set_IntEnable(INT_HSMMC0,Enable); //开启
return(errorstatus);
/*************************************************************************************************************************
* 函数 : static SD_Error SDEnWideBus(u8 EN)
* 功能 : 设置SD卡宽总线模式
* 参数 : Enable:4bit模式;Disable:1bit模式
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
设置SD卡宽总线模式
*************************************************************************************************************************/
static SD_Error SDEnWideBus(u8 EN)
SD_Error errorstatus = SD_OK;
u32 scr[2] = {0, 0};
if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)
errorstatus = SD_LOCK_UNLOCK_FAILED;
return(errorstatus);
errorstatus = FindSCR(RCA, scr);
if (errorstatus != SD_OK)
DEBUG("Get SCR error(%d)!\n",errorstatus);
return(errorstatus);
if (EN) //使能4bit dat
//如果请求的卡支持宽数据线模式
if ((scr[1] & SD_WIDE_BUS_SUPPORT) != SD_ALLZERO)
//发送CMD55,SDIO_APP_CMD,激活卡
//发送CMD55 SDIO_APP_CMD;命令参数:RCA;返回响应R1,设置RCA为0,短响应
SDIO_SendCommand(SDIO_APP_CMD,(u32)RCA && 16,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
if (errorstatus != SD_OK)
DEBUG("CMD55 error(%d)!\n",errorstatus); //调试,打印错误信息
return(errorstatus);
//发送ACMD6,SDIO_APP_SD_SET_BUSWIDTH,设置宽总线模式,参数0x2,短响应,R1
SDIO_SendCommand(SDIO_APP_SD_SET_BUSWIDTH,0x2,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
if (errorstatus != SD_OK)
DEBUG("ACMD6 error(%d)!\n",errorstatus); //调试,打印错误信息
return(errorstatus);
return(errorstatus);
else //请求的卡不支持宽总线模式
errorstatus = SD_REQUEST_NOT_APPLICABLE;
return(errorstatus);
else //失能宽总线模式
//如果请求的卡支持1bit总线模式
if ((scr[1] & SD_SINGLE_BUS_SUPPORT) != SD_ALLZERO)
//发送CMD55 SDIO_APP_CMD;命令参数:RCA;返回响应R1,设置RCA为0,短响应
SDIO_SendCommand(SDIO_APP_CMD,(u32)RCA && 16,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
if (errorstatus != SD_OK)
DEBUG("CMD55 error(%d)!\n",errorstatus); //调试,打印错误信息
return(errorstatus);
//发送ACMD6,SDIO_APP_SD_SET_BUSWIDTH,设置宽总线模式,参数0x0,短响应,R1
SDIO_SendCommand(SDIO_APP_SD_SET_BUSWIDTH,0x0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
if (errorstatus != SD_OK)
DEBUG("ACMD6 error(%d)!\n",errorstatus); //调试,打印错误信息
return(errorstatus);
return(errorstatus);
else //不支持1bit总线模式
errorstatus = SD_REQUEST_NOT_APPLICABLE;
return(errorstatus);
/*************************************************************************************************************************
* 函数 : SD_Error SD_SetDeviceMode(u32 Mode)
* 功能 : 配置SDIO操作模式
* 参数 : SD_DMA_MODE: DMA模式
SD_INTERRUPT_MODE: 中断模式
SD_POLLING_MODE: 查询模式(普通模式)
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
配置SDIO操作模式
*************************************************************************************************************************/
SD_Error SD_SetDeviceMode(u32 Mode)
SD_Error errorstatus = SD_OK;
/* if ((Mode == SD_DMA_MODE) || (Mode == SD_INTERRUPT_MODE) || (Mode == SD_POLLING_MODE))
DeviceMode = M
errorstatus = SD_INVALID_PARAMETER; //模式设置错误
return(errorstatus);
/*************************************************************************************************************************
* 函数 : SD_Error SD_SetBlockSize(u16 BlockSize)
* 功能 : 设置SD卡块大小
* 参数 : 块大小,512,1024,等等
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
通常取512B
*************************************************************************************************************************/
SD_Error SD_SetBlockSize(u16 BlockSize)
SD_Error errorstatus = SD_OK;
//如果卡锁定了则返回
if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)
errorstatus = SD_LOCK_UNLOCK_FAILED;
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
//判断块大小是否合理
if ((BlockSize & 0) && (BlockSize &= 2048) && ((BlockSize & (BlockSize - 1)) == 0))
//Set Block Size for Card
SDIO_SendCommand(SDIO_SET_BLOCKLEN,BlockSize,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
if (errorstatus != SD_OK)
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
else //块大小设置错误
errorstatus = SD_INVALID_PARAMETER;
return(errorstatus);
return(errorstatus);
/*************************************************************************************************************************
* 函数 : SD_Error SD_ReadBlock(u32 BlockAddr, u32 *BlockBuff)
* 功能 : 读SD卡一个块
* 参数 : BlockAddr:块地址;
BlockBuff:块缓冲区地址
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
读SD卡一个扇区
*************************************************************************************************************************/
SD_Error SD_ReadBlock(u32 BlockAddr, u32 *BlockBuff)
SD_Error errorstatus = SD_OK;
u32 timeout = SDIO_READTIMEOUT;
//读等待超时计数器
u16 cnt = 0;
if (BlockBuff == NULL)
//没有分配接收缓冲区,返回
errorstatus = SD_INVALID_PARAMETER;
return(errorstatus);
SDIO_SoftwareReset(SDIO_RSTDAT); //软件复位DAT,主要用来清空FIFO
SDIO_SoftwareReset(SDIO_RSTCMD); //软件复位DAT,主要用来清除状态以及命令
SDIO_ReadMode();
//设置主机控制器为读模式
SDIO_SetTransferBlockSize(SD_BlockSize); //设置单次传输的块大小为SD_BlockSize
SDIO_SingleBlockMode();
//设置为单块传输模式
//发送CMD17 READ_SINGLE_BLOCK,块读取指令,参数:块地址,短回复,R1
//此处花了我几天的时间调试,最终发现竟然是少了一条命令:SDIO_DataS当前数据选择,少了这条命令DAT线上没有数据回来
SDIO_SendCommand(SDIO_READ_SINGLE_BLOCK,(BlockAddr && 9),SDIO_DataSelect | SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error(); //获取回复
if (errorstatus != SD_OK)
//命令发送错误,返回
DEBUG("CMD17 error (%d)!\n",errorstatus);
return(errorstatus);
while(((SDIO0-&PRNSTS & BIT11) == 0) && timeout && (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) == 0)) //等待读缓冲区有效,或者等待超时
timeout --;
if (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) || (timeout == 0)) //超时
SDIO_ClearFlag(SDIO_FLAG_DATATIMEOUT); //清除标志
errorstatus = SD_DATA_TIMEOUT;
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
//缓冲区大小SD_BlockSize字节,共SD_BlockSize/4字
for(cnt = 0;cnt & SD_BlockSize / 4;cnt ++)
*(BlockBuff ++) = SDIO_ReadData();
//清除所有标志
SDIO_ClearFlag(SDIO_FLAG_ALL);
return(errorstatus);
/*************************************************************************************************************************
* 函数 : SD_Error SD_ReadMultiBlocks(u32 BlockAddr, u32 *BlockBuff, u32 NumberOfBlocks)
* 功能 : 读SD卡多个块
* 参数 : BlockAddr:块地址;
BlockBuff:块缓冲区地址
NumberOfBlocks:块数量
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
读SD卡多个(大于1个)扇区
*************************************************************************************************************************/
SD_Error SD_ReadMultiBlocks(u32 BlockAddr, u32 *BlockBuff, u16 NumberOfBlocks)
SD_Error errorstatus = SD_OK;
u32 timeout = SDIO_READTIMEOUT;//读等待超时计数器
u16 BlockCnt = NumberOfB //需要传输的块计数
u16 cnt = 0;
if (BlockBuff == NULL) //没有分配接收缓冲区,返回
errorstatus = SD_INVALID_PARAMETER;
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
if (NumberOfBlocks & 1)
if (NumberOfBlocks * SD_BlockSize & SD_MAX_DATA_LENGTH)//判定地址是否超出范围
errorstatus = SD_INVALID_PARAMETER;
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
SDIO_SoftwareReset(SDIO_RSTDAT);
//软件复位DAT,主要用来清空FIFO
SDIO_SoftwareReset(SDIO_RSTCMD); //软件复位DAT,主要用来清除状态以及命令
SDIO_MultipleBlockMode();
//设置为多区段传输模式
SDIO_SetTransferBlockCnt(NumberOfBlocks); //设置传输块数量
SDIO_SetTransferBlockSize(SD_BlockSize); //设置单次传输的块大小为SD_BlockSize
SDIO_ReadMode();
//设置为读数据模式
SDIO_BlockCountEnable();
//块计数启动
//发送CMD18 SDIO_READ_MULT_BLOCK;多区段读命令,参数:开始地址,短返回,R1
SDIO_SendCommand(SDIO_READ_MULT_BLOCK,(BlockAddr && 9),SDIO_DataSelect | SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
if (errorstatus != SD_OK)
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
if(SDIO0-&PRNSTS & BIT11) //读缓冲区有效
SDIO_ClearFlag(SDIO_FLAG_BUFFREAD);
//清除读缓冲区有效标志
//缓冲区大小SD_BlockSize字节,共SD_BlockSize/4字
for(cnt = 0;cnt & SD_BlockSize / 4;cnt ++)
*(BlockBuff ++) = SDIO_ReadData();
BlockCnt --; //读完了一块
timeout = SDIO_READTIMEOUT; //读完了一块,超时计数器重新开始计数
timeout --;
}while(BlockCnt && (timeout != 0) && (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) == 0)); //剩余块数量不为0,没超时
//发送CMD12 SDIO_STOP_TRANSMISSION命令,终止读取;参数:0,短响应,R1
SDIO_SendCommand(SDIO_STOP_TRANSMISSION,0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
if (errorstatus != SD_OK)
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
if(timeout == 0) //超时
errorstatus = SD_DATA_TIMEOUT;
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
SDIO_ClearFlag(SDIO_FLAG_ALL); //清除所有中断标志
return(errorstatus);
/*************************************************************************************************************************
* 函数 : SD_Error SD_WriteBlock(u32 BlockAddr, u32 *BlockBuff)
* 功能 : 写SD卡一个块
* 参数 : BlockAddr:块地址;
writebuff:写缓冲区地址
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
写SD卡一个扇区
:修改了写入函数,现在可以成功写入数据
*************************************************************************************************************************/
SD_Error SD_WriteBlock(u32 BlockAddr, u32 *BlockBuff)
SD_Error errorstatus = SD_OK;
u32 timeout = SDIO_WRITETIMEOUT;
//写等待超时计数器
u32 cardstatus = 0;
u8 cardstate = 0;
u16 cnt = 0;
if (BlockBuff == NULL)
errorstatus = SD_INVALID_PARAMETER;
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
SDIO_SoftwareReset(SDIO_RSTDAT); //软件复位DAT,主要用来清空FIFO
SDIO_SoftwareReset(SDIO_RSTCMD); //软件复位DAT,主要用来清除状态以及命令
SDIO_WriteMode();
//设置主机控制器为写模式
SDIO_SetTransferBlockSize(SD_BlockSize); //设置单次传输的块大小为SD_BlockSize
SDIO_SingleBlockMode();
//设置为单块传输模式
timeout --;
//发送CMD13,SDIO_SEND_STATUS,读 Card_Status 寄存器,参数,RCA地址,短返回,R1;
SDIO_SendCommand(SDIO_SEND_STATUS,(u32) RCA && 16,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
if (errorstatus != SD_OK)
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
cardstatus = SDIO_GetResponse(SDIO_RESP1);
while (((cardstatus & 0x) == 0) && (timeout & 0));
if (timeout == 0)
DEBUG("%d\r\n",errorstatus);
return(SD_ERROR);
//发送CMD24,SDIO_WRITE_SINGLE_BLOCK,写命令,参数:地址,短响应,R1
SDIO_SendCommand(SDIO_WRITE_SINGLE_BLOCK,(BlockAddr && 9),SDIO_DataSelect | SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
if (errorstatus != SD_OK)
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
timeout = SDIO_WRITETIMEOUT;
//写等待超时计数器
//写缓冲区是否有效应该判断PRNSTS这个寄存器
while(((SDIO0-&PRNSTS & BIT10) == 0) && (SDIO_GetFlagStatus(SDIO_FLAG_BUFFWRITE) == 0) && timeout && (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) == 0)) //等待写缓冲区有效,或者等待超时
timeout --;
if (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) || (timeout == 0)) //超时
SDIO_ClearFlag(SDIO_FLAG_DATATIMEOUT); //清除标志
errorstatus = SD_DATA_TIMEOUT;
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
//缓冲区大小SD_BlockSize字节,共SD_BlockSize / 4字
for(cnt = 0;cnt & SD_BlockSize / 4;cnt ++)
SDIO_WriteData(BlockBuff[cnt]);
//清除所有标志
SDIO_ClearFlag(SDIO_FLAG_ALL);
//读取卡状态,等待写入完成
errorstatus = IsCardProgramming(&cardstate);
}while ((errorstatus == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING)));
return(errorstatus);
/*************************************************************************************************************************
* 函数 : SD_Error SD_WriteMultiBlocks(u32 BlockAddr, u32 *BlockBuff, u16 NumberOfBlocks)
* 功能 : 写SD卡多个块
* 参数 : BlockAddr:块地址;
BlockBuff:块缓冲区地址
NumberOfBlocks:块数量
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
写SD卡多个(大于1个)扇区
:修改了写入函数,现在可以成功写入数据
*************************************************************************************************************************/
SD_Error SD_WriteMultiBlocks(u32 BlockAddr, u32 *BlockBuff, u16 NumberOfBlocks)
SD_Error errorstatus = SD_OK;
u32 timeout = SDIO_WRITETIMEOUT;
//写等待超时计数器
u16 BlockCnt = NumberOfB //传输的块数量计数
u8 cardstate = 0;
u32 cardstatus = 0;
u16 cnt = 0;
if (BlockBuff == NULL)
errorstatus = SD_INVALID_PARAMETER;
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
if (NumberOfBlocks & 1)
if (NumberOfBlocks * SD_BlockSize & SD_MAX_DATA_LENGTH) //判断地址
errorstatus = SD_INVALID_PARAMETER;
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
SDIO_SoftwareReset(SDIO_RSTDAT);
//软件复位DAT,主要用来清空FIFO
SDIO_SoftwareReset(SDIO_RSTCMD); //软件复位DAT,主要用来清除状态以及命令
SDIO_MultipleBlockMode();
//设置为多区段传输模式
SDIO_SetTransferBlockCnt(NumberOfBlocks); //设置传输块数量
SDIO_SetTransferBlockSize(SD_BlockSize); //设置单次传输的块大小为SD_BlockSize
SDIO_WriteMode();
//设置为写数据模式
SDIO_BlockCountEnable();
//块计数启动
timeout --;
//发送CMD13,SDIO_SEND_STATUS,读 Card_Status 寄存器,参数,RCA地址,短返回,R1;
SDIO_SendCommand(SDIO_SEND_STATUS,(u32) RCA && 16,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
if (errorstatus != SD_OK)
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
cardstatus = SDIO_GetResponse(SDIO_RESP1);
while (((cardstatus & 0x) == 0) && (timeout & 0));
if (timeout == 0)
DEBUG("%d\r\n",errorstatus);
return(SD_ERROR);
timeout = SDIO_WRITETIMEOUT;
//发送CMD25,SDIO_WRITE_MULT_BLOCK,参数:字节地址,短返回,R1
SDIO_SendCommand(SDIO_WRITE_MULT_BLOCK,(BlockAddr && 9),SDIO_DataSelect | SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
if (errorstatus != SD_OK)
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
if(SDIO0-&PRNSTS & BIT10) //写缓冲区有效
SDIO_ClearFlag(SDIO_FLAG_BUFFWRITE);
//清除写缓冲区有效标志
//缓冲区大小SD_BlockSize字节,共SD_BlockSize / 4字
for(cnt = 0;cnt & SD_BlockSize / 4;cnt ++)
SDIO_WriteData(*BlockBuff ++);
BlockCnt --; //读完了一块
timeout = SDIO_READTIMEOUT; //读完了一块,超时计数器重新开始计数
timeout --;
}while(BlockCnt && (timeout != 0) && (SDIO_GetFlagStatus(SDIO_FLAG_DATATIMEOUT) == 0)); //剩余块数量不为0,没超时
//发送CMD12 SDIO_STOP_TRANSMISSION命令,终止读取;参数:0,短响应,R1
SDIO_SendCommand(SDIO_STOP_TRANSMISSION,0,SDIO_CMDIndexEn | SDIO_CMDCrcEn | SDIO_Response_Short);
errorstatus = CmdResp1Error();
if (errorstatus != SD_OK)
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
if(timeout == 0) //超时
errorstatus = SD_DATA_TIMEOUT;
DEBUG("%d\r\n",errorstatus);
return(errorstatus);
SDIO_ClearFlag(SDIO_FLAG_ALL); //清除所有中断标志
//读取卡状态,等待写入完成
errorstatus = IsCardProgramming(&cardstate);
}while ((errorstatus == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING)));
return(errorstatus);
/*************************************************************************************************************************
* 函数 : static SD_Error CmdError(void)
* 功能 : 指令执行状态(无响应)
* 参数 : 无
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
返回指令执行结果(内部函数)
*************************************************************************************************************************/
static SD_Error CmdError(void)
SD_Error errorstatus = SD_OK;
timeout = SDIO_CMD0TIMEOUT;
while ((timeout & 0) && (SDIO_GetFlagStatus(SDIO_FLAG_COMMANDEND) == 0))
timeout--;
if (timeout == 0)
errorstatus = SD_CMD_RSP_TIMEOUT;
return(errorstatus);
//清除所有标志
SDIO_ClearFlag(SDIO_FLAG_ALL);
return(errorstatus);
/*************************************************************************************************************************
* 函数 : static SD_Error CmdResp7Error(void)
* 功能 : 指令执行状态(R7)
* 参数 : 无
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
返回指令执行结果(内部函数)
*************************************************************************************************************************/
static SD_Error CmdResp7Error(void)
SD_Error errorstatus = SD_OK;
u32 timeout = SDIO_CMD0TIMEOUT;
timeout--;
while (!(SDIO_STATUS & (SDIO_FLAG_COMMANDCRC | SDIO_FLAG_COMMANDEND | SDIO_FLAG_COMMANDTIMEOUT)) && (timeout & 0));
if ((timeout == 0) || (SDIO_STATUS & SDIO_FLAG_COMMANDTIMEOUT))
/* Card is not V2.0 complient or card does not support the set voltage range */
errorstatus = SD_CMD_RSP_TIMEOUT;
SDIO_ClearFlag(SDIO_FLAG_COMMANDTIMEOUT);
return(errorstatus);
if (SDIO_STATUS & SDIO_FLAG_COMMANDEND)
/* Card is SD V2.0 compliant */
errorstatus = SD_OK;
SDIO_ClearFlag(SDIO_FLAG_COMMANDEND);
return(errorstatus);
//清除所有标志
SDIO_ClearFlag(SDIO_FLAG_ALL);
return(errorstatus);
/*************************************************************************************************************************
* 函数 : static SD_Error CmdResp1Error(void)
* 功能 : 指令执行状态(R1)
* 参数 : 无
* 返回 : SD_OK:成功,其它见SD Card Error code.
* 依赖 : 底层寄存器操作函数
* 作者 : 陈鹏
* 最后修改时间 :
返回指令执行结果(内部函数)
*************************************************************************************************************************/
static SD_Error CmdResp1Error(void)
SD_Error errorstatus = SD_OK;
u32 response_r1;
while (!(SDIO_STATUS & (SDIO_FLAG_COMMANDCRC | SDIO_FLAG_COMMANDEND | SDIO_FLAG_COMMANDTIMEOUT | SDIO_FLAG_COMMANDINDEX)));
if (SDIO_STATUS & SDIO_FLAG_COMMANDTIMEOUT)
errorstatus = SD_CMD_RSP_TIMEOUT;
SDIO_ClearFlag(SDIO_FLAG_COMMANDTIMEOUT);
return(errorstatus);
else if (SDIO_STATUS & SDIO_FLAG_COMMANDCRC)
errorstatus = SD_CMD_CRC_FAIL;
SDIO_ClearFlag(SDIO_FLAG_COMMANDCRC);
return(errorstatus);
else if (SDIO_STATUS & SDIO_FLAG_COMMANDINDEX)
errorstatus = SD_ILLEGAL_CMD;
SDIO_ClearFlag(SDIO_FLAG_COMMANDINDEX);
return(errorstatus);
//清除所有标志
SDIO_ClearFlag(SDIO_FLAG_ALL);
/* We have received response, retrieve it for analysis
response_r1 = SDIO_GetResponse(SDIO_RESP1);
if ((response_r1 & SD_OCR_ERRORBITS) == SD_ALLZERO)
return(errorstatus);
if (response_r1 & SD_OCR_ADDR_OUT_OF_RANGE)
return(SD_ADDR_OUT_OF_RANGE);
if (response_r1 & SD_OCR_ADDR_MISALIGNED)
return(SD_ADDR_MISALIGNED);
if (response_r1 & SD_OCR_BLOCK_LEN_ERR)
return(SD_BLOCK_LEN_ERR);
if (response_r1 & SD_OCR_ERASE_SEQ_ERR)
return(SD_ERASE_SEQ_ERR);
if (response_r1 & SD_OCR_BAD_ERASE_PARAM)
return(SD_BAD_ERASE_PARAM);
if (response_r1 & SD_OCR_WRITE_PROT_VIOLATION)
return(SD_WRITE_PROT_VIOLATION);
if (response_r1 & SD_OCR_LOCK_UNLOCK_FAILED)
return(SD_LOCK_UNLOCK_FAILED);
if (response_r1 & SD_OCR_COM_CRC_FAILED)
return(SD_COM_CRC_FAILED);
if (response_r1 & SD_OCR_ILLEGAL_CMD)
return(SD_ILLEGAL_CMD);
if (response_r1 & SD_OCR_CARD_ECC_FAILED)
return(SD_CARD_ECC_FAILED);
if (response_r1 & SD_OCR_CC_ERROR)
return(SD_CC_ERROR);
if (response_r1 & SD_OCR_GENERAL_UNKNOWN_ERROR)
return(SD_GENERAL_UNKNOWN_ERROR);
if (response_r1 & SD_OCR_STREAM_READ_UNDERRUN)
return(SD_STREAM_READ_UNDERRUN);
if (response_r1 & SD_OCR_STREAM_WRITE_OVERRUN)
return(SD_STREAM_WRITE_OVERRUN);
if (response_r1 & SD_OCR_CID_CSD_OVERWRIETE)
return(SD_CID_CSD_OVERWRITE);
if (response_r1 & SD_OCR_WP_ERASE_SKIP)
return(SD_WP_ERASE_SKIP);
if (response_r1 & SD_OCR_CARD_ECC_DISABLED)
return(SD_CARD_ECC_DISABLED);
if (response_r1 & SD_OCR_ERASE_RESET)
return(SD_ERASE_RESET);
if (res}

我要回帖

更多关于 烧录好的SD卡是否分盘 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信