娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

歷史上的今天

今天是:2025年03月05日(星期三)

正在發生

2020年03月05日 | 【ARM裸板】Nand Flash編程

發布者:火箭飛人 來源: eefocus關鍵字:ARM裸板  Nand  Flash  編程 手機看文章 掃描二維碼
隨時隨地手機看文章

1.讀芯片ID

1.1 讀芯片ID時序

簡化為4個步驟:


1.使能片選

2.寫命令0x90

3.寫地址0x00

4.讀ID信息

/* 識別NAND FLASH */

void scan_nand_flash(void)

{

   int i;

   //保存讀取ID信息的數組

   unsigned char id_info[5] = {0};


   nand_enable_cs();//使能CS

   nand_write_cmd(0x90);

   nand_write_addr(0x00);


   for(i = 0;i < 5;i++){

    id_info[i] = nand_read_data();

   }

   nand_disable_cs();//禁止CS

   

   printf("Maker  Code: 0x%xrn",id_info[0]);

   printf("Device Code: 0x%xrn",id_info[1]);

   printf("3rd   cycle: 0x%xnr",id_info[2]);

   printf("Page   size: %d KBnr",1  << (id_info[3] & 0x03));//頁大小與id_info[3]最低2位有關

   printf("Block  size: %d KBnr",64 << ((id_info[3] >> 4) & 0x03));//塊大小與id_info[3]第4、5位有關


   printf("5th   cycle: 0x%xnr",id_info[4]);


1.2 由ID數據獲得芯片參數

ID信息的第4字節為0x95

頁大小與id_info[3]最低2位有關,可得頁大小為:2KB

塊大小與id_info[3]第4、5位有關,可得塊大小為:128KB

注意:如果此時燒寫到Nand Flash,并從Nand Flash啟動程序是不會成功的,因為這個bin文件大小已經超過了4K,且現在還沒有實現nand flash的讀函數。


2.讀數據

目標:實現從NAND FLASH中啟動,重定位所有數據至SDRAM,并實現讀取芯片ID數據


2.1 NAND內部結構分析

OOB:out of bank(在bank之外)

由上圖可得:

1Page = 2KB + 64B

1Block = 64 * Pages = 128KB + 4KB

1Device = 2048 * Blocks = 256MB + 8MB

OOB區的作用:因為nand的缺點是會發生“位反轉”,為了解決這個問題,nand中的OOB區,用于校驗數據區的數據是否發生錯誤,當有錯誤時,可以恢復數據。(其本身不存儲數據)

因為OOB中并不存放數據,只是用于校驗數據區是否發生錯誤,因此當CPU讀取Nand Flash第2048個數據,該數據為 Page1中的第0個byte


2.2 地址序列與時序

由地址序列可以看出:發出地址信號共需5個周期,前2個周期發出列地址(Column Address),后3個周期發出行地址(Row Address)

地址線序列有一些位是沒有用到的,其目的也是以后兼容更大芯片的nand falsh

Nand Flash內部結構展開大致如下:

2.3 讀數據流程

1.發出片選信號

2.發出0x00命令

3.發送5個周期的地址(兩個列地址,三個行地址(page))

4.再發送0x30命令

5.等待就緒

6.讀數據

7.禁止片選

2.4 轉換所讀地址的列與頁

將輸入的地址addr轉換為:


列地址(Col Address)

page是定位到哪一個頁,col變量定位的就是在這個頁的偏移量(在這個頁上的第幾列0~2047)

行地址(頁)

因為讀取數據的時候是一次性讀出一頁,因此當給出地址addr之后,每一頁的數據大小是2K,因此我們可以根據地址知道我們讀取的數據是哪一個頁

int col  = addr % 2048;//列地址  addr &(2048-1); 


int page = addr / 2048;//行地址(相當于頁地址)


2.5 NAND等待就緒

當NFSATA[0] = 0時,表示正忙

當NFSATA[0] = 1時,表示就緒

/* 等待NAND就緒 */

void nand_wait_ready(void)

{

while(!(NFSTAT & 0x01));//當NFSATA[0] = 1時,表示就緒

}


2.6 讀取數據函數

/* NAND FLASH讀取數據

 * param:讀取的地址、存放的地址、讀取的長度

 */

void read_nand_data(unsigned int addr,unsigned char *buf,unsigned int len)

{

int i = 0;


/*page是定位到哪一個頁,col變量定位的就是在這個

*頁的偏移量(在這個頁上的第幾列0~2047)

*/

int col  = addr % 2048;//列地址  addr &(2048-1); 


    /* 因為讀取數據的時候是一次性讀出一頁,因此當給出

* 地址addr之后,每一頁的數據大小是2K,因此我們可以

* 根據地址知道我們讀取的數據是哪一個頁

*/

int page = addr / 2048;//行地址(相當于頁地址)


nand_enable_cs();//1.使能CS


while(i < len){

nand_write_cmd(0x00);       //2.發出0x00命令


/* col addr */

nand_write_addr(col & 0xFF);//3.發出地址

nand_write_addr((col >> 8) & 0xFF);  


  /* row/page addr */

    nand_write_addr(page & 0xFF);

    nand_write_addr((page >>  8) & 0xFF);

nand_write_addr((page >> 16) & 0xFF);


nand_write_cmd(0x30);//4.發出0x30命令


        nand_wait_ready(); //5.等待就緒

        /* for循環中有2個條件

         * 1.當讀到頁尾,但還是沒有讀完,說明需要讀取下一頁

         * 2.當已經讀取指定字節數,則不再讀取

         */     

        for(; (col < 2048) && (i < len); col++){//6.讀數據

        buf[i++] = nand_read_data_byte();

        }

        if(i == len){

        break;

        }

        col = 0;

        page++;//指向下一頁

}

nand_disable_cs(); //7.禁止CS

}


2.7 NAND重定位

從Nand Flash啟動,此時片內SRAM的地址對應的就是CPU的0地址,如果從Nand Flash啟動,2440硬件會把nand Flash前4K的數據復制到片內SRAM,如果Nand Flash上的程序大于4K,那后續數據就會丟失,相當于只重定位了前4K的代碼


如何解決上述問題:


1.前提:實現了NAND FLASH讀取數據函數

2.代碼燒寫到NAND FLASH,并從NAND中啟動

3.程序運行到重定位代碼的位置判斷一下,是從Nand Flash啟動還是NOR Flash啟動(通過往0地址寫數據,因為Nand是支持讀寫的,所以讀出的結果和寫的結果一樣,而NOR Flash不能像內存一樣讀寫,因此讀寫的內容是不一致的)

4.如果從NOR Flash啟動,直接使用簡單的重定位代碼就行,如果是Nand Flash啟動,那就是用Nnad Flash的讀函數進行代碼的重定位。

首先判斷從NorFlash or NandFlash中啟動


/* 檢查是否從NorFlash中啟動

 * 方法:寫0x12345678到0地址,在讀取出來,如果得到0x12345678,表示0地址上的內容被修改,即為片內RAM,則為nand啟動

 * 原因:原因:nor不能直接寫入,寫入需要發出一定格式的數據,才能寫入

 * 返回0為nand啟動,返回1為nor啟動

*/

int isBootFromNorFlash(void)

{

volatile unsigned int *p = (volatile unsigned int *)0;

unsigned int val = *p;//暫存[0]上的數據

*p = 0xdeadc0de;//dead code任意值

if(0xdeadc0de == *p){

/* 寫成功,對應nand啟動 */

*p = val;//恢復原來的值

return 0;

}

else{

return 1;

}

}


重定位代碼


/*

 * 將除bss段的全部數據拷貝到sdram中

 * 傳遞形參,原地址src:_start  目標地址dest:__bss_start  長度len:__bss_start-_star

 */

void copy_to_sdram(void)

{

/* 要從lds文件中獲取__code_start、__bss_start

* 然后從0地址把數據復制到__code_start

*/

extern int __code_start,__bss_start; //聲明外部變量


volatile unsigned int *src  = (volatile unsigned int *)0; //flash中0地址 

volatile unsigned int *dest = (volatile unsigned int *)&__code_start; //目標地址:sdram中的0x30000000地址

volatile unsigned int *end  = (volatile unsigned int *)&__bss_start;  //結束地址:bss的起始地址


int len = (int)&__bss_start - (int)&__code_start;//獲取數據總長度


if(isBootFromNorFlash()){//如果從Nor中啟動

while(dest < end){

*dest++ = *src++; //拷貝

}

}

else{//從Nand中啟動,需要先初始化nand,然后重定位代碼

nand_init();

        //從 src 復制到 des ,總共復制len字節,也就是重定位的代碼

read_nand_data((unsigned int)src,(unsigned char *)dest,len);

}

}


2.7 讀數據測試

讀取0地址后160bytes的數據,如果跟.bin文件前160字節數據相同,則讀取成功,否則讀取失敗


/* 測試函數:讀數nand上160bytes數據 

 */

void read_nand_flash(void)

{

int i,j;

unsigned int addr,hex_addr;

unsigned char c,str[16],data[160];

volatile unsigned char *p;


/* 獲得地址 */

printf("*****Enter the address to read:");

addr = get_uint();


read_nand_data(addr,data,160);//獲取到地址上的數據

p = (volatile unsigned char *)data;//p指向data,用于打印data數據


hex_addr = addr;//起始地址

printf("Read Data:rn");

printf("            00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0fnr");

  /* 長度固定為160 bytes */

for(i = 0; i < 10; i++){

printf("0x%08x  ",hex_addr);

//每行打印16個16進制數

for(j = 0; j < 16; j++){

c = *p++;//讀取16個

str[j] = c;//保存字符

//先打印數值

printf("%02x ",c);

}

printf(" | ");

//后打印字符

for(j = 0; j < 16; j++){

if(str[j] < 0x20 || str[j] > 0x7e){//不可視字符,打印‘.’

printf(".");

}

else{

printf("%c",str[j]);

}

}

hex_addr+=16;//換行+16

printf("nr");

}


}

由上測試可知讀取成功


3.擦除

3.1 擦除時序

1.發出片選信號

2.發出0x60命令

3.發送3個行地址(page)

4.再發送0xD0命令

5.等待就緒(等待擦除完成)

6.禁止片選

3.2 地址和參數合法性

由于按塊來擦除(128KB),因此地址和參數都必須是128K的倍數

/* 檢查參數合法性 */

if(addr & (0x1FFFF)){ //128K

printf("Err addr! Please enter an integral multiple of 128Krn");

return -1;

}

if(len & (0x1FFFF)){ //128K

printf("Err len! Please enter an integral multiple of 128Krn");

return -1;

}


3.3 擦除函數

/* NAND FLASH擦除數據

 * param:擦除的起始地址、擦除的長度(byte)

 * ret:失敗-1,成功0

*/

int erase_nand_data(unsigned int addr,unsigned int len)

{

int page = addr / 2048;//行地址


/* 檢查參數合法性 */

if(addr & (0x1FFFF)){ //128K

printf("Err addr! Please enter an integral multiple of 128Krn");

return -1;

}

if(len & (0x1FFFF)){ //128K

printf("Err len! Please enter an integral multiple of 128Krn");

return -1;

}

/* 1.使能CS */

nand_enable_cs();

while(1)

{

page = addr / 2048;//行地址


/* 2.發出0x60命令 */

nand_write_cmd(0x60); 

/* 3.發出地址row/page addr */

nand_page(page);      

/* 4.發出0xD0命令 */

nand_write_cmd(0xD0); 

/* 5.等待就緒(等待擦除完成) */

nand_wait_ready();    


len -= (128*1024);//長度減去一個block

if(0 == len){

break;

}

addr += (128*1024);//指向下一塊

/* 6.禁止CS */

nand_disable_cs();

return 0;

}


3.4 擦除數據測試

/* 擦除測試函數:固定擦除一個1block = 128K

*/

void erase_nand_flash(void)

{

int addr;

unsigned int whichblock;

/* 獲得第幾個Block */

printf("Enter the address of sector to erase: ");

addr = get_uint();


whichblock = addr / (128*1024);


printf("***** block number : [ %d ]rn",whichblock);


/* 提示擦除數據的范圍 */

printf("***** Erase range : 0x%08x - 0x%08xnr",addr,(addr+(128*1024)));

  printf("***** erase ...rn");


  if(erase_nand_data(addr,128*1024) == 0){//如果擦除成功

  printf("***** Erase finished!rn");

  }

  else{

  printf("***** Erase fail!rn");

  }

}

4.寫數據

4.1 寫數據時序

1.發出片選信號

2.發出0x80命令

3.發送5個周期的地址(兩個列地址,三個行地址(page))

4.寫入數據

5.再發送0x10命令

6.等待就緒(等待擦除完成)

7.禁止片選

4.2 寫數據函數

/* NAND FLASH寫入數據

 * param:寫入的地址、數據指針、寫入的長度

 */

void write_nand_data(unsigned int addr,unsigned char *buf,unsigned int len)

{

int i = 0;

int page = addr / 2048;

int col = addr & (2048 - 1);

/* 1.使能CS */

nand_enable_cs();

while(1){

/* 2.發出0x80命令 */

nand_write_cmd(0x80);

/* 3.發出地址 */

nand_col(col);

nand_page(page);

/* 4.寫入數據*/

for(; (col < 2048) && (i < len); ){

nand_write_data_byte(buf[i++]);

}

/* 5.發出0x10命令 */

nand_write_cmd(0x10);

/* 6.等待就緒(等待寫入完成) */

nand_wait_ready();

if(i == len){

break;

}

else{

col = 0;

page++;

}


}

/* 7.禁止CS */

nand_disable_cs();

}


4.3 寫數據測試

此處注意:一般在燒寫數據之前需要對數據進行擦除操作,除非原本的數據全f,否則都需要進行擦除,不然寫入的數據會有問題。


void write_nand_flash(void)

{

unsigned int addr;

unsigned char str[50];

unsigned int len;


/* 獲得第幾個Block */

printf("***** Enter addr to write: ");

addr = get_uint();


printf("***** Enter the string to write: ");

gets(str);

len = strlen(str) + 1;


printf("***** write range : 0x%08x - 0x%08xrn",addr,(addr + len));

printf("***** writing ...rn");


write_nand_data(addr,str,strlen(str)+1);//strlen不包括結束符'

主站蜘蛛池模板: 新平| 静宁县| 酉阳| 饶平县| 易门县| 翁牛特旗| 曲阳县| 临澧县| 酉阳| 司法| 天台县| 长沙市| 长武县| 秦皇岛市| 福安市| 普宁市| 五大连池市| 大渡口区| 秦皇岛市| 收藏| 乐安县| 南江县| 普安县| 新营市| 连平县| 临沧市| 济宁市| 淳化县| 西畴县| 枣庄市| 通河县| 天祝| 甘谷县| 中山市| 凌源市| 疏勒县| 宁南县| 敦煌市| 信阳市| 法库县| 德令哈市|