溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

NAND FLASH控制器怎么實(shí)現(xiàn)

發(fā)布時(shí)間:2021-12-20 10:43:34 來源:億速云 閱讀:122 作者:iii 欄目:互聯(lián)網(wǎng)科技

本篇內(nèi)容介紹了“NAND FLASH控制器怎么實(shí)現(xiàn)”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

  1. 存儲組織形式

    NAND FLASH控制器怎么實(shí)現(xiàn)

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. 引腳定義及接法

NAND FLASH控制器怎么實(shí)現(xiàn)

NAND FLASH控制器怎么實(shí)現(xiàn)

3. 尋址方式

NAND FLASH控制器怎么實(shí)現(xiàn)

列地址: 進(jìn)行 Block 和 Page 尋址

行地址: 進(jìn)行 Page 內(nèi)尋址

4. 命令

以下為幾個(gè)命令操作示意, 更多命令請參靠芯片手冊.

(1) Read ID

NAND FLASH控制器怎么實(shí)現(xiàn)

說明: 先發(fā)送  0x90  然后再發(fā)送 0x00, 然后 nand flash 會返回5個(gè)數(shù)據(jù), 依據(jù)芯片型號的不同數(shù)據(jù)內(nèi)容也不盡相同, 具體值見手冊

(2) Page Read

NAND FLASH控制器怎么實(shí)現(xiàn)

說明: 先發(fā)送 0x00 然后發(fā)送要讀取數(shù)據(jù)的地址, 之后發(fā)送 0x30, 根據(jù) R/B 可以判斷是否發(fā)送完成. 命令發(fā)送完成之后 從RE 的第一個(gè)下降沿開始, 芯片將從該地址開始到當(dāng)頁結(jié)束的所有數(shù)據(jù)依次輸出

(3) Page Program

NAND FLASH控制器怎么實(shí)現(xiàn)

說明: 先發(fā)送 0x80 然后發(fā)送 地址 和數(shù)據(jù), 之后發(fā)送 0x10, 讀取 R/B , 命令寫入完成之后 發(fā)送 0x70 再依據(jù) I/O0來判斷寫入是否成功, 0 : 成功 1 : 失敗

(4) Block Erase 

NAND FLASH控制器怎么實(shí)現(xiàn)

說明: 先發(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í)用文章!

向AI問一下細(xì)節(jié)

免責(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)容。

AI