NandFlash 控制器操作实例:读Flash
生活随笔
收集整理的這篇文章主要介紹了
NandFlash 控制器操作实例:读Flash
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
摘要: 本文以S3C2440為例來講解NAND FLASH控制器的使用方法. 例程中故意將一部分代碼放置到 nand 的4k 字節之后, 因無法自動拷貝到steppingstone, 所以需要讀取nand中的內容到sdram。
代碼執行示意圖:
nand.lds
SECTIONS { firtst 0x00000000 : { head.o init.o nand.o}/*head.o、init.o和nand.o組成,加載地址和運行地址都是0,運行前不需要重新移動代碼*/second 0x30000000 : AT(4096) { main.o }/*由main.o組成,運行地址為0x30000000,加載地址為4096(即偏移地址),表明段second*存放在編譯所得映象文件地址2048處,在運行前將它重定位到地址0x30000000處,*/ }head.S
@****************************************************************************** @ 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 @將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 ldr sp, =0x34000000 @設置棧 ldr lr, =halt_loop @設置返回地址 ldr pc, =main @b指令和bl指令只能前后跳轉32M的范圍,所以這里使用向pc賦值的方法進行跳轉 halt_loop: b halt_loopinit.c
/* WOTCH DOG register */ #define WTCON (*(volatile unsigned long *)0x53000000)/* SDRAM regisers */ #define MEM_CTL_BASE 0x48000000void disable_watch_dog(); void memsetup();/*上電后,WATCH DOG默認是開著的,要把它關掉 */ void disable_watch_dog() {WTCON = 0; }/* 設置控制SDRAM的13個寄存器 */ void memsetup() {int i = 0;unsigned long *p = (unsigned long *)MEM_CTL_BASE;/* SDRAM 13個寄存器的值 */unsigned long const mem_cfg_val[]={ 0x22011110, //BWSCON0x00000700, //BANKCON00x00000700, //BANKCON10x00000700, //BANKCON20x00000700, //BANKCON3 0x00000700, //BANKCON40x00000700, //BANKCON50x00018005, //BANKCON60x00018005, //BANKCON70x008C07A3, //REFRESH0x000000B1, //BANKSIZE0x00000030, //MRSRB60x00000030, //MRSRB7};for(; i < 13; i++)p[i] = mem_cfg_val[i]; }nand.c
#define LARGER_NAND_PAGE#define GSTATUS1 (*(volatile unsigned int *)0x560000B0) #define BUSY 1#define NAND_SECTOR_SIZE 512 #define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)#define NAND_SECTOR_SIZE_LP 2048 #define NAND_BLOCK_MASK_LP (NAND_SECTOR_SIZE_LP - 1)typedef unsigned int S3C24X0_REG32;/* NAND FLASH (see S3C2410 manual chapter 6) */ typedef struct {S3C24X0_REG32 NFCONF;S3C24X0_REG32 NFCMD;S3C24X0_REG32 NFADDR;S3C24X0_REG32 NFDATA;S3C24X0_REG32 NFSTAT;S3C24X0_REG32 NFECC; } S3C2410_NAND;/* NAND FLASH (see S3C2440 manual chapter 6, www.100ask.net) */ typedef struct {S3C24X0_REG32 NFCONF;S3C24X0_REG32 NFCONT;S3C24X0_REG32 NFCMD;S3C24X0_REG32 NFADDR;S3C24X0_REG32 NFDATA;S3C24X0_REG32 NFMECCD0;S3C24X0_REG32 NFMECCD1;S3C24X0_REG32 NFSECCD;S3C24X0_REG32 NFSTAT;S3C24X0_REG32 NFESTAT0;S3C24X0_REG32 NFESTAT1;S3C24X0_REG32 NFMECC0;S3C24X0_REG32 NFMECC1;S3C24X0_REG32 NFSECC;S3C24X0_REG32 NFSBLK;S3C24X0_REG32 NFEBLK; } S3C2440_NAND;typedef struct {void (*nand_reset)(void);void (*wait_idle)(void);void (*nand_select_chip)(void);void (*nand_deselect_chip)(void);void (*write_cmd)(int cmd);void (*write_addr)(unsigned int addr);unsigned char (*read_data)(void); }t_nand_chip;static S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000; static S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;static t_nand_chip nand_chip;/* 供外部調用的函數 */ void nand_init(void); void nand_read(unsigned char *buf, unsigned long start_addr, int size);/* NAND Flash操作的總入口, 它們將調用S3C2410或S3C2440的相應函數 */ static void nand_reset(void); static void wait_idle(void); static void nand_select_chip(void); static void nand_deselect_chip(void); static void write_cmd(int cmd); static void write_addr(unsigned int addr); static unsigned char read_data(void);/* S3C2410的NAND Flash處理函數 */ static void s3c2410_nand_reset(void); static void s3c2410_wait_idle(void); static void s3c2410_nand_select_chip(void); static void s3c2410_nand_deselect_chip(void); static void s3c2410_write_cmd(int cmd); static void s3c2410_write_addr(unsigned int addr); static unsigned char s3c2410_read_data();/* S3C2440的NAND Flash處理函數 */ static void s3c2440_nand_reset(void); static void s3c2440_wait_idle(void); static void s3c2440_nand_select_chip(void); static void s3c2440_nand_deselect_chip(void); static void s3c2440_write_cmd(int cmd); static void s3c2440_write_addr(unsigned int addr); static unsigned char s3c2440_read_data(void);/* S3C2410的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; i<10; i++); }/* 發出片選信號 */ 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); }/* 發出命令 */ 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; 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++); }/* 讀取數據 */ 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(); /// 等待nand就緒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 : readywhile(!(*p & BUSY))for(i=0; i<10; i++); }/* 發出片選信號 */ 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); }/* 發出命令 */ 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; 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++); }/* 發出地址(大頁 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//或者參考http://blog.csdn.net/czg13548930186/article/details/75043343 大頁尋址方式page = addr / NAND_SECTOR_SIZE_LP;//2048 = 2^11, 這里將數據右移11位, 獲取高位數據*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++); }/* 讀取數據 */ 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(); }static void wait_idle(void) {nand_chip.wait_idle(); }static void nand_select_chip(void) {int i;nand_chip.nand_select_chip();for(i=0; i<10; i++); }static void nand_deselect_chip(void) {nand_chip.nand_deselect_chip(); }static void write_cmd(int cmd) {nand_chip.write_cmd(cmd); } static void write_addr(unsigned int addr) {nand_chip.write_addr(addr); }static unsigned char read_data(void) {return nand_chip.read_data(); }/* 初始化NAND Flash */ void nand_init(void) { #define TACLS 0 #define TWRPH0 3 #define TWRPH1 0/* 判斷是S3C2410還是S3C2440 */if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002)){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 = (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_PAGEnand_chip.write_addr = s3c2440_write_addr_lp; #elsenand_chip.write_addr = s3c2440_write_addr; #endifnand_chip.read_data = s3c2440_read_data;/* 設置時序 */s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);/* 使能NAND Flash控制器, 初始化ECC, 禁止片選 */s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);}/* 復位NAND Flash */nand_reset(); }/* 讀函數 */ void nand_read(unsigned char *buf, unsigned long start_addr, int size)//在head.S中設置的r0 r1 r2 分別為該函數的三個參數 {int i, j; //NAND Flash 每次讀操作是以page為單位的,一個page在此是2048byte(不同的NAND Flash的page大小不一定相同), //因為2047的二進制表示是11個1, 即11111111111, 一個數如果是2048的倍數,低11bit必須是0, 即 ****00000000000 //所以把一個數跟2047按位與就可判斷它是不是2048的倍數。 #ifdef LARGER_NAND_PAGEif ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {return ; /* 地址或長度不對齊 */} #elseif ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {return ; /* 地址或長度不對齊 */} #endif /* 選中芯片 */nand_select_chip();for(i=start_addr; i < (start_addr + size);) {/* 發出READ0命令 */write_cmd(0);/* Write Address */write_addr(i); #ifdef LARGER_NAND_PAGEwrite_cmd(0x30); #endifwait_idle();#ifdef LARGER_NAND_PAGEfor(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) { #elsefor(j=0; j < NAND_SECTOR_SIZE; j++, i++) { #endif*buf = read_data();buf++;}}/* 取消片選信號 */nand_deselect_chip();return ; /*總結一下:(1)選中芯片(2)發送00h(3)發出地址(4)發30h(5)等待就緒(6)讀一頁數據*/ }main.c
#define GPFCON (*(volatile unsigned long *)0x56000050) #define GPFDAT (*(volatile unsigned long *)0x56000054)#define GPF4_out (1<<(4*2)) #define GPF5_out (1<<(5*2)) #define GPF6_out (1<<(6*2))void wait(volatile unsigned long dly) {for(; dly > 0; dly--); }int main(void) {unsigned long i = 0;GPFCON = GPF4_out|GPF5_out|GPF6_out; // 將LED1-3對應的GPF4/5/6三個引腳設為輸出while(1){wait(30000);GPFDAT = (~(i<<4)); // 根據i的值,點亮LED1-3if(++i == 8)i = 0;}return 0; }Makefile
objs := head.o init.o nand.o main.o # $^ 代表所有的依賴文件。 $@--目標文件,$<--第一個依賴文件。 nand.bin : $(objs)arm-linux-ld -Tnand.lds -o nand_elf $^ arm-linux-objcopy -O binary -S nand_elf $@ # binary:二進制的 -S:不從源文件復制重定位信息和符號信息到目標文件中去arm-linux-objdump -D -m arm nand_elf > nand.dis # -D:反匯編所有段 -m arm:指定反匯編文件使用arm架構%.o:%.carm-linux-gcc -Wall -c -O2 -o $@ $< #-Wall:打開警告信息 -O2:2級優化(常用) -c:只編譯不連接%.o:%.Sarm-linux-gcc -Wall -c -O2 -o $@ $<clean:rm -f nand.dis nand.bin nand_elf *.o按照代碼分析順序擺放代碼,拿到裸機程序一般都先分析連接腳本!
總結
以上是生活随笔為你收集整理的NandFlash 控制器操作实例:读Flash的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 建议收藏!高企申报全流程梳理:带你了解安
- 下一篇: 局域网ip冲突检测工具_只需一台Andr