目录
前言
1. SDIO协议简介
2. SDIO命令及响应
3. SD卡的操作模式及切换
4. STM32的SDIO接口
5. SDIO结构体
6. SDIO相关寄存器
7. 实验程序
7.1 main.c
7.2 SDIO_Card.c
7.3 SDIO_Card.h
在之前的单片机学习过程中,我们已经了解到了单片机系统都需要大容量的存储设备,以存储数据。目前比较常用的是U盘、FLASH芯片,SD卡。他们各有优先,其中SD卡的容量可以做到很大(32GB以上),支持SPI/SDIO驱动,以满足用户对大容量单片机内存读取数据的要求。
在STM32F4中,只需要几个简单的IO口就可以外扩一个32GB以上的外部存储器,容量从几十M到几十G;STM32F4自带了一个标准的SD卡接口,使用STM32F4自带的SDIO接口驱动。
本节我们就来学习STM32F4的SD卡外设!!!
SD卡(Secure Digital Memory Card)在我们日常生活中已经是很普遍了,控制器对SD卡的读写通信操作一般有两种通信接口可选,一种是SPI接口,另外一种是SDIO接口。SDIO全称是安全数字输入/输出接口,像多媒体卡(MMC)、SD卡、SD I/O卡都有SDIO接口。
SD存储卡目前主要是分为三种:SD(不大于2GB)、SDHC(大于2GB,不大于32GB)、SDXC(大于32GB,不大于2TGB)
SD卡物理结构:
一张SD卡包括有:存储单元、存储单元接口、电源检测、卡及接口控制器和接口驱动器5个部分
存储单元是存储数据的部件,存储单元通过存储单元接口与卡控制单元进行数据传输;
电源检测单元保证SD卡工作在合适的电压下,如果出现掉电或者上电状态时,它会使存储单元接口和卡控制单元复位(也就是图中电源检测指向的Reset);
卡及接口控制单元控制SD卡的运行状态,主要包括8个寄存器;这8个寄存器用于设定或表示SD卡信息。
接口驱动器控制SD卡引脚的输入输出;
注:
卡及接口控制单元的8个寄存器只能通过对应的命令去访问,SDIO定义了64个命令,每个命令都有特殊的意义,可以实现某一特定的功能,SD卡接收到命令后,根据命令要求对SD卡内部寄存器进行修改,从而实现SD卡的控制及读写操作;
这类似于我们宏定义64个命令,然后设置读写程序,读写这些命令即可实现SD卡的控制及读写操作;
SD卡寄存器列表:
- CID寄存器:128位,卡识别号(Card Identification Number):用来识别的卡的个体号码(这个个体号码是唯一的)
- RCA寄存器:16位,相对地址(Relative Card Address):卡的本地系统地址,初始化时,动态地由卡建议,主机审核
- DSR寄存器:16位,驱动级寄存器(Driver Stage Register):配置卡的输出驱动
- CSD寄存器:128位,卡的特定数据(Card Specific Data):卡的操作条件信息
- SCR寄存器:64位,SD配置寄存器(SD Configuration Register):SD卡特殊特性信息
- OCR寄存器:32位,操作条件寄存器(Operation condition Register)
- SSR寄存器:512位,SD状态(SD Status):SD卡专有特性的信息
- CSR寄存器:32位,卡状态(Card Status):卡状态信息
SD卡总线拓扑:
总线拓扑结构:总线型拓扑结构简称为总线拓扑,它是将网络中各个节点设备用一根总线挂接起来,实现计算机网络的功能。(类似于IIC、SPI的总线结构)
如上图,总线拓扑结构中:
左侧HOST为STM32主机,右侧分别是卡槽A和卡槽B,卡槽A和卡槽B共用总线时钟CLK,但是卡槽A和卡槽B各自拥有自己独立的数据线和主机进行通讯;
SD卡引脚简介:
SD卡采用9-Pin接口通信,其中3根电源线,1根时钟线,1根命令线和4根数据线;
SDIO CLK:时钟线,由SDIO主机产生,即由STM32控制器输出;
SDIO CMD:命令控制器,SDIO主机通过该线发送命令控制SD卡,如果命令要求SD卡提供应答,那么SD卡也是通过该线传输应答信息;
SDIO D0-3:数据线,传输读写数据;SD卡可以将D0拉低表示忙碌状态;
VSS VDD GND:电源和地信号;
SDIO总线:
SDIO的通信时序比较简单,SDIO不管是STM32主机控制器向SD卡传输,还是SD卡向STM32传输,都是以CLK时钟的上升沿为有效。(也就是说,不管是主从方向还是从主方向都是CLK时钟上升沿有效)
SD卡操作过程会使用两种不同的频率的时钟同步数据,一个是识别卡阶段时钟频率FOD,最高为400KHz;另外一个是数据传输模式下时钟频率FPP,默认最高为25MHz(如果通过寄存器配置使SDIO工作在高速模式,此时的数据传输模式最高频率为50MHz)
SDIO总线协议:
SD总线通信是基于命令和数据传输的。通讯由一个起始位(“0”),由一个停止位(“1”)终止。SD通信一般是主机发送一个命令(Command),从设备在接收到命令后作出响应(Response),如果有需要会有数据(Data)传输参与。
SD卡传输可以有响应,也可以没有响应;(例如上图中左侧,主机发送Command命令到SD卡,SD卡不作响应的情况下进行数据传输;右侧主机发送Command命令到SD卡,SD卡发送应答信号通过CMD总线传输至主机)
SD数据以块Black形式传输,SDHC卡数据块长度一般为512字节,数据可以从主机到卡,也可以从卡到主机。数据块需要CRC校验位(CRC位由SD卡系统硬件生成)来保证数据传输成功。STM32控制器可以控制使用单线或4线传输。
写数据的过程如上图:主机发送Command命令到从机,然后从机发送应答信号到主机,主机写数据到卡,以数据块的方式写数据到SD卡,其中数据块中包括CRC校验位(保证数据传输成功),以及可以将SDIO D0引脚拉低表示忙碌状态;
如果想要突然停止数据的发送,那么同样也是可以主机发送Command命令,从机做出应答,通过数据块发送命令和CRC校验位,使得数据停止发送。
SD卡数据传输支持单块和多块读写,分别对应不同的操作命令。数据写入之前需要检测SD卡忙状态,因为SD卡接收到数据后编程到存储区过程需要一定的操作时间。忙状态通过把D0引脚拉低来实现。
数据块读操作是不需要忙状态检测的;(因为忙状态是接收数据到数据存储区的过程需要时间,所以需要判断状态;读的过程中无此步骤)
4数据线传输:
使用4数据线传输时,每次传输4bit数据,每根数据线都必须有起始位、终止位和CRC校验位,CRC位每根数据线都要分别检查,并把检查结果汇总然后在数据传输完后通过D0线反馈给主机。
SD卡数据包有两种格式,一种是常规数据(8bit宽),它先发低字节,然后发高字节,而每个字节则是先发高位再发低位;
另外一种数据包发送格式是宽位数据包格式,对SD卡而言,宽位数据包发送方式是针对SD卡SSR状态寄存器内容发送的,SSR寄存器总共有512位,在主机发出ACMD13命令后SD卡将SSR寄存器内容通过DAT线发送给主机。
发送数据包的方式相同,也是1个时钟周期内发送4位数据,从高位到低位进行发送;
SD命令是由主机发出的,以广播命令和寻址命令为例,广播命令是针对于SD主机总线连接的所有从设备发出的(广播命令就类似于我一个STM32的SD卡总线上挂载着卡槽A和卡槽B以及卡槽C,那么通过广播命令发送的指令所有卡槽都可以收到),寻址命令是指定某个地址设备进行命令传输的(而寻址命令是针对于某个固定卡槽来讲的,可以是主机和卡槽A通信,也可能是主机和卡槽B进行通信)。
命令格式:
SD命令格式固定为48bit,都是通过CMD命令线连续传输的,数据线不参与。
SD命令的格式是固定的,起始位是0,终止位是1,分别各占一位,命令的主体包含在起始位和终止位之间;起始位以后,有一个传输标志1,占一位;命令+地址信息(CONTENT)占6+32位,其中命令占6位,地址信息占32位;最后有一个CRC校验位,这些校验位是通过算法提供的,占7位;
命令格式:
命令号:他固定占用6位,总共有64个命令(代号:CMD0~CMD63),每个命令都有特殊的用途,部分命令不适用于SD卡操作,只是专门用于MMC卡或者SD I/O卡
地址/参数:每个命令有32位地址信息/参数用于命令附加内容,例如,广播命令没有地址信息,这32位用于指定参数;寻址命令这32位用于指定目标SD卡的地址
CRC7校验:长度为7位的校验位用于验证命令传输内容的正确性,如果发生外部干扰导致传输数据个别位状态改变将导致校验失败,也意味着命令传输失败,SD卡不执行命令
命令类型:
SD命令有4种类型:
无响应广播命令(bc),发送到所有卡,不返回任务响应;
带响应广播命令(bcr),发送到所有卡,同时接收来自所有卡响应;
寻址命令(ac),发送到选定卡,DAT线无数据传输;
寻址数据传输命令(adtc),发送到选定卡,DAT线有数据传输;
另外,SD卡主机模块系统旨在为各种应用程序类型提供一个标准接口。为实现这些功能,在标准中定义了两种类型的通用命令:特定应用命令(ACMD)和常规命令(GEN_CMD)。要使用SD卡制造商特定的ACMD命令,需要在发送该命令之前发送CMD55命令,告知SD卡接下来的命令为特定应用命令,CMD55只对紧接着的第一个命令有效,SD卡如果检测到CMD55之后的命令为ACMD则执行特定应用命令,如果检测发现不是ACMD命令,则执行常规命令GEN_CMD;
基本命令简介:
基本命令(Class 0)
CMD0:GO_IDLE_STATE,复位所有的卡到idle状态
CMD2:ALL_SEND_CID,通知所有卡通过CMD命令线返回CID的值
CMD3:SEND_RELATIVE_ADDR,通知所有卡发布新RCA
CMD4:SET_DSR,编程所有卡的DSR
CMD7:SELECT/DESELECT_CARD,选择/取消选择RCA地址卡
CMD8:SEND_IF_COND,发送SD卡接口条件,包含主机支持的电压信息,并询问卡是否支持
CMD9:SEND_CSD,选定卡通过CMD线发送CSD内容
CMD10:SEND_CID,选定卡通过CMD线发送CID内容
CMD12:STOP_TRANSMISSION,强制卡停止传输
CMD13:SEND_STATUS,选定卡通过CMD线发送它的状态寄存器
CMD15:GO_INACTIVE_STATE,使选定卡进入 “inactive” 状态
面向块的读操作(Class 2)
CMD16:SET_BLOCK_LEN,对于标准的SD卡,设置块命令的长度,对于SDHC卡块命令长度固定为512字节
CMD17:READ_SINGLE_BLOCK,对于标准卡,读取SEL_BLOCK_LEN长度字节的块;对于SDHC卡,读取512字节的块
CMD18:READ_MULTIPLE_BLOCK,连续从SD卡读取数据块,直到被CMD12中断。块长度同CMD17
面向块的写操作(Class 4)
CMD24:WRITE_BLOCK,对于标准卡,写入SEL_BLOCK_LEN长度字节的块;对于SDHC卡,写入512字节的块
CMD25:WRITE_MILTIPLE_BLOCK,连续向SD卡写入数据块,直到被CMD12中断。块长度同CMD17
CMD27:PROGRAM_CSD,对CSD的可编程位进行编程
擦除命令(Class 5)
CMD32:ERASE_WR_BLK_START,设置擦除的起始块地址
CMD33:ERASE_WR_BLK_END,设置擦除的结束块地址
CMD38:ERASE,擦除预先选定的块
加载命令(Class 7)
CMD42:LOCK_UNLOCK,加载/解锁SD卡
特定应用命令(Class 8)
CMD55:APP_CMD,指定下一个命令为特定应用命令,不是标准命令
CMD56:GEN_CMD,通用命令,或者特定应用命令中,用于传输一个数据块,最低位为1表示读数据,为0表示写数据
SD卡特定应用命令
ACMD6:SET_BUS_WIDTH,定义数据总线宽度(‘00’=1bit,‘10’=4bit)
ACMD13:SD_STATUS,发送SD状态
ACMD41:SD_SEND_OP_COND,主机要求卡发送它的支持信息(HCS)和OCR寄存器内容
ACMD51:SEND_SCR,读取配置寄存器SCR
SD卡操作模式:
SD卡系统(包括主机和SD卡)定义了两种操作模式:卡识别模式和数据传输模式。在系统复位后,主机处于卡识别模式,寻找总线上可用的SDIO设备;同时卡也处于卡识别模式,直到被主机识别到(类似于IIC的空闲状态),当SD卡接收到SEND_RCA(CMD3)命令后,SD卡就会进入数据传输模式,而主机在总线上所有卡被识别后也进入数据传输模式。
SD卡操作模式下的状态:
在每一种操作模式下,SD卡都有几种状态。
卡识别模式:
数据传输模式:
STM32控制器有一个SDIO,由两部分组成:SDIO适配器和APB2接口,SDIO适配器提供SDIO主机功能,可以提供SD时钟、发送命令和进行数据传输。APB2接口用于控制器访问SDIO适配器寄存器并且可以产生中断和DMA请求信号。
(简单来说就是SDIO适配器提外部引脚和SD卡相连,分别由时钟引脚SDIO_CLK、命令引脚SDIO_CMD和数据引脚SDIO_D;APB2接口是STM32控制器和SDIO适配器访问的中间媒介,STM32必须通过APB2接口才可以访问SDIO适配器,并且APB2接口可以产生中断和DMA请求信号,中断和DMA请求信号都是相对于STM32控制器而言的)
SDIO使用两个时钟信号(如上图),一个是SDIO适配器时钟(SDIOCLK=48MHz),另外一个是APB2总线时钟(PCLK2,一般是84MHz)。
STM32控制器的SDIO是针对MMC卡和SD卡的主要设备,所以预留有8根数据线,根据原理图上可知,SD卡最多只用4根数据线。
SDIO适配器内部逻辑框图:
SDIO适配器由五个单元组成,分别是控制单元、命令路径单元、数据路径单元、寄存器单元以及FIFO。
命令路径控制命令发送,并接受卡的响应,当SD卡处于某一状态时,SDIO适配器必然处于特定状态与之对应。STM32控制器以命令路径状态机(CPSM)来描述SDIO适配器状态变化,并加入了等待超时检测功能,以便退出永久等待的情况。
数据FIFO(先进先出)部件是一个数据缓冲器,带发送和接收单元。控制器的FIFO包含宽度为32bit、深度为32字的数据缓冲器和发送/接收逻辑。
SDIO状态寄存器(SDIO_STA)的TXACT位用于指示当前正在发送数据,RXACT位指示当前正在接收数据,这两个位不可能同时为1;
//SDIO初始化结构体
typedef struct
{
uint32_t SDIO_ClockEdge; //时钟沿
//主时钟SDIOCLK产生的CLK引脚时钟有效沿选择,可选择上升沿或者下降沿
//SDIO_ClockEdge_Falling或者SDIO_ClockEdge_Rising
uint32_t SDIO_ClockBypass; //旁路时钟
//时钟分频旁路使用,可选择使能或者禁用
uint32_t SDIO_ClockPowerSave; //节能模式
//节能模式,可选择使能或者禁用
uint32_t SDIO_BusWide; //数据宽度
//选择1位或者4位数据
uint32_t SDIO_HardwareFlowControl; //硬件流控制
//可选择使能或者禁用
//硬件流控制功能可以避免FIFO发送上溢和下溢错误
uint8_t SDIO_ClockDiv; //时钟分频
}SDIO_InitTypeDef;
//SDIO命令初始化结构体
typedef struct
{
uint32_t SDIO_Argument; //命令参数
//作为命令的一部分发送到卡的命令参数
uint32_t SDIO_CmdIndex; //命令号
//CMD16 16就是命令号
uint32_t SDIO_Response; //响应类型
//长响应还是短响应
uint32_t SDIO_Wait; //等待使能 等待类型选择
//一种是无等待状态,超时检测功能启动
//一种是等待中断
//另外一种是等待传输完成
uint32_t SDIO_CPSM; //命令路径状态机
//使能
}SDIO_CmdInitTypeDef;
//SDIO数据初始化结构体
typedef struct
{
uint32_t SDIO_DataTimeOut; //数据传输超时
uint32_t SDIO_DataLength; //数据长度
uint32_t SDIO_DataBlockSize; //数据块大小
uint32_t SDIO_TransferDir; //数据传输方向
uint32_t SDIO_TransferMode; //数据传输模式
uint32_t SDIO_DPSM; //数据路径状态机
}SDIO_DataInitTypeDef;
1. SDIO电源控制寄存器(SDIO_POWER)
该寄存器的电源复位值为0,所以SDIO的电源是关闭的,我们要启动SDIO,第一步就是电源控制寄存器的最低两位为11,让SDIO上电,开启卡时钟。
2. SDIO时钟控制寄存器(SDIO_CLKCR)
位12:11 WIDBUS:宽总线模式使能位
位10 BYPASS:时钟分频器旁路使能位
位8 CLKEN:时钟使能位
位7:0 CLKDIV:时钟分频系数
该字段定义输入时钟SDIOCLK与输出时钟SDIO_CK之间的分频系数
SDIO_CK频率=SDIOCLK/[CLKDIV+2] 一般设置为0,得到24MHz的SDIO_CK频率
3. SDIO参数寄存器(SDIO_ARG)
位31:0 CMDARG:命令参数
用于存储命令,不过必须在写命令之前先写这个参数寄存器!
4. SDIO命令响应寄存器(SDIO_RESPCMD)
位5:0 RESPCMD:响应命令索引
低6位有效,用于存储最后收到的命令响应中的命令索引。如果最后输出的命令响应不包含命令索引,则该寄存器的内容不可预知。
5. SDIO响应寄存器组(SDIO_RESP1~SDIO_RESP4)
6. SDIO命令寄存器(SDIO_CMD)
位10 CPSMEN:命令路径状态机CPSM使能位
此位置 1 表示使能CPSM。
位7:6 WAITRESP:等待响应位 用于配置CPSM(命令通道状态机)是否等待响应,如果等待,将等待哪种响应
位5:0 CMDINDEX:命令索引
命令索引作为命令消息的一部分发送给卡 比如CMD1 ,那么最低六位就发送1
7. SDIO数据定时器寄存器(SDIO_DTIMER)
位31:0 DATATIME:数据超时周期
以卡总线时钟周期表示数据超时周期
8. SDIO数据长度寄存器(SDIO_DLEN)
位24:0 DATALENGTH:数据长度值
要传输的数据字节数量
9. SDIO数据控制寄存器(SDIO_DCTRL)
位11 SDIOEN:SD I/O使能功能
该位置1,则DPSM执行特定于SD I/O卡的操作
位10 RWMOD:读取等待模式
位9 RWSTOP:读取等待停止
位8 RWSTART:读取等待开始
该位置1,表示读取等待开始
位7:4 DBLOCKSIZE:数据块大小
位3 DMAEN:DMA使能位
位2 DTMODE:数据传输模式选择
位1 DTDIR:数据传输方向选择
位0 DTEN:数据传输使能位
该位置1表示数据传输开始
10. SDIO数据FIFO寄存器
位31:0 FIFOData:接收和传输FIFO数据
数据FIFO寄存器包括接收和发送FIFO,他们由一组连续的32个地址上的32个寄存器组成,CPU可以使用FIFO读写多个操作数。例如我们要从SD卡读数据,就必须读SDIO_FIFO寄存器,要写数据到SD卡,则要写SDIO_FIFO寄存器。SDIO将这32个地址分为16个一组,发送和接收各占一半。
注意:我们操作的SDIO_FIFO(无论是读出还是写入)必须是以4字节对齐的内存进行操作,否则将会导致出错!
实验功能:
开机初始化SD卡,如果SD卡初始化成功,则提示LCD初始化成功。按下KEY0,读取SD卡扇区0的数据,通过串口发送到电脑。如果没初始化通过,则在LCD上提示初始化失败。
#include "stm32f4xx.h"
#include "delay.h"
#include "usart.h"
#include "LED.h"
#include "lcd.h"
#include "Key.h"
#include "usmart.h"
#include "SRAM.h"
#include "Malloc.h"
#include "SDIO_Card.h"
//LCD状态设置函数
void led_set(u8 sta)//只要工程目录下有usmart调试函数,主函数就必须调用这两个函数
{
LED1=sta;
}
//函数参数调用测试函数
void test_fun(void(*ledset)(u8),u8 sta)
{
led_set(sta);
}
//通过串口打印SD卡相关信息
void show_sdcard_info(void)
{
switch(SDCardInfo.CardType)
{
case SDIO_STD_CAPACITY_SD_CARD_V1_1:printf("Card Type:SDSC V1.1\r\n");
break;
case SDIO_STD_CAPACITY_SD_CARD_V2_0:printf("Card Type:SDSC V2.0\r\n");
break;
case SDIO_HIGH_CAPACITY_SD_CARD:printf("Card Type:SDHC V2.0\r\n");
break;
case SDIO_MULTIMEDIA_CARD:printf("Card Type:MMC Card\r\n");
break;
}
printf("Card ManufacturerID:%d\r\n",SDCardInfo.SD_cid.ManufacturerID); //制造商ID
printf("Card RCA:%d\r\n",SDCardInfo.RCA); //卡相对地址
printf("Card Capacity:%d MB\r\n",(u32)(SDCardInfo.CardCapacity>>20)); //显示容量
printf("Card BlockSize:%d\r\n\r\n",SDCardInfo.CardBlockSize); //显示块大小
}
int main(void)
{
u8 key;
u32 sd_size;
u8 t=0;
u8 *buf;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为115200
LED_Init(); //初始化LED
LCD_Init(); //LCD初始化
Key_Init(); //按键初始化
my_mem_init(SRAMIN); //初始化内部内存池
my_mem_init(SRAMCCM); //初始化CCM内存池
POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");
LCD_ShowString(30,70,200,16,16,"SD CARD TEST");
LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,110,200,16,16,"2023/20/23");
LCD_ShowString(30,130,200,16,16,"KEY0:Read Sector 0");
while(SD_Init())//检测不到SD卡
{
LCD_ShowString(30,150,200,16,16,"SD Card Error!");
delay_ms(500);
LCD_ShowString(30,150,200,16,16,"Please Check! ");
delay_ms(500);
LED0=!LED0;//DS0闪烁
}
show_sdcard_info(); //打印SD卡相关信息
POINT_COLOR=BLUE; //设置字体为蓝色
//检测SD卡成功
LCD_ShowString(30,150,200,16,16,"SD Card OK ");
LCD_ShowString(30,170,200,16,16,"SD Card Size: MB");
LCD_ShowNum(30+13*8,170,SDCardInfo.CardCapacity>>20,5,16);//显示SD卡容量
while(1)
{
key=KEY_Scan(0);
if(key==1)//KEY0按下了
{
buf=mymalloc(0,512); //申请内存
if(SD_ReadDisk(buf,0,1)==0) //读取0扇区的内容
{
LCD_ShowString(30,190,200,16,16,"USART1 Sending Data...");
printf("SECTOR 0 DATA:\r\n");
for(sd_size=0;sd_size<512;sd_size++)printf("%x ",buf[sd_size]);//打印0扇区数据
printf("\r\nDATA ENDED\r\n");
LCD_ShowString(30,190,200,16,16,"USART1 Send Data Over!");
}
myfree(0,buf);//释放内存
}
t++;
delay_ms(10);
if(t==20)
{
LED0=!LED0;
t=0;
}
}
}
#include "sys.h"
#include "SDIO_Card.h"
#include "string.h"
#include "usart.h"
/*用于sdio初始化的结构体*/
SDIO_InitTypeDef SDIO_InitStructure;
SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
SDIO_DataInitTypeDef SDIO_DataInitStructure;
SD_Error CmdError(void);
SD_Error CmdResp7Error(void);
SD_Error CmdResp1Error(u8 cmd);
SD_Error CmdResp3Error(void);
SD_Error CmdResp2Error(void);
SD_Error CmdResp6Error(u8 cmd,u16*prca);
SD_Error SDEnWideBus(u8 enx);
SD_Error IsCardProgramming(u8 *pstatus);
SD_Error FindSCR(u16 rca,u32 *pscr);
u8 convert_from_bytes_to_power_of_two(u16 NumberOfBytes);
static u8 CardType=SDIO_STD_CAPACITY_SD_CARD_V1_1; //SD卡类型(默认为1.x卡)
static u32 CSD_Tab[4],CID_Tab[4],RCA=0; //SD卡CSD,CID以及相对地址(RCA)数据
static u8 DeviceMode=SD_DMA_MODE; //工作模式,注意,工作模式必须通过SD_SetDeviceMode,后才算数.这里只是定义一个默认的模式(SD_DMA_MODE)
static u8 StopCondition=0; //是否发送停止传输标志位,DMA多块读写的时候用到
volatile SD_Error TransferError=SD_OK; //数据传输错误标志,DMA读写时使用
volatile u8 TransferEnd=0; //传输结束标志,DMA读写时使用
SD_CardInfo SDCardInfo; //SD卡信息
//SD_ReadDisk/SD_WriteDisk函数专用buf,当这两个函数的数据缓存区地址不是4字节对齐的时候,
//需要用到该数组,确保数据缓存区地址是4字节对齐的.
__align(4) u8 SDIO_DATA_BUFFER[512]; // __align(4)是保证数据缓存区地址是4字节对齐的
void SDIO_Register_Deinit() //初始化寄存器,初始化寄存器的复位值可参照中文参考手册
{
SDIO->POWER=0x00000000; //初始化电源控制寄存器为掉电模式
SDIO->CLKCR=0x00000000; //初始化时钟控制寄存器
SDIO->ARG=0x00000000; //初始化参数寄存器
SDIO->CMD=0x00000000; //初始化命令寄存器
SDIO->DTIMER=0x00000000; //初始化数据定时器寄存器
SDIO->DLEN=0x00000000; //初始化数据长度寄存器
SDIO->DCTRL=0x00000000; //初始化数据控制寄存器
SDIO->ICR=0x00C007FF; //初始化中断清零寄存器
SDIO->MASK=0x00000000; //初始化屏蔽寄存器
}
//初始化SD卡
//返回值:错误代码(0,无错误)
SD_Error SD_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
SD_Error errorstatus=SD_OK; //SD枚举结构体初始化为SD_OK,设置枚举结构体变量errorstatus
u8 clkdiv=0;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_DMA2, ENABLE);//使能GPIOC,GPIOD DMA2时钟
//GPIOC对应于SDIO_D0 SDIO_D1 SDIO_D2 SDIO_D3 SDIO_SCK
//GPIOD对应于SDIO_CMD
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);//SDIO时钟使能
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SDIO, ENABLE);//SDIO复位
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12; //PC8,9,10,11,12复用功能输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50M
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOC, &GPIO_InitStructure);// PC8,9,10,11,12复用功能输出
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_2; //PD2对应于SDIO_CMD
GPIO_Init(GPIOD, &GPIO_InitStructure);//PD2复用功能输出
//引脚复用映射设置
GPIO_PinAFConfig(GPIOC,GPIO_PinSource8,GPIO_AF_SDIO); //PC8
GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_SDIO); //PC9
GPIO_PinAFConfig(GPIOC,GPIO_PinSource10,GPIO_AF_SDIO); //PC10
GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_SDIO); //PC11
GPIO_PinAFConfig(GPIOC,GPIO_PinSource12,GPIO_AF_SDIO); //PC12
GPIO_PinAFConfig(GPIOD,GPIO_PinSource2,GPIO_AF_SDIO); //PD2
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SDIO,DISABLE);//SDIO结束复位
//SDIO外设寄存器设置为默认值
SDIO_Register_Deinit();
NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化NVIC寄存器
errorstatus=SD_PowerON(); //SD卡上电
if(errorstatus==SD_OK)
errorstatus=SD_InitializeCards(); //初始化SD卡
if(errorstatus==SD_OK)
errorstatus=SD_GetCardInfo(&SDCardInfo); //获取卡信息 SDCardInfo SD卡信息结构体
if(errorstatus==SD_OK)
errorstatus=SD_SelectDeselect((u32)(SDCardInfo.RCA<<16));//选中SD卡
if(errorstatus==SD_OK)
errorstatus=SD_EnableWideBusOperation(SDIO_BusWide_4b); //4位宽度,如果是MMC卡,则不能用4位模式
if((errorstatus==SD_OK)||(SDIO_MULTIMEDIA_CARD==CardType))
{
if(SDCardInfo.CardType==SDIO_STD_CAPACITY_SD_CARD_V1_1||SDCardInfo.CardType==SDIO_STD_CAPACITY_SD_CARD_V2_0)
{
clkdiv=SDIO_TRANSFER_CLK_DIV+2; //V1.1/V2.0卡,设置最高48/4=12Mhz
}
else
clkdiv=SDIO_TRANSFER_CLK_DIV; //SDHC等其他卡,设置最高48/2=24Mhz
SDIO_Clock_Set(clkdiv); //设置时钟频率,SDIO时钟计算公式:SDIO_CK时钟=SDIOCLK/[clkdiv+2];其中,SDIOCLK固定为48Mhz
//errorstatus=SD_SetDeviceMode(SD_DMA_MODE); //设置为DMA模式
errorstatus=SD_SetDeviceMode(SD_POLLING_MODE);//设置为查询模式
}
return errorstatus;
}
//SDIO时钟初始化设置
//clkdiv:时钟分频系数
//CK时钟=SDIOCLK/[clkdiv+2];(SDIOCLK时钟固定为48Mhz)
void SDIO_Clock_Set(u8 clkdiv)
{
u32 tmpreg=SDIO->CLKCR;
tmpreg&=0XFFFFFF00; //SDIO时钟控制寄存器的低8位为时钟分频系数,tmpreg&=0XFFFFFF00;表示将寄存器对应的低8位清零
tmpreg|=clkdiv; //然后将新的u8位时钟分频系数和tmpreg进行或运算,表示将值写入寄存器的低8位
SDIO->CLKCR=tmpreg; //然后把值给到寄存器,相当于引入了中间变量tmpreg
}
//卡上电
//查询所有SDIO接口上的卡设备,并查询其电压和配置时钟
//返回值:错误代码;(0,无错误)
SD_Error SD_PowerON(void)
{
u8 i=0;
SD_Error errorstatus=SD_OK;
u32 response=0,count=0,validvoltage=0;
u32 SDType=SD_STD_CAPACITY;
/*初始化时的时钟不能大于400KHz*/
SDIO_InitTypeDef SDIO_InitStructure;
SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV; //设置时钟分频 /* HCLK = 72MHz, SDIOCLK = 72MHz, SDIO_CK = HCLK/(178 + 2) = 400 KHz */
SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising; //选择上升沿捕获
SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable; //不使用旁路时钟Bypass模式,直接用HCLK进行分频得到SDIO_CK
SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable; // 空闲时不关闭时钟电源
SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b; //1位数据线 表示数据宽度为1位
SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;//不使用硬件流控制
SDIO_Init(&SDIO_InitStructure);
SDIO_SetPowerState(SDIO_PowerState_ON); //上电状态,开启卡时钟
SDIO->CLKCR|=1<<8; //SDIOCK使能 SDIO时钟控制寄存器的第8位是时钟使能位,该位置1表示使能SDIO_CK
//卡上电首先要发送CMD0让所有卡进入空闲状态
for(i=0;i<74;i++)
{
SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
SDIO_CmdInitStructure.SDIO_Argument = 0x0;//命令参数设置为CMD0 发送CMD0进入IDLE STAGE模式命令.
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_GO_IDLE_STATE; //cmd0 设置命令号 CMD0 其中0就表示命令号
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No; //无响应 响应类型在此可以设置为长响应和短响应以及无响应
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; //等待使能位,在此设置无等待状态
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; //则CPSM在开始发送命令之前等待数据传输结束。 命令路径状态机CPSM设置
SDIO_SendCommand(&SDIO_CmdInitStructure); //写命令进命令寄存器
errorstatus=CmdError(); //检查CMD0的执行状态 CMD0让所有卡软复位从而进入空闲状态
if(errorstatus==SD_OK)
break;
}
if(errorstatus)
return errorstatus;//返回错误状态
//所有卡进入空闲状态以后,使用CMD8命令根据响应确定卡的电压支持范围
//CMD8是V2.0版本才有的命令,所以SD卡接收到CMD8后没有应答,就表示是V1.0版本,如果有应答,则表示SD卡是V2.0或者更高的版本
SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN; //发送CMD8,短响应,检查SD卡接口特性
SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND; //cmd8
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r7 短响应
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; //关闭等待中断
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; //不使能命令路径状态机
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp7Error(); //等待CMD8的响应,判断SD卡版本
if(errorstatus==SD_OK) //CMD8响应正常,表示是V2.0版本
{
CardType=SDIO_STD_CAPACITY_SD_CARD_V2_0; //SD 2.0卡
SDType=SD_HIGH_CAPACITY; //高容量卡
}
//只有发送CMD55之后,才能发送下一个命令
SDIO_CmdInitStructure.SDIO_Argument = 0x00;//发送CMD55,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //短响应
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure); //发送CMD55,短响应
errorstatus=CmdResp1Error(SD_CMD_APP_CMD); //等待R1响应
if(errorstatus==SD_OK)//SD2.0/SD 1.1,否则为MMC卡
{
//SD卡,发送ACMD41 SD_APP_OP_COND,参数为:0x80100000
while((!validvoltage)&&(countRESP1;; //得到响应
validvoltage=(((response>>31)==1)?1:0); //判断SD卡上电是否完成
count++;
}
if(count>=SD_MAX_VOLT_TRIAL)
{
errorstatus=SD_INVALID_VOLTRANGE;
return errorstatus;
}
if(response&=SD_HIGH_CAPACITY)
{
CardType=SDIO_HIGH_CAPACITY_SD_CARD;
}
}
else//MMC卡
{
//MMC卡,发送CMD1 SDIO_SEND_OP_COND,参数为:0x80FF8000
while((!validvoltage)&&(countRESP1;; //得到响应
validvoltage=(((response>>31)==1)?1:0);
count++;
}
if(count>=SD_MAX_VOLT_TRIAL)
{
errorstatus=SD_INVALID_VOLTRANGE;
return errorstatus;
}
CardType=SDIO_MULTIMEDIA_CARD;
}
return(errorstatus);
}
//SD卡 Power OFF
//返回值:错误代码;(0,无错误)
SD_Error SD_PowerOFF(void)
{
SDIO_SetPowerState(SDIO_PowerState_OFF);//SDIO电源关闭,时钟停止
return SD_OK;
}
//初始化所有的卡,并让卡进入就绪状态
//返回值:错误代码
SD_Error SD_InitializeCards(void)
{
SD_Error errorstatus=SD_OK;
u16 rca = 0x01;
if (SDIO_GetPowerState() == SDIO_PowerState_OFF) //检查电源状态,确保为上电状态
{
errorstatus = SD_REQUEST_NOT_APPLICABLE;
return(errorstatus);
}
if(SDIO_SECURE_DIGITAL_IO_CARD!=CardType) //非SECURE_DIGITAL_IO_CARD
{
//CMD2用于控制所有卡返回他们的卡识别号CID
SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
SDIO_CmdInitStructure.SDIO_Argument = 0x0;//发送CMD2,取得CID,长响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ALL_SEND_CID;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);//发送CMD2,取得CID,长响应
errorstatus=CmdResp2Error(); //等待R2响应
if(errorstatus!=SD_OK)
return errorstatus; //响应错误
CID_Tab[0]=SDIO->RESP1;
CID_Tab[1]=SDIO->RESP2;
CID_Tab[2]=SDIO->RESP3;
CID_Tab[3]=SDIO->RESP4;
}
if((SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType)||(SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType)||(SDIO_SECURE_DIGITAL_IO_COMBO_CARD==CardType)||(SDIO_HIGH_CAPACITY_SD_CARD==CardType))//判断卡类型
{
//处于准备状态的卡返回它们CID号之后就进入了识别状态
//单个卡槽在接收到CMD3并且发出响应之后就会进入数据传输模式,并且处于待机状态;
//等待所有卡槽都发出RCA命令后,主机获取到所有卡的RCA命令之后进入数据传输模式
SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
SDIO_CmdInitStructure.SDIO_Argument = 0x00;//发送CMD3,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_REL_ADDR; //cmd3
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r6
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure); //发送CMD3,短响应
errorstatus=CmdResp6Error(SD_CMD_SET_REL_ADDR,&rca);//等待R6响应
if(errorstatus!=SD_OK)
return errorstatus; //响应错误
}
if (SDIO_MULTIMEDIA_CARD==CardType)
{
SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
SDIO_CmdInitStructure.SDIO_Argument = (u32)(rca<<16);//发送CMD3,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_REL_ADDR; //cmd3
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r6
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure); //发送CMD3,短响应
errorstatus=CmdResp2Error(); //等待R2响应
if(errorstatus!=SD_OK)
return errorstatus; //响应错误
}
if (SDIO_SECURE_DIGITAL_IO_CARD!=CardType) //非SECURE_DIGITAL_IO_CARD
{
RCA = rca;
//CMD9选定卡通过CMD线发送CSD内容
SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)(rca << 16);//发送CMD9+卡RCA,取得CSD,长响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_CSD;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp2Error(); //等待R2响应
if(errorstatus!=SD_OK)
return errorstatus; //响应错误
CSD_Tab[0]=SDIO->RESP1;
CSD_Tab[1]=SDIO->RESP2;
CSD_Tab[2]=SDIO->RESP3;
CSD_Tab[3]=SDIO->RESP4;
}
return SD_OK;//卡初始化成功
}
//得到卡信息
//cardinfo:卡信息存储区
//返回值:错误状态
SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo)
{
SD_Error errorstatus=SD_OK;
u8 tmp=0;
cardinfo->CardType=(u8)CardType; //卡类型
cardinfo->RCA=(u16)RCA; //卡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((CardType==SDIO_STD_CAPACITY_SD_CARD_V1_1)||(CardType==SDIO_STD_CAPACITY_SD_CARD_V2_0)||(SDIO_MULTIMEDIA_CARD==CardType))//标准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(CardType==SDIO_HIGH_CAPACITY_SD_CARD) //高容量卡
{
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;
}
//设置SDIO总线宽度(MMC卡不支持4bit模式)
//wmode:位宽模式.0,1位数据宽度;1,4位数据宽度;2,8位数据宽度
//返回值:SD卡错误状态
//设置SDIO总线宽度(MMC卡不支持4bit模式)
// @arg SDIO_BusWide_8b: 8-bit data transfer (Only for MMC)
// @arg SDIO_BusWide_4b: 4-bit data transfer
// @arg SDIO_BusWide_1b: 1-bit data transfer (默认)
//返回值:SD卡错误状态
SD_Error SD_EnableWideBusOperation(u32 WideMode)
{
SD_Error errorstatus=SD_OK;
if (SDIO_MULTIMEDIA_CARD == CardType)
{
errorstatus = SD_UNSUPPORTED_FEATURE;
return(errorstatus);
}
else if((SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType)||(SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType)||(SDIO_HIGH_CAPACITY_SD_CARD==CardType))
{
if (SDIO_BusWide_8b == WideMode) //2.0 sd不支持8bits
{
errorstatus = SD_UNSUPPORTED_FEATURE;
return(errorstatus);
}
else
{
errorstatus=SDEnWideBus(WideMode);
if(SD_OK==errorstatus)
{
SDIO->CLKCR&=~(3<<11); //清除之前的位宽设置
SDIO->CLKCR|=WideMode;//1位/4位总线宽度
SDIO->CLKCR|=0<<14; //不开启硬件流控制
}
}
}
return errorstatus;
}
//设置SD卡工作模式
//Mode:
//返回值:错误状态
SD_Error SD_SetDeviceMode(u32 Mode)
{
SD_Error errorstatus = SD_OK;
if((Mode==SD_DMA_MODE)||(Mode==SD_POLLING_MODE)) // 查询模式或者DMA模式
DeviceMode=Mode;
else
errorstatus=SD_INVALID_PARAMETER; //否则报错
return errorstatus;
}
//选卡
//发送CMD7,选择相对地址(rca)为addr的卡,取消其他卡.如果为0,则都不选择.
//addr:卡的RCA地址
SD_Error SD_SelectDeselect(u32 addr)
{
//CMD7选择和取消指定的卡,
//待在待机状态下是不能进行通讯的,必须选择一个RCA地址目标使其进入数据传输状态才能进行通讯。
//CMD7也可以让已经进入通讯状态的卡回到待机状态
SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
SDIO_CmdInitStructure.SDIO_Argument = addr;//发送CMD7,选择卡,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEL_DESEL_CARD;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);//发送CMD7,选择卡,短响应
return CmdResp1Error(SD_CMD_SEL_DESEL_CARD);
}
//SD卡读取一个块
//buf:读数据缓存区(必须4字节对齐!!)
//addr:读取地址
//blksize:块大小
SD_Error SD_ReadBlock(u8 *buf,long long addr,u16 blksize)
{
SD_Error errorstatus=SD_OK;
u8 power;
u32 count=0,*tempbuff=(u32*)buf;//转换为u32指针
u32 timeout=SDIO_DATATIMEOUT;
if(NULL==buf)
return SD_INVALID_PARAMETER;
SDIO->DCTRL=0x0; //数据控制寄存器清零(关DMA)
if(CardType==SDIO_HIGH_CAPACITY_SD_CARD)//大容量卡
{
blksize=512;
addr>>=9;
}
SDIO_DataInitTypeDef SDIO_DataInitStructure;
SDIO_DataInitStructure.SDIO_DataBlockSize= SDIO_DataBlockSize_1b ; //数据块大小
SDIO_DataInitStructure.SDIO_DataLength= 0 ; //数据长度
SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ; //数据传输超时
SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable; //数据路径状态机使能
SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard; //数据传输方向为STM32从卡读取数据
SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block; //数据传输模式为数据块
SDIO_DataConfig(&SDIO_DataInitStructure);
if(SDIO->RESP1&SD_CARD_LOCKED)return SD_LOCK_UNLOCK_FAILED;//卡锁了
if((blksize>0)&&(blksize<=2048)&&((blksize&(blksize-1))==0))
{
power=convert_from_bytes_to_power_of_two(blksize);
//使用CMD16对于标准的SD卡,设置块命令长度,对于SDHC卡块命令长度固定为512字节
SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
SDIO_CmdInitStructure.SDIO_Argument = blksize;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);//发送CMD16+设置数据长度为blksize,短响应
errorstatus=CmdResp1Error(SD_CMD_SET_BLOCKLEN); //等待R1响应
if(errorstatus!=SD_OK)
return errorstatus; //响应错误
}
else
return SD_INVALID_PARAMETER;
SDIO_DataInitStructure.SDIO_DataBlockSize= power<<4 ;//清除DPSM状态机配置
SDIO_DataInitStructure.SDIO_DataLength= blksize ;
SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToSDIO; //从STM32读出SD卡的内容
SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
SDIO_DataConfig(&SDIO_DataInitStructure);
//CMD17读取长度为SEL_BLOCK_LEN长度字节的块;对于SDHC卡,读取512字节的块
SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
SDIO_CmdInitStructure.SDIO_Argument = addr;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_READ_SINGLE_BLOCK;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);//发送CMD17+从addr地址出读取数据,短响应
errorstatus=CmdResp1Error(SD_CMD_READ_SINGLE_BLOCK);//等待R1响应
if(errorstatus!=SD_OK)
return errorstatus; //响应错误
if(DeviceMode==SD_POLLING_MODE) //查询模式,轮询数据
{
INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
while(!(SDIO->STA&((1<<5)|(1<<1)|(1<<3)|(1<<10)|(1<<9))))//无上溢/CRC/超时/完成(标志)/起始位错误
{
if(SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET) //接收区半满,表示至少存了8个字
{
for(count=0;count<8;count++) //循环读取数据
{
*(tempbuff+count)=SDIO->FIFO;
}
tempbuff+=8;
timeout=0X7FFFFF; //读数据溢出时间
}
else //处理超时
{
if(timeout==0)
return SD_DATA_TIMEOUT;
timeout--;
}
}
if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET) //数据超时错误
{
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); //清错误标志
return SD_DATA_TIMEOUT;
}
else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET) //数据块CRC错误
{
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL); //清错误标志
return SD_DATA_CRC_FAIL;
}
else if(SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET) //接收fifo上溢错误
{
SDIO_ClearFlag(SDIO_FLAG_RXOVERR); //清错误标志
return SD_RX_OVERRUN;
}
else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) //接收起始位错误
{
SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
return SD_START_BIT_ERR;
}
while(SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET) //FIFO里面,还存在可用数据
{
*tempbuff=SDIO->FIFO; //循环读取数据
tempbuff++;
}
INTX_ENABLE();//开启总中断
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
}
else if(DeviceMode==SD_DMA_MODE)
{
TransferError=SD_OK;
StopCondition=0; //单块读,不需要发送停止传输指令
TransferEnd=0; //传输结束标置位,在中断服务置1
SDIO->MASK|=(1<<1)|(1<<3)|(1<<8)|(1<<5)|(1<<9); //配置需要的中断
SDIO->DCTRL|=1<<3; //SDIO DMA使能
SD_DMA_Config((u32*)buf,blksize,DMA_DIR_PeripheralToMemory);
while(((DMA2->LISR&(1<<27))==RESET)&&(TransferEnd==0)&&(TransferError==SD_OK)&&timeout)timeout--;//等待传输完成
if(timeout==0)
return SD_DATA_TIMEOUT;//超时
if(TransferError!=SD_OK)errorstatus=TransferError;
}
return errorstatus;
}
//SD卡读取多个块
//buf:读数据缓存区
//addr:读取地址
//blksize:块大小
//nblks:要读取的块数
//返回值:错误状态
__align(4) u32 *tempbuff; //设置4字节对齐
SD_Error SD_ReadMultiBlocks(u8 *buf,long long addr,u16 blksize,u32 nblks)
{
SD_Error errorstatus=SD_OK;
u8 power;
u32 count=0;
u32 timeout=SDIO_DATATIMEOUT;
tempbuff=(u32*)buf;//转换为u32指针
SDIO->DCTRL=0x0; //数据控制寄存器清零(关DMA)
if(CardType==SDIO_HIGH_CAPACITY_SD_CARD)//大容量卡
{
blksize=512;
addr>>=9;
}
SDIO_DataInitTypeDef SDIO_DataInitStructure;
SDIO_DataInitStructure.SDIO_DataBlockSize= 0; ;//清除DPSM状态机配置
SDIO_DataInitStructure.SDIO_DataLength= 0 ;
SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard;
SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
SDIO_DataConfig(&SDIO_DataInitStructure);
if(SDIO->RESP1&SD_CARD_LOCKED)
return SD_LOCK_UNLOCK_FAILED;//卡锁了
if((blksize>0)&&(blksize<=2048)&&((blksize&(blksize-1))==0))
{
power=convert_from_bytes_to_power_of_two(blksize);
SDIO_CmdInitStructure.SDIO_Argument = blksize;//发送CMD16+设置数据长度为blksize,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_SET_BLOCKLEN); //等待R1响应
if(errorstatus!=SD_OK)
return errorstatus; //响应错误
}
else
return SD_INVALID_PARAMETER;
if(nblks>1) //多块读
{
if(nblks*blksize>SD_MAX_DATA_LENGTH)
return SD_INVALID_PARAMETER;//判断是否超过最大接收长度
SDIO_DataInitStructure.SDIO_DataBlockSize= power<<4; ;//nblks*blksize,512块大小,卡到控制器
SDIO_DataInitStructure.SDIO_DataLength= nblks*blksize ;
SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToSDIO;
SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
SDIO_DataConfig(&SDIO_DataInitStructure);
//CMD18连续读取数据,直到CMD12中断
SDIO_CmdInitStructure.SDIO_Argument = addr;//发送CMD18+从addr地址出读取数据,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_READ_MULT_BLOCK;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_READ_MULT_BLOCK);//等待R1响应
if(errorstatus!=SD_OK)
return errorstatus; //响应错误
if(DeviceMode==SD_POLLING_MODE)
{
INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
while(!(SDIO->STA&((1<<5)|(1<<1)|(1<<3)|(1<<8)|(1<<9))))//无上溢/CRC/超时/完成(标志)/起始位错误
{
if(SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET) //接收区半满,表示至少存了8个字
{
for(count=0;count<8;count++) //循环读取数据
{
*(tempbuff+count)=SDIO->FIFO;
}
tempbuff+=8;
timeout=0X7FFFFF; //读数据溢出时间
}
else //处理超时
{
if(timeout==0)return SD_DATA_TIMEOUT;
timeout--;
}
}
if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET) //数据超时错误
{
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); //清错误标志
return SD_DATA_TIMEOUT;
}
else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET) //数据块CRC错误
{
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL); //清错误标志
return SD_DATA_CRC_FAIL;
}
else if(SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET) //接收fifo上溢错误
{
SDIO_ClearFlag(SDIO_FLAG_RXOVERR); //清错误标志
return SD_RX_OVERRUN;
}
else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) //接收起始位错误
{
SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
return SD_START_BIT_ERR;
}
while(SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET) //FIFO里面,还存在可用数据
{
*tempbuff=SDIO->FIFO; //循环读取数据
tempbuff++;
}
if(SDIO_GetFlagStatus(SDIO_FLAG_DATAEND) != RESET) //接收结束
{
if((SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType)||(SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType)||(SDIO_HIGH_CAPACITY_SD_CARD==CardType))
{
//CMD12结束传输
SDIO_CmdInitStructure.SDIO_Argument = 0;//发送CMD12+结束传输
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_STOP_TRANSMISSION;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_STOP_TRANSMISSION);//等待R1响应
if(errorstatus!=SD_OK)
return errorstatus;
}
}
INTX_ENABLE();//开启总中断
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
}
else if(DeviceMode==SD_DMA_MODE)
{
TransferError=SD_OK;
StopCondition=1; //多块读,需要发送停止传输指令
TransferEnd=0; //传输结束标置位,在中断服务置1
SDIO->MASK|=(1<<1)|(1<<3)|(1<<8)|(1<<5)|(1<<9); //配置需要的中断
SDIO->DCTRL|=1<<3; //SDIO DMA使能
SD_DMA_Config((u32*)buf,nblks*blksize,DMA_DIR_PeripheralToMemory);
while(((DMA2->LISR&(1<<27))==RESET)&&timeout)timeout--;//等待传输完成
if(timeout==0)
return SD_DATA_TIMEOUT;//超时
while((TransferEnd==0)&&(TransferError==SD_OK));
if(TransferError!=SD_OK)
errorstatus=TransferError;
}
}
return errorstatus;
}
//SD卡写1个块
//buf:数据缓存区
//addr:写地址
//blksize:块大小
//返回值:错误状态
SD_Error SD_WriteBlock(u8 *buf,long long addr, u16 blksize)
{
SD_Error errorstatus = SD_OK;
u8 power=0,cardstate=0;
u32 timeout=0,bytestransferred=0;
u32 cardstatus=0,count=0,restwords=0;
u32 tlen=blksize; //总长度(字节)
u32*tempbuff=(u32*)buf;
if(buf==NULL)
return SD_INVALID_PARAMETER;//参数错误
SDIO->DCTRL=0x0; //数据控制寄存器清零(关DMA)
SDIO_DataInitStructure.SDIO_DataBlockSize= 0; ;//清除DPSM状态机配置
SDIO_DataInitStructure.SDIO_DataLength= 0 ;
SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard;
SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
SDIO_DataConfig(&SDIO_DataInitStructure);
if(SDIO->RESP1&SD_CARD_LOCKED)
return SD_LOCK_UNLOCK_FAILED;//卡锁了
if(CardType==SDIO_HIGH_CAPACITY_SD_CARD) //大容量卡
{
blksize=512;
addr>>=9;
}
if((blksize>0)&&(blksize<=2048)&&((blksize&(blksize-1))==0))
{
power=convert_from_bytes_to_power_of_two(blksize);
SDIO_CmdInitStructure.SDIO_Argument = blksize;//发送CMD16+设置数据长度为blksize,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_SET_BLOCKLEN); //等待R1响应
if(errorstatus!=SD_OK)
return errorstatus; //响应错误
}
else return SD_INVALID_PARAMETER;
SDIO_CmdInitStructure.SDIO_Argument = (u32)RCA<<16;//发送CMD13,查询卡的状态,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_SEND_STATUS); //等待R1响应
if(errorstatus!=SD_OK)
return errorstatus;
cardstatus=SDIO->RESP1;
timeout=SD_DATATIMEOUT;
while(((cardstatus&0x00000100)==0)&&(timeout>0)) //检查READY_FOR_DATA位是否置位
{
timeout--;
SDIO_CmdInitStructure.SDIO_Argument = (u32)RCA<<16;//发送CMD13,查询卡的状态,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_SEND_STATUS); //等待R1响应
if(errorstatus!=SD_OK)
return errorstatus;
cardstatus=SDIO->RESP1;
}
if(timeout==0)
return SD_ERROR;
SDIO_CmdInitStructure.SDIO_Argument = addr;//发送CMD24,写单块指令,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_WRITE_SINGLE_BLOCK);//等待R1响应
if(errorstatus!=SD_OK)
return errorstatus;
StopCondition=0; //单块写,不需要发送停止传输指令
SDIO_DataInitStructure.SDIO_DataBlockSize= power<<4; ; //blksize, 控制器到卡
SDIO_DataInitStructure.SDIO_DataLength= blksize ;
SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard;
SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
SDIO_DataConfig(&SDIO_DataInitStructure);
timeout=SDIO_DATATIMEOUT;
if (DeviceMode == SD_POLLING_MODE)
{
INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
while(!(SDIO->STA&((1<<10)|(1<<4)|(1<<1)|(1<<3)|(1<<9))))//数据块发送成功/下溢/CRC/超时/起始位错误
{
if(SDIO_GetFlagStatus(SDIO_FLAG_TXFIFOHE) != RESET) //发送区半空,表示至少存了8个字
{
if((tlen-bytestransferred)FIFO=*tempbuff;
}
}
else
{
for(count=0;count<8;count++)
{
SDIO->FIFO=*(tempbuff+count);
}
tempbuff+=8;
bytestransferred+=32;
}
timeout=0X3FFFFFFF; //写数据溢出时间
}else
{
if(timeout==0)
return SD_DATA_TIMEOUT;
timeout--;
}
}
if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET) //数据超时错误
{
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); //清错误标志
return SD_DATA_TIMEOUT;
}
else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET) //数据块CRC错误
{
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL); //清错误标志
return SD_DATA_CRC_FAIL;
}
else if(SDIO_GetFlagStatus(SDIO_FLAG_TXUNDERR) != RESET) //接收fifo下溢错误
{
SDIO_ClearFlag(SDIO_FLAG_TXUNDERR); //清错误标志
return SD_TX_UNDERRUN;
}
else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) //接收起始位错误
{
SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
return SD_START_BIT_ERR;
}
INTX_ENABLE();//开启总中断
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
}
else if(DeviceMode==SD_DMA_MODE)
{
TransferError=SD_OK;
StopCondition=0; //单块写,不需要发送停止传输指令
TransferEnd=0; //传输结束标置位,在中断服务置1
SDIO->MASK|=(1<<1)|(1<<3)|(1<<8)|(1<<4)|(1<<9); //配置产生数据接收完成中断
SD_DMA_Config((u32*)buf,blksize,DMA_DIR_MemoryToPeripheral); //SDIO DMA配置
SDIO->DCTRL|=1<<3; //SDIO DMA使能.
while(((DMA2->LISR&(1<<27))==RESET)&&timeout)timeout--;//等待传输完成
if(timeout==0)
{
SD_Init(); //重新初始化SD卡,可以解决写入死机的问题
return SD_DATA_TIMEOUT; //超时
}
timeout=SDIO_DATATIMEOUT;
while((TransferEnd==0)&&(TransferError==SD_OK)&&timeout)timeout--;
if(timeout==0)
return SD_DATA_TIMEOUT; //超时
if(TransferError!=SD_OK)
return TransferError;
}
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
errorstatus=IsCardProgramming(&cardstate);
while((errorstatus==SD_OK)&&((cardstate==SD_CARD_PROGRAMMING)||(cardstate==SD_CARD_RECEIVING)))
{
errorstatus=IsCardProgramming(&cardstate);
}
return errorstatus;
}
//SD卡写多个块
//buf:数据缓存区
//addr:写地址
//blksize:块大小
//nblks:要写入的块数
//返回值:错误状态
SD_Error SD_WriteMultiBlocks(u8 *buf,long long addr,u16 blksize,u32 nblks)
{
SD_Error errorstatus = SD_OK;
u8 power = 0, cardstate = 0;
u32 timeout=0,bytestransferred=0;
u32 count = 0, restwords = 0;
u32 tlen=nblks*blksize; //总长度(字节)
u32 *tempbuff = (u32*)buf;
if(buf==NULL)
return SD_INVALID_PARAMETER; //参数错误
SDIO->DCTRL=0x0; //数据控制寄存器清零(关DMA)
SDIO_DataInitStructure.SDIO_DataBlockSize= 0; ; //清除DPSM状态机配置
SDIO_DataInitStructure.SDIO_DataLength= 0 ;
SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard;
SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
SDIO_DataConfig(&SDIO_DataInitStructure);
if(SDIO->RESP1&SD_CARD_LOCKED)
return SD_LOCK_UNLOCK_FAILED;//卡锁了
if(CardType==SDIO_HIGH_CAPACITY_SD_CARD)//大容量卡
{
blksize=512;
addr>>=9;
}
if((blksize>0)&&(blksize<=2048)&&((blksize&(blksize-1))==0))
{
power=convert_from_bytes_to_power_of_two(blksize);
SDIO_CmdInitStructure.SDIO_Argument = blksize; //发送CMD16+设置数据长度为blksize,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_SET_BLOCKLEN); //等待R1响应
if(errorstatus!=SD_OK)
return errorstatus; //响应错误
}
else
return SD_INVALID_PARAMETER;
if(nblks>1)
{
if(nblks*blksize>SD_MAX_DATA_LENGTH)
return SD_INVALID_PARAMETER;
if((SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType)||(SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType)||(SDIO_HIGH_CAPACITY_SD_CARD==CardType))
{
//提高性能
SDIO_CmdInitStructure.SDIO_Argument = (u32)RCA<<16; //发送ACMD55,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_APP_CMD); //等待R1响应
if(errorstatus!=SD_OK)
return errorstatus;
SDIO_CmdInitStructure.SDIO_Argument =nblks; //发送CMD23,设置块数量,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCK_COUNT;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_SET_BLOCK_COUNT);//等待R1响应
if(errorstatus!=SD_OK)
return errorstatus;
}
SDIO_CmdInitStructure.SDIO_Argument =addr; //发送CMD25,多块写指令,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_WRITE_MULT_BLOCK;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_WRITE_MULT_BLOCK); //等待R1响应
if(errorstatus!=SD_OK)
return errorstatus;
SDIO_DataInitStructure.SDIO_DataBlockSize= power<<4; ; //blksize, 控制器到卡
SDIO_DataInitStructure.SDIO_DataLength= nblks*blksize ;
SDIO_DataInitStructure.SDIO_DataTimeOut=SD_DATATIMEOUT ;
SDIO_DataInitStructure.SDIO_DPSM=SDIO_DPSM_Enable;
SDIO_DataInitStructure.SDIO_TransferDir=SDIO_TransferDir_ToCard;
SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
SDIO_DataConfig(&SDIO_DataInitStructure);
if(DeviceMode==SD_POLLING_MODE)
{
timeout=SDIO_DATATIMEOUT;
INTX_DISABLE();//关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!)
while(!(SDIO->STA&((1<<4)|(1<<1)|(1<<8)|(1<<3)|(1<<9))))//下溢/CRC/数据结束/超时/起始位错误
{
if(SDIO_GetFlagStatus(SDIO_FLAG_TXFIFOHE) != RESET) //发送区半空,表示至少存了8字(32字节)
{
if((tlen-bytestransferred)FIFO=*tempbuff;
}
}else //发送区半空,可以发送至少8字(32字节)数据
{
for(count=0;countFIFO=*(tempbuff+count);
}
tempbuff+=SD_HALFFIFO;
bytestransferred+=SD_HALFFIFOBYTES;
}
timeout=0X3FFFFFFF; //写数据溢出时间
}else
{
if(timeout==0)return SD_DATA_TIMEOUT;
timeout--;
}
}
if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET) //数据超时错误
{
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); //清错误标志
return SD_DATA_TIMEOUT;
}else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET) //数据块CRC错误
{
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL); //清错误标志
return SD_DATA_CRC_FAIL;
}else if(SDIO_GetFlagStatus(SDIO_FLAG_TXUNDERR) != RESET) //接收fifo下溢错误
{
SDIO_ClearFlag(SDIO_FLAG_TXUNDERR); //清错误标志
return SD_TX_UNDERRUN;
}else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) //接收起始位错误
{
SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
return SD_START_BIT_ERR;
}
if(SDIO_GetFlagStatus(SDIO_FLAG_DATAEND) != RESET) //发送结束
{
if((SDIO_STD_CAPACITY_SD_CARD_V1_1==CardType)||(SDIO_STD_CAPACITY_SD_CARD_V2_0==CardType)||(SDIO_HIGH_CAPACITY_SD_CARD==CardType))
{
SDIO_CmdInitStructure.SDIO_Argument =0;//发送CMD12+结束传输
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_STOP_TRANSMISSION;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_STOP_TRANSMISSION);//等待R1响应
if(errorstatus!=SD_OK)return errorstatus;
}
}
INTX_ENABLE();//开启总中断
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
}else if(DeviceMode==SD_DMA_MODE)
{
TransferError=SD_OK;
StopCondition=1; //多块写,需要发送停止传输指令
TransferEnd=0; //传输结束标置位,在中断服务置1
SDIO->MASK|=(1<<1)|(1<<3)|(1<<8)|(1<<4)|(1<<9); //配置产生数据接收完成中断
SD_DMA_Config((u32*)buf,nblks*blksize,DMA_DIR_MemoryToPeripheral); //SDIO DMA配置
SDIO->DCTRL|=1<<3; //SDIO DMA使能.
timeout=SDIO_DATATIMEOUT;
while(((DMA2->LISR&(1<<27))==RESET)&&timeout)timeout--;//等待传输完成
if(timeout==0) //超时
{
SD_Init(); //重新初始化SD卡,可以解决写入死机的问题
return SD_DATA_TIMEOUT; //超时
}
timeout=SDIO_DATATIMEOUT;
while((TransferEnd==0)&&(TransferError==SD_OK)&&timeout)timeout--;
if(timeout==0)return SD_DATA_TIMEOUT; //超时
if(TransferError!=SD_OK)return TransferError;
}
}
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
errorstatus=IsCardProgramming(&cardstate);
while((errorstatus==SD_OK)&&((cardstate==SD_CARD_PROGRAMMING)||(cardstate==SD_CARD_RECEIVING)))
{
errorstatus=IsCardProgramming(&cardstate);
}
return errorstatus;
}
//SDIO中断服务函数
void SDIO_IRQHandler(void)
{
SD_ProcessIRQSrc();//处理所有SDIO相关中断
}
//SDIO中断处理函数
//处理SDIO传输过程中的各种中断事务
//返回值:错误代码
SD_Error SD_ProcessIRQSrc(void)
{
if(SDIO_GetFlagStatus(SDIO_FLAG_DATAEND) != RESET)//接收完成中断
{
if (StopCondition==1)
{
SDIO_CmdInitStructure.SDIO_Argument =0;//发送CMD12+结束传输
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_STOP_TRANSMISSION;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
TransferError=CmdResp1Error(SD_CMD_STOP_TRANSMISSION);
}else TransferError = SD_OK;
SDIO->ICR|=1<<8;//清除完成中断标记
SDIO->MASK&=~((1<<1)|(1<<3)|(1<<8)|(1<<14)|(1<<15)|(1<<4)|(1<<5)|(1<<9));//关闭相关中断
TransferEnd = 1;
return(TransferError);
}
if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)//数据CRC错误
{
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL); //清错误标志
SDIO->MASK&=~((1<<1)|(1<<3)|(1<<8)|(1<<14)|(1<<15)|(1<<4)|(1<<5)|(1<<9));//关闭相关中断
TransferError = SD_DATA_CRC_FAIL;
return(SD_DATA_CRC_FAIL);
}
if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)//数据超时错误
{
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); //清中断标志
SDIO->MASK&=~((1<<1)|(1<<3)|(1<<8)|(1<<14)|(1<<15)|(1<<4)|(1<<5)|(1<<9));//关闭相关中断
TransferError = SD_DATA_TIMEOUT;
return(SD_DATA_TIMEOUT);
}
if(SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)//FIFO上溢错误
{
SDIO_ClearFlag(SDIO_FLAG_RXOVERR); //清中断标志
SDIO->MASK&=~((1<<1)|(1<<3)|(1<<8)|(1<<14)|(1<<15)|(1<<4)|(1<<5)|(1<<9));//关闭相关中断
TransferError = SD_RX_OVERRUN;
return(SD_RX_OVERRUN);
}
if(SDIO_GetFlagStatus(SDIO_FLAG_TXUNDERR) != RESET)//FIFO下溢错误
{
SDIO_ClearFlag(SDIO_FLAG_TXUNDERR); //清中断标志
SDIO->MASK&=~((1<<1)|(1<<3)|(1<<8)|(1<<14)|(1<<15)|(1<<4)|(1<<5)|(1<<9));//关闭相关中断
TransferError = SD_TX_UNDERRUN;
return(SD_TX_UNDERRUN);
}
if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)//起始位错误
{
SDIO_ClearFlag(SDIO_FLAG_STBITERR); //清中断标志
SDIO->MASK&=~((1<<1)|(1<<3)|(1<<8)|(1<<14)|(1<<15)|(1<<4)|(1<<5)|(1<<9));//关闭相关中断
TransferError = SD_START_BIT_ERR;
return(SD_START_BIT_ERR);
}
return(SD_OK);
}
//检查CMD0的执行状态
//返回值:sd卡错误码
SD_Error CmdError(void)
{
SD_Error errorstatus = SD_OK;
u32 timeout=SDIO_CMD0TIMEOUT;
while(timeout--)
{
if(SDIO_GetFlagStatus(SDIO_FLAG_CMDSENT) != RESET)break; //命令已发送(无需响应)
}
if(timeout==0)return SD_CMD_RSP_TIMEOUT;
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
return errorstatus;
}
//检查R7响应的错误状态
//返回值:sd卡错误码
SD_Error CmdResp7Error(void)
{
SD_Error errorstatus=SD_OK;
u32 status;
u32 timeout=SDIO_CMD0TIMEOUT;
while(timeout--)
{
status=SDIO->STA;
if(status&((1<<0)|(1<<2)|(1<<6)))break;//CRC错误/命令响应超时/已经收到响应(CRC校验成功)
}
if((timeout==0)||(status&(1<<2))) //响应超时
{
errorstatus=SD_CMD_RSP_TIMEOUT; //当前卡不是2.0兼容卡,或者不支持设定的电压范围
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT); //清除命令响应超时标志
return errorstatus;
}
if(status&1<<6) //成功接收到响应
{
errorstatus=SD_OK;
SDIO_ClearFlag(SDIO_FLAG_CMDREND); //清除响应标志
}
return errorstatus;
}
//检查R1响应的错误状态
//cmd:当前命令
//返回值:sd卡错误码
SD_Error CmdResp1Error(u8 cmd)
{
u32 status;
while(1)
{
status=SDIO->STA;
if(status&((1<<0)|(1<<2)|(1<<6)))break;//CRC错误/命令响应超时/已经收到响应(CRC校验成功)
}
if(SDIO_GetFlagStatus(SDIO_FLAG_CTIMEOUT) != RESET) //响应超时
{
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT); //清除命令响应超时标志
return SD_CMD_RSP_TIMEOUT;
}
if(SDIO_GetFlagStatus(SDIO_FLAG_CCRCFAIL) != RESET) //CRC错误
{
SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL); //清除标志
return SD_CMD_CRC_FAIL;
}
if(SDIO->RESPCMD!=cmd)return SD_ILLEGAL_CMD;//命令不匹配
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
return (SD_Error)(SDIO->RESP1&SD_OCR_ERRORBITS);//返回卡响应
}
//检查R3响应的错误状态
//返回值:错误状态
SD_Error CmdResp3Error(void)
{
u32 status;
while(1)
{
status=SDIO->STA;
if(status&((1<<0)|(1<<2)|(1<<6)))break;//CRC错误/命令响应超时/已经收到响应(CRC校验成功)
}
if(SDIO_GetFlagStatus(SDIO_FLAG_CTIMEOUT) != RESET) //响应超时
{
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT); //清除命令响应超时标志
return SD_CMD_RSP_TIMEOUT;
}
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
return SD_OK;
}
//检查R2响应的错误状态
//返回值:错误状态
SD_Error CmdResp2Error(void)
{
SD_Error errorstatus=SD_OK;
u32 status;
u32 timeout=SDIO_CMD0TIMEOUT;
while(timeout--)
{
status=SDIO->STA;
if(status&((1<<0)|(1<<2)|(1<<6)))break;//CRC错误/命令响应超时/已经收到响应(CRC校验成功)
}
if((timeout==0)||(status&(1<<2))) //响应超时
{
errorstatus=SD_CMD_RSP_TIMEOUT;
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT); //清除命令响应超时标志
return errorstatus;
}
if(SDIO_GetFlagStatus(SDIO_FLAG_CCRCFAIL) != RESET) //CRC错误
{
errorstatus=SD_CMD_CRC_FAIL;
SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL); //清除响应标志
}
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
return errorstatus;
}
//检查R6响应的错误状态
//cmd:之前发送的命令
//prca:卡返回的RCA地址
//返回值:错误状态
SD_Error CmdResp6Error(u8 cmd,u16*prca)
{
SD_Error errorstatus=SD_OK;
u32 status;
u32 rspr1;
while(1)
{
status=SDIO->STA;
if(status&((1<<0)|(1<<2)|(1<<6)))break;//CRC错误/命令响应超时/已经收到响应(CRC校验成功)
}
if(SDIO_GetFlagStatus(SDIO_FLAG_CTIMEOUT) != RESET) //响应超时
{
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT); //清除命令响应超时标志
return SD_CMD_RSP_TIMEOUT;
}
if(SDIO_GetFlagStatus(SDIO_FLAG_CCRCFAIL) != RESET) //CRC错误
{
SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL); //清除响应标志
return SD_CMD_CRC_FAIL;
}
if(SDIO->RESPCMD!=cmd) //判断是否响应cmd命令
{
return SD_ILLEGAL_CMD;
}
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
rspr1=SDIO->RESP1; //得到响应
if(SD_ALLZERO==(rspr1&(SD_R6_GENERAL_UNKNOWN_ERROR|SD_R6_ILLEGAL_CMD|SD_R6_COM_CRC_FAILED)))
{
*prca=(u16)(rspr1>>16); //右移16位得到,rca
return errorstatus;
}
if(rspr1&SD_R6_GENERAL_UNKNOWN_ERROR)return SD_GENERAL_UNKNOWN_ERROR;
if(rspr1&SD_R6_ILLEGAL_CMD)return SD_ILLEGAL_CMD;
if(rspr1&SD_R6_COM_CRC_FAILED)return SD_COM_CRC_FAILED;
return errorstatus;
}
//SDIO使能宽总线模式
//enx:0,不使能;1,使能;
//返回值:错误状态
SD_Error SDEnWideBus(u8 enx)
{
SD_Error errorstatus = SD_OK;
u32 scr[2]={0,0};
u8 arg=0X00;
if(enx)arg=0X02;
else arg=0X00;
if(SDIO->RESP1&SD_CARD_LOCKED)return SD_LOCK_UNLOCK_FAILED;//SD卡处于LOCKED状态
errorstatus=FindSCR(RCA,scr); //得到SCR寄存器数据
if(errorstatus!=SD_OK)return errorstatus;
if((scr[1]&SD_WIDE_BUS_SUPPORT)!=SD_ALLZERO) //支持宽总线
{
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16;//发送CMD55+RCA,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_APP_CMD);
if(errorstatus!=SD_OK)return errorstatus;
SDIO_CmdInitStructure.SDIO_Argument = arg;//发送ACMD6,短响应,参数:10,4位;00,1位.
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_SD_SET_BUSWIDTH;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_APP_SD_SET_BUSWIDTH);
return errorstatus;
}else return SD_REQUEST_NOT_APPLICABLE; //不支持宽总线设置
}
//检查卡是否正在执行写操作
//pstatus:当前状态.
//返回值:错误代码
SD_Error IsCardProgramming(u8 *pstatus)
{
vu32 respR1 = 0, status = 0;
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16; //卡相对地址参数
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;//发送CMD13
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
status=SDIO->STA;
while(!(status&((1<<0)|(1<<6)|(1<<2))))status=SDIO->STA;//等待操作完成
if(SDIO_GetFlagStatus(SDIO_FLAG_CCRCFAIL) != RESET) //CRC检测失败
{
SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL); //清除错误标记
return SD_CMD_CRC_FAIL;
}
if(SDIO_GetFlagStatus(SDIO_FLAG_CTIMEOUT) != RESET) //命令超时
{
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT); //清除错误标记
return SD_CMD_RSP_TIMEOUT;
}
if(SDIO->RESPCMD!=SD_CMD_SEND_STATUS)return SD_ILLEGAL_CMD;
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
respR1=SDIO->RESP1;
*pstatus=(u8)((respR1>>9)&0x0000000F);
return SD_OK;
}
//读取当前卡状态
//pcardstatus:卡状态
//返回值:错误代码
SD_Error SD_SendStatus(uint32_t *pcardstatus)
{
SD_Error errorstatus = SD_OK;
if(pcardstatus==NULL)
{
errorstatus=SD_INVALID_PARAMETER;
return errorstatus;
}
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16;//发送CMD13,短响应
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_SEND_STATUS); //查询响应状态
if(errorstatus!=SD_OK)return errorstatus;
*pcardstatus=SDIO->RESP1;//读取响应值
return errorstatus;
}
//返回SD卡的状态
//返回值:SD卡状态
SDCardState SD_GetState(void)
{
u32 resp1=0;
if(SD_SendStatus(&resp1)!=SD_OK)return SD_CARD_ERROR;
else return (SDCardState)((resp1>>9) & 0x0F);
}
//查找SD卡的SCR寄存器值
//rca:卡相对地址
//pscr:数据缓存区(存储SCR内容)
//返回值:错误状态
SD_Error FindSCR(u16 rca,u32 *pscr)
{
u32 index = 0;
SD_Error errorstatus = SD_OK;
u32 tempscr[2]={0,0};
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)8; //发送CMD16,短响应,设置Block Size为8字节
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN; // cmd16
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r1
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_SET_BLOCKLEN);
if(errorstatus!=SD_OK)return errorstatus;
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;//发送CMD55,短响应
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_APP_CMD);
if(errorstatus!=SD_OK)return errorstatus;
SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
SDIO_DataInitStructure.SDIO_DataLength = 8; //8个字节长度,block为8字节,SD卡到SDIO.
SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DataBlockSize_8b ; //块大小8byte
SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToSDIO;
SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
SDIO_DataConfig(&SDIO_DataInitStructure);
SDIO_CmdInitStructure.SDIO_Argument = 0x0;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_SEND_SCR; //发送ACMD51,短响应,参数为0
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r1
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus=CmdResp1Error(SD_CMD_SD_APP_SEND_SCR);
if(errorstatus!=SD_OK)return errorstatus;
while(!(SDIO->STA&(SDIO_FLAG_RXOVERR|SDIO_FLAG_DCRCFAIL|SDIO_FLAG_DTIMEOUT|SDIO_FLAG_DBCKEND|SDIO_FLAG_STBITERR)))
{
if(SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)//接收FIFO数据可用
{
*(tempscr+index)=SDIO->FIFO; //读取FIFO内容
index++;
if(index>=2)break;
}
}
if(SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET) //数据超时错误
{
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); //清错误标志
return SD_DATA_TIMEOUT;
}else if(SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET) //数据块CRC错误
{
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL); //清错误标志
return SD_DATA_CRC_FAIL;
}else if(SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET) //接收fifo上溢错误
{
SDIO_ClearFlag(SDIO_FLAG_RXOVERR); //清错误标志
return SD_RX_OVERRUN;
}else if(SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) //接收起始位错误
{
SDIO_ClearFlag(SDIO_FLAG_STBITERR);//清错误标志
return SD_START_BIT_ERR;
}
SDIO_ClearFlag(SDIO_STATIC_FLAGS);//清除所有标记
//把数据顺序按8位为单位倒过来.
*(pscr+1)=((tempscr[0]&SD_0TO7BITS)<<24)|((tempscr[0]&SD_8TO15BITS)<<8)|((tempscr[0]&SD_16TO23BITS)>>8)|((tempscr[0]&SD_24TO31BITS)>>24);
*(pscr)=((tempscr[1]&SD_0TO7BITS)<<24)|((tempscr[1]&SD_8TO15BITS)<<8)|((tempscr[1]&SD_16TO23BITS)>>8)|((tempscr[1]&SD_24TO31BITS)>>24);
return errorstatus;
}
//得到NumberOfBytes以2为底的指数.
//NumberOfBytes:字节数.
//返回值:以2为底的指数值
u8 convert_from_bytes_to_power_of_two(u16 NumberOfBytes)
{
u8 count=0;
while(NumberOfBytes!=1)
{
NumberOfBytes>>=1;
count++;
}
return count;
}
//配置SDIO DMA
//mbuf:存储器地址
//bufsize:传输数据量
//dir:方向;DMA_DIR_MemoryToPeripheral 存储器-->SDIO(写数据);DMA_DIR_PeripheralToMemory SDIO-->存储器(读数据);
void SD_DMA_Config(u32*mbuf,u32 bufsize,u32 dir)
{
DMA_InitTypeDef DMA_InitStructure;
while (DMA_GetCmdStatus(DMA2_Stream3) != DISABLE){}//等待DMA可配置
DMA_DeInit(DMA2_Stream3);//清空之前该stream3上的所有中断标志
DMA_InitStructure.DMA_Channel = DMA_Channel_4; //通道选择
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SDIO->FIFO;//DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = (u32)mbuf;//DMA 存储器0地址
DMA_InitStructure.DMA_DIR = dir;//存储器到外设模式
DMA_InitStructure.DMA_BufferSize = 0;//数据传输量
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//外设数据长度:32位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;//存储器数据长度:32位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//最高优先级
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; //FIFO使能
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;//全FIFO
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC4;//外设突发4次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4;//存储器突发4次传输
DMA_Init(DMA2_Stream3, &DMA_InitStructure);//初始化DMA Stream
DMA_FlowControllerConfig(DMA2_Stream3,DMA_FlowCtrl_Peripheral);//外设流控制
DMA_Cmd(DMA2_Stream3 ,ENABLE);//开启DMA传输
}
//读SD卡
//buf:读数据缓存区
//sector:扇区地址
//cnt:扇区个数
//返回值:错误状态;0,正常;其他,错误代码;
u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
{
u8 sta=SD_OK;
long long lsector=sector;
u8 n;
lsector<<=9;
if((u32)buf%4!=0)
{
for(n=0;n
#ifndef _SDIO_CARD__H_
#define _SDIO_CARD__H_
#include "stm32f4xx.h"
//SDIO相关标志位,拷贝自:stm32f4xx_sdio.h
#define SDIO_FLAG_CCRCFAIL ((uint32_t)0x00000001)
#define SDIO_FLAG_DCRCFAIL ((uint32_t)0x00000002)
#define SDIO_FLAG_CTIMEOUT ((uint32_t)0x00000004)
#define SDIO_FLAG_DTIMEOUT ((uint32_t)0x00000008)
#define SDIO_FLAG_TXUNDERR ((uint32_t)0x00000010)
#define SDIO_FLAG_RXOVERR ((uint32_t)0x00000020)
#define SDIO_FLAG_CMDREND ((uint32_t)0x00000040)
#define SDIO_FLAG_CMDSENT ((uint32_t)0x00000080)
#define SDIO_FLAG_DATAEND ((uint32_t)0x00000100)
#define SDIO_FLAG_STBITERR ((uint32_t)0x00000200)
#define SDIO_FLAG_DBCKEND ((uint32_t)0x00000400)
#define SDIO_FLAG_CMDACT ((uint32_t)0x00000800)
#define SDIO_FLAG_TXACT ((uint32_t)0x00001000)
#define SDIO_FLAG_RXACT ((uint32_t)0x00002000)
#define SDIO_FLAG_TXFIFOHE ((uint32_t)0x00004000)
#define SDIO_FLAG_RXFIFOHF ((uint32_t)0x00008000)
#define SDIO_FLAG_TXFIFOF ((uint32_t)0x00010000)
#define SDIO_FLAG_RXFIFOF ((uint32_t)0x00020000)
#define SDIO_FLAG_TXFIFOE ((uint32_t)0x00040000)
#define SDIO_FLAG_RXFIFOE ((uint32_t)0x00080000)
#define SDIO_FLAG_TXDAVL ((uint32_t)0x00100000)
#define SDIO_FLAG_RXDAVL ((uint32_t)0x00200000)
#define SDIO_FLAG_SDIOIT ((uint32_t)0x00400000)
#define SDIO_FLAG_CEATAEND ((uint32_t)0x00800000)
//用户配置区
//SDIO时钟计算公式:SDIO_CK时钟=SDIOCLK/[clkdiv+2];其中,SDIOCLK固定为48Mhz
//使用DMA模式的时候,传输速率可以到48Mhz(bypass on时),不过如果你的卡不是高速
//卡,可能也会出错,出错就请降低时钟
#define SDIO_INIT_CLK_DIV 0x76 //SDIO初始化频率,最大400Kh
#define SDIO_TRANSFER_CLK_DIV 0x00 //SDIO传输频率,该值太小可能会导致读写文件出错
//SDIO工作模式定义,通过SD_SetDeviceMode函数设置.
#define SD_POLLING_MODE 0 //查询模式,该模式下,如果读写有问题,建议增大SDIO_TRANSFER_CLK_DIV的设置.
#define SD_DMA_MODE 1 //DMA模式,该模式下,如果读写有问题,建议增大SDIO_TRANSFER_CLK_DIV的设置.
//SDIO 各种错误枚举定义
typedef enum
{
//特殊错误定义
SD_CMD_CRC_FAIL = (1), /*!< 收到命令响应(但CRC检查失败) */
SD_DATA_CRC_FAIL = (2), /*!< 发送/接收数据帧(CRC检查失败) */
SD_CMD_RSP_TIMEOUT = (3), /*!< 命令响应超时时间 */
SD_DATA_TIMEOUT = (4), /*!< 数据超时 */
SD_TX_UNDERRUN = (5), /*!< 发送FIFO欠运行 */
SD_RX_OVERRUN = (6), /*!< 接收FIFO超时 */
SD_START_BIT_ERR = (7), /*!< 在宽总线模式下,所有数据信号上未检测到起始位 */
SD_CMD_OUT_OF_RANGE = (8), /*!< CMD的参数超出范围 */
SD_ADDR_MISALIGNED = (9), /*!< 偏差处理 */
SD_BLOCK_LEN_ERR = (10), /*!< 对于该卡不允许传输的块长度或传输的字节数与块长度不匹配 */
SD_ERASE_SEQ_ERR = (11), /*!< 擦除命令的顺序出错 */
SD_BAD_ERASE_PARAM = (12), /*!< 对擦除组的选择无效 */
SD_WRITE_PROT_VIOLATION = (13), /*!< 尝试编写一个写保护块 */
SD_LOCK_UNLOCK_FAILED = (14), /*!< 在解锁命令中检测到序列或密码错误,或者试图访问锁定的卡 */
SD_COM_CRC_FAILED = (15), /*!< 日志含义上一条命令CRC校验失败 */
SD_ILLEGAL_CMD = (16), /*!< 命令对于卡片状态不合法 */
SD_CARD_ECC_FAILED = (17), /*!< 日志含义应用卡内部ECC,但未能纠正数据 */
SD_CC_ERROR = (18), /*!< 内部卡控制器错误 */
SD_GENERAL_UNKNOWN_ERROR = (19), /*!< 一般错误或未知错误 */
SD_STREAM_READ_UNDERRUN = (20), /*!< 在流读操作中,卡不能支持数据传输 */
SD_STREAM_WRITE_OVERRUN = (21), /*!< 卡不能支持流模式下的数据编程 */
SD_CID_CSD_OVERWRITE = (22), /*!< CID/CSD覆盖错误 */
SD_WP_ERASE_SKIP = (23), /*!< 只删除了部分地址空间 */
SD_CARD_ECC_DISABLED = (24), /*!< 未使用内部ECC执行过命令 */
SD_ERASE_RESET = (25), /*!< 在执行之前清除擦除序列,因为收到了一个超出擦除序列的命令 */
SD_AKE_SEQ_ERROR = (26), /*!< 身份验证顺序错误 */
SD_INVALID_VOLTRANGE = (27),
SD_ADDR_OUT_OF_RANGE = (28),
SD_SWITCH_ERROR = (29),
SD_SDIO_DISABLED = (30),
SD_SDIO_FUNCTION_BUSY = (31),
SD_SDIO_FUNCTION_FAILED = (32),
SD_SDIO_UNKNOWN_FUNCTION = (33),
//标准错误定义
SD_INTERNAL_ERROR,
SD_NOT_CONFIGURED,
SD_REQUEST_PENDING,
SD_REQUEST_NOT_APPLICABLE,
SD_INVALID_PARAMETER,
SD_UNSUPPORTED_FEATURE,
SD_UNSUPPORTED_HW,
SD_ERROR,
SD_OK = 0
} SD_Error;
//*******************************************************************************
//SD卡一般有5个寄存器
//CID寄存器,128位寄存器,卡标识寄存器,提供制造商ID、OEM/应用ID、产品名称、版本、序列号、制造日期等信息
//RCA寄存器,16位寄存器,相对卡地址寄存器,提供本地系统中卡的地址,可动态变化,在主机初始化的时候确定
//CSD寄存器,128位寄存器,卡描述数据寄存器,提供SD卡操作条件相关信息和数据
//SCR寄存器,64位寄存器,SD配置寄存器,提供SD卡一些特定的数据
//OCR寄存器,32位寄存器,操作条件寄存器,主要是SD卡的操作电压等信息
//*******************************************************************************
//SD卡CSD寄存器数据
typedef struct
{
u8 CSDStruct; /*!< CSD的结构 */
u8 SysSpecVersion; /*!< 系统规格版本 */
u8 Reserved1; /*!< 保留 */
u8 TAAC; /*!< 数据读访问时间 */
u8 NSAC; /*!< CLK周期内的数据读取访问时间2 */
u8 MaxBusClkFrec; /*!< Max。总线时钟频率 */
u16 CardComdClasses; /*!< 卡片命令类 */
u8 RdBlockLen; /*!< Max。读数据块长度 */
u8 PartBlockRead; /*!< 允许读取部分块 */
u8 WrBlockMisalign; /*!< 写块不对齐 */
u8 RdBlockMisalign; /*!< 读块不对齐 */
u8 DSRImpl; /*!< 域的实现 */
u8 Reserved2; /*!< 保留 */
u32 DeviceSize; /*!< 设备尺寸 */
u8 MaxRdCurrentVDDMin; /*!< Max。读取当前@ VDD最小值 */
u8 MaxRdCurrentVDDMax; /*!< MMax。读取当前@ VDD最大值 */
u8 MaxWrCurrentVDDMin; /*!< Max。写入当前@ VDD最小值 */
u8 MaxWrCurrentVDDMax; /*!< Max。写入当前@ VDD最大值 */
u8 DeviceSizeMul; /*!< 设备大小倍增器 */
u8 EraseGrSize; /*!< 擦除组大小 */
u8 EraseGrMul; /*!< 擦掉组大小乘数 */
u8 WrProtectGrSize; /*!< 写保护组大小 */
u8 WrProtectGrEnable; /*!< 写保护组启用 */
u8 ManDeflECC; /*!< 厂家默认ECC */
u8 WrSpeedFact; /*!< 写入速度因子 */
u8 MaxWrBlockLen; /*!< Max。写数据块长度 */
u8 WriteBlockPaPartial; /*!< 允许写入部分块 */
u8 Reserved3; /*!< 保留 */
u8 ContentProtectAppli; /*!< 内容保护应用 */
u8 FileFormatGrouop; /*!< 文件格式组 */
u8 CopyFlag; /*!< 复制标志(OTP) */
u8 PermWrProtect; /*!< 永久写保护 */
u8 TempWrProtect; /*!< 临时写保护 */
u8 FileFormat; /*!< 文件格式 */
u8 ECC; /*!< 排队等 */
u8 CSD_CRC; /*!< CSD CRC */
u8 Reserved4; /*!< 总1*/
} SD_CSD;
//SD卡CID寄存器数据
typedef struct
{
u8 ManufacturerID; /*!< 制造商ID */
u16 OEM_AppliID; /*!< OEM /应用程序ID */
u32 ProdName1; /*!< 产品名称 */
u8 ProdName2; /*!< 产品名称part2 */
u8 ProdRev; /*!< 产品修改 */
u32 ProdSN; /*!< 产品编号 */
u8 Reserved1; /*!< 保留1 */
u16 ManufactDate; /*!< 生产日期 */
u8 CID_CRC; /*!< CID CRC */
u8 Reserved2; /*!< 总1 */
} SD_CID;
//SD卡状态
typedef enum
{
SD_CARD_READY = ((uint32_t)0x00000001),
SD_CARD_IDENTIFICATION = ((uint32_t)0x00000002),
SD_CARD_STANDBY = ((uint32_t)0x00000003),
SD_CARD_TRANSFER = ((uint32_t)0x00000004),
SD_CARD_SENDING = ((uint32_t)0x00000005),
SD_CARD_RECEIVING = ((uint32_t)0x00000006),
SD_CARD_PROGRAMMING = ((uint32_t)0x00000007),
SD_CARD_DISCONNECTED = ((uint32_t)0x00000008),
SD_CARD_ERROR = ((uint32_t)0x000000FF)
}SDCardState;
//SD卡信息,包括CSD,CID等数据
typedef struct
{
SD_CSD SD_csd;
SD_CID SD_cid;
long long CardCapacity; //SD卡容量,单位:字节,最大支持2^64字节大小的卡.
u32 CardBlockSize; //SD卡块大小
u16 RCA; //卡相对地址
u8 CardType; //卡类型
} SD_CardInfo;
extern SD_CardInfo SDCardInfo;//SD卡信息
//SDIO 指令集
#define SD_CMD_GO_IDLE_STATE ((u8)0)
#define SD_CMD_SEND_OP_COND ((u8)1)
#define SD_CMD_ALL_SEND_CID ((u8)2)
#define SD_CMD_SET_REL_ADDR ((u8)3) /*!< SDIO_SEND_REL_ADDR for SD卡 */
#define SD_CMD_SET_DSR ((u8)4)
#define SD_CMD_SDIO_SEN_OP_COND ((u8)5)
#define SD_CMD_HS_SWITCH ((u8)6)
#define SD_CMD_SEL_DESEL_CARD ((u8)7)
#define SD_CMD_HS_SEND_EXT_CSD ((u8)8)
#define SD_CMD_SEND_CSD ((u8)9)
#define SD_CMD_SEND_CID ((u8)10)
#define SD_CMD_READ_DAT_UNTIL_STOP ((u8)11) /*!< SD卡不支持 */
#define SD_CMD_STOP_TRANSMISSION ((u8)12)
#define SD_CMD_SEND_STATUS ((u8)13)
#define SD_CMD_HS_BUSTEST_READ ((u8)14)
#define SD_CMD_GO_INACTIVE_STATE ((u8)15)
#define SD_CMD_SET_BLOCKLEN ((u8)16)
#define SD_CMD_READ_SINGLE_BLOCK ((u8)17)
#define SD_CMD_READ_MULT_BLOCK ((u8)18)
#define SD_CMD_HS_BUSTEST_WRITE ((u8)19)
#define SD_CMD_WRITE_DAT_UNTIL_STOP ((u8)20)
#define SD_CMD_SET_BLOCK_COUNT ((u8)23)
#define SD_CMD_WRITE_SINGLE_BLOCK ((u8)24)
#define SD_CMD_WRITE_MULT_BLOCK ((u8)25)
#define SD_CMD_PROG_CID ((u8)26)
#define SD_CMD_PROG_CSD ((u8)27)
#define SD_CMD_SET_WRITE_PROT ((u8)28)
#define SD_CMD_CLR_WRITE_PROT ((u8)29)
#define SD_CMD_SEND_WRITE_PROT ((u8)30)
#define SD_CMD_SD_ERASE_GRP_START ((u8)32) /*!< 设置要擦除的第一个写块的地址。(只适用于SD卡) */
#define SD_CMD_SD_ERASE_GRP_END ((u8)33) /*!< 设置要擦除的连续范围的最后一个写块的地址。(只适用于SD卡) */
#define SD_CMD_ERASE_GRP_START ((u8)35) /*!< 设置要擦除的第一个写块的地址(仅针对MMC卡规范3.31) */
#define SD_CMD_ERASE_GRP_END ((u8)36) /*!< 设置要擦除的连续范围的最后一个写块的地址。(仅适用于MMC卡3.31规格) */
#define SD_CMD_ERASE ((u8)38)
#define SD_CMD_FAST_IO ((u8)39) /*!< SD卡不支持 */
#define SD_CMD_GO_IRQ_STATE ((u8)40) /*!< SD卡不支持 */
#define SD_CMD_LOCK_UNLOCK ((u8)42)
#define SD_CMD_APP_CMD ((u8)55)
#define SD_CMD_GEN_CMD ((u8)56)
#define SD_CMD_NO_CMD ((u8)64)
/**
* @brief 以下命令为SD卡相关命令。
* SDIO_APP_CMD :在发送这些命令之前,应该首先发送CMD55。
*/
#define SD_CMD_APP_SD_SET_BUSWIDTH ((u8)6) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_STAUS ((u8)13) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SEND_NUM_WRITE_BLOCKS ((u8)22) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_OP_COND ((u8)41) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SET_CLR_CARD_DETECT ((u8)42) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SEND_SCR ((u8)51) /*!< 只适用于SD卡 */
#define SD_CMD_SDIO_RW_DIRECT ((u8)52) /*!< 仅适用于SD I/O卡 */
#define SD_CMD_SDIO_RW_EXTENDED ((u8)53) /*!< 仅适用于SD I/O卡 */
/**
* @brief 以下是SD卡相关的安全命令。
* 在发送这些命令之前,应该发送SDIO_APP_CMD。
*/
#define SD_CMD_SD_APP_GET_MKB ((u8)43) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_GET_MID ((u8)44) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SET_CER_RN1 ((u8)45) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_GET_CER_RN2 ((u8)46) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SET_CER_RES2 ((u8)47) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_GET_CER_RES1 ((u8)48) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SECURE_READ_MULTIPLE_BLOCK ((u8)18) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SECURE_WRITE_MULTIPLE_BLOCK ((u8)25) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SECURE_ERASE ((u8)38) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_CHANGE_SECURE_AREA ((u8)49) /*!< 只适用于SD卡 */
#define SD_CMD_SD_APP_SECURE_WRITE_MKB ((u8)48) /*!< 只适用于SD卡 */
//支持的SD卡定义
#define SDIO_STD_CAPACITY_SD_CARD_V1_1 ((u32)0x00000000)
#define SDIO_STD_CAPACITY_SD_CARD_V2_0 ((u32)0x00000001)
#define SDIO_HIGH_CAPACITY_SD_CARD ((u32)0x00000002)
#define SDIO_MULTIMEDIA_CARD ((u32)0x00000003)
#define SDIO_SECURE_DIGITAL_IO_CARD ((u32)0x00000004)
#define SDIO_HIGH_SPEED_MULTIMEDIA_CARD ((u32)0x00000005)
#define SDIO_SECURE_DIGITAL_IO_COMBO_CARD ((u32)0x00000006)
#define SDIO_HIGH_CAPACITY_MMC_CARD ((u32)0x00000007)
//SDIO相关参数定义
#define NULL 0
#define SDIO_STATIC_FLAGS ((u32)0x000005FF)
#define SDIO_CMD0TIMEOUT ((u32)0x00010000)
#define SDIO_DATATIMEOUT ((u32)0xFFFFFFFF)
#define SDIO_FIFO_Address ((u32)0x40018080)
//错误掩码卡状态R1 (OCR寄存器)
#define SD_OCR_ADDR_OUT_OF_RANGE ((u32)0x80000000)
#define SD_OCR_ADDR_MISALIGNED ((u32)0x40000000)
#define SD_OCR_BLOCK_LEN_ERR ((u32)0x20000000)
#define SD_OCR_ERASE_SEQ_ERR ((u32)0x10000000)
#define SD_OCR_BAD_ERASE_PARAM ((u32)0x08000000)
#define SD_OCR_WRITE_PROT_VIOLATION ((u32)0x04000000)
#define SD_OCR_LOCK_UNLOCK_FAILED ((u32)0x01000000)
#define SD_OCR_COM_CRC_FAILED ((u32)0x00800000)
#define SD_OCR_ILLEGAL_CMD ((u32)0x00400000)
#define SD_OCR_CARD_ECC_FAILED ((u32)0x00200000)
#define SD_OCR_CC_ERROR ((u32)0x00100000)
#define SD_OCR_GENERAL_UNKNOWN_ERROR ((u32)0x00080000)
#define SD_OCR_STREAM_READ_UNDERRUN ((u32)0x00040000)
#define SD_OCR_STREAM_WRITE_OVERRUN ((u32)0x00020000)
#define SD_OCR_CID_CSD_OVERWRIETE ((u32)0x00010000)
#define SD_OCR_WP_ERASE_SKIP ((u32)0x00008000)
#define SD_OCR_CARD_ECC_DISABLED ((u32)0x00004000)
#define SD_OCR_ERASE_RESET ((u32)0x00002000)
#define SD_OCR_AKE_SEQ_ERROR ((u32)0x00000008)
#define SD_OCR_ERRORBITS ((u32)0xFDFFE008)
//R6响应掩码
#define SD_R6_GENERAL_UNKNOWN_ERROR ((u32)0x00002000)
#define SD_R6_ILLEGAL_CMD ((u32)0x00004000)
#define SD_R6_COM_CRC_FAILED ((u32)0x00008000)
#define SD_VOLTAGE_WINDOW_SD ((u32)0x80100000)
#define SD_HIGH_CAPACITY ((u32)0x40000000)
#define SD_STD_CAPACITY ((u32)0x00000000)
#define SD_CHECK_PATTERN ((u32)0x000001AA)
#define SD_VOLTAGE_WINDOW_MMC ((u32)0x80FF8000)
#define SD_MAX_VOLT_TRIAL ((u32)0x0000FFFF)
#define SD_ALLZERO ((u32)0x00000000)
#define SD_WIDE_BUS_SUPPORT ((u32)0x00040000)
#define SD_SINGLE_BUS_SUPPORT ((u32)0x00010000)
#define SD_CARD_LOCKED ((u32)0x02000000)
#define SD_CARD_PROGRAMMING ((u32)0x00000007)
#define SD_CARD_RECEIVING ((u32)0x00000006)
#define SD_DATATIMEOUT ((u32)0xFFFFFFFF)
#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 ((u32)0x00000008)
#define SD_HALFFIFOBYTES ((u32)0x00000020)
//支持的命令类别
#define SD_CCCC_LOCK_UNLOCK ((u32)0x00000080)
#define SD_CCCC_WRITE_PROT ((u32)0x00000040)
#define SD_CCCC_ERASE ((u32)0x00000020)
//CMD8指令
#define SDIO_SEND_IF_COND ((u32)0x00000008)
SD_Error SD_Init(void);
void SDIO_Clock_Set(u8 clkdiv);
SD_Error SD_PowerON(void);
SD_Error SD_PowerOFF(void);
SD_Error SD_InitializeCards(void);
SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo);
SD_Error SD_EnableWideBusOperation(u32 wmode);
SD_Error SD_SetDeviceMode(u32 mode);
SD_Error SD_SelectDeselect(u32 addr);
SD_Error SD_SendStatus(uint32_t *pcardstatus);
SDCardState SD_GetState(void);
SD_Error SD_ReadBlock(u8 *buf,long long addr,u16 blksize);
SD_Error SD_ReadMultiBlocks(u8 *buf,long long addr,u16 blksize,u32 nblks);
SD_Error SD_WriteBlock(u8 *buf,long long addr, u16 blksize);
SD_Error SD_WriteMultiBlocks(u8 *buf,long long addr,u16 blksize,u32 nblks);
SD_Error SD_ProcessIRQSrc(void);
void SD_DMA_Config(u32*mbuf,u32 bufsize,u32 dir);
//void SD_DMA_Config(u32*mbuf,u32 bufsize,u8 dir);
u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt); //读SD卡,fatfs/usb调用
u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt); //写SD卡,fatfs/usb调用
#endif