1. 程式人生 > >個人對nandflash驅動的總結(ok6410版)

個人對nandflash驅動的總結(ok6410版)

1,首先說明要用nandflash的原因,當你從nand啟動時,6410中的硬體會自動將nand中的8k內容拷貝到開發板中記憶體空間的iRAM中,然後iRAM再將這8k內容拷貝到內從中進行執行,一旦nand中的內容大於8k則多餘的那些將無法被拷貝機執行,因此需要一個驅動程式來將多餘的程式碼移到記憶體中那就是nandflash驅動程式

其次說說使用了nandflash之後的程式碼搬移過程;第一步,硬體會自動將nand中的8k內容拷貝到開發板中記憶體空間的iRAM中,然後iRAM再將這8k內容拷貝到內從中進行執行,  第二步,將nand中剩餘的程式碼直接拷貝到記憶體中接著執行

3現在到了程式碼編寫時間,其他的不多說因為已經總結完了,就說自己被卡的地方

  就在頁讀這裡出錯了結果導致整個程式有問題,之後參考了正確的程式碼,執行出來了

程式碼如下;

 #define NFCONF             (*((volatile unsigned long*)0x70200000))

#define NFCONT             (*((volatile unsigned long*)0x70200004))

#define NFCMMD             (*((volatile unsigned char*)0x70200008))

#define NFSTAT             (*((volatile unsigned char*)0x70200028))

#define NFADDR             (*((volatile unsigned char*)0x7020000c))

#define NFDATA             (*((volatile unsigned char*)0x70200010))

void select_ship(void)

{

    NFCONT &= ~(1<<1);

}

void delselect_ship(void)

{

    NFCONT |= (1<<1);

}

void clean_RnB()

{

    NFSTAT |= (1<<4);

void nand_cmd(unsigned char cmd)

{

    NFCMMD = cmd;   

}

void wait_RnB(void)

{

    while(!(NFSTAT & 0x1));

}

void nand_addr(unsigned char addr)

{

    NFADDR = addr;

}

void nand_reset(void)

{

    /* 選中 */

    select_ship();

    /* 清除RnB */

    clean_RnB();

    /* 發出復位訊號 */

    nand_cmd(0xff);

    /* 等待就緒 */

    wait_RnB();

    /* 取消選中 */

    delselect_ship();

}

void nand_init(void)

/*

HCLK的頻率為100MHZ,週期就為10ns

TACLS > 0 ns

TWRPH0 > 15ns

TWRPH1 > 5ns

TACLS的值 = HCLK x TACLS > 0ns

TWRPH0的值 = HCLK x (TWRPH0 + 1) > 15ns

TWRPH1的值 = HCLK x (TWRPH1 +1) > 5ns 

*/

    /* 設定時間引數 */

#define TACLS  1

#define TWRPH0 2

#define TWRPH1 1

    NFCONF &= ~((7<<12)|(7<<8)|(7<<4));

    NFCONF |= (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);

    /* 使能 nandflash controller*/

    NFCONT = 1 | (1<<1);

    /* 復位 */

    nand_reset();

}

void NF_PageRead(unsigned long addr,unsigned char* buff)

{

    int i;

    /* 選中晶片 */

    select_ship();

    /* 清除RnB */

    clean_RnB();

    /* 發出命令0x00 */

     nand_cmd(0x00);

     /* 發出列地址 */

    nand_addr(0x00);

    nand_addr(0x00);

    /* 發出行地址 */

    nand_addr(addr&0xff);

    nand_addr((addr >>8 ) & (0xff));

    nand_addr((addr >>16 ) & (0xff));

    /* 發出命令0x30 */

     nand_cmd(0x30);

    /* 等待就緒 */

     wait_RnB();

    /* 讀資料 */

     for(i = 0; i<1024*4; i++)

    {

     buff[i] = NFDATA;

    }

     /* 取消片選 */

     delselect_ship();

}

void nand_to_ram(unsigned long start_addr,unsigned char* sdram_addr,int size)

{

/* i為頁號、sdram_addr為記憶體中的位置、size拷貝資料的大小 */

int i;

unsigned int page_shift = 12;

/* 頁的起始地址給ii為頁號),這個start_addr包含列地址和行地址,我們只需要頁地址(行地址) */

/*for(i=(start_addr >> 12);size>0;)

{

NF_PageRead(i,sdram_addr);  //讀一頁的資料

     size -= 1024*4;   //ok6410頁的大小是4K

     start_addr += 1024*4;

     i++;

}

*/

/* Read pages */

        for (i = 0; i < 4; i++, sdram_addr+=(1<<(page_shift-1))) 

        {

            NF_PageRead(i,sdram_addr);

        }

        /* Read pages */

        for (i = 4; i < (0x3c000>>page_shift); i++, sdram_addr+=(1<<page_shift))

        {

            NF_PageRead(i,sdram_addr);

        }

}

int NF_Erase(unsigned long addr)

{

int ret;

//選中flash晶片

select_ship();

//清除RnB

clean_RnB();

//傳送命令60

nand_cmd(0x60);

//傳送行地址(3個週期)

nand_addr(addr&0xff);

     nand_addr((addr >>8 ) & (0xff));

     nand_addr((addr >>16 ) & (0xff));

//傳送命令D0

nand_cmd(0xD0);

//等待RnB

wait_RnB();

//傳送命令70

nand_cmd(0x70);

//讀取擦除結果

ret = NFDATA;

//取消選中flash晶片

delselect_ship();

return ret;

}

int NF_WritePage(unsigned long addr,unsigned char* buff)

{

int ret,i;

//選中flash晶片

select_ship();

//清除RnB

clean_RnB();

//傳送命令80

nand_cmd(0x80);

//傳送列地址(2個週期)

nand_addr(0x00);

     nand_addr(0x00);

//傳送行地址(3個週期)

nand_addr(addr&0xff);

     nand_addr((addr >>8 ) & (0xff));

     nand_addr((addr >>16 ) & (0xff));

//寫入資料

for(i=0;i<1024*4;i++)

{

NFDATA = buff[i];

}

//傳送命令10

nand_cmd(0x10);

//等待RnB

wait_RnB();

//傳送命令70

nand_cmd(0x70);

//讀取寫入結果

ret = NFDATA;

//取消選中flash晶片

delselect_ship();

return ret;

}