zoukankan      html  css  js  c++  java
  • 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...
    ");
    
        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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",rxdata1);
    		
       if(!(rxdata0>>30 & 0x1)){  //判断CCS,CCS=1为高容量卡
       	  uart_printf("CCS = 0
    ");
       }
       else{
       	  uart_printf("CCS = 1   High Capacity SD Memory Card
    ");			
       }
         		
       if(!(rxdata0>>31 & 0x1)){  //判断电压设置,上电是否完成
       	  uart_printf("Finished = 0
    ");
       }
       else{
       	  uart_printf("Finished = 1
    ");			
       }
        
        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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",rxdata1);
        uart_printf("rxdata2 = %x.
    ",rxdata2);
        uart_printf("rxdata3 = %x.
    ",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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",rxdata1);
    
        uart_printf("RCA = %x.
    ",(unsigned int)rxdata0>>16);		
        
        rca = (unsigned int)rxdata0>>16;
    		
        n = 100;
        while(n--);
    
    		
    //======================================================
    //cmd 9 + RCA -> CSD
    //======================================================
        CMD_Send(9,rca<<16);
    
    		uart_printf("
    RCA << 16 = %x
    ",(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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",rxdata1);
        uart_printf("rxdata2 = %x.
    ",rxdata2);
        uart_printf("rxdata3 = %x.
    ",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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",rxdata1);
    
        
        n = 100;
        while(n--);			
    
    		current_status = (rxdata0>>9) & 0xf;
    		error_status   = (rxdata0>>19) & 0x1;
    		uart_printf("
     current_status = %x.
    ",current_status);
    		uart_printf("
     error_status = %x.
    ",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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",rxdata1);
    
        
        n = 100;
        while(n--);			
    
    		current_status = (rxdata0>>9) & 0xf;
    		uart_printf("current_status = %x.
    ",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.
    ");
               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.
    ",rxdata0);
    //    uart_printf("rxdata1 = %x.
    ",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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",rxdata1);
    		
        n = 100;
        while(n--);		
    
        complete = SDIO1->BUF_CTL & 0x1;
        uart_printf("
    
    complete = %d.
    
    ",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.
    ");
    
        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.
    ");
               break;
           }
        }
    		
        complete = SDIO1->BUF_CTL & 0x1;
        uart_printf("
    
    complete = %d.
    
    ",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.
    ");
               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.
    ",rxdata0);
        uart_printf("rxdata1 = %x.
    ",rxdata1);
    
        uart_printf("Read data from data_buf
    ");
        SDIO1->BUF_CTL   =  0x000;    //read buf
    
        uart_printf("
    
    ");
        for(i = 0;i<128;i++){
    			 uart_printf("%x ",SDIO1->DATA_BUF0);
        } 
        uart_printf("
    
    ");
    
        uart_printf("Read data OK
    ");
    		
        n = 100;
        while(n--);		
        uart_printf("Finish.
    ");
    }
    

    参考资料


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

  • 相关阅读:
    Linux 学习 step by step (1)
    ubuntu server nginx 安装与配置
    ubuntu server samba服务器配置
    iOS app集成支付宝支付流程及后台php订单签名处理
    mac 连接windows 共享内容
    linux 文件查找,which,whereis,locate,find
    ubuntu server vsftpd 虚拟用户及目录
    ubuntu server 安装 mantis bug tracker 中文配置
    ubuntu server vsftpd 匿名用户上传下载及目录设置
    linux 用户管理,用户权限管理,用户组管理
  • 原文地址:https://www.cnblogs.com/OneFri/p/6978283.html
Copyright © 2011-2022 走看看