SDIO学习

SDIO学习

内容提要


摸索SD操作许久,发现很多资料都是基于库函数开发,为真正理解SDIO的操作流程,本文引导读者一起去阅读Spec文件,深入理解SDIO操作的来龙去脉。(注意:本文主要是自己的学习心得,记录学习中感觉重要的知识点,细节还需参考Spec)

协议手册


SDIO操作协议主要包括两个部分

  • SDIO接口协议 SDIO Card Specification:SDIO接口操作SD/MMC等的规范
  • SD物理层协议 SD Specifications Physical Layer Spec:SD卡的操作规范

SD卡结构


如上图所示,SD卡主要包括输入输出引脚、卡接口控制器、电源管理、内部寄存器、Memory接口和Memory组成。

协议理解


总线数据传输协议




command和response通过双向传输线CMD传输
command表示SDIO接口传输给SD卡的指令,response表示SD卡传输个SDIO接口的信息
数据可以是1bit或4bit通过DAT传输(data0/data0-3)
数据线DAT是双向的,SDIO通过它进行SD卡的读写操作

CMD结构


CMD命令结构


每条指令由起始位(1bit)、传输位(1bit)、命令索引(6bit)、CRC校验(7bit)和结束位(1bit)组成,总长48bit。
传输位标识传输的方向,SDIO(host)传输的为command,transmmitter bit = 1

Responds类型


SD卡的response有多种类型,请参考Spec文档。
response主要包含SD卡的内部寄存器内容和状态信息,在操作过程中需密切关注。
传输位标识传输的方向,SD(host)传输的为response,transmmitter bit = 0

数据结构


SDIO支持1bit和4bit数据传输,数据发送通过移位寄存器进行串行处理

SD读写操作


卡状态与操作模式


卡状态可以通过response或CMD13得到,标识SD操作的状态
操作模式是上电操作一般的过程

初始化


上电后,需要识别SD卡的类型,得到SD卡的状态信息,并将SD置于stand-by模式,故需要进行初始化

初始化的步骤(SDHC卡为例)

  • 发送CMD0,将卡状态复位到idle状态。
  • 发送CMD8,得到response。
  • 持续发送ACMD41(CMD55+CMD41),检测response的CCS(30bit),若CCS = 1,则为高容量卡,检测识别是否完成response的finish(31bit)= 1执行下一步。
  • 发送CMD2得到CID信息
  • 发送CMD3得到SD卡地址信息(RCA)初始化完成,进入到stand-by模式

传输状态


  • 如图所示,通过发送不同的CMD,切换SD的状态
  • 注意状态的转移情况

卡状态确认


  • 卡状态可以通过CMD13查看SD卡所处的状态,确认操作正确与否

参考代码


void SDIORead_Test(){
    int rca;
    int complete;
    int current_status;
    int error_status;
    int i;
    int n = 1000;
    int temp = 0;
    
    int rxdata0 = 0;
    int rxdata1 = 0;
    int rxdata2 = 0;
    int rxdata3 = 0;

    uart_printf("Start testing SDIO tranfer...\n");

    SDIO1_GPIOInitRemap(); //配置GPIO

//======================================================
// set up
// Test:  Init sequence, With response check  
// CMD 0  Reset Card
// CMD 8  Get voltage (Only 2.0 Card response to this)            ////
// CMD55  Indicate Next Command are Application specific
// ACMD44 Get Voltage windows
// CMD 2  CID reg
// CMD 3  Get RCA.
//======================================================

    //配置MCU的SDIO(根据不同的SDIO而定)
    SDIO1->MMC_CARDSEL = 0xdf;   //enable module, enable mmcclk
    SDIO1->MMC_CTRL    = 0x83;      //4bit,low speed,1/16 divider		
    SDIO1->MMC_INT_MASK = 0x01;  //unmask interrupt
    SDIO1->MMC_CRCCTL   = 0xC0;  

//======================================================
//reset card :CMD0
//======================================================
    CMD_Send(0,0);
		
    n = 100;
    while(n--);
//======================================================
//cmd 8 
//======================================================
    CMD_Send(8,0x1AA);
    
    n = 1000;
    while(n--);
 		
    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD8 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }

    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 =  SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    
    n = 100;
    while(n--);
		
while(1)
{	
//======================================================
//cmd 55 
//======================================================
    CMD_Send(55,0);
		n = 1000;
    while(n--);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD55 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    
    n = 100;
    while(n--);
//======================================================
//acmd 41 
//======================================================
		CMD_Send(41,0xC0100000);
		n = 1000;
    while(n--);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD41 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);
		
   if(!(rxdata0>>30 & 0x1)){  //判断CCS,CCS=1为高容量卡
   	  uart_printf("CCS = 0\n");
   }
   else{
   	  uart_printf("CCS = 1   High Capacity SD Memory Card\n");			
   }
     		
   if(!(rxdata0>>31 & 0x1)){  //判断电压设置,上电是否完成
   	  uart_printf("Finished = 0\n");
   }
   else{
   	  uart_printf("Finished = 1\n");			
   }
    
    n = 100;
    while(n--);	
		
    if((rxdata0>>31 & 0x1)){
	  break;             //上电完成退出循环 
    }		

}
//======================================================
//cmd 2 CID
//======================================================
    CMD_Send(2,0);

    SDIO1->MMC_IO = 0x1c;  //auto only response transfer (136bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD2 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF7<<24  |SDIO1->CMD_BUF6<<16  |SDIO1->CMD_BUF5<<8  | SDIO1->CMD_BUF4;
    rxdata2 = SDIO1->CMD_BUF11<<24 |SDIO1->CMD_BUF10<<16 |SDIO1->CMD_BUF9<<8  | SDIO1->CMD_BUF8;
    rxdata3 = SDIO1->CMD_BUF15<<24 |SDIO1->CMD_BUF14<<16 |SDIO1->CMD_BUF13<<8 | SDIO1->CMD_BUF12;
    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);
    uart_printf("rxdata2 = %x.\n",rxdata2);
    uart_printf("rxdata3 = %x.\n",rxdata3);
    
    n = 100;
    while(n--);
//======================================================
//cmd 3 RCA  :得到RCA,后续传输需要
//======================================================
    CMD_Send(3,0);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD3 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    uart_printf("RCA = %x.\n",(unsigned int)rxdata0>>16);		
    
    rca = (unsigned int)rxdata0>>16;
		
    n = 100;
    while(n--);

		
//======================================================
//cmd 9 + RCA -> CSD
//======================================================
    CMD_Send(9,rca<<16);

		uart_printf("\nRCA << 16 = %x\n",(unsigned int)rca<<16);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD9 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF7<<24  |SDIO1->CMD_BUF6<<16  |SDIO1->CMD_BUF5<<8  | SDIO1->CMD_BUF4;
    rxdata2 = SDIO1->CMD_BUF11<<24 |SDIO1->CMD_BUF10<<16 |SDIO1->CMD_BUF9<<8  | SDIO1->CMD_BUF8;
    rxdata3  = SDIO1->CMD_BUF15<<24 |SDIO1->CMD_BUF14<<16 |SDIO1->CMD_BUF13<<8 | SDIO1->CMD_BUF12;
    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);
    uart_printf("rxdata2 = %x.\n",rxdata2);
    uart_printf("rxdata3 = %x.\n",rxdata3);
		
    n = 100;
    while(n--);
//======================================================
//cmd 13 status  stand-by 
//======================================================
while(1){	
    CMD_Send(13,rca<<16);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD13 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    
    n = 100;
    while(n--);			

		current_status = (rxdata0>>9) & 0xf;
		error_status   = (rxdata0>>19) & 0x1;
		uart_printf("\r\n current_status = %x.\r\n",current_status);
		uart_printf("\r\n error_status = %x.\r\n",error_status);
		
		if(current_status == 3){
			break;
		}
}		
		
//======================================================
//cmd 4 设置频率
//======================================================
    CMD_Send(4,0x04040000);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD4 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    n = 100;
    while(n--);
		SDIO1->MMC_CTRL    = 0xc3;      //4bit,high speed,1/2 divider	
//======================================================
//cmd 7  
//======================================================
    CMD_Send(7,rca<<16);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD7 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);
		
    n = 100;
    while(n--);		

	
//======================================================
//cmd 13 status   tran mode
//======================================================
while(1){	
    CMD_Send(13,rca<<16);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD13 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    
    n = 100;
    while(n--);			

		current_status = (rxdata0>>9) & 0xf;
		uart_printf("current_status = %x.\n",current_status);
		
		if(current_status == 4){
			break;
		}
}		
//======================================================
//cmd 55 
//======================================================
    CMD_Send(55,rca<<16);
		n = 1000;
    while(n--);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
//           uart_printf("Recieve CMD55 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

//    uart_printf("rxdata0 = %x.\n",rxdata0);
//    uart_printf("rxdata1 = %x.\n",rxdata1);

    
    n = 100;
    while(n--);		
//		
//======================================================
//acmd 6  设置bus宽度
//======================================================
    CMD_Send(6,0x2);  //4bit

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD6 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    
    n = 100;
    while(n--);	

//======================================================
//cmd 16  
//======================================================
    CMD_Send(16,0x200);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD16 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;
    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);
	
		
    n = 100;
    while(n--);		
	
//======================================================
//cmd 17 read data 
//======================================================
//    CMD_Send(17,0x300);

    CMD_Send(17,0x0);		

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD17 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);
		
    n = 100;
    while(n--);		

    complete = SDIO1->BUF_CTL & 0x1;
    uart_printf("\r\n\ncomplete = %d.\r\n\n",complete);
//======================================================
//read data
//======================================================
    SDIO1->BUF_CTL         = 0x020;    //disable dma, read sd card
    SDIO1->MMC_IO          = 0x3;      //!!!read data, auto transfer   
    uart_printf("Wait read data from sd card.\n");

    while(1){                                    //wait FIFO full interrupt
			 n = 100;
       while(n--);		
       if((SDIO1->BUF_CTL & 0x1)){                 //judge which interrupt generation
           uart_printf("Data transmission is completed.\n");
           break;
       }
    }
		
    complete = SDIO1->BUF_CTL & 0x1;
    uart_printf("\r\n\ncomplete = %d.\r\n\n",complete);	
//======================================================
//cmd 12
//======================================================
    CMD_Send(12,0);

    SDIO1->MMC_IO = 0x0c;  //auto only response transfer (48bit)
    while(1){
       if(SDIO1->CLR_MMC_INT & 0x1){             //judge which interrupt generation
           uart_printf("Recieve CMD12 response OK.\n");
           SDIO1->CLR_MMC_INT = 0x1;   //write 1 clear interrup
           break;
       }
    }
		
    rxdata0 = 0;
    rxdata1 = 0;
    rxdata2 = 0;
    rxdata3 = 0;
    rxdata0 = SDIO1->CMD_BUF3<<24  |SDIO1->CMD_BUF2<<16  |SDIO1->CMD_BUF1<<8  | SDIO1->CMD_BUF0;
    rxdata1 = SDIO1->CMD_BUF4;

    uart_printf("rxdata0 = %x.\n",rxdata0);
    uart_printf("rxdata1 = %x.\n",rxdata1);

    uart_printf("Read data from data_buf\n");
    SDIO1->BUF_CTL   =  0x000;    //read buf

    uart_printf("\r\n\r\n");
    for(i = 0;i<128;i++){
			 uart_printf("%x ",SDIO1->DATA_BUF0);
    } 
    uart_printf("\r\n\r\n");

    uart_printf("Read data OK\n");
		
    n = 100;
    while(n--);		
    uart_printf("Finish.\n");
}

参考资料


[1]. SD_Physical_Layer_Spec_Version 2.00.pdf
[2]. Simplified_SDIO_Card_Spec_Version 2.00.pdf

posted @ 2017-06-10 11:48  乔_木  阅读(8948)  评论(0编辑  收藏  举报