一、Nand Flash命令

1.1 命令表

对NAND FLASH的操作需要发出命令,下面有个NAND FLASH的命令表格,那么我们可以此表格上的命令来访问我们的Nand Flash。

Mini2440裸机开发之Nand Flash 编程_数据

 针对每一个命令的时序可以参考NAND FLASH芯片使用手册。下面我们以Read ID命令为例进行介绍。

  • 当ALE为高电平时传输的是地址;
  • 当CLE为高电平时传输的是命令;
  • 当ALE,CLE都为低电平表示传输的是数据 ;
  • $\overline{CE}$片选信号,低电平有效;
  • $\overline{RE}$读使能,低电平有效;
  • $\overline{WE}$写使能,低电平有效;

1.2 Read ID时序分析

Mini2440裸机开发之Nand Flash 编程_#define_02

  • 第一条竖线位置,发送了$\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个周期含义对应如下表:

Mini2440裸机开发之Nand Flash 编程_访问周期_03

该Nand Flash的5个周期读取出来的值对应如下:

Mini2440裸机开发之Nand Flash 编程_数据_04

第三个访问周期含义如下表:

Mini2440裸机开发之Nand Flash 编程_#define_05

 第四个访问周期含义如下表:

Mini2440裸机开发之Nand Flash 编程_数据_06

 第五个访问周期含义如下表:

Mini2440裸机开发之Nand Flash 编程_访问周期_07

 根据第4、5个访问周期的结果0x15、0x44我们得知该NAND FLASH的block_size=128K,page_size=2k, 有2个plane,plane_size=1Gb = 128M, 共256M。

 二、初始化

2.1  寄存器

Nand控制器要按照我们Nand Flash的实际型号和性能来设置初始值。

S3C2440 NAND FLASH相关寄存器如下:

Mini2440裸机开发之Nand Flash 编程_访问周期_08

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 存储器。
0:支持256 字或512 字节/页的NAND Flash 存储器;
1:支持1K 字或2K 字节/页的NAND Flash 存储器。
此位由在复位和从睡眠模式中唤醒时的NCON0 引脚状态所决定。

硬件设置
(NCON0)

PageSize
(只读)

[2]

自动引导启动用的NAND Flash 存储器的页面大小。
先进闪存页面大小
当AdvFlash 为0 时
0=256 字/页;1=512 字节/页
当AdvFlash 为1 时
0=1024 字/页;1=2048 字节/页
此位由在复位和从睡眠模式中唤醒时的GPG13 引脚状态所决定。
复位后,GPG13 可以用于通用I/O 口或外部中断。

硬件设置
(GPG13)

AddrCycle
(只读)

[1]

自动引导启动用的NAND Flash 存储器的地址周期。
先进闪存地址周期
当AdvFlash 为0 时
0=3 个地址周期;1=4 个地址周期
当AdvFlash 为1 时
0=4 个地址周期;1=5 个地址周期
此位由在复位和从睡眠模式中唤醒时的GPG14 引脚状态所决定。
复位后,GPG14 可以用于通用I/O 口或外部中断。

硬件设置
(GPG14)

BusWidth
(R/W)

[0]

自动引导启动和普通访问用的NAND Flash 存储器的输入输出总线宽
度。
0=8 位总线;1=16 位总线
此位由在复位和从睡眠模式中唤醒时的GPG15 引脚状态所决定。
复位后,GPG15 可以用于通用I/O 口或外部中断。
此位可以被软件改变。

硬件设置
(GPG15)

假设$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$,满足要求;

$TWRPH0 = 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: 禁止紧锁 1:使能紧锁
只要此位被设置为1 一次,你就不能清除了。只有复位或从睡眠模式中被唤醒才能使此
位为禁止(即不能由软件清零)。当此位被设置为1 的情况下,在NFSBLK(0x4E000038)
到NFEBLK(0x4E00003C)-1 的区域设置未被上锁,除了这些区域以外的区域,写入或
擦除命令将会无效,只有只读命令有效。

0
SotLock [12]

软件上锁设置
0: 禁止上锁 1:使能上锁
软件锁定区域可以随时用软件修改。当此位被设置为1 的情况下, 在
NFSBLK(0x4E000038)到NFEBLK(0x4E00003C)-1 的区域设置未被上锁,除了这些区
域以外的区域,写入或擦除命令将会无效,只有只读命令有效。当你试图写入或擦除这
些锁定区域时,将发生非法访问(NFSTAT[3]位将会置位)。如果NFSBLK 和NFEBLK
相同时,整个区域都被锁定。

1
保留 [11] 保留 0
EnbIllegalAccINT [10]

非法访问中断控制
0: 禁止中断 1:使能中断
当CPU 试图编程或擦除锁定区域( 由NFSBLK(0x4E000038) 到
NFEBLK(0x4E00003C)-1 的区域设置)而产生非法访问中断。

0
EnbRnBINT [9]

RnB 状态输入信号传输中断控制
0: 禁止RnB 中断 1:使能RnB 中断

0

RnB_TransMode

[8]

RnB 传输检测配置
0: 检测上升沿 1:检测下降沿

0

保留

[7]

保留

0

SpareECCLock

[6]

锁定备份区域ECC 产生
0: 开锁备份 ECC 1:锁定备份 ECC
备份区域ECC 寄存器为NFSECC(0x4E000034)。

1

MainECCLock

[5]

锁定主数据区域ECC 生成
0: 开锁主数据区域 ECC生成 1:锁定主数据区域 ECC生成
主数据区域ECC 状态寄存器为NFMECC0/1(0x4E00002C/30)。

1

InitECC

[4]  

初始化ECC 编码器/译码器(只写)
1:初始化ECC 编码器/译码器

 0
保留 [3:2]  保留  00
Reg_nCE [1]  

NAND Flash 存储器nFCE 信号控制
0:强制 nFCE 为低(使能片选) 1:强制 nFCE 为高(禁止片选)
注意:在引导启动期间其自动被控制。只有MODE 位为1 该值才有效。

 1
MODE [0]  

NAND Flash 控制器运行模式
0:NAND Flash 控制器禁止(不工作) 1: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~A30,称作页号,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位的,所以访问时数据组织形式如下:

Mini2440裸机开发之Nand Flash 编程_片选_09

从上图可以看出,当word access时,只需一个时钟周期;当byteaccess的时候,需要4个时钟周期,小端模式下第一个时钟周期对应低字节,第四个时钟周期对应高字节。

2.7 代码

识别NAND FLASH代码如下:

 

/*初始化nand控制器*/
void nand_init(void)
{
    #define  TACLS   0
    #define  TWRPH0  1
    #define  TWRPH1  0
    NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);

    NFCONT = (1<<1) | (1<<0);
}

/*使能片选*/
void nand_select(void)
{        
    NFCONT &=~(1<<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;
}


/*识别nandflash*/
void nand_chip_probe(void)
{ 
    unsigned char buf[5]={0};
    
    nand_select(); 
    nand_cmd(0x90);
    nand_addr_byte(0x00);

    buf[0] = nand_data();
    buf[1] = nand_data();    
    buf[2] = nand_data();
    buf[3] = nand_data();
    buf[4] = nand_data();    
    nand_deselect();     

    printf("maker   id  = 0x%x\n\r",buf[0]);
    printf("device  id  = 0x%x\n\r",buf[1]);    
    printf("3rd byte    = 0x%x\n\r",buf[2]);        
    printf("4th byte    = 0x%x\n\r",buf[3]);            
    printf("page  size  = %d kb\n\r",1  <<  (buf[3] & 0x03));    
    printf("block size  = %d kb\n\r",64 << ((buf[3] >> 4) & 0x03));    
    printf("5th byte    = 0x%x\n\r",buf[4]);
}

 

参考文章:

[1] s3c2440裸机-nandflash编程(三. 初始化及识别)