在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

    
    
    <address id="vxupu"><td id="vxupu"></td></address>

      <pre id="vxupu"><small id="vxupu"></small></pre>
      <dfn id="vxupu"></dfn>
      <div id="vxupu"><small id="vxupu"></small></div>
    1. 新聞中心

      s3c2440對(duì)norflash的操作

      作者: 時(shí)間:2016-11-11 來(lái)源:網(wǎng)絡(luò) 收藏
      norflash和nandflash是應(yīng)用不同技術(shù)而實(shí)現(xiàn)的非易失閃存。它們之間的各自特點(diǎn)在這里就不做介紹了,而只把s3c2440對(duì)norflash的操作做一講解。我們用的norflash為EN29LV160AB,其實(shí)對(duì)各種型號(hào)的norflash進(jìn)行讀寫等操作差別不大。

      本文引用地址:http://www.biyoush.com/article/201611/316866.htm

      對(duì)norflash的操作主要就是讀、寫、擦除和識(shí)別等。EN29LV160AB的數(shù)據(jù)寬度可以是8位字節(jié)型,也可以是16位的字型,它由EN29LV160AB的某一引腳配置實(shí)現(xiàn)的。在這里我們選擇字型。

      對(duì)norflash的讀操作比較簡(jiǎn)單,系統(tǒng)上電后會(huì)自動(dòng)進(jìn)入讀模式,而且也不需要額外的命令來(lái)實(shí)現(xiàn)讀操作。下面的函數(shù)實(shí)現(xiàn)了讀操作:

      U16 read_en29lv160ab(U32 addr)

      {

      return *((volatile U16 *)(addr));

      }

      norflash不僅能夠?qū)崿F(xiàn)硬件復(fù)位,而且可以實(shí)現(xiàn)軟件復(fù)位。軟件復(fù)位的操作是向任一地址寫入復(fù)位命令0xF0。下面的函數(shù)實(shí)現(xiàn)了軟件復(fù)位:

      void reset_en29lv160ab(void)

      {

      *((volatile U16 *)0x0) = 0xf0;

      }

      norflash的擦除操作和寫操作要稍微復(fù)雜一些,它們需要4個(gè)或6個(gè)周期來(lái)完成,每一個(gè)周期都要把相應(yīng)的命令寫入norflash中的某一命令寄存器中。寫操作的過(guò)程為第一個(gè)周期是把命令0xAA寫入地址為0x555的命令寄存器中,第二個(gè)周期是把命令0x55寫入地址為0x2AA命令寄存器中,第三個(gè)周期是把命令0xA0再寫入地址為0x555命令寄存器中,第四個(gè)周期為真正地把要寫入的數(shù)據(jù)寫入到norflash的地址中。下面的函數(shù)實(shí)現(xiàn)了寫操作,其中該函數(shù)的兩個(gè)輸入?yún)?shù)分別為要寫入的數(shù)據(jù)和地址,為了方便,我們事先定義好命令寄存器:

      #define flash_base 0x00000000

      #define CMD_ADDR0 *((volatile U16 *)(0x555<<1+flash_base))

      #define CMD_ADDR1 *((volatile U16 *)(0x2aa<<1+flash_base))

      U8 en29lv160ab_program(U32 addr, U16 dat)

      {

      CMD_ADDR0 = 0xaa;

      CMD_ADDR1 = 0x55;

      CMD_ADDR0 = 0xa0;

      *((volatile U16 *)(addr)) = dat;

      return check_toggle();

      }

      由于我們是把norflash連接到了s3c2440的bank 0上,因此norflash中的地址相對(duì)于s3c2440來(lái)說(shuō)基址為0x00000000。而之所以又把norflash中的地址向左移一位(即乘以2),是因?yàn)槲覀兪前裺3c2440的ADDR1連接到了norflash的A0上的緣故。在該函數(shù)中,我們還調(diào)用了check_toggle函數(shù),它的作用是用于判斷這次操作是否正確,它的原型為:

      U8 check_toggle()

      {

      volatile U16 newtoggle,oldtoggle;

      oldtoggle = *((volatile U16 *)0x0);

      while(1)

      {

      newtoggle = *((volatile U16 *)0x0);

      if((oldtoggle & 0x40)==(newtoggle & 0x40))

      break;

      if(newtoggle & 0x20) //DQ5

      {

      oldtoggle = *((volatile U16 *)0x0);

      newtoggle = *((volatile U16 *)0x0);

      if((oldtoggle & 0x40)==(newtoggle & 0x40))

      break;

      else

      return 0; //錯(cuò)誤

      }

      oldtoggle = newtoggle;

      }

      return 1; //正確

      }

      它的原理是連續(xù)兩次讀取數(shù)據(jù)總線上的數(shù)據(jù),判斷數(shù)據(jù)總線上的第6位數(shù)值(DQ6)是否翻轉(zhuǎn),如果沒(méi)有翻轉(zhuǎn)則正確,否則還要判斷第5位(DQ5),以確定是否是因?yàn)槌瑫r(shí)而引起的翻轉(zhuǎn)。

      寫操作只能使“1”變?yōu)?ldquo;0”,而只有擦除才能使“0”變?yōu)?ldquo;1”。因此在寫之前一定要先擦除。擦除分為塊擦除和整片擦除。塊擦除的過(guò)程為第一個(gè)周期是把命令0xAA寫入地址為0x555的命令寄存器中,第二個(gè)周期是把命令0x55寫入地址為0x2AA命令寄存器中,第三個(gè)周期是把命令0x80再寫入地址為0x555命令寄存器中,第四個(gè)周期是把命令0xAA寫入地址為0x555的命令寄存器中,第五個(gè)周期是把命令0x55再寫入地址為0x2AA命令寄存器中,第六個(gè)周期是把命令0x30寫入要擦除塊的首地址內(nèi)。下面的函數(shù)為塊擦除,其中輸入?yún)?shù)為要擦除塊的首地址:

      U8 en29lv160ab_sector_erase(U32 section_addr)

      {

      CMD_ADDR0 = 0xaa;

      CMD_ADDR1 = 0x55;

      CMD_ADDR0 = 0x80;

      CMD_ADDR0 = 0xaa;

      CMD_ADDR1 = 0x55;

      *((volatile U16 *)(section_addr)) = 0x30;

      return check_toggle();

      }

      對(duì)norflash另一個(gè)比較常用的操作是讀取芯片的ID。讀取廠商ID的過(guò)程為第一個(gè)周期是把命令0xAA寫入地址為0x555的命令寄存器中,第二個(gè)周期是把命令0x55寫入地址為0x2AA命令寄存器中,第三個(gè)周期是把命令0x90再寫入地址為0x555命令寄存器中,第四個(gè)周期為讀取地址為0x100中的內(nèi)容,即廠商ID(0x1C)。讀取設(shè)備ID的過(guò)程的前三個(gè)周期與讀取廠商ID相同,第四個(gè)周期是讀取地址為0x01中的內(nèi)容,即設(shè)備ID(0x2249)。下面的函數(shù)為讀取芯片ID:

      U32 get_en29lv160ab_id(void)

      {

      U32 temp=0;

      CMD_ADDR0 = 0xaa;

      CMD_ADDR1 = 0x55;

      CMD_ADDR0 = 0x90;

      temp = (*(volatile unsigned short *)(flash_base+ (0x100<<1)))<<16;

      temp |= *(volatile unsigned short *)(flash_base + (1<<1));

      return temp;

      }

      下面的程序?qū)崿F(xiàn)了對(duì)一塊區(qū)域進(jìn)行擦除,寫入,并讀出的操作,判斷寫入的數(shù)據(jù)是否與讀出的數(shù)據(jù)相同:

      …… ……

      U16 buffer[1024];

      char cmd;

      …… ……

      void test_en29lv160ab(void)

      {

      U32 temp;

      U8 sta;

      int i;

      for(i=0;i<1024;i++)

      buffer[i]=2*i+1;

      //讀ID

      temp = get_en29lv160ab_id();

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)((temp&0xff000000)>>24);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)((temp&0x00ff0000)>>16);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)((temp&0x0000ff00)>>8);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)((temp&0x000000ff));

      reset_en29lv160ab(); //這里一定要復(fù)位

      delay(100);

      //擦除塊33

      sta=en29lv160ab_sector_erase(0xf0000);

      if(sta == 0)

      {

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=0xaf; //擦除出錯(cuò)

      }

      else

      {

      for(i=0;i<1024;i++)

      {

      sta = en29lv160ab_program(0xf0000+(i<<1),buffer[i]); //寫

      if(sta == 0) //寫出錯(cuò)

      {

      while(!(rUTRSTAT0 & 0x2));

      rUTXH0=0xbf;

      break;

      }

      delay(200);

      }

      if(sta == 1)

      {

      for(i=0;i<1024;i++)

      {

      if(read_en29lv160ab(0xf0000+(i<<1))!=buffer[i]) //讀出錯(cuò)

      {

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=0xcf;

      sta = 3;

      break;

      }

      }

      if(sta !=3) //全部操作都正確

      {

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=0x66;

      }

      }

      }

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=0x88; //結(jié)束

      }

      //簡(jiǎn)單測(cè)試CFI

      void test_en29lv160ab_CFI(void)

      {

      U16 temp;

      *((volatile U16 *)(0x55<<1+flash_base))=0x98; //CFI命令

      temp = (*(volatile unsigned short *)(flash_base+ (0x10<<1)));

      //while(!(rUTRSTAT0 & 0x2)) ;

      //rUTXH0=(U8)((temp&0xff00)>>8);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)(temp&0x00ff);

      temp = (*(volatile unsigned short *)(flash_base+ (0x11<<1)));

      //while(!(rUTRSTAT0 & 0x2)) ;

      //rUTXH0=(U8)((temp&0xff00)>>8);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)(temp&0x00ff);

      temp = (*(volatile unsigned short *)(flash_base+ (0x12<<1)));

      //while(!(rUTRSTAT0 & 0x2)) ;

      //rUTXH0=(U8)((temp&0xff00)>>8);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)(temp&0x00ff);

      temp = (*(volatile unsigned short *)(flash_base+ (0x13<<1)));

      //while(!(rUTRSTAT0 & 0x2)) ;

      //rUTXH0=(U8)((temp&0xff00)>>8);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)(temp&0x00ff);

      temp = (*(volatile unsigned short *)(flash_base+ (0x14<<1)));

      //while(!(rUTRSTAT0 & 0x2)) ;

      //rUTXH0=(U8)((temp&0xff00)>>8);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)(temp&0x00ff);

      temp = (*(volatile unsigned short *)(flash_base+ (0x15<<1)));

      //while(!(rUTRSTAT0 & 0x2)) ;

      //rUTXH0=(U8)((temp&0xff00)>>8);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)(temp&0x00ff);

      temp = (*(volatile unsigned short *)(flash_base+ (0x16<<1)));

      //while(!(rUTRSTAT0 & 0x2)) ;

      //rUTXH0=(U8)((temp&0xff00)>>8);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)(temp&0x00ff);

      temp = (*(volatile unsigned short *)(flash_base+ (0x17<<1)));

      //while(!(rUTRSTAT0 & 0x2)) ;

      //rUTXH0=(U8)((temp&0xff00)>>8);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)(temp&0x00ff);

      temp = (*(volatile unsigned short *)(flash_base+ (0x18<<1)));

      //while(!(rUTRSTAT0 & 0x2)) ;

      //rUTXH0=(U8)((temp&0xff00)>>8);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)(temp&0x00ff);

      temp = (*(volatile unsigned short *)(flash_base+ (0x19<<1)));

      //while(!(rUTRSTAT0 & 0x2)) ;

      //rUTXH0=(U8)((temp&0xff00)>>8);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)(temp&0x00ff);

      temp = (*(volatile unsigned short *)(flash_base+ (0x1a<<1)));

      //while(!(rUTRSTAT0 & 0x2)) ;

      //rUTXH0=(U8)((temp&0xff00)>>8);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)(temp&0x00ff);

      }

      void __irq uartISR(void)

      {

      char ch;

      rSUBSRCPND |= 0x1;

      rSRCPND |= 0x1<<28;

      rINTPND |= 0x1<<28;

      ch=rURXH0;

      switch(ch)

      {

      case 0x11: //get ID

      cmd = 1;

      break;

      case 0x66: //test CFI

      cmd = 6;

      break;

      case 0x77: //test norflash

      cmd = 7;

      break;

      }

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=ch;

      }

      void Main(void)

      {

      U32 temp;

      int i;

      //uart0 port

      rGPHCON = 0x00faaa;

      rGPHUP = 0x7ff;

      //init uart0

      rULCON0 = 0x3;

      rUCON0 = 0x5;

      rUFCON0 = 0;

      rUMCON0 = 0;

      rUBRDIV0 = 26;

      rSRCPND = (0x1<<19)|(0x1<<28);

      rSUBSRCPND = 0x1;

      rINTPND = (0x1<<19)|(0x1<<28);

      rINTSUBMSK = ~(0x1);

      rINTMSK = ~((0x1<<19)|(0x1<<28));

      pISR_UART0 = (U32)uartISR;

      cmd = 0;

      while(1)

      {

      switch(cmd)

      {

      case 1: //讀ID

      cmd = 0;

      temp = get_en29lv160ab_id();

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)((temp&0xff000000)>>24);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)((temp&0x00ff0000)>>16);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)((temp&0x0000ff00)>>8);

      while(!(rUTRSTAT0 & 0x2)) ;

      rUTXH0=(U8)((temp&0x000000ff));

      reset_en29lv160ab();

      break;

      case 0x7:

      cmd = 0;

      test_en29lv160ab();

      break;

      case 0x6:

      cmd = 0;

      test_en29lv160ab_CFI();

      reset_en29lv160ab();

      break;

      }

      }

      }



      關(guān)鍵詞: s3c2440norflas

      評(píng)論


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

      關(guān)閉