1:开发环境

芯片:NUC977
控制器:FMI
flash芯片:W29N02GVS1AA

2:Nandflash原理

2.1 命名含义

2.2 引脚含义

CE :chip Enable 片选信号 低电平有效(上面带横杠表示低电平有效)
WE:Write Enable 写使能 低电平有效
RE: Read Enable 读使能 低电平有效
ALE:Address Latch Enable 地址占有使能
CLE:Command Latch Enable 命令占有使能
WP: write Project 写保护 低电平有效
RY/#BY: Read/Busy 空闲与繁忙状态
I/Ox : Input and Output 输入与输出引脚

一般工作得方式是:CE为低选中芯片,WE控制要写入数据 , RE控制读出数据。 当ALE为高时,表示可以写入地址。 当CLE为高时,表示可以协议命令。当ALE和CLE都为低可以经行数据得读写。
当操作都完成后可以通过RY/#BY得状态来判断是否真正得完成。

3:内部存储格式

3.1 page

再nand flash内部 最小操作单位时page,可以时512, 2K, 4K。这里得一个page是2K。

3.2 OOB/Spare Area / Redundant Area /

nand flash中每一页对应一块区域,用于存放校验的ECC数据和其他一些信息,比如上层文件系统放的和自己文件系统相关的数据。这个区域,在Linux MTD相关系统中,被称作oob(out of band),可以翻译为带外,也就是nand flash的一个页,可以称作一个band,band之外,对应的就是指那个多出来的,特殊的区域了。而nand flash的datasheet中,一般成为spare area,可译为空闲区域,另外,在ID的含义解释中也叫做redundant area,可译为冗余区域,归根结底,都是一个含义。不要被搞糊涂了就好

3.3 block

64个页是一个block,这里的大小是 64 * 2K = 128 K。 block是擦除的最小单元

3.4 Plane

1024个block是一个Plane ,这里的大小为 1024 * 128K = 128M

3.5 Chip

对于chip,其实任何某个型号的flash,都可以称其是一个chip,但是实际上,此处的chip,是针对内部来说的,也就是某型号的flash,内部有几个chip,比如下面会举例说到的,三星的2GB的K9WAG08U1A芯片(可以理解为外部芯片/型号)内部装了2个单片是1GB的K9K8G08U0A,此时就称 K9WAG08U1A内部有2个chip,而有些单个的chip,内部又包含多个plane,比如上面的W29N02GVS1AA内部包含2个单片是2Gb的Plane。只有搞清楚了此处的chip和plane的关系,才能明白后面提到的多页(Multi Plane / Multi Page)编程和交互(interleave)编程的含义。

这里的大小为 2 * 128M = 256M

3.6 Page Register(页寄存器)

nand flash硬件中的一块地方,名字叫做register,实际就是一个数据缓存,一个buffer,用于存放那些从flash读出来或者将要写入到flash中的。其实叫做页缓存,更合适,更容易明白其含义。此页寄存器的大小=页大小+ oob 大小,即pagesize+oob,对于常见的页是2KB的,此页寄存器就是2KB+64=2112字节

4 地址写入循环:

不同的flash,地址写入方式不同,有些把一个地址分为3次写入,有些分为5次写入

这个图表示:
有效地址为29位,地址分为5次写入
之所以这样划分起始是为了行地址和列地址,也就是页内的地址和页的地址
A0-A11:在前两次写入。这是因为一个页的大小是2048,用二进制表示就是1000 0000 0000,是12位。也是是说,要访问一个页内的0-2047处的数据,最多需要11位就可以了就可以表示(000 0000 0000 - 111 1111 1111)。
这里用了12位,是为了访问OOB区。当地址A0-A12为1000 0000 0000时,就表示访问该页后面的OOB的数据。

A11-A28:17位就是来表示哪一个页。这里有2102464 个页。 二进制表示10 0000 0000 0000 0000
所以对应的17位就可以访问所有的页

总结:地址可以分成2部分,后面3次的地址用来寻找在哪一个页。前面2次的地址用力寻找在该页的哪一个位置。

5 操作的命令

5.1 读ID READ ID(0x90)

基本过程就是:
1:先发出命令0x90
2:再发出地址0x00
3:再读取5 byte数据即可

void read_nand_id(void)
{char id[6]={0};int i;outpw(REG_NANDCTL, (inpw(REG_NANDCTL)&(~0x06000000))|0x04000000); //CS enableoutpw(REG_NANDCMD, NAND_CMD_READID);outpw(REG_NANDADDR, 0x80000000); //这里地址最高位置1 来表示时最后一笔地址
//  outpw(REG_NANDADDR, 0x80000020);for(i = 0; i< 6; i++) {id[i] = (unsigned char)inpw(REG_NANDDATA);}for(i = 0; i< 6; i++) {rt_kprintf("id[%d] = 0x%02x\n", i, id[i]);}outpw(REG_NANDCTL, (inpw(REG_NANDCTL)&(~0x06000000))); //CS disable
}
MSH_CMD_EXPORT(read_nand_id, read_nand_id);

5.2 读数据 PAGE READ (00h-30h)

过程:
1:先发出读命令0x00
2: 发出5次地址
3:发出命令0x30
4:等待RY/#BY变成1,表示数据由flash中的page读到page buffer这个动作结束
5:读出数据

int nand_read(int argc, char *argv[])
{rt_uint8_t *pBuffer;;rt_uint32_t StartAddress;rt_uint32_t NumByteToRead;rt_uint32_t i;rt_uint32_t column,  page_addr;if(argc > 2) {StartAddress =  htoi(argv[1]);NumByteToRead =  htoi(argv[2]);}else{rt_kprintf("please input >> nand_read <addr> <length>\n");return RT_ERROR;}pBuffer = rt_malloc(NumByteToRead);column = StartAddress % 2048;page_addr = StartAddress / 2048;outpw(REG_NANDCTL, (inpw(REG_NANDCTL)&(~0x06000000))|0x04000000); //CS enableoutpw(REG_NANDCMD, NAND_CMD_READ0); // read0 cmdoutpw(REG_NANDADDR, column&0xff);outpw(REG_NANDADDR, column >> 8);outpw(REG_NANDADDR, page_addr&0xFF);outpw(REG_NANDADDR, (page_addr >> 8)&0xFF);outpw(REG_NANDADDR, ((page_addr >> 16)&0xFF)|ENDADDR);outpw(REG_NANDCMD, NAND_CMD_READSTART); // cmd read startwhile (!(inpw(REG_NANDINTSTS) & READYBUSY)); //waitfor(i = 0; i<NumByteToRead; i++){pBuffer[i] = (unsigned char)inpw(REG_NANDDATA);}rt_kprintf("data:\n");for(i = 0; i<NumByteToRead; i++) {if(i%16 == 0) {rt_kprintf("\n");rt_kprintf("0x%08x: ", StartAddress+i);}rt_kprintf("0x%02x ", pBuffer[i]);}rt_kprintf("\n");outpw(REG_NANDCTL, (inpw(REG_NANDCTL)&(~0x06000000))); //CS disablereturn RT_EOK;
}
MSH_CMD_EXPORT(nand_read, read_nand test);

5.3 写操作 PAGE PROGRAM (80h-10h)

通常flash 用program(编程)来表示写


过程:
1:发送命令0x80
2:发送5次地址
3:发送数据
4:发送命令0x10
5:等待RY/#BY变成1,表示数据由page buffer写入到flash中的page这个动作结束

rt_uint32_t nand_write(int argc, char *argv[])
{rt_uint8_t *pBuffer;rt_uint8_t data;rt_uint32_t StartAddress;rt_uint32_t NumByteToWrite;rt_uint32_t i;rt_uint32_t column,  page_addr;if(argc > 3) {StartAddress =  htoi(argv[1]);NumByteToWrite =  htoi(argv[2]);data =  htoi(argv[3]);}else{rt_kprintf("please input >> nand_write <addr> <length> <data>\n");return RT_ERROR;}column = StartAddress % 2048;page_addr = StartAddress / 2048;rt_kprintf("Write addr: 0x%02x, length:%d, data:%x\n\n", StartAddress, NumByteToWrite, data);pBuffer = rt_malloc(NumByteToWrite);for(i = 0; i<NumByteToWrite; i++){pBuffer[i] = data;}outpw(REG_NANDCTL, (inpw(REG_NANDCTL)&(~0x06000000))|0x04000000); //CS enableoutpw(REG_NANDCMD, NAND_CMD_SEQIN); // pargram cmdoutpw(REG_NANDADDR, column&0xff);outpw(REG_NANDADDR, column >> 8);outpw(REG_NANDADDR, page_addr&0xFF);outpw(REG_NANDADDR, (page_addr >> 8)&0xFF);outpw(REG_NANDADDR, ((page_addr >> 16)&0xFF)|ENDADDR);for(i = 0; i<NumByteToWrite; i++){outpw(REG_NANDDATA, pBuffer[i]);}outpw(REG_NANDCMD, NAND_CMD_PAGEPROG); // data inputwhile (!(inpw(REG_NANDINTSTS) & READYBUSY)); //waitoutpw(REG_NANDCMD, NAND_CMD_STATUS); // write status pass: bit0 = 0  fail: bit0 = 1if(inpw(REG_NANDDATA) & 0x1 ){rt_kprintf("write data to address: 0x%08x failed\n", StartAddress);rt_kprintf("status:0x%02x\n", inpw(REG_NANDDATA));}else{rt_kprintf("write data to address: 0x%08x success\n", StartAddress);}outpw(REG_NANDCTL, (inpw(REG_NANDCTL)&(~0x06000000))); //CS disablereturn RT_EOK;
}
MSH_CMD_EXPORT(nand_write, read_nand test);

5.4 块擦除 BLOCK ERASE (60h-D0h)


过程:
1:写入命令0x60
2:写入3次地址,表示页的地址,会删除这个页所在的block
3:写入命令0xDO
4:等待RY/#BY变成1,表示擦删完成
5:写入命令0x70
6:读出1byte数据,查看读出数据的bit0 是不是位0

int nand_erase(int argc, char *argv[])
{rt_uint32_t StartAddress = 0x00030000;rt_uint32_t column,  page_addr;
//  column = StartAddress % 2048;if(argc > 1) {StartAddress =  htoi(argv[1]);}else{rt_kprintf("please input >> nand_erase <addr> <length> <data>\n");return RT_ERROR;}page_addr = StartAddress / 2048;outpw(REG_NANDCTL, (inpw(REG_NANDCTL)&(~0x06000000))|0x04000000); //CS enableoutpw(REG_NANDCMD, NAND_CMD_ERASE1); // erase pageoutpw(REG_NANDADDR, page_addr&0xFF);outpw(REG_NANDADDR, (page_addr >> 8)&0xFF);outpw(REG_NANDADDR, ((page_addr >> 16)&0xFF)|ENDADDR);outpw(REG_NANDCMD, NAND_CMD_ERASE2); // erase confirm commandwhile (!(inpw(REG_NANDINTSTS) & READYBUSY)); //waitoutpw(REG_NANDCMD, NAND_CMD_STATUS); // write status pass: bit0 = 0  fail: bit0 = 1if(inpw(REG_NANDDATA) & 0x1 ){rt_kprintf("erase address: 0x%08x failed\n", page_addr);rt_kprintf("status:0x%02x\n", inpw(REG_NANDDATA));}else{rt_kprintf("erase address: 0x%08x success\n", page_addr);}outpw(REG_NANDCTL, (inpw(REG_NANDCTL)&(~0x06000000))); //CS disablereturn RT_EOK;
}
MSH_CMD_EXPORT(nand_erase, read_nand test);

Nandflash原理W29N02GVS1AA相关推荐

  1. nandflash原理及硬件操作

    我们先看下nandflash的布线 有data0 到data7 八根数据线 nandflash是个存储芯片,那我提出请求:读地址a的数据,把数据b写到a地址上去 那么我们看原理图只看到data0-da ...

  2. freertos nand flash 读取错误_Flash失效小谈

    SOC中往往会集成供应商flash芯片,但完成可靠性实验后偶尔会遇到code丢失,bit翻转等问题,接下来,我们聊一聊flash失效机理及一些可靠性实验. 要分析flash的失效机理,需要先清楚其工作 ...

  3. 收集整理的ARM嵌入式linux开发入门视频教程

    嵌入式Linux作为一个系统学科,具有知识点多,知识难度大,实践操作性强等特点,很多踌躇满志的同学最终倒在了学习嵌入式Linux的道路上,绝大部分也是因为没有掌握嵌入式Linux 的知识规律和学习方法 ...

  4. nand falsh 111

    copy from http://blog.csdn.net/renpine/article/details/4570538 目錄 Architecture NAND Flash是由4096個Bloc ...

  5. 郭天祥ARM9架构嵌入式linux培训视频教程

    第一部分  嵌入式系统开发流程概述 第一讲嵌入式基础知识 1. 嵌入式的定义.特点.应用 2. 嵌入式硬件结构 3. 嵌入式软件结构 第二讲如何学习嵌入式 1. 嵌入式系统开发流程 2. 视频内容介绍 ...

  6. Linux内核4.14版本——Nand子系统(1)——hisi504_nand.c分析

    1. 简介 2. DTS 3. hisi_nfc_probe函数 3.1 获取dts中的资源 3.2 设置nand-chip结构体中必要的字段 3.3 nand_scan_ident扫描识别nand控 ...

  7. bootloader功能介绍/时钟初始化设置/串口工作原理/内存工作原理/NandFlash工作原理...

    bootloader功能介绍 初始化开发板上主要硬件(时钟,内存,硬盘), 把操作系统从硬盘拷贝到内存,然后让cpu跳转到内存中执行操作系统. boot阶段 1.关闭影响CPU正常执行的外设 -关闭看 ...

  8. NandFlash ECC校验原理与实现

    关注+星标公众号,不错过精彩内容 来源 | nhczp 编排 | strongerHuang 大家应该都在用U盘,而U盘中的存储芯片就是NandFlash,你买的64G的U盘,实际并没有64G,其中一 ...

  9. linux系统下操作nandflash指令,Linux驱动之Nand Flash原理及硬件操作

    Nand Flash 是一个存储芯片 那么:这样的操作很理" 读地址A的数据,把数据B写到地址A" 问1:原理图上的Nand Flash和SC2440之间只有数据线,怎么传输地址? ...

最新文章

  1. 【鲁班学院】一个三年工作经验和月薪16k的java程序员应该要具备什么样的技能?...
  2. 最近的状态很不好,需要调整
  3. 递归二分查找时间复杂度、空间复杂度和稳定性
  4. WIN32 使用事件实现高效生产者消费者模型
  5. 【网络安全】Windows cmd的命令混淆学习思路
  6. 神策“营销云·微信生态”全面开放,限时免费申请通道开启!
  7. JAVA I/O操作那些事之标准I/0
  8. 突发!吴恩达确诊新冠,46岁生日还有不到3个月
  9. Python——列表中存放字典遇到的问题
  10. 初探Golang(3)-数据类型
  11. Python3 基础学习笔记 C03【操作列表】
  12. jstl与EL表达式处理字符串
  13. django2与ajax,Python-Django-Ajax进阶2
  14. java基本语法 2017_Java基本语法——(用于日后复习)
  15. DeepLearningAI 学习笔记 1.2 logistic 回归
  16. 洛谷 1373 dp 小a和uim之大逃离 良心题解
  17. 怎样用python录音_python实现录音功能(可随时停止录音)
  18. SQL Nexus Tool
  19. creo减速器建模实例,减速箱proE整体及零件图
  20. Picasso 源码解读

热门文章

  1. vue 中使用 Windi CSSS 样式库
  2. Linux中配置uGet和aria2
  3. 智慧校园管理在疫情防控中的作用有哪些?
  4. 读《文明之光》第三册 吴军
  5. 唐朔飞版本计算机组成原理(第二版)各章知识点思维导图
  6. 高速公路视联网解决方案来了!全面助力行业智能运行监测升级
  7. 【计算机网络】IPV4地址和IPV6地址 电脑是如何相互访问和连接的?
  8. 对进行神经网络的图片进行预处理
  9. 【DB2报错】SQLSTATE:-668 SQLCODE:57016 code “3“
  10. Bash(shellshock)