嵌入式nand flash詳解

1、s3c2440啓動後會將nand flash的前4K程序複製到內部的sram中,這個過程是硬件自動完成的,可是若是咱們的程序遠遠大於4K,這個時候就須要將程序從flash拷貝到內存中來運行了。linux

2、nand flash 接線圖能夠看出,nand flash沒有地址總線,是八根數據線,SDRAM和網卡有地址總接到s3c2440的地址總線了,而nand flash沒有地址線,因此他們的尋址方式不同,SDRAM和網卡的地址是CPU能夠看得見的,也就是CPU統一編址,而nand flash呢?也有地址空間,以256M爲例,尋址空間256M,SDRAM尋址空間0x30000000-0x34000000 ,片內內存及gpio及內部寄存器,網卡都有一塊地址,由CPU統一的編址空間,因爲尋址的方式不一樣咱們說0地址時概念是不同的。從圖上能夠看出,不論是命令地址仍是數據都是經過8條數據線傳輸的,那麼控制信號就起到了重要的做用,CLE命令使能信號、ALE地址使能信號、FWE寫使能信號、FRE讀使能信號若是CLE和ALE都無效就是數據。函數

3、nand flash的結構oop

從圖中能夠看出一個大葉是2K加64字節 64頁組成一塊 加的64字節是00Bspa

讀nand flash 上2049地址,實際上是讀第一頁。.net

對於你特定的某一頁,非要強調一頁的2049頗有多是OOB上的地址。code

nand flash編址以下圖:blog

4、訪問nand flaship

回憶訪問內存:一、發出地址、二、傳輸數據


訪問nand flash相似  一、發出地址、二、傳輸數據
a、發出命令(讀、寫、擦除等等),b、發出地址,c、傳輸數據
看手冊命令:
如圖命令集內存

訪問nand flash 都須要引腳來控制,那麼nand flash控制器就完成這些操做。
全部的操做都交給nand flash控制器
好比要發出命令,將命令值寫進寄存器NFCMMD中,s3c2440就會自動的驅動CLE引腳,把命令發送到nand flash中去,操做地址時,僅須要將值寫進寄存器NFADDR,讀數據和寫數據時,也是將地址值寫進NFADDR。cmd

先看連接地址和運行地址:

SECTIONS {   
  firtst    0x00000000 : { head.o init.o nand.o}  
  second    0x30000000 : AT(4096) { main.o }  
}   

這是段,分爲兩段,0x00000000和0x30000000是運行地址,第二段AT,代表加載地址是nand flash 4096處,沒有AT,運行地址和加載地址同樣都是起始地址。

head.o init.o nand.o從nand flash0地址開始放,s3c2440啓動會將這段程序copy到sram中運行,main.o放在nand flash4096處,會被讀到SDRAM的0x30000000地址中執行。

以下圖:

總結:
a、從硬件訪問nand flash
一、發出命令:CLE引腳,命令放進數據總線上
二、發出地址:ALE,地址放進數據總線上
三、傳輸數據:R/W


b、2440精簡了以上操做:
一、發出命令:NFCMMD,把命令寫進這個寄存器後,會自動的發送信號
二、發出地址:NFADDR,把地址值寫進這個寄存器後,會自動的發送地址
三、傳輸數據:NFDATA,
四、狀態,好比擦除,只有先發出擦除命令,再發出地址,就開始擦除,那麼須要等待一會才能擦除成功,那麼這個狀態須要讀回來,NFSTAT

主要操做的nand flash控制器寄存器:

命令寄存器NFCMMD
地址寄存器NFADDR
數據寄存器NFDAYA
狀態寄存器NFSTAT

從nand flash讀數據,那麼就要確認從哪裏讀,讀到哪裏去,讀多少

下面分析程序:

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_loop  

init.c

/* WOTCH DOG register */  
#define     WTCON               (*(volatile unsigned long *)0x53000000)  
  
/* SDRAM regisers */  
#define     MEM_CTL_BASE        0x48000000  
   
void 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,     //BWSCON  
                                            0x00000700,     //BANKCON0  
                                            0x00000700,     //BANKCON1  
                                            0x00000700,     //BANKCON2  
                                            0x00000700,     //BANKCON3    
                                            0x00000700,     //BANKCON4  
                                            0x00000700,     //BANKCON5  
                                            0x00018005,     //BANKCON6  
                                            0x00018005,     //BANKCON7  
                                            0x008C07A3,     //REFRESH  
                                            0x000000B1,     //BANKSIZE  
                                            0x00000030,     //MRSRB6  
                                            0x00000030,     //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();  
    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();  
    s3c2440_nand_deselect_chip();  
}  
  
/* 等待NAND Flash就緒 */  
static void s3c2440_wait_idle(void)  
{  
    int i;  
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;  
    while(!(*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;  
    *p = cmd;  
}  
  
/* 發出地址 */  
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++);  
}  
  
  
static void s3c2440_write_addr_lp(unsigned int addr)  
{  
    int i;  
    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;  
    int col, page;  
  
    col = addr & NAND_BLOCK_MASK_LP;  
    page = addr / NAND_SECTOR_SIZE_LP;  
      
    *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;  
    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_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 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)  
{  
    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);) {  
      /* 發出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 ;  
}  

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-3  
        if(++i == 8)  
            i = 0;  
    }  
  
    return 0;  
}  

nand.lds

SECTIONS {   
  firtst    0x00000000 : { head.o init.o nand.o}  
  second    0x30000000 : AT(4096) { main.o }  
}   

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 $@ arm-linux-objdump -D -m arm  nand_elf > nand.dis %.o:%.c arm-linux-gcc -Wall -c -O2 -o $@ $<  
  
%.o:%.S arm-linux-gcc -Wall -c -O2 -o $@ $< clean: rm -f  nand.dis nand.bin nand_elf *.o  
相關文章
相關標籤/搜索