您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“NAND FLASH控制器怎么實(shí)現(xiàn)”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
存儲組織形式
K9F2G08X0A共有2048個(gè)Block(塊), 每個(gè)Block含有 64 Page(頁), 每個(gè)Page含有2k byte的正常存儲空間以及64 byte的校驗(yàn)空間 .
總空間 = 2048 * 64 * (2 * 1024 + 64) byte
實(shí)際存儲空間 = 2048 * 64 * 2 * 1024 byte
2. 引腳定義及接法
3. 尋址方式
列地址: 進(jìn)行 Block 和 Page 尋址
行地址: 進(jìn)行 Page 內(nèi)尋址
4. 命令
以下為幾個(gè)命令操作示意, 更多命令請參靠芯片手冊.
(1) Read ID
說明: 先發(fā)送 0x90 然后再發(fā)送 0x00, 然后 nand flash 會返回5個(gè)數(shù)據(jù), 依據(jù)芯片型號的不同數(shù)據(jù)內(nèi)容也不盡相同, 具體值見手冊
(2) Page Read
說明: 先發(fā)送 0x00 然后發(fā)送要讀取數(shù)據(jù)的地址, 之后發(fā)送 0x30, 根據(jù) R/B 可以判斷是否發(fā)送完成. 命令發(fā)送完成之后 從RE 的第一個(gè)下降沿開始, 芯片將從該地址開始到當(dāng)頁結(jié)束的所有數(shù)據(jù)依次輸出
(3) Page Program
說明: 先發(fā)送 0x80 然后發(fā)送 地址 和數(shù)據(jù), 之后發(fā)送 0x10, 讀取 R/B , 命令寫入完成之后 發(fā)送 0x70 再依據(jù) I/O0來判斷寫入是否成功, 0 : 成功 1 : 失敗
(4) Block Erase
說明: 先發(fā)送 0x90 然后再發(fā)送 行地址 1 2 3, 然后再發(fā)送 擦除命令 0xD0, 根據(jù) R/B 引腳判斷擦除操作是否完成, 完成之后發(fā)送 0x70 根據(jù) I/O0的狀態(tài)來判斷擦除是否成功, 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, 禁止片選, 設(shè)置時(shí)序 */ s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0); } 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; /* 設(shè)置時(shí)序 */ s3c2440nand->NFCONF = (TACLS << 12)|(TWRPH0 << 8)|(TWRPH1 << 4); /* 使能NAND控制器, 初始化ECC, 禁止片選 */ s3c2440nand->NFCONT = (1 << 4)|(1 << 1)|(1 << 0); } /* 復(fù)位NAND Flash */ nand_reset(); }
這里需要注意的是 大頁 nand , 地址發(fā)送五次, 前兩次是 colum addr 后三次是 row addr, colum addr負(fù)責(zé)頁內(nèi)尋址, 我們實(shí)際尋址的空間為2k = 2^11, 所以只需要11位即可, 所以程序中只取了低11位
A0~A10用來頁內(nèi)尋址. 另外64byte的OOB空間可以使用A11來尋址.
A12~A17用來在塊內(nèi)尋址頁, 共64頁
A18~A28用來尋址塊, 共2048塊
nand flash 底層操作函數(shù):
/* 復(fù)位 */ static void s3c2410_nand_reset(void) { s3c2410_nand_select_chip(); // 選中芯片 s3c2410_write_cmd(0xff); // 復(fù)位命令 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; i<10; i++); } /* 發(fā)出片選信號 */ static void s3c2410_nand_select_chip(void) { int i; s3c2410nand->NFCONF &= ~(1<<11); for(i=0; i<10; i++); } /* 取消片選信號 */ static void s3c2410_nand_deselect_chip(void) { s3c2410nand->NFCONF |= (1<<11); } /* 發(fā)出命令 */ static void s3c2410_write_cmd(int cmd) { volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFCMD; *p = cmd; } /* 發(fā)出地址 */ 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; i<10; i++); *p = (addr >> 9) & 0xff; for(i=0; i<10; i++); *p = (addr >> 17) & 0xff; for(i=0; i<10; i++); *p = (addr >> 25) & 0xff; for(i=0; i<10; i++); } /* 讀取數(shù)據(jù) */ static unsigned char s3c2410_read_data(void) { volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFDATA; return *p; } /* S3C2440的NAND Flash操作函數(shù) */ /* 復(fù)位 */ static void s3c2440_nand_reset(void) { s3c2440_nand_select_chip(); s3c2440_write_cmd(0xff); // 復(fù)位命令 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;//狀態(tài)寄存器, 只用到位0. 0 : busy 1 : ready while(!(*p & BUSY)) for(i=0; i<10; i++); } /* 發(fā)出片選信號 */ static void s3c2440_nand_select_chip(void) { int i; s3c2440nand->NFCONT &= ~(1<<1); for(i=0; i<10; i++); } /* 取消片選信號 */ static void s3c2440_nand_deselect_chip(void) { s3c2440nand->NFCONT |= (1<<1); } /* 發(fā)出命令 */ static void s3c2440_write_cmd(int cmd) { volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;//NFCMD 不同的flash命令不一樣, 發(fā)送命令信號 *p = cmd; } /* 發(fā)出地址(小頁 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; i<10; i++); *p = (addr >> 9) & 0xff; for(i=0; i<10; i++); *p = (addr >> 17) & 0xff; for(i=0; i<10; i++); *p = (addr >> 25) & 0xff; for(i=0; i<10; i++); } /* 發(fā)出地址(大頁 5周期) */ static void s3c2440_write_addr_lp(unsigned int addr) { int i; volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;//NFADDR當(dāng)向該寄存器寫入數(shù)據(jù)時(shí), 芯片向nand發(fā)送地址信號 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位數(shù)據(jù), 因?yàn)閷ぶ房臻g只到 2k = 2^11 , 所以最多用11位, 這里直接不考慮第12位 //參考鏈接:http://bbs.csdn.net/topics/360034390 page = addr / NAND_SECTOR_SIZE_LP; //2048 = 2^11, 這里將數(shù)據(jù)右移11位, 獲取高位數(shù)據(jù) *p = col & 0xff; /* Column Address A0~A7 */ for(i=0; i<10; i++); *p = (col >> 8) & 0x0f; /* Column Address A8~A11 */ for(i=0; i<10; i++); *p = page & 0xff; /* Row Address A12~A19 */ for(i=0; i<10; i++); *p = (page >> 8) & 0xff; /* Row Address A20~A27 */ for(i=0; i<10; i++); *p = (page >> 16) & 0x03; /* Row Address A28~A29 */ for(i=0; i<10; i++); } /* 讀取數(shù)據(jù) */ static unsigned char s3c2440_read_data(void) { volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;//數(shù)據(jù)寄存器, 讀寫都是這個(gè)寄存器. 只用到它的低 8 位 return *p; } /* 在第一次使用NAND Flash前,復(fù)位一下NAND Flash */ static void nand_reset(void) { nand_chip.nand_reset(); }
????發(fā)送地址: NFADDR 發(fā)送命令: NFCMD 發(fā)送/讀取數(shù)據(jù): NFDATA 讀取狀態(tài): NFSTAT 初始化控制器: NFCONT?
由以上代碼可以看出: 初始化完畢之后就不必關(guān)系總線上的時(shí)序只需要把 地址/命令/數(shù)據(jù)放到對應(yīng)的寄存器, 芯片就能在總線上發(fā)出對應(yīng)的時(shí)序
而初始化需要配置的是: 時(shí)序的參數(shù)/數(shù)據(jù)位寬/只讀位/頁的大小
注釋2:
/* 讀函數(shù) */ void nand_read(unsigned char *buf, unsigned long start_addr, int size)//在head.S中設(shè)置的r0 r1 r2 分別為該函數(shù)的三個(gè)參數(shù) { 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 < (start_addr + size);){ /* 發(fā)出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 < NAND_SECTOR_SIZE_LP; j++, i++) { #else for(j=0; j < NAND_SECTOR_SIZE; j++, i++) { #endif *buf = read_data(); buf++; } } /* 取消片選信號 */ nand_deselect_chip(); return ; }
總結(jié)一下:
(1)選中芯片
(2)發(fā)送00h
(3)發(fā)出地址
(4)發(fā)30h
(5)等待就緒
(6)讀一頁數(shù)據(jù)
鏈接文件:
SECTIONS { firtst 0x00000000 : { head.o init.o nand.o} second 0x30000000 : AT(4096) { main.o } }
main.c存放到了nand的4096地址處.
入口文件:
@****************************************************************************** @ File:head.s @ 功能:設(shè)置SDRAM,將程序復(fù)制到SDRAM,然后跳到SDRAM繼續(xù)執(zhí)行 @****************************************************************************** .text .global _start _start: @函數(shù)disable_watch_dog, memsetup, init_nand, nand_read_ll在init.c中定義 ldr sp, =4096 @設(shè)置堆棧 bl disable_watch_dog @關(guān)WATCH DOG bl memsetup @初始化SDRAM bl nand_init @初始化NAND Flash 注釋1 @將NAND Flash中地址4096開始的1024字節(jié)代碼(main.c編譯得到)復(fù)制到SDRAM中 @nand_read_ll函數(shù)需要3個(gè)參數(shù): ldr r0, =0x30000000 @1. 目標(biāo)地址=0x30000000,這是SDRAM的起始地址 mov r1, #4096 @2. 源地址 = 4096,連接的時(shí)候,main.c中的代碼都存在NAND Flash地址4096開始處 mov r2, #2048 @3. 復(fù)制長度= 2048(bytes),對于本實(shí)驗(yàn)的main.c,這是足夠了 bl nand_read @調(diào)用C函數(shù)nand_read 注釋2 ldr sp, =0x34000000 @設(shè)置棧 ldr lr, =halt_loop @設(shè)置返回地址 ldr pc, =main @b指令和bl指令只能前后跳轉(zhuǎn)32M的范圍,所以這里使用向pc賦值的方法進(jìn)行跳轉(zhuǎn) halt_loop: b halt_loop
這里將nand flash 從4096地址開始的2048字節(jié)復(fù)制到sdram的0x3000 0000地址處
main.c中是led閃爍程序.
“NAND FLASH控制器怎么實(shí)現(xiàn)”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。