sd卡(secure digital memory card)即:安全数字内存卡,它是在mmc的基础上发展而来,是一种基于半导体快闪记忆器的新一代记忆设备,它被广泛地于便携式装置上使用,例如数码相机、个人数码助理(pda)和多媒体播放器等。sd卡由日本松下、东芝及美国sandisk公司于1999年8月共同开发研制。
sd卡简介sd非常小巧,可以嵌入到设备中,在嵌入式开发中,产品需要存储一些容量叫大的文件,就可能会运用到sd卡。sd卡按容量分类,可以分为3类:sd卡、sdhc卡、sdxc卡,如下表所示。
容量大小不同的sd卡,其内部的操作标准是不同的。很多外设会明确告诉用户本设备最大能够支持容量多大的外扩,不能无限制的扩存,因为容量越大,操作不同,对控制器的要求比较高。当前设备的控制器不足以支持大容量,所以有外扩限制。
sd卡由9个引脚与外部通信,支持spi和sdio两种模式,不同模式下,sd卡引脚功能描述如下表所示。
sd卡的物理结构一张sd卡包括有存储单元、存储单元接口、电源检测、卡及接口控制器和接口驱动器5个部分。
存储单元:是存储数据部件,存储单元通过存储单元接口与卡控制单元进行数据传输;
电源检测单元:保证sd卡工作在合适的电压下,如出现掉电或上状态时,它会使控制单元和存储单元接口复位;
卡及接口控制单元:控制sd卡的运行状态,它包括有8个寄存器;
接口驱动器:控制sd卡引脚的输入输出。
sd卡内部寄存器sd卡总共有8个寄存器,用于设定或表示sd卡信息。这些寄存器只能通过对应的命令访问,程序控制中只需要发送组合命令就可以实现sd卡的控制以及读写操作。
sdio接口sdio全称是安全数字输入/输出接口,多媒体卡(mmc)、sd卡、sd i/o卡都有sdio接口。stm32f407系列控制器有一个sdio主机接口,它可以与mmc卡、sd卡、sd i/o卡以及ce-ata设备进行数据传输。也就是说sdio接口不仅仅只会操作sd卡,凡是符合sdio接口通信的设备都可以被操作。
sdio 具有以下特性:
完全兼容 多媒体卡系统规范版本 4.2。卡支持三种不同数据总线模式:1 位(默认)、4 位和 8 位
完全兼容先前版本的多媒体卡(向前兼容性)
完全兼容 sd 存储卡规范版本2.0
完全兼容 sd i/o 卡规范版本 2.0 : 卡支持两种不同数据总线模式:1 位(默认)和 4 位
完全支持 ce-ata 功能(完全符合 ce-ata 数字协议版本 1.1)
对于 8 位模式,数据传输高达 48 mhz
数据和命令输出使能信号,控制外部双向驱动程序。
sdio 不具备兼容 spi 的通信模式。
sdio组成sdio 适配器块提供特定于 mmc/sd/sd i/o 卡的所有功能,如时钟生成单元、命令和数据传输。
apb2 接口访问 sdio 适配器寄存器,并且生成中断和 dma 请求信号。
注:
1、默认情况下,sdio_d0用于数据传输。初始化后,主机可以更改数据总线宽度。
2、sd 卡连接到总线,主机可以将数据传输配置为sdio_d[3:0]
3、sdio使用两个时钟信号:sdio适配器时钟(sdioclk= 48 mhz)和apb2总线时钟(pclk2)。
4、卡时钟(sdio_ck):每个时钟周期在命令和数据线上传输1位命令或数据。对于sd或sdi/o卡,时钟频率可以在0mhz至25mhz间变化,当数据正式稳定传输的时候配置为24mhz。sdio_ck计算公式:sdio_ck=sdioclk/(2+clkdiv)
5、sdio适配器时钟(sdioclk):该时钟用于驱动sdio适配器,可用于产生sdio_ck时钟。对f4来说,sdioclk来自pll48ck(48mhz)。
6、f4:apb2总线接口时钟(pclk2):该时钟用于驱动sdio的apb2总线接口,其频率为pclk2=84mhz。
注意:在sd卡初始化时,sdio_ck不可以超过400khz,初始化完成后,可以设置为最大频率(但不可以超过sd卡最大操作频率)。
该适配器由五个子单元组成:
1.适配器寄存器块 :适配器寄存器模块包含所有系统寄存器。
2.控制单元 : 控制单元包含电源管理功能和存储卡时钟的时钟分频器。
3.命令路径 :命令路径单元向卡发送命令并从卡接收响应。
4.数据路径 :数据路径子单元负责与卡相互传输数据。
5.数据 fifo :数据 fifo(先进先出)子单元是一个数据缓冲器,带发送和接收单元。fifo 包含一个宽度为 32 位且深度为 32 字的数据缓冲器和发送/接收逻辑。(一共32 个单元,一个单元一个字)。所有的数据传输都要经过fifo,便于管理。
sdio 命令简介sd命令由主机发出,以广播命令和寻址命令为例,广播命令是针对与sd主机总线连接的所有从设备发送的,寻址命令是指定某个地址设备进行命令传输。
sd命令格式固定为48bit,都是通过cmd线连续传输的,数据线不参与。
sd命令的组成如下:
起始位和终止位:命令的主体包含在起始位与终止位之间,它们都只包含一个数据位,起始位为 0,终止位为 1。
传输标志:用于区分传输方向,该位为 1 时表示命令,方向为主机传输到 sd 卡,该位为 0时表示响应,方向为 sd卡传输到主机。
命令主体内容包括命令、地址信息/参数和 crc 校验三个部分。
命令号:它固定占用 6bit,所以总共有 64个命令(代号:cmd0~cmd63),每个命令都有特定的用途,部分命令不适用于 sd 卡操作,只是专门用于 mmc卡或者sd i/o卡。
地址/参数:每个命令有 32bit地址信息/参数用于命令附加内容,例如,广播命令没有地址信息,这 32bit用于指定参数,而寻址命令这 32bit用于指定目标 sd卡的地址。
crc7 校验:长度为 7bit的校验位用于验证命令传输内容正确性,如果发生外部干扰导致传输数据个别位状态改变将导致校准失败,也意味着命令传输失败,sd卡不执行命令。
sd命令有4种类型:
1.无响应广播命令(bc),发送到所有卡,不返回任务响应;
2.带响应广播命令(bcr),发送到所有卡,同时接收来自所有卡响应;
3.寻址命令(ac),发送到选定卡,dat线无数据传输;
5.寻址数据传输命令(adtc),发送到选定卡,dat线有数据传输。
在标准中定义了两种类型的通用命令:特定应用命令(acmd)和常规命令(gen_cmd),也就是说在64个命令作为常规命令的基础上加了特定的命令
要使用sd卡制造商特定的acmd命令如acmd6,需要在发送该命令之前无发送cmd55命令,告知sd卡接下来的命令为特定应用命令。cmd55命令只对紧接的第一个命令有效,sd卡如果检测到cmd55之后的第一条命令为acmd则执行其特定应用功能,如果检测发现不是acmd命令,则执行标准命令。
sd命令响应由sd卡向主机发出,部分命令要求sd卡作出响应,这些响应多用于反馈sd卡的状态。基本特性如下:
lsdio总共有7个响应类型(代号:r1~r7),其中sd卡没有r4、r5类型响应。特定的命令对应有特定的响应类型,比如当主机发送cmd3命令时,可以得到响应r6。与命令一样,sd卡的响应也是通过cmd线连续传输的。根据响应内容大小可以分为短响应和长响应。短响应是48bit长度,只有r2类型是长响应,其长度为136bit。
sdio读数据
单个块读操作与多个块的读操作除命令不同外,还体现在读操作结束时,单个块读取一个块自动结束,而多个块还需要主机发送停止命令。写操作类似,也要多发一个结束命令,只不过写操作写数据前需要检查卡的状态是否为忙状态。
sdio写数据
sd卡操作模式sd卡有多个版本,stm32控制器目前最高支持《physical layer simplifiedspecification v2.0》定义的sd卡,stm32控制器对sd卡进行数据读写之前需要识别卡的种类:v1.0标准卡、v2.0标准卡、v2.0高容量卡或者不被识别卡。
sd卡系统定义了两种操作模式:卡识别模式和数据传输模式。
在系统复位后,主机处于卡识别模式,寻找总线上可用的sdio设备;同时,sd卡也处于卡识别模式,直到被主机识别到,即当sd卡接收到send_rca(cmd3)命令后,sd卡就会进入数据传输模式,而主机在总线上所有卡被识别后也进入数据传输模式。
每个不同的操作模式下,sd卡都有不同状态,通过命令控制实现卡状态的切换,在不同的状态下做不同的事,比如在发送数据前需要sd卡处于传输状态,发送数据时,sd卡处于接收状态。
卡识别模式
①上电后,主机发送cmd0让所有卡软复位从而进入空闲状态。
②主机发送cmd8确定卡的电压范围,并识别是否为2.0的卡
③主机发送acmd41识别或拒绝不匹配它的电压范围的卡,sd卡需要工作在特定的电压范围之内
④主机发送cmd2来控制所有卡返回它们的卡识别号cid(128位)
⑤主机发送cmd3命令,让卡推荐一个rca(16)地址作为以后通信的标识,之后都以rca值作为身份标识进行信息交互。
注:在卡识别过程中,要求sd卡工作在识别时钟频率fod的状态下,在sd卡初始化时,sdio_ck不可以超过400khz
数据传输模式
只有sd卡系统处于数据传输模式下才可以进行数据读写操作。数据传输模式下可以将主机sd时钟频率设置为fpp,默认最高为25mhz,频率切换可以通过cmd4命令来实现。通过cmd7命令加上rca值来选定指定的卡,选中后sd卡进入数据传输状态,就可以发送cmd17读单个块,cmd18读多个块,读多个块时只有发送cmd12命令才会停止。sd卡再次进入传输状态,若不想对卡有任何操作可以再次发送cmd7命令加上rca值来取消指定的卡,写操作与上述原理相同。
sd卡普通模式操作实例实验内容:向sd卡写入数据后读出
实验步骤:
1.配置rcc,与以往不同的是sdio适配器的时钟是单独配置的,需要专用的sdioclk,标准工作在48mhz
2.配置sdio
3.编写代码
//mian.c#include main.h#include stm32f4xx_hal.h#include sdio.h#include usart.h#include gpio.h#define sdbuf_size 1024uint8_t sdbuf_tx[sdbuf_size],sdbuf_rx[sdbuf_size];//数据传输的buf,一个用于传输,一个用于接收//定义全局变量,最好不定义局部变量,防止因过大造成栈溢出int main(void){ uint32_t i; hal_sd_cardinfotypedef pcardinfo;//定义结构体用来接收卡信息 hal_init(); systemclock_config(); mx_gpio_init(); mx_sdio_sd_init(); mx_usart1_uart_init(); printf(this is sd testn); //卡识别结束后就可以调用hal_sd_getcardinfo()函数获取卡信息并打印 hal_sd_getcardinfo(&hsd, &pcardinfo); printf(pcardinfo.cardtype = %un,pcardinfo.cardtype); printf(pcardinfo.cardversion = %un,pcardinfo.cardversion);//版本 printf(pcardinfo.blocknbr = %un,pcardinfo.blocknbr);//sd卡块数 printf(pcardinfo.blocksize = %un,pcardinfo.blocksize);//每一块大小 /*--------------------sd卡写测试----------------------------------*/ memset(sdbuf_tx, 0x8, sdbuf_size); /、填充txbuf为0x8 /** //函数功能及参数描述 *hal_statustypedef hal_sd_writeblocks(sd_handletypedef *hsd, uint8_t *pdata, *uint32_t blockadd, uint32_t numberofblocks, uint32_t timeout) * @param hsd pointer to sd handle * @param pdata pointer to the buffer that will contain the data to transmit * @param blockadd block address where data will be written,从哪一个块开始写 * @param numberofblocks number of sd blocks to write 写几个块 * @param timeout specify timeout value 超时时间 * @retval hal status if( hal_sd_writeblocks(&hsd, sdbuf_tx, 0 , 2, 1000) == hal_ok) { while(hal_sd_getcardstate(&hsd) != hal_sd_card_transfer);//处于传输状态退出 printf(writeblocks successfullyn); for(i=0; i< sdbuf_size; i++) { printf(%d ,sdbuf_tx[i]); } printf(rn); } else { printf(writeblocks failedn); } /*--------------------sd 卡读测试----------------------------------*/ //与hal_sd_writeblocks函数的参数功能相同 if( hal_sd_readblocks(&hsd, sdbuf_rx , 0, 2, 1000) == hal_ok) { while(hal_sd_getcardstate(&hsd) != hal_sd_card_transfer);//返回到传输状态退出 printf(readblocks successfullyn); for(i=0; i< sdbuf_size; i++) { printf(%d ,sdbuf_rx[i]); } printf(rn); } else { printf(readblocks failedn); } /*--------------------sd 擦除测试----------------------------------*/ if (hal_sd_erase(&hsd, 0, 1) == hal_ok ) { while(hal_sd_getcardstate(&hsd) != hal_sd_card_transfer); printf(sd_erase successfullyn); } else { printf(sd_erase failedn); } /*--------------------sd 卡读测试----------------------------------*/ if( hal_sd_readblocks(&hsd, sdbuf_rx , 0, 2, 1000) == hal_ok) { while(hal_sd_getcardstate(&hsd) != hal_sd_card_transfer); printf(readblocks successfullyn); for(i=0; iinstance, init);/* disable sdio clock */ __hal_sd_disable(hsd); /* set power state to on 对sd卡进行上电 */ sdio_powerstate_on(hsd- >instance);/* enable sdio clock */ __hal_sd_enable(hsd);/* required power up waiting time before starting the sd initialization sequence */ hal_delay(2u);/* identify card operating voltage */ errorstate = sd_poweron(hsd);if(errorstate != hal_sd_error_none) { hsd- >state = hal_sd_state_ready; hsd- >errorcode |= errorstate;return hal_error; }/* card initialization */ errorstate = sd_initcard(hsd);if(errorstate != hal_sd_error_none) { hsd- >state = hal_sd_state_ready; hsd- >errorcode |= errorstate; return hal_error; } return hal_ok;}sd卡dma模式操作实例当sd卡中有大量的音视频需要读取时,整个过程需要cpu干预,这样cpu的利用率就会降低,因此大量数据的传输最好启用dma。
实验内容:向sd卡写入数据后读出。
实验步骤:工程的时钟配置和sdio配置与普通模式相同,只有一点不同需要打开sdio的全局中断,因为sdio发送与接收完成后都需要中断去生成dma请求。设置sdio全局中断优先级更高一些,因为它内部还有很多其他中断,发生错误时更需要处理。
配置dma
编写代码:
//mian.c#include main.h#include stm32f4xx_hal.h#include dma.h#include sdio.h#include usart.h#include gpio.h#define sdbuf_size 1024uint8_t sdbuf_tx[sdbuf_size],sdbuf_rx[sdbuf_size];//数据传输的buf,一个用于传输,一个用于接收//定义全局变量,最好不定义局部变量,防止因过大造成栈溢出uint8_t dma_send_ok, dma_rcv_ok;int main(void){ uint32_t i; hal_sd_cardinfotypedef pcardinfo;//定义结构体用来接收卡信息 hal_init(); systemclock_config(); mx_gpio_init(); mx_dma_init(); mx_sdio_sd_init(); mx_usart1_uart_init(); printf(this is sd testn); //卡识别结束后就可以调用hal_sd_getcardinfo()函数获取卡信息并打印 hal_sd_getcardinfo(&hsd, &pcardinfo); printf(pcardinfo.cardtype = %un,pcardinfo.cardtype); printf(pcardinfo.cardversion = %un,pcardinfo.cardversion);//版本 printf(pcardinfo.blocknbr = %un,pcardinfo.blocknbr);//sd卡块数 printf(pcardinfo.blocksize = %un,pcardinfo.blocksize);//每一块大小 /*------------------- sd dma 写测试-------------------------------------*/ memset(sdbuf_tx, 0x2, sdbuf_size ); dma_send_ok = 0;//设置发送完成标志位为0,完成时为1 /** //函数原型 *hal_statustypedef hal_sd_writeblocks_dma(sd_handletypedef *hsd, uint8_t *pdata, uint32_t blockadd, uint32_t numberofblocks) * @param hsd pointer to sd handle * @param pdata pointer to the buffer that will contain the data to transmit * @param blockadd block address where data will be written 从哪个块开始写 * @param numberofblocks number of blocks to write写几个块 * @retval hal status */ if( hal_sd_writeblocks_dma(&hsd, sdbuf_tx, 0, 1) == hal_ok ) { //等待dma传输完成,并且sd卡状态为传输状态 while( (dma_send_ok ==0 ) || (hal_sd_getcardstate(&hsd) != hal_sd_card_transfer)); printf(writeblocks successfullyn); for(i=0; i< sdbuf_size; i++) { printf(%d ,sdbuf_tx[i]); } printf(rn); } else { printf(writeblocks failedn); } /*------------------- sd dma 读测试-------------------------------------*/ dma_rcv_ok = 0; //设置读取完成标志位为0,完成时为1 if(hal_sd_readblocks_dma(&hsd, sdbuf_rx, 0, 1) == hal_ok) { while( (dma_rcv_ok ==0) || (hal_sd_getcardstate(&hsd) != hal_sd_card_transfer)); printf(readblocks successfullyn); for(i=0; i< sdbuf_size; i++) { printf(%d ,sdbuf_rx[i]); } printf(rn); } else { printf(readblocks failedn); } while (1){}}//sdio.cextern uint8_t dma_send_ok, dma_rcv_ok;//发送完成中断处理void hal_sd_txcpltcallback(sd_handletypedef *hsd){ dma_send_ok = 1;}//接收完成中断处理 void hal_sd_rxcpltcallback(sd_handletypedef *hsd){ dma_rcv_ok = 1;}
1.23亿,吉利旗下晶能微电子,收购益中封装
这样的诺基亚8,能激发你的购买欲吗?
Mobileye披露2023财年第三季度业务亮点
MQTT over QUIC:EMQ 携手英特尔、上海交大与全球名校共同探索下一代物联网协议
关于连接显示屏与键盘的接口IC的推出将助力简化平板电脑设计
SD卡是什么意思 SD卡普通模式操作实例
Intel出手修复win10频繁死机蓝屏等问题
电源之LDO-5. LDO的噪声
日本停止销售日立品牌电视,通过其经销店销售索尼产品
直线马达激光打标在竹筛中的应用
X-ray点料机:高效生产的工具
单结晶体管的特性/主要参数
新型土壤肥料养分速测仪 仪器原理
印尼鹰航已正式取消了波音737 MAX飞机的订单
保加利亚已拥有世界上第二大比特币储备
基于科里奥利力测量的流量传感器优化
大功率无线输出电台使用时的注意事项有哪些
摘要模型理解或捕获输入文本的要点
1GW40T60F管好坏测量方法
谈谈CMOS反相器的静态特性与动态特性