Mini2440裸机开发之Nand Flash 编程
目录
一、Nand Flash命令
1.1 命令表
对Nand Flash的操作需要发出命令,下面有个Nand Flash的命令表格,那么我们可以此表格上的命令来访问我们的Nand Flash。
针对每一个命令的时序可以参考Nand Flash芯片使用手册。下面我们将会分析一些常用命令的时序。时序中部分信号的信息如下:
- 当ALE为高电平时传输的是地址;
- 当CLE为高电平时传输的是命令;
- 当ALE,CLE都为低电平表示传输的是数据 ;
- $\overline{CE}$片选信号,低电平有效;
- $\overline{RE}$读使能,低电平有效;
- $\overline{WE}$写使能,低电平有效;
1.2 Read ID时序分析
- 第一条竖线位置,写命令,发送了$\overline{CE}$、$CLE$、$\overline{WE}$信号,90h命令被锁存;
- 第二条竖线,写地址,发送了$\overline{WE}$、$ALE$、$\overline{CE}$信号,地址00被锁存;
- 继续往后,命令、地址都发完了,要read数据了,所以释放$\overline{WE}$,$ALE$,这里$tAR$表示$ALE$释放多久后才可以发送$\overline{RE}$信号,$tREA$表示$\overline{RE}$信号的建立时间;
- 第三条竖线位置,发送了$\overline{CE}$,$\overline{RE}$信号,所以数据被锁存,第一个访问周期锁存的数据为marker code,值为0xEC,第二个访问周期的数据为device code,值为0xDA。读id时读5个周期含义对应如下表:
该Nand Flash的5个周期读取出来的值对应如下:
第三个访问周期含义如下表:
第四个访问周期含义如下表:
第五个访问周期含义如下表:
根据第4、5个访问周期的结果0x15、0x44我们得知该Nand Flash的block_size=128K,page_size=2k, 有2个plane,plane_size=1Gb = 128M, 共256M。
1.3 页读取(page read)
- 第一条竖线,写命令,发送了$\overline{CE}$、$CLE$、$\overline{WE}$信号,00h命令被锁存;
- 然后,写地址,发送了$\overline{WE}$、$ALE$、$\overline{CE}$信号,NDFLASH的地址周期中可以看出来,先发出2个周期的col列地址,再发出3个周期的Row行地址,关于5个周期地址的计算可以参考上一篇博客;
- 写命令,发送了$\overline{CE}$、$CLE$、$\overline{WE}$信号,30h命令被锁存;
- 然后会有一个busy时间段,$R/\overline{B}$为低电平。$tRR$表示busy状态的持续时间(手册上最小为20ns);
- .开始锁存数据,$\overline{RE}$使能,nand上的数据被同步到数据nand控制器上。我们的nand是8bit数据位宽,所以每隔一个read时钟周期($tRC$),传输1byte数据。每传输1byte数据,地址会自动往后偏移1byte,一般我们会连续读取1page数据;
1.4 块擦除(block erase)
- 首先发送0x60命令;
- 发送row地址(由于擦除是以block为单位的,所以无需知道页内地址,只需要知道要擦除哪个page、哪个block即可);
- 发送0xDO命令,执行擦除动作
- 然后会有一个busy时间段,$R/\overline{B}$为低电平;
- 发送0x70命令,用来读取状态;
- 判断NFDATA寄存器的第0位是否擦除成功;
1.5 页写入(page write)
- 首先发送0x80命令;
- 发送地址(5个周期);
- 发送数据;
- 发送0x10命令,执行烧写动作;
- 然后会有一个busy时间段,$R/\overline{B}$为低电平;
- 发送0x70命令,用来读取状态;
- 判断NFDATA寄存器的第0位是否烧写成功
二、寄存器介绍以及初始化
2.1 寄存器
Nand控制器要按照我们Nand Flash的实际型号和性能来设置初始值。
S3C2440 Nand Flash相关寄存器如下:
2.2 配置寄存器(NFCONF)
寄存器信息:
寄存器 | 地址 | R/W | 描述 | 复位值 |
NFCONF | 0X4E000000 | R/W | Nand Flash配置寄存器 | 0x0000100X |
寄存器位信息:
NFCONF | 位 | 描述 | 初始状态 |
保留 | [15:14] | 保留 | —— |
TACLS | [13:12] |
CLE 和ALE 持续值设置(0 至3) Duration = HCLK × TACLS |
01 |
保留 | [11] | 保留 | 0 |
TWRPH0 | [10:8] |
TWRPH0 持续值设置(0~7) Duration = HCLK × ( TWRPH0 + 1 ) |
000 |
保留 | [7] | 保留 | 0 |
TWRPH1 | [6:4] |
TWRPH1 持续值设置(0~7) Duration = HCLK × ( TWRPH1 + 1 ) |
000 |
AdvFlash |
[3] |
自动引导启动用的先进NAND Flash 存储器。 |
硬件设置 |
PageSize |
[2] |
自动引导启动用的NAND Flash 存储器的页面大小。 |
硬件设置 |
AddrCycle |
[1] |
自动引导启动用的NAND Flash 存储器的地址周期。 |
硬件设置 |
BusWidth |
[0] |
自动引导启动和普通访问用的NAND Flash 存储器的输入输出总线宽 |
硬件设置 |
假设$HCLK=100MHZ$,则$T=10ns$。前面一节分析了:
$$TACLS = max(tCLS,tALS) - tWP$$
我们从NAND手册得知$tCLS$、$tALS$、$tWP$最小都可以取到12ns, 所以我们可以取$TACLS=0$;
$$TWRPH0 = tWP$$
我们的NAND手册上要求$tWP$最少12ns, 那么取$TWRPH0 =1$, $Duration = HCLK*(TWRPH0+1)=20ns>12ns$,满足要求;
$$TWRPH1 = max(tCLH,tALH)$$
我们的NAND手册上要求$tCLH$、$tALH$最少5ns, 那么取$TWRPH1 =0$, $Duration = HCLK*(TWRPH1+1)=10ns>5ns$,满足要求。
再配置BusWidth总线位宽为8bit;
所以NFCONF寄存器设置如下:
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
/*设置Nand Flash的时序*/
NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
2.3 控制寄存器(NFCONT)
寄存器信息:
寄存器 | 地址 | R/W | 描述 | 复位值 |
NFCONF | 0X4E000004 | R/W | Nand Flash控制寄存器 | 0x0384 |
寄存器位信息:
NFCONT | 位 | 描述 | 初始状态 |
保留 | [15:14] | 保留 | 0 |
Lock-tight | [13] |
紧锁配置(Lock-tight) |
0 |
SotLock | [12] |
软件上锁设置 |
1 |
保留 | [11] | 保留 | 0 |
EnbIllegalAccINT | [10] |
非法访问中断控制 |
0 |
EnbRnBINT | [9] |
RnB 状态输入信号传输中断控制 |
0 |
RnB_TransMode |
[8] |
RnB 传输检测配置 |
0 |
保留 |
[7] |
保留 |
0 |
SpareECCLock |
[6] |
锁定备份区域ECC 产生 |
1 |
MainECCLock |
[5] |
锁定主数据区域ECC 生成 |
1 |
InitECC |
[4] |
初始化ECC 编码器/译码器(只写) |
0 |
保留 | [3:2] | 保留 | 00 |
Reg_nCE | [1] |
NAND Flash 存储器nFCE 信号控制 |
1 |
MODE | [0] |
NAND Flash 控制器运行模式 |
0 |
MODE [0]: 设置为1,使能NAND控制器。
Reg_nCE [1]: 设置为1,禁止片选(等要使用的时候再使能片选信号)。
所以NFCONF寄存器设置如下:
/*使能Nand Flash控制器,禁止片选*/
NFCONT = (1<<1) | (1<<0);
2.4 命令寄存器(NFCMMD)
寄存器信息:
寄存器 | 地址 | R/W | 描述 | 复位值 |
NFCMMD | 0X4E000008 | R/W | Nand Flash命令寄存器 | 0x00 |
寄存器位信息:
NFCMMD | 位 | 描述 | 初始状态 |
保留 | [15:8] | 保留 | 0x00 |
NFCMMD | [7:0] | Nand Flash存储器命令值 | 0x00 |
我们可以使用2440上的Nand Flash控制器简化操作,只需要往NFCMMD寄存器写入要传输的命令就可以了,Nand Flash控制器默认把上面复杂的时序发出来。
2.5 地址寄存器(NFADDR)
寄存器信息:
寄存器 | 地址 | R/W | 描述 | 复位值 |
NFADDR | 0X4E00000C | R/W | Nand Flash地址寄存器 | 0x00000XX00 |
寄存器位信息:
NFADDR | 位 | 描述 | 初始状态 |
保留 | [15:8] | 保留 | 0x00 |
NFADDR | [7:0] | Nand Flash存储器地址值 | 0x00 |
发命令后,后面就需要发送地址了,当$nWE$和$ALE$有效的时候,表示锁存的是地址,往NFADDR寄存器中写值就可以了,比如:NFADDR=0x00。
上一节我们得知地址需要用5个周期来发送,前2个周期为col地址,后三个周期为row(page)地址。
① column:列地址A0~A10,就是页内地址,地址范围是从0到2047。(A11用来确定oob的地址,即2048-2111这64个字节的范围)
② page:A12~A28,称作页号,page(row)编号。
2.6 数据寄存器(NFDATA)
寄存器信息:
寄存器 | 地址 | R/W | 描述 | 复位值 |
NFDATA | 0X4E000010 | R/W | Nand Flash数据寄存器 | 0xXXXX |
寄存器位信息:
NFDATA | 位 | 描述 | 初始状态 |
NFDATA | [31:0] | NAND Flash 读取/编程数据给I/O | 0xXXXX |
当命令、地址都发送完后就可以从数据总线上DATA[7:0]获取数据或者写入数据。同样往NFDATA寄存器中写值或者读值就可以了,如unsigned char buf=NFDATA,由于是数据位宽是8位的,所以访问时数据组织形式如下:
从上图可以看出,当word access时,只需一个时钟周期;当byteaccess的时候,需要4个时钟周期,小端模式下第一个时钟周期对应低字节,第四个时钟周期对应高字节。nand_wait_rdle函数等待Nand Flash空闲,从上图可以看出当NFSTAT寄存器[0]的值为1时Nand Flash是空闲的,我们可以通过该位来判断Nand Flash是否繁忙。代码如下:
/* 等待NAND Flash就绪 */ void _nand_wait_idle(void) { int i; while(!(NFSTAT & BUSY)); for(i=0; i<10; i++); }
亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。
日期 | 姓名 | 金额 |
---|---|---|
2023-09-06 | *源 | 19 |
2023-09-11 | *朝科 | 88 |
2023-09-21 | *号 | 5 |
2023-09-16 | *真 | 60 |
2023-10-26 | *通 | 9.9 |
2023-11-04 | *慎 | 0.66 |
2023-11-24 | *恩 | 0.01 |
2023-12-30 | I*B | 1 |
2024-01-28 | *兴 | 20 |
2024-02-01 | QYing | 20 |
2024-02-11 | *督 | 6 |
2024-02-18 | 一*x | 1 |
2024-02-20 | c*l | 18.88 |
2024-01-01 | *I | 5 |
2024-04-08 | *程 | 150 |
2024-04-18 | *超 | 20 |
2024-04-26 | .*V | 30 |
2024-05-08 | D*W | 5 |
2024-05-29 | *辉 | 20 |
2024-05-30 | *雄 | 10 |
2024-06-08 | *: | 10 |
2024-06-23 | 小狮子 | 666 |
2024-06-28 | *s | 6.66 |
2024-06-29 | *炼 | 1 |
2024-06-30 | *! | 1 |
2024-07-08 | *方 | 20 |
2024-07-18 | A*1 | 6.66 |
2024-07-31 | *北 | 12 |
2024-08-13 | *基 | 1 |
2024-08-23 | n*s | 2 |
2024-09-02 | *源 | 50 |
2024-09-04 | *J | 2 |
2024-09-06 | *强 | 8.8 |
2024-09-09 | *波 | 1 |
2024-09-10 | *口 | 1 |
2024-09-10 | *波 | 1 |
2024-09-12 | *波 | 10 |
2024-09-18 | *明 | 1.68 |
2024-09-26 | B*h | 10 |
2024-09-30 | 岁 | 10 |
2024-10-02 | M*i | 1 |
2024-10-14 | *朋 | 10 |
2024-10-22 | *海 | 10 |
2024-10-23 | *南 | 10 |
2024-10-26 | *节 | 6.66 |
2024-10-27 | *o | 5 |
2024-10-28 | W*F | 6.66 |
2024-10-29 | R*n | 6.66 |
2024-11-02 | *球 | 6 |
2024-11-021 | *鑫 | 6.66 |
2024-11-25 | *沙 | 5 |
2024-11-29 | C*n | 2.88 |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2018-09-15 第十八节、图像描述符匹配算法、以及目标匹配