SDIO、SD卡和FATFS文件系统理解

一、SDIO接口协议定义说明

1.1 介绍

  SDIO 是基于SD标准开发的一种外设接口,其接口定义主要有时钟线命令/响应线数据线,数据线分为1位、4位和8位,半双工通信方式,可以与MMC(多媒体卡,Mutiny Media Card )卡、SD存储卡和SDIO卡通信。

在这里插入图片描述

  与SD卡和SD IO卡的通信速率(卡时钟)可以设置在0-25MHZ,与MMC卡(V4.0以上)的通信速率可以设置在0-48MHZ,(V3.3以下的设置在0-20Mhz)

  • SDIO_CK:卡时钟是用来和外部卡进行数据交互的时钟,SDIO_CK = SDIOCLK/(2+CLKDIV)
  • CLKDIV:分频系数
  • SDIOCLK:数据通道到以及控制单元的时钟,用来产生卡时钟
  • HCLK/2:寄存器和FIFO的时钟。

在这里插入图片描述

1.2 通信过程

  通过命令线去发送指令,同样通过命令线接收响应,这种类似于IIC通过并转串然后将数据1bit1bit发出来,先传输高位MSB,再传输低位LSB

在这里插入图片描述

  如果是多字节传输,先传输低字节,后传输高字节,低字节在低数据总线,高字节在高数据总线
在这里插入图片描述
在这里插入图片描述
  如果是宽字节传输,同样是高位先传输,低位后传输,
在这里插入图片描述

  如下图所示,可以看到CMD线通过移位寄存器将串行数据接收回来,同样之后会进行CRC校验(硬件),再然后会存入到寄存器中。

在这里插入图片描述

  命令传输过程:中间会有等待状态,发送命令时是有控制器驱动,响应的时候是由卡来驱动。

在这里插入图片描述

  数据线说明:寄存器可以配置数据总线宽度,如果位宽没有限制,只是在SDIO_D0上面有传输,其中FIFO缓存空间是128个字节(32个字,每个字为4字节),
在这里插入图片描述

  SDIO的有响应操作和无响应操作(比如广播)

在这里插入图片描述

  如果是读操作和写操作,则需要有数据线去参与。在进行写操作的时候需要注意判断卡处于繁忙状态,不会被写入数据,最后需要发送停止数据传输 指令。

在这里插入图片描述
在这里插入图片描述

  此外也可以进行连续读和连续写操作,即流操作,数据末尾没有CRC校验码,只适用于多媒体卡
在这里插入图片描述
在这里插入图片描述

1.3 通信协议

(命令格式:发送,传输位为1
在这里插入图片描述

命令格式:接收(长响应和短响应,传输位为0
在这里插入图片描述
具体的命令举例说明:见指令表及程序代码。

二、SD卡/SD IO卡/MMC卡

2.1 SD卡
SD卡类型
  • 标准卡,内存在2GB(2^31 bytes)以内,

  • 大容量卡(2GB<X<32GB),由SD卡2.0协议定义,大容量卡有两种类型,

​ 一种是 单状态卡:一块大容量区域

​ 一种是 双状态卡:两块区域,一块是大容量卡区域,一块是标准容量卡区域。同一时间只能访问一种区域,可以通过一种机制来选择对应的容量卡区域

SD卡信息寄存器定义:
  • CID:128位,卡识别号,无法修改

  • RCA:16位,Relative card address,卡相对地址,无法修改,

  • DSR:16位,驱动阶段寄存器,可修改

  • CSD:128位,卡特定数据,关于卡的操作情况说明,不可修改

  • SCR:64位,SD配置寄存器,SD卡的容量,不可修改

  • OCR:32位,运行条件寄存器,不可修改

  • SSR:512位,SD状态,SD卡的专用功能说明,不可修改

  • CSR:32位,卡状态,关于卡状态的说明,不可修改

两种模式:卡识别模式和数据传输模式。
  • 卡识别模式

    ①卡复位:CMD0可以进行软复位,使得所有卡进入空闲状态,处于不激活的卡会忽略这条指令

    ②操作条件验证:首先会进行电压验证,通过CMD8指令,如果可以当前电压可以与卡进行通信,则存在响应,否则无响应,ACMD41指令用来识别和否决不适应由主机提供的电压的卡片。ACMD41是应用特定指令,因此在发送其之前需要发送CMD55指令。先发送CMD8,然后再发送ACMD41。

    卡识别流程图
    在这里插入图片描述

  首先进行CMD0.软复位所以状态卡,之后进行CMD8,检验电压范围是否有效,在发送ACMD41之前,需要发送CMD55,指示下一条指令是应用指令,不是通用指令。

  ACMD41,识别到可以正常进行通信的卡,可以OCR里设置HCS(Host Capacity Support)即置1,表明主机(Host)支持大容量SD卡,响应里面会带有CCS位,表明卡状态,1代表是大容量卡。如果CMD8指令无响应,则说明不支持大容量SD卡,ACMD41中OCR busy位置1表明初始化完成,置0表明还处于初始化中。

  主机初始化完成后,执行CMD2指令,获取CID码(unique card identification),通过CMD指令线返回,不是数据线。

  之后再发送CMD3,询问RCA(Relative card address) 相对卡地址,在传输模式中使用,之后进入旁路状态。

以STM32F1代码为例,来讲解 SD卡的初始化及读写流程。
代码实现:初始化时钟

	/*初始化时的时钟不能大于400KHz*/ 
  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位数据线
  SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;//硬件流
  SDIO_Init(&SDIO_InitStructure);
  SDIO_SetPowerState(SDIO_PowerState_ON);	//上电状态,开启卡时钟
  SDIO_ClockCmd(ENABLE);//SDIOCK使能 

在这里插入图片描述

  发送CMD0,进入空闲状态,循环发送,如果发送成功,则退出循环,cmderror判断发送是否成功,寄存器初始化为0。

for(i=0;i<74;i++)
{
	SDIO_CmdInitStructure.SDIO_Argument = 0x0;//发送CMD0进入IDLE STAGE模式命令.
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_GO_IDLE_STATE; //cmd0
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No;  //无响应
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;  //则CPSM在开始发送命令之前等待数据传输结束。 
    SDIO_SendCommand(&SDIO_CmdInitStructure);	  		//写命令进命令寄存器
		
		errorstatus=CmdError();    //判断是否发送成功
		if(errorstatus==SD_OK)break;
 }
 if(errorstatus)return errorstatus;//返回错误状态

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;
}	 

在这里插入图片描述

CMD寄存器变为400,代表指令0,不需要响应。1000 0000

之后发送CMD8,检查SD卡接口电压,

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();						//等待R7响应
if(errorstatus==SD_OK) 								//R7响应正常
{
    CardType=SDIO_STD_CAPACITY_SD_CARD_V2_0;		//SD 2.0卡
    SDType=SD_HIGH_CAPACITY;			   			//高容量卡
}

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;
}	   

在这里插入图片描述

  CMD寄存器变为448,10001001000,前六位代表指令8,01代表短响应,100代表使能CPSM状态机,进入空闲状态,响应时R7响应,收到响应,代表支持该电压范围,如果超时,则不是2.0卡或者不支持电压范围。ARG寄存器为发送的参数,1AA 代表检查。。。?

  第6位为1,则代表接收响应成功,其他则代表失败
在这里插入图片描述

  之后发送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响应

errorstatus=CmdResp1Error(SD_CMD_APP_CMD); 	 	//等待R1响应   
if(errorstatus!=SD_OK)return errorstatus;   	//响应错误

在这里插入图片描述
CMD寄存器变为477,10001 110111,前6位为55,01则为短响应,100使能CPSM状态机

  接下来发送ACMD41指令,判断SD卡是否为大容量卡,不支持CMD55指令的卡为MMC卡,469,100 01 101001 41指令,短响应

在这里插入图片描述

SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDType;	//发送ACMD41,短响应	
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;  //r3
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus=CmdResp3Error(); 					//等待R3响应

response=SDIO->RESP1;;			   				//得到响应

if(response&=SD_HIGH_CAPACITY)     //SD_HIGH_CAPCITY = 0x400 0000
{
    CardType=SDIO_HIGH_CAPACITY_SD_CARD;  //支持大容量卡
}

  OCR寄存器各位定义,倒数第二位是容量卡定义。

在这里插入图片描述

  再之后是CMD2和CMD3指令,CMD2获取SD卡信息,4C2 100 11 000010 指令码为2,11为长响应。
在这里插入图片描述

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,长响应	  128位

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;

  CID寄存器定义,Manufacture ID = 0x27 = 39.
在这里插入图片描述
在这里插入图片描述

  • 数据传输模式:

    在这里插入图片描述

  通过CMD9可以获取CSD寄存器数据,比如块长度,块存储容量等。CMD4指令可以配置总线布局以及卡的数量,之后时钟频率从初始化频率的不大于400K,调节到10-25M这个数据传输频段。

RCA = rca;
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;	

  CMD7指令可以配置卡进入传输数据状态,但是同时只有一个卡进入传输数据状态,同时发送默认地址0x00,也可以使得卡退出传输状态,重新进入旁路状态。地址由RCA决定,因为在高16位,所以读取的RCA地址需要左移16位,才可以选中该卡 通过RCA来区分各个卡的地址。

SDIO_CmdInitStructure.SDIO_Argument =  addr;//发送CMD7,选择卡,短响应	
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEL_DESEL_CARD;//cmd7
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);	 
	

  读写之前的一些操作指令:CMD16设置读写块的大小,一次读多少个字节,CMD32,CMD33,擦除开始和擦除结束指令,ACMD6,设置总线数据宽度,(1bit 4bit 8bit),ACMD23,设置即将擦除块的大小等,ACMD42设置或者清除50K欧姆的上拉电阻。

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响应  
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响应 
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响应 

  写数据块:CMD24(单块写入):写入一个块的大小,在标准容量卡有效,大容量卡,固定512字节。CMD25(多块写入):直到CMD12 停止写入指令。

CMD42:上锁或者解锁,设置密码或者复位密码。CMD56:主机设置读卡或者写卡。

CMD254单块写入

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响应 

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);

CMD25 多块写入

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);

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;	 

  读数据块:CMD17读单个块,CMD18读多个块,CMD30,写保护,大容量卡 不支持改指令。ACMD13:发送卡状态,ACMD:22:发送写入块的数量,ACMD51:读取SCR寄存器内容。

SDIO_DataInitStructure.SDIO_DataBlockSize= power<<4 ;//配置读取的数据个数
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;
SDIO_DataInitStructure.SDIO_TransferMode=SDIO_TransferMode_Block;
SDIO_DataConfig(&SDIO_DataInitStructure);

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地址出读取数据,短响应 
各指令定义表。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 SD I/O卡

  SDIO卡就是支持SDIO接口的卡,其卡的功能多种多样,比如支持WIFI或者BlueTooth等,SDIO卡和SD存储卡是兼容的,在机械、电气指令和软件上面,SDIO卡对于移动电子设备,提供了一个高速度的数据传输,可以作为SIOD设备被识别。

SDIO卡分为两种:高速和低速。

  • 高速:支持SPI模式和SDIO(1bit、4bit(必须))0-25MHZ
  • 低速:支持SPI模式和SDIO(1bit、4bit(可选)) 0-400KHZ

SD卡以及SDIO卡不同的指令,因为对于SDIO卡来说,SD卡的有些指令没用,比如擦除指令等。
在这里插入图片描述

2.3 MMC卡(多媒体卡)

再续

三、FATFS文件系统

再续

  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张一西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值