• 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

  • 相关阅读:
    UVA 11019 Matrix Matcher ( 二维字符串匹配, AC自动机 || 二维Hash )
    蓝桥杯 修改数组 (巧用并查集)
    luoguP3242 [HNOI2015]接水果
    CF757F Team Rocket Rises Again
    luoguP2597 [ZJOI2012]灾难
    luoguP4103 [HEOI2014]大工程
    luoguP3233 [HNOI2014]世界树
    luoguP2495 [SDOI2011]消耗战
    CF613D Kingdom and its Cities
    51nod 1584 加权约数和
  • 原文地址:https://www.cnblogs.com/OneFri/p/6978283.html
Copyright © 2020-2023  润新知