新聞中心

        s3c2440的SD/MMC的應(yīng)用

        作者: 時(shí)間:2016-11-19 來(lái)源:網(wǎng)絡(luò) 收藏

        SD(全名為Secure Digital Memory Card,安全數(shù)碼卡),是一種存儲(chǔ)卡的標(biāo)準(zhǔn),它被廣泛地用于便攜式設(shè)備上,如數(shù)碼相機(jī)、個(gè)人數(shù)字助理(PDA)和多媒體播放器等。它的技術(shù)是基于MMC(MultiMedia Card)格式,因此SD兼容MMC。

        s3c2440集成了SD控制器,可以方便地讀寫SD、MMC和對(duì)SDIO進(jìn)行操作。在這里,我們只研究對(duì)SD/MMC的操作。

        要想能夠使s3c2440正確讀寫SD/MMC,就首先要清楚SD的規(guī)范協(xié)議,由于SD兼容MMC,所以兩者的協(xié)議差別不大。SD的協(xié)議較為繁瑣,下面只簡(jiǎn)略介紹最基本的內(nèi)容:

        對(duì)SD進(jìn)行操作包括兩個(gè)階段:卡的識(shí)別和卡的數(shù)據(jù)傳輸。主機(jī)通過(guò)各種命令對(duì)SD進(jìn)行操作,絕大多數(shù)命令都需要SD進(jìn)行應(yīng)答響應(yīng)。在卡的識(shí)別階段,用到的命令只有CMD1(得到主機(jī)的操作電壓)、CMD2(得到卡的識(shí)別碼)和CMD3(配置或得到卡的相對(duì)地址),其中也可以使用CMD0命令使卡進(jìn)入空閑狀態(tài)。CMD1只能用于MMC,SD要用ACMD41輔助命令。在正確配置完該階段后,卡進(jìn)入待機(jī)狀態(tài)。在卡的數(shù)據(jù)傳輸階段可以完成對(duì)卡內(nèi)存地址的讀寫等操作。

        卡內(nèi)還配備了幾個(gè)寄存器,主要有OCR寄存器,用于配置操作電壓范圍,使用命令CMD1可以獲得;CID寄存器,用于得到卡的基本信息,使用命令CMD2或CMD10可以獲得;CSD寄存器,用于提供卡特性信息,使用CMD9可以獲得;RCA寄存器,保存卡的相對(duì)地址。另外在卡應(yīng)答響應(yīng)信息中,會(huì)包括卡的狀態(tài)信息,主機(jī)可以利用該信息獲知卡的各種狀態(tài),以便進(jìn)一步操作。

        s3c2440只要按照SD的協(xié)議去操作,就能正確讀寫SD。在初始化階段,要配置SDICON寄存器以及負(fù)責(zé)傳輸頻率的SDIPRE寄存器,并且還要等待一段時(shí)間,以保證初始化正確執(zhí)行。在命令傳輸階段,SDICmdArg寄存器負(fù)責(zé)傳輸命令參數(shù),SDICmgCon寄存器負(fù)責(zé)傳輸命令索引值,通過(guò)SDICmdSta寄存器可以獲知命令傳輸過(guò)程中的各種狀態(tài),命令的響應(yīng)信息存儲(chǔ)在SDIRSPn中。在數(shù)據(jù)傳輸階段,SDIDTimer寄存器可以設(shè)置數(shù)據(jù)傳輸?shù)某瑫r(shí)時(shí)間,SDIBSize寄存器用于設(shè)置數(shù)據(jù)傳輸塊的大小,寄存器SDIDatCon和SDIDatSta用于數(shù)據(jù)傳輸?shù)目刂坪蜖顟B(tài),而數(shù)據(jù)是通過(guò)SDIDAT寄存器利用內(nèi)部的FIFO來(lái)進(jìn)行傳輸?shù)?,其中寄存器SDIFSTA用于獲知FIFO的各種狀態(tài)。

        下面就具體給出一個(gè)讀寫SD的測(cè)試實(shí)例。該段程序是先對(duì)SD進(jìn)行寫操作,然后再?gòu)腟D中讀取該組數(shù)據(jù),檢查寫入的數(shù)據(jù)和讀取的數(shù)據(jù)是否一致,其中我們利用UART來(lái)獲知一些必要的傳輸狀態(tài)。我們只用查詢方式進(jìn)行數(shù)據(jù)傳輸,并且使用的是塊操作模式。該段程序是針對(duì)MMC所編寫,并不適用于SD,但只需做少許改動(dòng)(在設(shè)置相對(duì)地址的地方)就可以用于SD。


        unsigned int *Tx_buffer;
        unsigned int *Rx_buffer;

        …………

        void Main(void)
        {
        int i;
        int tempSta;
        int block=16;//傳輸數(shù)據(jù)塊大小
        char flag;
        int response;

        //UART0的基本配置
        …………

        //SDI端口配置
        rGPEUP = 0xf83f;//SDCMD, SDDAT[3:0]上拉有效.
        rGPECON = 0xaaa<<10;//SDCMD, SDDAT[3:0], SDCLK

        //初始化SDI
        rSDIPRE=124;//SDI初始階段傳輸頻率為400KHz
        rSDICON=(3<<4)|1;//SDCLK為MMC類型,字節(jié)順序?yàn)門ype B,使能SDCLK輸出
        rSDIFSTA|=1<<16;//FIFO復(fù)位
        rSDIBSIZE=0x200;//傳輸數(shù)據(jù)塊大小為512字節(jié)(128字)
        rSDIDTIMER=0x7fffff;//設(shè)置數(shù)據(jù)傳輸?shù)某瑫r(shí)時(shí)間

        flag=1;

        for(i=0;i<0x1000;i++)
        ;//等待74個(gè)SDCLK

        //卡的識(shí)別階段
        //CMD0GO_IDLE_STATE
        rSDICARG=0x0;//設(shè)置CMD0參數(shù)為0
        rSDICCON=(1<<8)|0x40;//無(wú)響應(yīng),開(kāi)始傳輸CMD0,命令信息為命令索引值加0x40
        //等待CMD0結(jié)束
        tempSta=rSDICSTA;//讀取命令狀態(tài)寄存器
        while((tempSta&0x800)!=0x800)//判斷命令是否結(jié)束
        tempSta=rSDICSTA;//沒(méi)有結(jié)束,則繼續(xù)等待
        rSDICSTA=tempSta;//清命令狀態(tài)
        rSDICSTA=0xa00;//

        //CMD1CEND_OP_COND
        for(i=0;i<200;i++)
        {
        rSDICARG=0xff8000;//CMD1參數(shù):2.7V~3.6V
        rSDICCON=(0x1<<9)|(0x1<<8)|0x41;//有響應(yīng),開(kāi)始傳輸CMD1

        //檢查命令狀態(tài)
        tempSta=rSDICSTA;
        while( !( ((tempSta&0x200)==0x200) | ((tempSta&0x400)==0x400) ))
        tempSta=rSDICSTA;//檢查命令傳輸是否結(jié)束或超時(shí)

        if( (tempSta&0xf00) == 0xa00 )//如果命令傳輸沒(méi)有錯(cuò)誤或超時(shí)
        {
        if((rSDIRSP0>>16)==0x80ff)//OCR內(nèi)容正確,且不忙
        {
        rSDICSTA=0xa00;//清命令狀態(tài)
        break;//退出循環(huán)
        }
        }
        }

        if(i>190)//沒(méi)有檢測(cè)到MMC
        {
        flag=0;//清標(biāo)志
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=0x66;//向UART0發(fā)送信息,表示無(wú)MMC
        rGPBDAT =~0x1e0;//亮4個(gè)LED
        }
        else//檢測(cè)到了MMC
        {
        rSDICSTA=0xa00;//清命令狀態(tài)

        //CMD2ALL_SEND_CID
        while(flag)
        {
        rSDICARG=0x0;//CMD2無(wú)需參數(shù)
        rSDICCON=(0x1<<10)|(0x1<<9)|(0x1<<8)|0x42;//有128位長(zhǎng)響應(yīng),開(kāi)始傳輸CMD2
        tempSta=rSDICSTA;
        while(!(((tempSta&0x200)==0x200) | ((tempSta&0x400)==0x400)))
        tempSta=rSDICSTA;//檢查命令傳輸是否結(jié)束或超時(shí)

        if( (tempSta&0x1f00) == 0xa00 )//如果命令傳輸沒(méi)有錯(cuò)誤或超時(shí)
        {
        rSDICSTA=0xa00;
        break;//退出循環(huán)體
        }
        rSDICSTA=0xF<<9;
        }
        //通過(guò)UART0輸出MMC的CID信息,一共128位
        //在這里得到的CID信息為15 00 00 30 30 30 30 30 30 11 F1 01 11 28 29 ED
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=0xee;
        response=rSDIRSP0;
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response>>24);
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response>>16);
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response>>8);
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response);

        response=rSDIRSP1;
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response>>24);
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response>>16);
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response>>8);
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response);

        response=rSDIRSP2;
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response>>24);
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response>>16);
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response>>8);
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response);

        response=rSDIRSP3;
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response>>24);
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response>>16);
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response>>8);
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=(char)(response);

        //CMD3SET_RELATIVE_ADDR,設(shè)置卡的相對(duì)地址
        while(flag)
        {
        rSDICARG=1<<16;//設(shè)置CMD3參數(shù),即相對(duì)地址,為1
        rSDICCON=(0x1<<9)|(0x1<<8)|0x43;//等待響應(yīng),開(kāi)始傳輸CMD3

        tempSta=rSDICSTA;
        while( !( ((tempSta&0x200)==0x200) | ((tempSta&0x400)==0x400) ))
        tempSta=rSDICSTA;

        if( (tempSta&0x1f00) == 0xa00 )
        {
        rSDICSTA=0xa00;
        break;
        }
        rSDICSTA=0xF<<9;
        }

        //卡的數(shù)據(jù)傳輸階段
        rSDIPRE=2;//重新設(shè)置SDI的傳輸頻率,約為16MHz

        //CMD13SEND_STATUS
        //檢查當(dāng)前狀態(tài)是否為待機(jī)狀態(tài),否則等待直到變?yōu)榇龣C(jī)狀態(tài)為止
        while(flag)
        {
        rSDICARG=1<<16;//設(shè)置CMD13參數(shù),即相對(duì)地址
        rSDICCON= (0x1<<9)|(0x1<<8)|0x4d;

        tempSta=rSDICSTA;
        while( !( ((tempSta&0x200)==0x200) | ((tempSta&0x400)==0x400) ))
        tempSta=rSDICSTA;

        if( (tempSta&0x1f00) == 0xa00 )
        {
        rSDICSTA=0xa00;
        if((rSDIRSP0 & 0x1e00)==0x600)
        break;
        }
        rSDICSTA=0xF<<9;
        }

        //CMD7SELECT/DESELECT_CARD,把當(dāng)前狀態(tài)從待機(jī)狀態(tài)變?yōu)閭鬏敔顟B(tài)
        while(flag)
        {
        rSDICARG=1<<16;
        rSDICCON= (0x1<<9)|(0x1<<8)|0x47;

        tempSta=rSDICSTA;
        while( !( ((tempSta&0x200)==0x200) | ((tempSta&0x400)==0x400) ))
        tempSta=rSDICSTA;

        if( ((tempSta&0x1f00) == 0xa00) )// Check no error and tranfro state
        {
        rSDICSTA=0xa00;
        break;
        }
        rSDICSTA=0xF<<9;
        }

        //CMD13SEND_STATUS
        //檢查當(dāng)前狀態(tài)是否為傳輸狀態(tài),否則等待直到變?yōu)閭鬏敔顟B(tài)為止
        while(flag)
        {
        rSDICARG=1<<16;
        rSDICCON= (0x1<<9)|(0x1<<8)|0x4d;

        tempSta=rSDICSTA;
        while( !( ((tempSta&0x200)==0x200) | ((tempSta&0x400)==0x400) ))
        tempSta=rSDICSTA;

        if( (tempSta&0x1f00) == 0xa00 )
        {
        rSDICSTA=0xa00;
        if((rSDIRSP0 & 0x1e00)==0x800)
        break;
        }
        rSDICSTA=0xF<<9;//clear all
        }

        //由于MMC是1位的總線寬,而系統(tǒng)默認(rèn)就是1位總線寬,所以在這里無(wú)需改動(dòng)數(shù)據(jù)總線寬度

        //為數(shù)據(jù)的讀寫,準(zhǔn)備緩存數(shù)組
        Tx_buffer=(unsigned int *)0x31000000;//發(fā)送數(shù)組
        for(i=0;i<2048;i++)//512(一塊數(shù)據(jù)的字節(jié)數(shù))×16(數(shù)據(jù)塊)=2048×4
        *(Tx_buffer+i)=2*i+1;//寫值

        Rx_buffer=(unsigned int *)0x31800000;//接收數(shù)組
        for(i=0;i<2048;i++)
        *(Rx_buffer+i)=0;//清零

        //寫數(shù)據(jù),查詢方式
        rSDIFSTA |= 1<<16;//FIFO復(fù)位

        rSDIDCON=(2<<22)|(1<<20)|(1<<17)|(1<<14)|(3<<12)|(block<<0);//字、塊發(fā)送
        rSDICARG=0;//寫入MMC的內(nèi)存首地址

        //CMD25WRITE_MULTIPLE_BLOCK,多塊寫入命令
        while(flag)
        {
        rSDICCON=(0x1<<9)|(0x1<<8)|0x59;

        tempSta=rSDICSTA;
        while( !( ((tempSta&0x200)==0x200) | ((tempSta&0x400)==0x400) ))
        tempSta=rSDICSTA;

        if( (tempSta&0x1f00) == 0xa00 )
        {
        rSDICSTA=0xa00;
        break;
        }
        rSDICSTA=0xF<<9;
        }

        //寫入MMC內(nèi)存數(shù)據(jù)
        i=0;
        while(i<128*block)
        {
        //檢查FIFO狀態(tài)
        tempSta=rSDIFSTA;
        if((tempSta&0x2000)==0x2000)//FIFO沒(méi)有滿
        {
        rSDIDAT=*Tx_buffer++;
        i++;
        }
        }

        //判斷數(shù)據(jù)是否發(fā)送正確
        //檢查數(shù)據(jù)狀態(tài)
        tempSta=rSDIDSTA;
        while( !( ((tempSta&0x10)==0x10) | ((tempSta&0x20)==0x20) ))
        tempSta=rSDIDSTA;//判斷數(shù)據(jù)傳輸是否結(jié)束或超時(shí)

        if( (tempSta&0xfc) != 0x10 )//數(shù)據(jù)傳輸沒(méi)有結(jié)束
        {
        rSDIDSTA=0xec;//清狀態(tài)
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=0x88;//向UART0發(fā)送一個(gè)信息,表示SDI的某種錯(cuò)誤
        flag=0;//清標(biāo)志,結(jié)束SDI的傳輸
        }

        if(flag)
        {
        rSDIDCON=rSDIDCON&~(7<<12);//清數(shù)據(jù)傳輸
        rSDIDSTA=0x10;
        }

        //CMD12STOP_TRANSMISSION,結(jié)束傳輸,回到傳輸狀態(tài)
        while(flag)
        {
        rSDIDCON=(1<<18)|(1<<17)|(0<<16)|(1<<14)|(1<<12)|(block<<0);//忙檢查
        rSDICARG=0x0;//CMD12無(wú)參數(shù)
        rSDICCON=(0x1<<9)|(0x1<<8)|0x4c;

        tempSta=rSDICSTA;
        while( !( ((tempSta&0x200)==0x200) | ((tempSta&0x400)==0x400) ))
        tempSta=rSDICSTA;

        if( (tempSta&0x1f00) == 0xa00 )
        {
        rSDICSTA=0xa00;
        break;
        }
        rSDICSTA=0xF<<9;
        }

        //檢查是否忙
        if(flag)
        {
        tempSta=rSDIDSTA;
        while( !( ((tempSta&0x08)==0x08) | ((tempSta&0x20)==0x20) ))
        tempSta=rSDIDSTA;

        if( (tempSta&0xfc) != 0x08 )//數(shù)據(jù)傳輸不是正確結(jié)束
        {
        flag=0;//清標(biāo)志,結(jié)束SDI傳輸
        }
        rSDIDSTA=0xf4;
        }

        //讀取MMC內(nèi)存數(shù)據(jù)
        if(flag)
        {
        rSDIFSTA|=(1<<16);//FIFO復(fù)位
        rSDIDCON=(2<<22)|(1<<19)|(1<<17)|(1<<14)|(2<<12)|(block<<0);//字、塊接收
        rSDICARG=0;//設(shè)置讀取MMC的內(nèi)存首地址,要與寫入時(shí)的首地址一致
        }

        //CMD18READ_MULTIPLE_BLOCK,多塊讀命令
        while(flag)
        {
        rSDICCON=(0x1<<9)|(0x1<<8)|0x52;

        tempSta=rSDICSTA;
        while( !( ((tempSta&0x200)==0x200) | ((tempSta&0x400)==0x400) ))
        tempSta=rSDICSTA;

        if( (tempSta&0x1f00) == 0xa00 )
        {
        rSDICSTA=0xa00;
        break;
        }
        rSDICSTA=0xF<<9;//clear all
        }

        if(flag)
        {
        i=0;
        //讀MMC內(nèi)存
        while(i<128*block)
        {
        if((rSDIDSTA&0x20)==0x20)//判斷是否超時(shí)
        {
        rSDIDSTA=(0x1<<0x5);//清狀態(tài)
        flag=0;//清標(biāo)志,退出
        break;
        }
        tempSta=rSDIFSTA;
        if((tempSta&0x1000)==0x1000)//檢查FIFO是否為空
        {
        *Rx_buffer++=rSDIDAT;
        i++;
        }
        }

        rSDIDCON=rSDIDCON&~(7<<12);//清數(shù)據(jù)傳輸
        rSDIFSTA &= 0x200;//清FIFO
        rSDIDSTA=0x10;//清數(shù)據(jù)狀態(tài)
        }

        //CMD12STOP_TRANSMISSION,結(jié)束傳輸,回到傳輸狀態(tài)
        while(flag)
        {
        rSDICARG=0x0;
        rSDICCON=(0x1<<9)|(0x1<<8)|0x4c;

        tempSta=rSDICSTA;
        while( !( ((tempSta&0x200)==0x200) | ((tempSta&0x400)==0x400) ))
        tempSta=rSDICSTA;

        if( (tempSta&0x1f00) == 0xa00 )
        {
        rSDICSTA=0xa00;
        break;
        }
        rSDICSTA=0xF<<9;//clear all
        }

        if(flag)
        {
        //比較兩個(gè)數(shù)組的內(nèi)容
        Tx_buffer=(unsigned int *)0x31000000;
        Rx_buffer=(unsigned int *)0x31800000;

        for(i=0;i<128*block;i++)
        {
        if(Rx_buffer[i] != Tx_buffer[i])//有不相等的情況
        {
        while(!(rUTRSTAT0 & 0x2));
        rUTXH0=0x44;//向UART0發(fā)送一個(gè)信息,表示SDI的某種錯(cuò)誤
        break;
        }
        }
        }

        //CMD7SELECT/DESELECT_CARD,把當(dāng)前狀態(tài)從傳輸狀態(tài)變?yōu)榇龣C(jī)狀態(tài)
        while(flag)
        {
        rSDICARG=0<<16;//不帶參數(shù)
        rSDICCON= (0x1<<8)|0x47;//無(wú)回復(fù)

        tempSta=rSDICSTA;
        if( (tempSta&0x800) != 0x800 )
        {
        rSDICSTA=0xa00;
        break;
        }
        rSDICSTA=0xF<<9;
        }


        rSDICSTA=0x800;//結(jié)束SD
        rSDIDCON=0;
        rSDICSTA=0xffff;

        if(flag)
        rGPBDAT = ~0x60;//SD數(shù)據(jù)傳輸正確,亮2個(gè)LED
        else
        rGPBDAT =~0xe0;//SD數(shù)據(jù)傳輸失敗,亮3個(gè)LED
        }

        while(1)
        ;
        }


        關(guān)鍵詞: s3c2440SDMM

        評(píng)論


        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 沾化县| 鲜城| 高尔夫| 商水县| 辰溪县| 安顺市| 霍州市| 铁岭县| 阿克苏市| 鄂尔多斯市| 淳化县| 闽侯县| 兴化市| 铁岭县| 榆社县| 乌拉特前旗| 库车县| 麻阳| 昭苏县| 秦安县| 日土县| 开远市| 阳东县| 郯城县| 吉木萨尔县| 剑河县| 江山市| 棋牌| 苍山县| 岳池县| 缙云县| 巫山县| 高尔夫| 临猗县| 舞钢市| 宜宾市| 清涧县| 镇安县| 青河县| 微山县| 奉化市|