zoukankan      html  css  js  c++  java
  • NandFlash学习


    title: NandFlash学习
    tags: ARM
    date: 2018-10-27 20:18:48:59

    NandFlash学习

    概述

    • NAND是公用数据线和地址线的,所以是需要命令操作的
    • NAND和其他内存接口公用数据线,所以需要片选信号
    • NAND有位反转,所以内部存在OOB(out of bank),这个一般无需cpu处理.,同时存在坏块,使用ecc处理

    原理图(K9F2G08U0C)

    mark

    mark

    启动的引脚配置

    mark

    mark

    命令概述

    mark

    操作概述

    mark

    具体的操作时序,这个手册好评,短小好找

    mark

    比如读操作

    mark

    根据这个图就可以大致看出电平应该怎样,再查找时序图,基本就清楚了

    mark

    地址信号操作,256M需要地址线=256*1024*1024*8=2^8*2^20=2^28也就是28个地址线

    mark

    mark

    mark

    Uboot下操作体验

    上述的操作,对于MCU来说就更简单了,读写相关寄存器即可.

    mark

    NAND FLASH S3C2440
    发命令 选中芯片->CLE设为高电平 输出命令值->在DATA0~DATA7上->发出一个写脉冲 NFCONT的bit1设为0,->NFCMMD=命令值
    发地址 选中芯片->ALE设为高电平->在DATA0~DATA7上输出地址值->发出一个写脉冲 NFCONT的bit1设为0,->NFADDR=地址值
    发数据 选中芯片->ALE,CLE设为低电平-> 在DATA0~DATA7上输出数据值->发出一个写脉冲 NFCONT的bit1设为0,->NFDATA=数据值
    读数据 选中芯片->发出读脉冲->读DATA0~DATA7的数据 NFCONT的bit1设为0,->val=NFDATA

    读ID

    S3C2440 u-boot
    选中 NFCONT的bit1设为0 md.l 0x4E000004 1; mw.l 0x4E000004 1
    发出命令0x90 NFCMMD=0x90 mw.b 0x4E000008 0x90
    发出地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
    读数据得到0xEC val=NFDATA md.b 0x4E000010 1
    读数据得到device code val=NFDATA md.b 0x4E000010 1
    退出读ID的状态 NFCMMD=0xff mw.b 0x4E000008 0xff
    
    Enter your selection: q
    OpenJTAG> md.l 0x4E000004 1
    4e000004: 00000003    ....
    OpenJTAG> mw.l 0x4E000004 1
    OpenJTAG> mw.b 0x4E000008 0x90
    OpenJTAG> mw.b 0x4E00000C 0x00
    OpenJTAG> md.b 0x4E000010 1
    4e000010: ec    .
    OpenJTAG> md.b 0x4E000010 1
    4e000010: da    .
    OpenJTAG> md.b 0x4E000010 1
    4e000010: 10    .
    OpenJTAG> md.b 0x4E000010 1
    4e000010: 95 
    OpenJTAG> md.l 0x4E000010 1
    4e000010: 44    D
    OpenJTAG> mw.b 0x4E000008 0xff
    

    读数据

    uboot可以使用 nand dump 0 读取nand的内容

    mark

    S3C2440 u-boot
    选中 NFCONT的bit1设为0 md.l 0x4E000004 1; mw.l 0x4E000004 1
    发出命令0x00 NFCMMD=0x00 mw.b 0x4E000008 0x00
    发出地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
    发出地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
    发出地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
    发出地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
    发出地址0x00 NFADDR=0x00 mw.b 0x4E00000C 0x00
    发出命令0x30 NFCMMD=0x30 mw.b 0x4E000008 0x30
    读数据得到0x17 val=NFDATA md.b 0x4E000010 1
    读数据得到0x00 val=NFDATA md.b 0x4E000010 1
    读数据得到0x00 val=NFDATA md.b 0x4E000010 1
    读数据得到0xea val=NFDATA md.b 0x4E000010 1
    退出读状态 NFCMMD=0xff mw.b 0x4E000008 0xff
    OpenJTAG> mw.b 0x4E000008 0xff
    OpenJTAG> mw.l 0x4E000004 1
    OpenJTAG> mw.b 0x4E000008 0x00
    OpenJTAG> mw.b 0x4E00000C 0x00
    OpenJTAG> mw.b 0x4E00000C 0x00
    OpenJTAG> mw.b 0x4E00000C 0x00
    OpenJTAG> mw.b 0x4E00000C 0x00
    OpenJTAG> mw.b 0x4E00000C 0x00
    OpenJTAG> mw.b 0x4E000008 0x30
    OpenJTAG> md.b 0x4E000010 1
    4e000010: 17    .
    OpenJTAG> md.b 0x4E000010 1
    4e000010: 00    .
    OpenJTAG> md.b 0x4E000010 1
    4e000010: 00    .
    
    

    ID与地址编码

    mark

    mark

    mark

    mark

    使用uboot读到的是EC-DA-10-95-44对比下第四字节的9515,也就是手册上写的是15=50ns/30ns,芯片读出来是95=25ns

    • Internal Chip Number =1
    • Number of
      Simultaneously
      Programmed Pages =2
    • Page Size=2kb
    • Block Size=128kb,所以1个block有128/2=64page
    • Redundant Area Size=16
    • Serial Access Minimum= 25ns
    • Plane Number=2
    • Plane Size=1Gb

    最小擦除的单位是1个block=128k

    内部的组织结构可以参考 K9F2G08UXA的数据手册

    mark

    mark

    mark

    小结

    发送地址addr的时候,先发col低地址也就是页内地址,再发高地址也就是第几个page.地址本身也还是先发送低位,也就是说col有2字节,先发低字节.

    int page = addr / 2048;
    int col  = addr & (2048 - 1);//相当于addr%2048
    
    /* 发出地址 */
    /* col addr */
    nand_addr_byte(col & 0xff);
    nand_addr_byte((col>>8) & 0xff);
    
    /* row/page addr */
    nand_addr_byte(page & 0xff);
    nand_addr_byte((page>>8) & 0xff);
    nand_addr_byte((page>>16) & 0xff);
    

    时序初始化

    NAND的时序参数实际上大体分为两种,发送命令、地址以及发送数据,下图是MCU的时序配置图

    mark

    查看下NAND手册的命令时序图

    mark

    mark

    • 可以拿一个直尺来划分各时间点到拐角

    • 可以看出 CLE和ALE的时间参数是一致的

      • MCU中的TACLS 拐点在CLE有效之后TALS后才允许nWE有效,找到NAND中CLE>=12,tWp>=12.也就是说可以同时发出
      • TWRPH0为nWE的有效时间,对应NAND的tER>=12
      • TWRPH0为nWE失效到CLE失效的时间对应的是NAND的tCh>=5

      mark

    其他寄存器设置如下

    /*使能NAND FLASH控制器,初始化ECC,禁止片选*/
    NFCONT = (1<<4) | (1<<1) | (1<<0);
    

    程序设计

    忙判断

    手册上写: 软件模式下,你必须用定时查询或中断来检测 RnB 状态输入引脚。这个状态在NFSTAT的BIT0,0表示忙

    void wait_ready(void)
    {
    	while (!(NFSTAT & 1));
    }
    

    基本操作

    void nand_deselect(void)
    {
    	/*禁止片选*/
    	NFCONT |= (1<<1);
    }
    void nand_cmd(unsigned char cmd)
    {
    	volatile int i;
    	NFCCMD = cmd;
    	for(i=0; i<10; i++);
    }
    void nand_addr_byte(unsigned char addr)
    {
    	volatile int i;
    	NFADDR = addr;
    	for(i=0; i<10; i++);
    }
    unsigned char nand_data(void)
    {
    	return	NFDATA;
    }
    void nand_w_data(unsigned char val)
    {
    	NFDATA = val;
    }
    void wait_ready(void)
    {
    	while (!(NFSTAT & 1));
    }
    

    读NAND

    mark

    void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
    {
    	int i = 0;
    	int page = addr / 2048;
    	int col  = addr & (2048 - 1);
    	
    	nand_select(); 
    
    	while (i < len)
    	{
    		/* 发出00h命令 */
    		nand_cmd(00);
    
    		/* 发出地址 */
    		/* col addr */
    		nand_addr_byte(col & 0xff);
    		nand_addr_byte((col>>8) & 0xff);
    
    		/* row/page addr */
    		nand_addr_byte(page & 0xff);
    		nand_addr_byte((page>>8) & 0xff);
    		nand_addr_byte((page>>16) & 0xff);
    
    		/* 发出30h命令 */
    		nand_cmd(0x30);
    
    		/* 等待就绪 */
    		wait_ready();
    
    		/* 读数据 */
    		for (; (col < 2048) && (i < len); col++)
    		{
    			buf[i++] = nand_data();			
    		}
    		if (i == len)
    			break;
    
    		col = 0;
    		page++;
    	}
    	
    	nand_deselect(); 	
    }
    

    擦除

    mark

    NAND的擦除单位是一个blok=64page=64*2k=128k

    int nand_erase(unsigned int addr, unsigned int len)
    {
    	int page = addr / 2048;
    
    	if (addr & (0x1FFFF))
    	{
    		printf("nand_erase err, addr is not block align
    
    ");
    		return -1;
    	}
    	
    	if (len & (0x1FFFF))
    	{
    		printf("nand_erase err, len is not block align
    
    ");
    		return -1;
    	}
    	
    	nand_select(); 
    
    	while (1)
    	{
    		page = addr / 2048;
    		
    		nand_cmd(0x60);
    		
    		/* row/page addr */
    		nand_addr_byte(page & 0xff);
    		nand_addr_byte((page>>8) & 0xff);
    		nand_addr_byte((page>>16) & 0xff);
    
    		nand_cmd(0xD0);
    
    		wait_ready();
    
    		len -= (128*1024);
    		if (len == 0)
    			break;
    		addr += (128*1024);
    	}
    	
    	nand_deselect(); 	
    	return 0;
    }
    

    写NAND

    mark

    void nand_write(unsigned int addr, unsigned char *buf, unsigned int len)
    {
    	int page = addr / 2048;
    	int col  = addr & (2048 - 1);
    	int i = 0;
    
    	nand_select(); 
    
    	while (1)
    	{
    		nand_cmd(0x80);
    
    		/* 发出地址 */
    		/* col addr */
    		nand_addr_byte(col & 0xff);
    		nand_addr_byte((col>>8) & 0xff);
    		
    		/* row/page addr */
    		nand_addr_byte(page & 0xff);
    		nand_addr_byte((page>>8) & 0xff);
    		nand_addr_byte((page>>16) & 0xff);
    
    		/* 发出数据 */
    		for (; (col < 2048) && (i < len); )
    		{
    			nand_w_data(buf[i++]);
    		}
    		nand_cmd(0x10);
    		wait_ready();
    
    		if (i == len)
    			break;
    		else
    		{
    			/* 开始下一个循环page */
    			col = 0;
    			page++;
    		}
    		
    	}
    	
    	nand_deselect(); 	
    }
    
    

    其他注意

    • 使用nand 代码重定位的时候,注意make file 中的 链接文件 start ,nand 等文件放前面,保证在4k内
  • 相关阅读:
    web基础要点记录
    前端一些干货
    正则表达式手册
    JQuery实现旋转轮播图
    JQuery模拟常见的拖拽验证
    electron应用以管理员权限启动
    原生JS模拟百度搜索关键字与跳转
    关于Application的使用
    Android事件分发机制(相关文章)
    (转)Activity的四种launchMode
  • 原文地址:https://www.cnblogs.com/zongzi10010/p/10023625.html
Copyright © 2011-2022 走看看