加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

nand flash读取函数的理解

发布时间:2020-12-15 18:47:04 所属栏目:百科 来源:网络整理
导读:S3C2410处理器集成了8位NandFlash控制器。目前市场上常见的8位NandFlash有三星公司的k9f1208、k9f1g08、k9f2g08等。k9f1208、k9f1g08、k9f2g08的数据页大小分别为512Byte、2kByte、2kByte。它们在寻址方式上有一定差异,所以程序代码并不通用。本文以S3C2410

S3C2410处理器集成了8位NandFlash控制器。目前市场上常见的8位NandFlash有三星公司的k9f1208、k9f1g08、k9f2g08等。k9f1208、k9f1g08、k9f2g08的数据页大小分别为512Byte、2kByte、2kByte。它们在寻址方式上有一定差异,所以程序代码并不通用。本文以S3C2410处理器和k9f1208系统为例,讲述NandFlash的读写方法。

NandFlash的数据是以bit 的方式保存在memory cell里的,一般来说,一个cell 中只能存储一个bit,这些cell 以8 个或者16 个为单位,连成bit line,形成所谓的byte(x8)/word(x16),这就是NAND Device 的位宽。这些Line 组成Page, page 再组织形成一个Block。k9f1208的相关数据如下:

1block=32page;1page=528byte=512byte(Main Area)+16byte(Spare Area)。

总容量为=4096(block数量)*32(page/block)*512(byte/page)=64Mbyte

NandFlash以页为单位读写数据,而以块为单位擦除数据。按照k9f1208的组织方式可以分四类地址: Column Address、halfpage pointer、Page Address 、Block Address。A[0:25]表示数据在64M空间中的地址。

Column Address表示数据在半页中的地址,大小范围0~255,用A[0:7]表示;

halfpage pointer表示半页在整页中的位置,即在0~255空间还是在256~511空间,用A[8]表示;

Page Address表示页在块中的地址,大小范围0~31,用A[13:9]表示;

Block Address表示块在flash中的位置,大小范围0~4095,A[25:14] 表示;

把nand_flash想象成一本书,每一页纸就是一页数据(每一页书的宽就是flash的位宽,长就是flash的列地址),没几十页组成一个块,所有的块又组成一本书,就这样直观多了。

而页寄存器用来缓存一页数据。

?

?

#include <linux/tmd/nand.h> #define __REGb(x) (*(volatile unsigned char? *)(x)) #define __REGw(x) (*(volatile unsigned short *)(x)) #define __REGi(x) (*(volatile unsigned int?? *)(x)) #define NF_BASE? 0x4e000000 #if defined(CONFIG_S3C2440) #define NFCONF ?? ??? ?__REGi(NF_BASE + 0x0) #define NFCONT?? ??? ?__REGi(NF_BASE + 0x4) #define NFCMD?????? __REGb(NF_BASE + 0x8) #define NFADDR?? ??? ?__REGb(NF_BASE + 0xc) #define NFDATA?? ??? ?__REGb(NF_BASE + 0x10) #define NFDATA16 ?? ?__REGw(NF_BASE + 0x10) #define NFSTAT?? ??? ?__REGb(NF_BASE + 0x20) #define NFSTAT_BUSY?? ?1 #define nand_select()?? ?(NFCONT &= ~(1 << 1))? //cs低电平选中 #define nand_deselect()?? ?(NFCONT |=? (1 << 1)) #define nand_clear_RnB() (NFSTAT |= (1 << 2)) #endif static inline void nand_wait(void) { int i; while(!(NFSTAT & NFSTAT_BUSY)) for(i=0; i<10; i++); } struct boot_nand_t { int page_size; int block_size; int bad_block_offset; }; static int is_bad_block(struct boot_nand_t *nand,unsigned long i) { unsigned char data; unsigned long page_num; nand_clear_RnB(); if(nand->page_size == 512) { NFCMD = NAND_CMD_READOOB; NFADDR = nand->bad_block_offset & 0xf; NFADDR = (i >> 9) & 0xff; NFADDR = (i >> 17) & 0xff; NFADDR = (i >> 25) & 0xff; }else if(nand->page_size == 2048) { page_num = i >> 11;? /* addr / 2048 */ NFCMD = NAND_CMD_READ0; NFADDR = (nand->bad_block_offset ) & 0xff;???? // Check "FFh" at the column address 2048 NFADDR = (nand->bad_block_offset >> 8) & 0xff; // of the 1st and 2nd page in the block NFADDR = (page_num ) & 0xff;?????????????????? // address of block NFADDR = (page_num >> 8) & 0xff; NFADDR = (page_num >> 16) & 0xff; NFCMD? = NAND_CMD_READSTART; }else { return -1; } nand_wait(); data = (NFDATA & 0xff); if(data != 0xff) return 1; return 0; } static int nand_read_page_ll(struct boot_nand_t *nand,unsigned char *buf,unsigned long addr) { unsigned short *ptr16 = (unsigned short *)buf; unsigned int i,page_num; nand_clear_RnB(); NFCMD = NAND_CMD_READ0; if(nand->page_size == 512){ NFADDR = addr & 0xff; NFADDR = (addr >> 9)&0xff; NFADDR = (addr >> 17)&0xff; NFADDR = (addr >> 25)&0xff; }else if (nand->page_size == 2048){ page_num = addr >> 11; NFADDR = 0;?????????????? //页内地址 ,为0时读取整页 NFADDR = 0; NFADDR = page_num & 0Xff; //确定页地址 NFADDR = (page_num >> 8) & 0xff; NFADDR = (page_num >> 16) & 0xff; NFCMD? = NAND_CMD_READSTART; }else { return -1; } nand_wait();????????????????? //发送命令和地址后,flash ready?? ? #if defined(CONFIG_S3C2410) for(i = 0; i < nand->page_size; i++){ *buf = (NFDATA & 0xff); buf++; } #elif defined(CONFIG_S3C2440)??? //循环读出数据 for(i = 0; i < (nand->page_size >> 1); i++){ *ptr16 = NFDATA16; ptr16++; } #endif return nand->page_size;?? ??? ? } static unsigned short nand_read_id() { unsigned short ret = 0; NFCMD = NAND_CMD_READID; NFADDR = 0; res = NFDATA; res = (res << 8) | NFDATA; return res; } extern unsigned int dynpart_size[]; int nand_read_ll(unsigned char *buf,unsigned long start_addr,int size) { int i,j; unsigned short nand_id; struct boot_nand_t nand; nand_select(); nand_clear_RnB(); for(i = 0; i < 10; i++) ; nand_id = nand_read_id(); if(nand_id == 0xec76 || /* Samsung K91208 */ nand_id == 0xad76) { /*Hynix HY27US08121A*/ nand.page_size = 512; nand.block_size = 16 * 1024;?? ? } else if(nand_id == 0xecf1 ||/* Samsung K9F1G08U0B */ nand_id == 0xecda ||/* Samsung K9F2G08U0B */ nand_id == 0xecd3 ){/* Samsung K9K8G08 */ nand.page_size = 2048; nand.block_size = 128 * 1024; nand.bad_block_offset = nand.page_size;?? ??? ? }else{ return -1 ; //hang } if((start_addr & (nand.block_size - 1)) || (size & (nand.block_size - 1)))//检查块地址对齐,即地址的低17为只能为0。 return -1; for(i = start_addr; i < (start_addr + size);){ #ifdef CONFIG_S3C2410_NAND_SKIP_BAD if(i & (nand.block_size - 1) == 0){? //如果i时块地址对齐就执行,不是块地址对齐就不检查 if(is_bad_block(&nand,i) || is_bad_block(&nand,i+nand.page_size)){//the 1st and 2nd page in the block i += nand.block_size; size += nand.block_size; continue;? //跳回去检测,下一个块是否为坏块 } } #endif j = nand_read_page_ll(&nand,buf,i); i += j; buf += j; } nand_deselect(); return 0; }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读