NandFlash学习
title: NandFlash学习
tags: ARM
date: 2018-10-27 20:18:48:59
NandFlash学习
概述
- NAND是公用数据线和地址线的,所以是需要命令操作的
- NAND和其他内存接口公用数据线,所以需要片选信号
- NAND有位反转,所以内部存在OOB(out of bank),这个一般无需cpu处理.,同时存在坏块,使用ecc处理
原理图(K9F2G08U0C)
启动的引脚配置
命令概述
操作概述
具体的操作时序,这个手册好评,短小好找
比如读操作
根据这个图就可以大致看出电平应该怎样,再查找时序图,基本就清楚了
地址信号操作,256M需要地址线=256*1024*1024*8=2^8*2^20=2^28
也就是28个地址线
Uboot下操作体验
上述的操作,对于MCU来说就更简单了,读写相关寄存器即可.
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的内容
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与地址编码
使用uboot读到的是EC-DA-10-95-44
对比下第四字节的95
与15
,也就是手册上写的是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
的数据手册
小结
发送地址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的时序配置图
查看下NAND手册的命令时序图
可以拿一个直尺来划分各时间点到拐角
可以看出 CLE和ALE的时间参数是一致的
- MCU中的TACLS 拐点在CLE有效之后TALS后才允许nWE有效,找到NAND中CLE>=12,tWp>=12.也就是说可以同时发出
- TWRPH0为nWE的有效时间,对应NAND的tER>=12
- TWRPH0为nWE失效到CLE失效的时间对应的是NAND的tCh>=5
其他寄存器设置如下
/*使能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
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();
}
擦除
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\n\r");
return -1;
}
if (len & (0x1FFFF))
{
printf("nand_erase err, len is not block align\n\r");
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
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内
NandFlash学习的更多相关文章
- nandflash学习1——导致nandflash反转的原因【转】
转自:http://blog.csdn.net/gaosentao/article/details/7711311 Bit Flip/Bit Flipping/Bit-Flip/Bit twiddli ...
- s3c6410学习笔记-将内核zImage、文件系统写到nandflash、屏幕校准
1.之前已经将uboot写到nandflash里面了,接下来将内核zImage.文件系统写到nandflash. 2.编译内核 cd linux-2.6.28_smdk6410 make clean ...
- 驱动开发学习笔记. 0.02 基于EASYARM-IMX283 烧写uboot和linux系统
驱动开发读书笔记. 0.02 基于EASYARM-IMX283 怎么烧写自己裁剪的linux内核?(非所有arm9通用) 手上有一块tq2440,但是不知道什么原因,没有办法烧boot进norflas ...
- 1.ok6410移植bootloader,移植u-boot,学习u-boot命令
ok6410移植u-boot 既然是移植u-boot当然首先需要u-boot源码,这里的u-boot代码是由国嵌提供的. 一.配置编译u-boot A. 解压 u-boot 压缩文件 B. 进入解压生 ...
- ARM指令分类学习
指令分类: 1.算数和逻辑指令 2.比较指令 3.跳转指令 4.移位指令 5.程序状态字访问指令 6.存储器访问指令 +++++++++++++++++++++++++++++++++++++++++ ...
- 嵌入式Llinux学习路线图
版本 日期 作者 说明 V1 2016.07.29 韦东山 第1版本,Android部分未写 我是1999年上的大学,物理专业.在大一时,我们班里普遍弥漫着对未来的不安,不知道学习了物理后出去能做什么 ...
- NandFlash和iNand【转】
转自:https://www.cnblogs.com/PengfeiSong/p/6380447.html nand 1.nand的单元组织:block与page(大页Nand与小页Nand)(1)N ...
- NandFlash和iNand
nand 1.nand的单元组织:block与page(大页Nand与小页Nand)(1)Nand的页和以前讲过的块设备(尤其是硬盘)的扇区是类似的.扇区最早在磁盘中是512字节,后来也有些高级硬盘扇 ...
- EEPROM读写学习笔记与I2C总线(转)
reference:https://www.cnblogs.com/uiojhi/p/7565232.html 无论任何电子产品都会涉及到数据的产生与数据的保存,这个数据可能并不是用来长久保存,只是在 ...
随机推荐
- poj-1236(强连通分量)
题意:给你n个点,每个点可能有指向其他点的单向边,代表这个点可以把软件传给他指向的点,然后解决两个问题, 1.问你最少需要给几个点,才能使所有点都能拿到软件: 2.问你还需要增加几条单向边,才能使任意 ...
- 创建iview框架的项目
http://www.cnblogs.com/jf-67/p/8479176.html 在使用‘vue init webpack my-project’创建项目时,出现了错误 npm ERR! cod ...
- 双击jar文件运行程序
Java应用程序jar文件可以由 JVM(Java虚拟机)直接执行,只要操作系统安装了JVM便可以运行作为Java应用程序的jar文件.可是,很多朋友遇到一个难题,那就是下载了jar文件以后在Wind ...
- POJ1015-Jury Compromise-dp
略复杂的dp题. 有n个人,每个人有两个分数di,pi.从中选出m个人,要求|sigma(di)-sigma(pi)|最小,相同时则输出sigma(di)+sigma(pi)最大的情况. 答案完整输出 ...
- Windows server 2012 卸载iis 黑屏
转载:https://jingyan.baidu.com/article/ff42efa9fb6f16c19e2202dc.html 1 按 ctrl+alt+end 键,新建运行任务 ,输入cmd ...
- Python小练习
1.计算x的n次方 2.计算x的阶乘 3.计算1x1 + 2x2 + 3x3 ...+ NxN之和 def fun(n): s=0 while n > 0: s = s + n*n n = n ...
- 【BZOJ3379】【USACO2004】交作业 区间DP
题目描述 数轴上有\(n\)个点,你要从位置\(0\)去位置\(B\),你每秒钟可以移动\(1\)单位.还有\(m\)个限制,每个限制\((x,y)\)表示你要在第\(t\)秒之后(可以是第\(t\) ...
- Linux block(1k) block(4k) 换算 gb
输入 df 显示1k blocks 大小 再输入 df -h 显示 gb换算大小 结论 block(1k) 计算公式为: block(1k) /1024/1000 = xx gb ...
- <Android基础>(二) Activity Part 1
1.活动的基本用法: 1) 手动创建活动.创建加载布局 2) 在AndroidManifest文件中注册 3) 在活动中添加Button.Toast.Menu 4) 销毁活动 2.Intent 1) ...
- 「HNOI2016」网络 解题报告
「HNOI2016」网络 我有一个绝妙的可持久化树套树思路,可惜的是,它的空间是\(n\log^2 n\)的... 注意到对一个询问,我们可以二分答案 然后统计经过这个点大于当前答案的路径条数,如果这 ...