您好,登錄后才能下訂單哦!
nand flash按照我的理解,在開發(fā)板上就類似我們所用的電腦中的硬盤,用來保存系統(tǒng)運(yùn)行的操作系統(tǒng),應(yīng)用程序,數(shù)據(jù)等,掉電之后還可以永久得保存數(shù)據(jù)(不包括臨時數(shù)據(jù))。通過控制或配置NAND Flash的控制器寄存器,即可完成對nand的操作:包括讀、寫、擦除等。
而控制、配置這些寄存器是根據(jù)板子的原理圖、用戶手冊以及nand flash芯片手冊上的說明來配置的。
通過原理圖,可見nand flash與cpu之間的數(shù)據(jù)傳輸主要是通過LDDATA0~7這8根引腳線,其中傳輸?shù)摹皵?shù)據(jù)”可以是地址、數(shù)據(jù),也可以是命令,這就要靠CLE、ALE引腳的狀態(tài)進(jìn)行選擇。
對于命令的傳輸,主要是對NFCMD寄存器寫以上相對應(yīng)的命令值,但這個命令是分兩個周期進(jìn)行的。
而對于數(shù)據(jù)的傳輸,在數(shù)據(jù)傳輸模式下,傳輸數(shù)據(jù)也是要根據(jù)以上的格式去進(jìn)行傳輸,分5個周期,每一個周期傳輸?shù)臄?shù)據(jù)都十分講究,這就要求要有一個符合這種格式的巧妙算法(在接下來的代碼中體現(xiàn))。
了解了這些命令、數(shù)據(jù)的傳輸格式之后,就是要對具體的寄存器進(jìn)行相應(yīng)的配置了。首先要介紹這些寄存器的作用(數(shù)據(jù)手冊上對各寄存器都有說明):
(1)NFCONF:用來設(shè)置時序參數(shù),設(shè)置位寬。
(2)NFCMD:命令寄存器。
(3)NFADDR:地址寄存器。
(4)NFDATA:數(shù)據(jù)寄存器,用于讀寫數(shù)據(jù)。
(5)NFSTAT:狀態(tài)寄存器,只用到最低1位,表示是否忙碌。
編程舉例:
實現(xiàn)從nand flash中拷貝程序到sdram中運(yùn)行,其中涉及到啟動代碼的編程,初始化內(nèi)存控制器,讀取并拷貝nand flash上的數(shù)據(jù)。(只展示部分核心代碼)
head.S
.text .global _start _start: ldr sp,=4096 @設(shè)置堆棧 bl disable_watch_dog @關(guān)閉看門狗 bl set_mem @設(shè)置內(nèi)存控制器 bl nand_init @nand初始化 ldr r0,=0x30000000 ldr r1,=4096 ldr r2,=4096 @傳遞參數(shù) bl nand_read @從nand中拷貝 ldr sp,=0x38000000 ldr lr, =halt @設(shè)置返回地址 ldr pc, =main halt: b halt
nand.c
typedef struct s3c2440_nand { unsigned int NFCONF; unsigned int NFCONT; unsigned int NFCMMD; unsigned int NFADDR; unsigned int NFDATA; unsigned int NFMECCD0; unsigned int NFMECCD1; unsigned int NFSECCD; unsigned int NFSTAT; unsigned int NFESTAT0; unsigned int NFESTAT1; unsigned int NFMECC0; unsigned int NFMECC1; unsigned int NFSECC; unsigned int NFSBLK; unsigned int NFEBLK; }s3c2440_nand; //定義nandflash控制器的起始地址 static s3c2440_nand* nand_base = (s3c2440_nand*)0x4E000000; //片選 void select_chip_or_not(int flag)//0不片選,1片選 { if(flag == 1) { nand_base->NFCONT |= (0x1<<1); } if(flag == 0) { nand_base->NFCONT &= ~(0x1<<1); } } void write_command(unsigned char cmd) { volatile unsigned char *p = (volatile unsigned char *)&nand_base->NFCMMD; *p = cmd; } void write_addr(unsigned int addr) { int i; volatile unsigned char* p = (volatile unsigned char *)nand_base->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++); } //等待nand flash就緒 void wait_ldle(void) { volatile unsigned char* p = (volatile unsigned char*)nand_base->NFSTAT; int flag = *p & 1; while(!flag) { int i; for(i=0;i<20;i++); } } unsigned char read_data(void) { volatile unsigned char *p= (volatile unsigned char*)nand_base->NFDATA; return *p; } void nand_read(unsigned char* buf,unsigned char base_addr,unsigned int size) { int i,j; //片選 select_chip_or_not(1); //復(fù)制數(shù)據(jù) for(i=base_addr;i<base_addr+size;) { write_command(0);//發(fā)送讀命令 write_addr(i); //發(fā)送地址 write_command(0x30); wait_ldle(); for(j=0;j<512;j++,i++) { *buf = read_data(); //讀取數(shù)據(jù),一次讀取一頁(512個字節(jié)) buf++; } } select_chip_or_not(0);//取消片選 } void nand_reset(void) { select_chip_or_not(1);//片選 write_command(0xff); wait_ldle(); select_chip_or_not(0); } void nand_init(void) { nand_base->NFCONF = (0<<12)|(3<<8)|(0<<4); nand_base->NFCONT = (1<<4)|(1<<1)|(1<<0); nand_reset(); }
還要說下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 $@ %.o : %.S arm-linux-gcc -c $< -o $@ %.o : %.c arm-linux-gcc -c $< -o $@ clean : rm -f nand.bin *.o nand_elf
平時寫的Makefile不一樣,這里使用了一個名為nand.lds的鏈接腳本,這樣做主要是為了試驗讓編譯好的程序在鏈接時存放的地址和理論運(yùn)行地址都不同且不在同一個存儲設(shè)備上,方便看試驗效果。
nand.lds
SECTIONS { first 0x00000000 : {head.o init.o nand.o} second 0x30000000 : AT(4096) {main.o} }
鏈接腳本上的第一段是放head.S init.c nand.c編譯出的內(nèi)容,從0地址開始存放和執(zhí)行,而main.o則是需要從nand flash手動復(fù)制到sdram中去執(zhí)行。
實現(xiàn)的效果如圖:
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。