K9F2G08X0A共有2048個Block(塊), 每個Block含有 64 Page(頁), 每個Page含有2k byte的正常存盤空間以及64 byte的校驗空間 .
總空間 = 2048 * 64 * (2 * 1024 + 64) byte
實際存盤空間 = 2048 * 64 * 2 * 1024 byte
2. 引腳定義及接法
3. 尋址方式
列地址: 進行 Block 和 Page 尋址
行地址: 進行 Page 內尋址
4. 命令
以下為幾個命令操作示意, 更多命令請參靠芯片手冊.
(1) Read ID
說明: 先發送 0x90 然后再發送 0x00, 然后 nand flash 會回傳5個資料, 依據芯片型號的不同資料內容也不盡相同, 具體值見手冊
(2) Page Read
說明: 先發送 0x00 然后發送要讀取資料的地址, 之后發送 0x30, 根據 R/B 可以判斷是否發送完成. 命令發送完成之后 從RE 的第一個下降沿開始, 芯片將從該地址開始到當頁結束的所有資料依次輸出
(3) Page Program
說明: 先發送 0x80 然后發送 地址 和資料, 之后發送 0x10, 讀取 R/B , 命令寫入完成之后 發送 0x70 再依據 I/O0來判斷寫入是否成功, 0 : 成功 1 : 失敗
(4) Block Erase
說明: 先發送 0x90 然后再發送 行地址 1 2 3, 然后再發送 擦除命令 0xD0, 根據 R/B 引腳判斷擦除操作是否完成, 完成之后發送 0x70 根據 I/O0的狀態來判斷擦除是否成功, 0 : 成功 1: 失敗
注釋1:
/* 初始化NAND Flash */
void nand_init(void)
{
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0 /* 判斷是S3C2410還是S3C2440 */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002)) //2410 { nand_chip.nand_reset = s3c2410_nand_reset;
nand_chip.wait_idle = s3c2410_wait_idle; nand_chip.nand_select_chip = s3c2410_nand_select_chip; nand_chip.nand_deselect_chip = s3c2410_nand_deselect_chip; nand_chip.write_cmd = s3c2410_write_cmd; nand_chip.write_addr = s3c2410_write_addr; nand_chip.read_data = s3c2410_read_data; /* 使能NAND Flash控制器, 初始化ECC, 禁止片選, 設定時序 */ s3c2410nand->NFCONF = (115)|(112)|(111)|(TACLS8)|(TWRPH04)|(TWRPH10); } else { nand_chip.nand_reset = s3c2440_nand_reset; nand_chip.wait_idle = s3c2440_wait_idle; nand_chip.nand_select_chip = s3c2440_nand_select_chip; nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip; nand_chip.write_cmd = s3c2440_write_cmd;#ifdef LARGER_NAND_PAGE nand_chip.write_addr = s3c2440_write_addr_lp;#else nand_chip.write_addr = s3c2440_write_addr;#endif nand_chip.read_data = s3c2440_read_data; /* 設定時序 */ s3c2440nand->NFCONF = (TACLS 12)|(TWRPH0 8)|(TWRPH1 4); /* 使能NAND控制器, 初始化ECC, 禁止片選 */ s3c2440nand->NFCONT = (1 4)|(1 1)|(1 0); } /* 復位NAND Flash */ nand_reset();}
這里需要注意的是 大頁 nand , 地址發送五次, 前兩次是 colum addr 后三次是 row addr, colum addr負責頁內尋址, 我們實際尋址的空間為2k = 2^11, 所以只需要11位即可, 所以程式中只取了低11位
A0~A10用來頁內尋址. 另外64byte的OOB空間可以使用A11來尋址.
A12~A17用來在塊內尋址頁, 共64頁
A18~A28用來尋址塊, 共2048塊
nand flash 底層操作函式:
/* 復位 */static void s3c2410_nand_reset(void){ s3c2410_nand_select_chip(); // 選中芯片 s3c2410_write_cmd(0xff); // 復位命令 s3c2410_wait_idle(); // 等待nand就緒 s3c2410_nand_deselect_chip(); // 取消選中 }/* 等待NAND Flash就緒 */static void s3c2410_wait_idle(void){ int i; volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFSTAT; while(!(*p & BUSY)) for(i=0; i10; i++);}/* 發出片選信號 */static void s3c2410_nand_select_chip(void){ int i; s3c2410nand->NFCONF &= ~(111); for(i=0; i10; i++); }/* 取消片選信號 */static void s3c2410_nand_deselect_chip(void){ s3c2410nand->NFCONF |= (111);}/* 發出命令 */static void s3c2410_write_cmd(int cmd){ volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFCMD; *p = cmd;}/* 發出地址 */static void s3c2410_write_addr(unsigned int addr){ int i; volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFADDR; *p = addr & 0xff; for(i=0; i10; i++); *p = (addr >> 9) & 0xff; for(i=0; i10; i++); *p = (addr >> 17) & 0xff; for(i=0; i10; i++); *p = (addr >> 25) & 0xff; for(i=0; i10; i++);}/* 讀取資料 */static unsigned char s3c2410_read_data(void){ volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFDATA; return *p;}/* S3C2440的NAND Flash操作函式 *//* 復位 */static void s3c2440_nand_reset(void){ s3c2440_nand_select_chip(); s3c2440_write_cmd(0xff); // 復位命令 s3c2440_wait_idle(); s3c2440_nand_deselect_chip();}/* 等待NAND Flash就緒 */static void s3c2440_wait_idle(void){ int i; volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;//狀態暫存器, 只用到位0. 0 : busy 1 : ready while(!(*p & BUSY)) for(i=0; i10; i++);}/* 發出片選信號 */static void s3c2440_nand_select_chip(void){ int i; s3c2440nand->NFCONT &= ~(11); for(i=0; i10; i++); }/* 取消片選信號 */static void s3c2440_nand_deselect_chip(void){ s3c2440nand->NFCONT |= (11);}/* 發出命令 */static void s3c2440_write_cmd(int cmd){ volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;//NFCMD 不同的flash命令不一樣, 發送命令信號 *p = cmd;}/* 發出地址(小頁 4周期) */static void s3c2440_write_addr(unsigned int addr){ int i; volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR; *p = addr & 0xff; for(i=0; i10; i++); *p = (addr >> 9) & 0xff; for(i=0; i10; i++); *p = (addr >> 17) & 0xff; for(i=0; i10; i++); *p = (addr >> 25) & 0xff; for(i=0; i10; i++);}/* 發出地址(大頁 5周期) */static void s3c2440_write_addr_lp(unsigned int addr){ int i; volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;//NFADDR當向該暫存器寫入資料時, 芯片向nand發送地址信號 int col, page; //#define NAND_SECTOR_SIZE_LP 2048 //#define NAND_BLOCK_MASK_LP (NAND_SECTOR_SIZE_LP - 1) col = addr & NAND_BLOCK_MASK_LP; //2048 -1 = 11111111111b, 這里是屏蔽高位, 取低11位資料, 因為尋址空間只到 2k = 2^11 , 所以最多用11位, 這里直接不考慮第12位 //參考鏈接:http://bbs.csdn.net/topics/360034390 page = addr / NAND_SECTOR_SIZE_LP; //2048 = 2^11, 這里將資料右移11位, 獲取高位資料 *p = col & 0xff; /* Column Address A0~A7 */ for(i=0; i10; i++); *p = (col >> 8) & 0x0f; /* Column Address A8~A11 */ for(i=0; i10; i++); *p = page & 0xff; /* Row Address A12~A19 */ for(i=0; i10; i++); *p = (page >> 8) & 0xff; /* Row Address A20~A27 */ for(i=0; i10; i++); *p = (page >> 16) & 0x03; /* Row Address A28~A29 */ for(i=0; i10; i++);}/* 讀取資料 */static unsigned char s3c2440_read_data(void){ volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;//資料暫存器, 讀寫都是這個暫存器. 只用到它的低 8 位 return *p;}/* 在第一次使用NAND Flash前,復位一下NAND Flash */static void nand_reset(void){ nand_chip.nand_reset();}
發送地址: NFADDR 發送命令: NFCMD 發送/讀取資料: NFDATA 讀取狀態: NFSTAT 初始化控制器: NFCONT
由以上代碼可以看出: 初始化完畢之后就不必關系總線上的時序只需要把 地址/命令/資料放到對應的暫存器, 芯片就能在總線上發出對應的時序
而初始化需要配置的是: 時序的引數/資料位寬/只讀位/頁的大小
注釋2:
/* 讀函式 */void nand_read(unsigned char *buf, unsigned long start_addr, int size)//在head.S中設定的r0 r1 r2 分別為該函式的三個引數{ int i, j;#ifdef LARGER_NAND_PAGE if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) { return ; /* 地址或長度不對齊 */ }#else if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) { return ; /* 地址或長度不對齊 */ }#endif /* 選中芯片 */ nand_select_chip(); for(i=start_addr; i /* 發出READ0命令 */ write_cmd(0); /* Write Address */ write_addr(i);#ifdef LARGER_NAND_PAGE write_cmd(0x30);#endif wait_idle();#ifdef LARGER_NAND_PAGE for(j=0; j #else for(j=0; j #endif *buf = read_data(); buf++; } } /* 取消片選信號 */ nand_deselect_chip(); return ;}
總結一下:
(1)選中芯片
(2)發送00h
(3)發出地址
(4)發30h
(5)等待就緒
(6)讀一頁資料
鏈接檔案:
SECTIONS { firtst 0x00000000 : { head.o init.o nand.o} second 0x30000000 : AT(4096) { main.o }}
main.c存放到了nand的4096地址處.
入口檔案:
@******************************************************************************@ File:head.s@ 功能:設定SDRAM,將程式復制到SDRAM,然后跳到SDRAM繼續執行@****************************************************************************** .text.global _start_start: @函式disable_watch_dog, memsetup, init_nand, nand_read_ll在init.c中定義 ldr sp, =4096 @設定堆疊 bl disable_watch_dog @關WATCH DOG bl memsetup @初始化SDRAM bl nand_init @初始化NAND Flash 注釋1 @將NAND Flash中地址4096開始的1024位元組代碼(main.c編譯得到)復制到SDRAM中 @nand_read_ll函式需要3個引數: ldr r0, =0x30000000 @1. 目標地址=0x30000000,這是SDRAM的起始地址 mov r1, #4096 @2. 源地址 = 4096,連接的時候,main.c中的代碼都存在NAND Flash地址4096開始處 mov r2, #2048 @3. 復制長度= 2048(bytes),對于本實驗的main.c,這是足夠了 bl nand_read @呼叫C函式nand_read 注釋2 ldr sp, =0x34000000 @設定堆疊 ldr lr, =halt_loop @設定回傳地址 ldr pc, =main @b指令和bl指令只能前后跳轉32M的范圍,所以這里使用向pc賦值的方法進行跳轉halt_loop: b halt_loop
這里將nand flash 從4096地址開始的2048位元組復制到sdram的0x3000 0000地址處
main.c中是led閃爍程式.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/101528.html
標籤:硬件使用
