s3c2440 nand 控制器(以对K9F2G08U0A 256M读操作为例)

来源:互联网 发布:java license 编辑:程序博客网 时间:2024/06/10 05:37

2010-01-08 22:10:48|  分类: arm|字号 订阅

s3c2440 nand 控制器(以对K9F2G08U0A 256M读操作为例)

1NFCONF:24402410不同,它的NFCONF寄存器是用来设置NAND Flash的时序参数TACLSTWRPH0TWRPH1,设置数据位宽(K9F2G08U0A的位宽为8-bit bus,因此[0]设为0);还有一些只读位,用来指示是否支持其他大小的页(比如一页大小为256/512/1024/2048字节)。NFCONF没有实现对引脚的控制功能,这些功能在NFCONT里实现。

2NFCONT:用来使能/禁止NAND Flash控制器、使能/禁止控制引脚信号nFCE、初始化ECC。它还有其他功能,在一般的应用中用不到,比如锁定NAND Flash

3NFCMD:对于不同型号的Flash,操作命令一般不一样。参考K9F2G08U0A手册。

4NFADDR:当写这个寄存器时,它将对Flash发出地址信号。只用到低8位来传输,所以需要分次来写入一个完整的32位地址,写地址后面会有详细说明。

5NFDATA:只用到低8位,读、写此寄存器将启动对NAND Flash的读数据、写数据操作。

6NFSTAT:只用到位0,用来检测NAND是否准备好。0busy1ready

注意:TACLSTWRPH0TWRPH13个参数控制的是NAND Flash信号线CLE/ALE与写控制信号nWE的时序关系,如图

s3c2440 nand 控制器(以对K9F2G08U0A 256M读操作为例) - chenfang7977 - On my way

 

 s3c2440 nand 控制器(以对K9F2G08U0A 256M读操作为例) - chenfang7977 - On my way

 s3c2440 nand 控制器(以对K9F2G08U0A 256M读操作为例) - chenfang7977 - On my way

在设置NFCONF中的TACLSTWRPH0TWRPH1时,先查看K9F2G08U0A手册:

s3c2440 nand 控制器(以对K9F2G08U0A 256M读操作为例) - chenfang7977 - On my way

由表可知:

CLE Setup Time=12ns,CLE Hold Time=5ns

ALE Setup Time=12ns,ALE Setup Time=5ns,

nWE Pulse Width=12ns

为了满足K9F2G08U0A的时序要求,需要TACLS+TWRPH0+TWRPH1>=46ns,这里设TACLS=0,TWRPH0=3,TWRPH1=0TACLS+TWRPH0+TWRPH1=50ns,满足要求。

Nand flash的读操作

K9F2G08U0A总共有2048块,每块有64页,总共131072页,每页有(2048+64)个字节(列),故我们可以知道这块flash的容量为2048 *(64 *2112)= 276824064 Bytes = 264 MB1Page总共由2112 Bytes组成,这2112个字节按顺序由上而下以列为单位进行排列(1列代表一个Byte。第0列为第0 Byte ,第1列为第1 Byte,以此类推,每个列又由8个位组成,每个位表示1Byte里面的1bit),但事实上每个Page上的最后64BytesSpare Field)是用于存贮检验码和其他信息用的,并不能存放实际的数据,剩下的2048Bytes便是我们用于存放数据用的Data Field。所以实际上我们可以操作的芯片容量为2048 *(64*2048) = 268435456 Bytes = 256MB,。对K9F2G08U0A的读写操作要以页为单位,擦除操作要以块为单位。

nand.c中包含3个主要函数:

void nand_init(void)

static void nand_reset(void)

void nand_read(unsigned char *buf, unsigned long start_addr, int size)

nand_init()nand flash的初始化函数,在对nand flash进行任何操作之前,nand_init()必须被调用,其中实现的功能是NFCONF设置TACLSTWRPH0TWRPH1NAND数据位宽,NFCONT使能控制器、禁止片选nFCE(用的时候再选上),初始化ECC,然后调用nand_reset(每次使用前先复位下)。

nand_reset实现的功能是使能片选(NFCONT)、发出复位命令(NFCMD),循环查询NFSTAT0,直至它为1,最后禁止片选,用的时候再选中。

nand_read函数如下:

/* nand flash 位置start_addr开始,将数据复制到SDRAM地址处 */

void nand_read(unsigned char *buf, unsigned long start_addr, int size)

{

    int i, j;

   

    if ((start_addr & (2048-1)) || (size &(2048-1)))

    {

        return ;    /* 地址或长度不对齐 (需要考虑地址或长度对齐,按页对齐)*/

    }

 

    /* 选中芯片 */

    nand_select_chip();

   

    for(i=start_addr; i < (start_addr + size);)

    {

      /* 发出1st cycle READ命令 */

           write_cmd(0);

 

      /* Write Address */

           write_addr(i);

       /*发出2nd cycle read命令*/

           write_cmd(0x30);

       /*查询NFSTATnand是否准备好*/

           wait_idle();

         /*一个地址对应2048个字节数据。由于8bit位宽的限制,

         每次读取8位(1个字节),共读2048次得到12048Byte数据*/

          for(j=0; j < 2048; j++, i++)

           {

                 *buf = read_data();//寄存器NFDATA

              buf++;

          }

    }

 

    /* 取消片选信号 */

    nand_deselect_chip();

    return ;

}

Nand flash的寻址

其中需要注意的是发送地址函数write_addr()K9F2G08U0A的地址分为5cycle发送到NFADDR寄存器,前两个cycle是列地址(每个列是1个字节,8位数据,通过I/O0~7),也就是要从页的第几个列(字节)开始操作,后3cycle发送的是页地址。K9F2G08U0A总共131072页,每页有(2048+64)个字节(列),因此对页的寻址需要17根地址线,对列的寻址需要12根地址线。如下图所示:

s3c2440 nand 控制器(以对K9F2G08U0A 256M读操作为例) - chenfang7977 - On my way

也可以这么认为,当我们得到一个对nand操作的地址,A0~A11是它的列地址(一个页里的第几个字节)A12~A28是页地址,为了分解出列地址和页地址,可以这样操作:

 

col=addr&2047; //2047的到A0~A10得到列地址

page=addr/2048; // 2048为每页的字节数,不包括附加的64字节,得到页地址

或:

col=addr&4095; // 4095得到A0~A11的地址,得到列地址

page=addr/2112; // 2112为每页的字节数,包括附加的64字节,得到页地址

上面第一个操作表明,如果我们忽略每页附加的64字节,那么对列的寻址也不能寻到这64字节,因此只需11根地址线对每页的0~2047列寻址。

假如我们得到一个nand操作的地址是0x0a3e0000若通过第一种方法分解后,得到列地址是0,得到的页地址是83904,这表明,将从nand的第83904页的第0个字节开始读取数据。

完整的write_addr()函数如下:

static void write_addr(unsigned int addr)

{

    int i;

    //volatile unsigned char *p = (volatile unsigned char *)&rNFADDR;

    /*NFADDR寄存器也只用到低八位来传输,所以需要分4次来写入一个完整的32位地址,需要注意每次的移位操作*/

    int col,page;

    col=addr&NAND_BLOCK_MASK;// NAND_BLOCK_MASK=2048-1,得到列地址

    page=addr/NAND_PAGE_SIZE; // NAND_PAGE_SIZE=20481页的字节数),得到

//页地址

    rNFADDR = col & 0xff;//先传列地址的0~7

    for(i=0; i<10; i++);

    rNFADDR = (col >> 8) & 0x0f;//再传列地址的8~11

    for(i=0; i<10; i++);

   

    rNFADDR=page&0xff;//传页地址的低8(对应上图的A12~A19)

    for(i=0; i<10; i++);

    rNFADDR = (page >> 8) & 0xff;//页地址(对应上图的A20~A27)

    for(i=0; i<10; i++);

    rNFADDR = (page >> 16) & 0x01;//页地址(对应上图的A28)

    for(i=0; i<10; i++);

}