<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > s3c2440的SD/MMC的應用

          s3c2440的SD/MMC的應用

          作者: 時間:2016-11-19 來源:網(wǎng)絡 收藏

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

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

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

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

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

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

          下面就具體給出一個讀寫SD的測試實例。該段程序是先對SD進行寫操作,然后再從SD中讀取該組數(shù)據(jù),檢查寫入的數(shù)據(jù)和讀取的數(shù)據(jù)是否一致,其中我們利用UART來獲知一些必要的傳輸狀態(tài)。我們只用查詢方式進行數(shù)據(jù)傳輸,并且使用的是塊操作模式。該段程序是針對MMC所編寫,并不適用于SD,但只需做少許改動(在設置相對地址的地方)就可以用于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é)順序為Type B,使能SDCLK輸出
          rSDIFSTA|=1<<16;//FIFO復位
          rSDIBSIZE=0x200;//傳輸數(shù)據(jù)塊大小為512字節(jié)(128字)
          rSDIDTIMER=0x7fffff;//設置數(shù)據(jù)傳輸?shù)某瑫r時間

          flag=1;

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

          //卡的識別階段
          //CMD0GO_IDLE_STATE
          rSDICARG=0x0;//設置CMD0參數(shù)為0
          rSDICCON=(1<<8)|0x40;//無響應,開始傳輸CMD0,命令信息為命令索引值加0x40
          //等待CMD0結束
          tempSta=rSDICSTA;//讀取命令狀態(tài)寄存器
          while((tempSta&0x800)!=0x800)//判斷命令是否結束
          tempSta=rSDICSTA;//沒有結束,則繼續(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;//有響應,開始傳輸CMD1

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

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

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

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

          if( (tempSta&0x1f00) == 0xa00 )//如果命令傳輸沒有錯誤或超時
          {
          rSDICSTA=0xa00;
          break;//退出循環(huán)體
          }
          rSDICSTA=0xF<<9;
          }
          //通過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,設置卡的相對地址
          while(flag)
          {
          rSDICARG=1<<16;//設置CMD3參數(shù),即相對地址,為1
          rSDICCON=(0x1<<9)|(0x1<<8)|0x43;//等待響應,開始傳輸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;//重新設置SDI的傳輸頻率,約為16MHz

          //CMD13SEND_STATUS
          //檢查當前狀態(tài)是否為待機狀態(tài),否則等待直到變?yōu)榇龣C狀態(tài)為止
          while(flag)
          {
          rSDICARG=1<<16;//設置CMD13參數(shù),即相對地址
          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,把當前狀態(tài)從待機狀態(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
          //檢查當前狀態(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)默認就是1位總線寬,所以在這里無需改動數(shù)據(jù)總線寬度

          //為數(shù)據(jù)的讀寫,準備緩存數(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復位

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

          //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內存數(shù)據(jù)
          i=0;
          while(i<128*block)
          {
          //檢查FIFO狀態(tài)
          tempSta=rSDIFSTA;
          if((tempSta&0x2000)==0x2000)//FIFO沒有滿
          {
          rSDIDAT=*Tx_buffer++;
          i++;
          }
          }

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

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

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

          //CMD12STOP_TRANSMISSION,結束傳輸,回到傳輸狀態(tài)
          while(flag)
          {
          rSDIDCON=(1<<18)|(1<<17)|(0<<16)|(1<<14)|(1<<12)|(block<<0);//忙檢查
          rSDICARG=0x0;//CMD12無參數(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ù)傳輸不是正確結束
          {
          flag=0;//清標志,結束SDI傳輸
          }
          rSDIDSTA=0xf4;
          }

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

          //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內存
          while(i<128*block)
          {
          if((rSDIDSTA&0x20)==0x20)//判斷是否超時
          {
          rSDIDSTA=(0x1<<0x5);//清狀態(tài)
          flag=0;//清標志,退出
          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,結束傳輸,回到傳輸狀態(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)
          {
          //比較兩個數(shù)組的內容
          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ā)送一個信息,表示SDI的某種錯誤
          break;
          }
          }
          }

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

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


          rSDICSTA=0x800;//結束SD
          rSDIDCON=0;
          rSDICSTA=0xffff;

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

          while(1)
          ;
          }


          關鍵詞: s3c2440SDMM

          評論


          技術專區(qū)

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();