历史上的今天
今天是:2024年11月25日(星期一)
2019年11月25日 | TX2440裸机程序-nand flash
2019-11-25 来源:eefocus
一、开发环境说明
开发板:TX2440A
cpu:s3c2440
nand flash:K9F2G08U0B(256M)
编译软件:ADS1.2
二、nand flash简介
2.1K9F2G08U0B的存储阵列

图 2-1 K9F2G08U0B的存储阵列
由图2-1,我们可以知道:K9F2G08U0B的一页为(2K+64)字节(2K 表示的是 main 区容量,64 表示的是 spare 区容量),它的一块为 64 页,而整个设备包括了2048个块。这样算下来一共有 2112M 位容量,如果只算 main 区容量则有256M 字节(即 256M×8 位)。
要实现用 8 个 IO 口来要访问这么大的容量,如图 2-1 所示:K9F2G08U0A 规定了用 5 个周期来实现。第一个周期访问的地址为 A0-A7;第二个周期访问的地址为A8-A11,它作用在 IO0-IO3 上,而此时 IO4-IO7 必须为低电平;第三个周期访问的地址为 A12-A19;第四个周期访问的地址为 A20-A27;第五个周期访问的地址为 A28,它作用在 IO0上,而此时IO1~IO7 必须为低电平。前两个周期传输的是列地址,后三个周期传输的是行地址。
通过分析可知,
1、块寻址:K9F2G08U0B由2048个block组成,那么块寻址需要11位地址线进行寻址即A18-28(2^(28-18+1)=2048块)。
2、页寻址:一个block由64页组成,那么页寻址需要6位地址线进行寻址即A12-A17(2^6=64)
3、页内字节寻址(即上图中列地址) :页大小为2KB,只需要11位地址线进行寻址A0-10(2^11=2048byte),A11作为页内地址扩展未使用。
由于所有的命令、地址和数据全部从8 位 IO 口传输,所以 Nand flash 定义了一个命令集来完成各种操作。
2.2K9F2G08U0B的命令说明

图2-2 K9F2G08U0B命令表
图2-2是K9F2G08U0B芯片操作读写、擦除等操作的命令表。由于时序都有S3C2440的nand控制器控制。所以,这里的nand驱动。只要好好弄明白K9F2G08U0B这两个要点,就很容易掌握nand驱动。
二、硬件
在S3c2440中可通过NCON0、GPG13-15引脚来设置nand flash控制器所支持nand flash类型

图1实际芯片型号K9F2G08U0B 图2引脚配置
由上图可知
GPG13=3.3V(高电平),GPG14=3.3V(高电平)
GPG15=0.3V(按照图3的ARM芯片直流电气特性定义<0.8V,为低电平),NCON=3.3V(高电平)
根据GPG13-15、NCON引脚配置,配置nand flash存储器(配置表详见下面)

nand flash 存储器配置表
由上配置表可知:nand flash配置成:
1、先进nand(NCON0=1)
2、页容量2K字节(GPG13=1)
3、5个地址周期(GPG14=1)
4、8位宽(GPG15=0)
小结:上面nand flash配置结果与K9F2G08U0B一致。
三、软件
3.1初始化(时序图参数计算)
设置时序,其实是设置NFCONF 配置寄存器。S3C2440内部nand flash控制器时序图

TACLS:表示CLE/ALE的建立时间(setup time)。
TWRPH0:表示写控制信号nWE使能的持续时间。
TWRPH1:表示写控制信号new禁止到 CLE/ALE关闭的时间。
NFCONF配置寄存器

K9F2G08U0B下面的相关时序图

K9F2G08U0B对应时序参数

由上面两个时序图对比可知:TACLS就相当于tCLS或tALS参数,TWRPH0就相当于tWP,而TWRPH1就相当于tCLH或tALH。
其中:HCLK=100MHz(即10ns),TX2440开发板使用电源为3.3V,则tCLS=tALS=12ns(最小值),tWP=12ns(最小值),tCLH=tALH=5ns(最小值)。如果希望nand flash能正常读写操作,时序配置参数必须大于这些最小值。
验证程序中对nand flash的NFCONF寄存器 时序参数配置是否合适?
在nand flash的NFCONF寄存器中
1、TACLS=NFCONF[13:12]=3,即HCLK*TACLS=30ns >12ns(表中tCLSmin)
2、TWRPH0=NFCONF[10:8]=7 即HCLK*(TWRPH0+1)=80ns >12ns(表中tWPmin)
2、TWRPH1=NFCONF[6:4]=7 即HCLK*(TWRPH1+1)=80ns >5ns(表中tCLHmin),一般TWRPH1设置为0,也满足>5ns条件。
综上所述:设置nand flash寄存器的时序满足K9F2G08U0B要求。
3.2 读取ID
Nand芯片的每一个型号,都有固定的芯片ID和制造商ID。用户通过读取ID,确认是什么类型的nand芯片。
下表是K9F2G08U0B读取ID的代码。过程如下
1、激活芯片片选
2、写入复位命令,芯片复位(记得等待芯片内部操作完成)。复位命令不是必须的。
3、写入读取芯片ID命令(0x90),然后写入地址0x00
4、读取芯片ID(ID信息总共5个信息,每当从NF_RDDATA8读取一个信息后,NF_RDDATA8获取下一个的信息)
5、关掉片
读取ID时序图:
源码:
U32 ReadChipId(void)
{
U32 id;
unsigned char Makercode,Devcode,ID3rd,ID4rd,ID5rd;
NF_ChipEn(); //片选使能
NF_CMD(RdIDCMD); //写读nand flash IDC命令0x90
NF_ADDR(0);//写地址0x00
while(NFIsBusy());//判断nand flash是否busy?若busy,则继续等待。
Makercode = NF_RDDATA8();
Devcode = NF_RDDATA8();
ID3rd = NF_RDDATA8();
ID4rd = NF_RDDATA8();
ID5rd = NF_RDDATA8();
NF_ChipDs();//禁止片选使能
if((Makercode == 0xec) && (Devcode=0xda) && (ID3rd == 0x10) &&
(ID3rd == 0x10) && (ID4rd == 0x95) && (ID5rd == 0x44))
Uart_Printf("nK9F2G08U0Bn");
Uart_Printf("Makercode=%x,Devcode=%x,ID3rd=%x,ID4rd=%x,ID5rd=%xn",Makercode,Devcode,ID3rd,ID4rd,ID5rd);
运行结果:

由上图可知读取ID信息与K9F2G08U0B中ID信息一致。
3.3块擦除
nandflash擦除操作以块为单位,对任何Flash闪存存储器进行写操作之前,都必须先进行擦除,然后写入。读写操作是页为单位
快擦除操作步骤(参考下面时序图):
1、nand falsh芯片使能
2、写擦除命令 0x60
3、写 需要擦除的块地址(块地址只需要行地址[28:13])
4、写擦除命令 0xD0
5、nand flash 忙检测,若处于busy,则等待至不忙ready。
6、写读取状态命令0x70
8、操作成功判断,首先通过IO[6]做忙状态检测,然后IO[0]位进行判断是否成功(为什么是IO0位,请参考下面读取70h状态的返回值定义)。
9、关闭芯片使能
块擦除时序图

读取70h状态后,返回值说明(由K9F2G08U0B的datasheet提供)

块擦除源码
/*********************************************************
**函数名称:U8 EraseBlock_2G08(U32 block_number)
**函数功能:nand flash的块擦除
**入口参数:block---块号
**出口参数:无
**返回值 : 擦除成功标志位
1、Earse_ok表示擦除成功
2、Earse_fail表示擦除失败
3、Markbad_fail表示标注失败
************************************************************/
U8 EraseBlock_2G08(U32 block)
{
char stat, temp;
temp = IsBadBlock_2G08( block); //判断该块是否为坏块 ,这些语句测试通过
if(temp == Isbad_ok){ return Isbad_ok;} //是坏块,返回
NF_ChipEn(); //打开片选
NF_CLEAR_RB(); //清RnB信号
/*擦除命令0x60*/
NF_CMD(ERASECMD0); //擦除命令周期1
//写入块地址的3个地址周期,从A18开始写起
NF_ADDR((block << 6) & 0xff); //行地址A18~A19
NF_ADDR((block >> 2) & 0xff); //行地址A20~A27
NF_ADDR((block >> 10) & 0xff); //行地址A28
/*擦除命令0xD0*/
NF_CMD(ERASECMD1); //擦除命令周期2
NF_DETECT_RB_my();//nand flahs的busy状态检测
/*读取状态0x70*/
NF_CMD(QUERYCMD); //读状态命令
//判断状态值的第6位是否为1,即是否在忙,该语句的作用与NF_DETECT_RB();相同
do{
stat = NF_RDDATA8();
}while(!(stat&0x40));
NF_ChipDs(); //关闭nandflash片选
//判断状态值的第0位是否为0,为0则擦除操作正确,否则错误
if (stat & 0x1)
{
temp = MarkBadBlock_2G08(block); //标注该块为坏块
if (temp == Markbad_fail)
return Markbad_fail; //标注坏块失败
else
return Earse_fail; //擦除操作失败
}
else
return Earse_ok; //擦除操作成功
}
建议:在读取状态70h返回值时,加入忙状态检测(通过IO[6]位)
3.4 写入数据
nand falsh支持以页为单位写入、随机写入两种数据方式。
3.4.1 页写入
时序图

源码
/*********************************************************
**函数名称:static int WritePage_2G08(U32 block,U32 page,U8 *buffer)
**函数功能:在nand flash芯片中页读功能
**入口参数:
1、block---- 块号
2、page-----页号
3、*buffer----------存放读取整页的数据缓冲区
**出口参数:无
**返回值 : 写成功标志位
1、Write_ok表示写入成功
2、Write_fail表示写入失败
************************************************************/
static int WritePage_2G08(U32 block,U32 page,U8 *buffer)
{
int i;
U32 blockpage, Mecc, Secc;
U8 *bufPt=buffer,temp;
blockpage=(block<<6)+page;
temp = IsBadBlock_2G08(block); //判断该块是否为坏块
if(temp == Isbad_ok){return Isbad_ok ; } //是坏块,返回
NF_RSTECC(); // Initialize ECC
NF_MECC_UnLock();
NF_ChipEn();
NF_CMD(PROGCMD0); // Write 1st command
NF_ADDR(0); //Column (A[7:0]) = 0
NF_ADDR(0); // A[11:8]
NF_ADDR((blockpage)&0xff); // A[19:12]
NF_ADDR((blockpage>>8)&0xff); // A[27:20]
NF_ADDR((blockpage>>16)&0xff); //A[28]
for(i=0;i<2048;i++)
{
NF_WRDATA8(*bufPt++); // Write one page data from buffer
}
NF_CLEAR_RB();
NF_CMD(PROGCMD1); // Write 2nd command
NF_DETECT_RB();
NF_CMD(QUERYCMD); // Read status command
//判断状态值的第6位是否为1,即是否在忙,该语句的作用与NF_DETECT_RB();相同
do{
temp = NF_RDDATA8();
}while(!(temp&0x40));
//判断状态值的第0位是否为0,为0则写操作正确,否则错误
if (temp&0x1)
{
NF_ChipDs();
Uart_Printf("[PROGRAM_ERROR:block#=%d]n",block);
MarkBadBlock_2G08(block);
return Write_fail;
}
else
{
NF_ChipDs();
return Write_ok;
}
3.4.2随机写入
时序图

源码:
/*********************************************************
**函数名称:RamdomWrite_2G08(U32 blockpage, U32 page_add, U8 data)
**函数功能:在nand flash芯片中随机写
**入口参数:
1、blockpage--页号(由块和页信息组成),blockpage=(block<<6)+page;
2、page_add-----页内地址
3、data----------写入的数据
**出口参数:无
**返回值 : 写成功标志位
1、Write_ok表示写入成功
2、Write_fail表示写入失败
************************************************************/
U8 RamdomWrite_2G08(U32 blockpage, U32 page_add, U8 data)
{
U8 temp,stat;
NF_ChipEn(); //打开nandflash片选
NF_CLEAR_RB(); //清RnB信号
//随机写命令80h
NF_CMD(PROGCMD0);
//写入5个地址周期
NF_ADDR(0x00); //列地址A0~A7
NF_ADDR(0x00); //列地址A8~A11
NF_ADDR((blockpage) & 0xff); //行地址A12~A19
NF_ADDR((blockpage >> 8) & 0xff); //行地址A20~A27
NF_ADDR((blockpage >> 16) & 0xff); //行地址A28
//随机写命令85h
NF_CMD(PROGCMD2);
//页内地址
NF_ADDR((U8)(page_add&0xff)); //列地址A0~A7
NF_ADDR((U8)((page_add>>8)&0x0f)); //列地址A8~A11
NF_WRDATA8(data); //写入数据
//写第二写命令10h
NF_CMD(PROGCMD1); //页写命令周期2
NF_DETECT_RB_my(); //busy检测
NF_CMD(QUERYCMD); //读状态命令
//判断状态值的第6位是否为1,即是否在忙,该语句的作用与NF_DETECT_RB();相同
do{
stat = NF_RDDATA8();
}while(!(stat&0x40));
NF_ChipDs(); //关闭nandflash片选
//判断状态值的第0位是否为0,为0则写操作正确,否则错误
if (stat & 0x1){return Write_fail; } //失败
else {return Write_ok; } //成功
}
3.5读取数据
3.5.1页读取
时序图

源码
/*********************************************************
**函数名称:static int ReadPage_2G08(U32 block,U32 page,U8 *buffer)
**函数功能:在nand flash芯片中页读功能
**入口参数:
1、block---- 块号
2、page-----页号
**出口参数:*buffer----------存放读取整页的数据缓冲区
史海拾趣
|
笔者从事手机测试校准系统集成有段时间,感觉到手机发射功率在不同的系统、不同的协议下有很多的不同。笔者对此深感有意思,故把PHS、GSM、cdma2000 1x、wcdma下对手机发射功率的规定罗列于此,希望能给同行起到抛砖引玉的作用,斧正我的错误 ...… 查看全部问答> |
|
-- a:dial[3:0] library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY bcd IS PORT ( clk ...… 查看全部问答> |
|
我用程序下面的程序使我输入的字变大并且变为了红色,但字体变大了编辑框中的光标并没有变大,举个例子,我在编辑框框中输入8,框内只能显示8的上半部分,下半部分显示不出来,而且即使把框拉大后数字还是无法显示完全,请问是程序的问题还是其他问 ...… 查看全部问答> |
|
C8051F120+CP2200 我使用例子程序UDP来实现接收数据相关问题 C8051F120+CP2200 我基于例子程序UDP来实现接收数据相关问题,往板子里传数据,但是传了不到2秒就断开了,就算是使用其例子程序与PC机交互,数据传了一段时间也会停止传输,传输时间时长时短,我想问问有没使用过该网卡CP2200的大侠,一般使用该网卡 ...… 查看全部问答> |
|
现在课程设计要求自己设计一个微指令系统,我打算实现除法运算,但是目前遇到困难,不知道该如何实现。我的思路是利用加法和乘法的思路,比如要实现 M / N 的话,则是对1/N实现M次累加。。。可是不知道如何得到1/N。 ...… 查看全部问答> |
|
#include #include main() { SCON=0x50; TMOD|=0x20; TH1=0xf3; TR1=1; TI=1; switch(1) { case 1: printf(\"%d\\n\" ...… 查看全部问答> |
|
易电源试用报告3:LMZ12001的负输出电压应用与LMZ12010模块试用 送的套装里有两个赠送的芯片 LMZ12001和LMZ12010 前者与DEMO板上的LMZ12002是同样的封装不同的最大电流值,LMZ12010是个大块头,最大10A输出。昨天参考应用手册AN-2027做了个LMZ12001的负输出电压应用的板子,和一个12010的板子,参考手 ...… 查看全部问答> |




