NAND Flash驱动程序设计

来源:互联网 发布:布偶猫哪里买 知乎 编辑:程序博客网 时间:2024/05/29 08:39

一 NAND Flash概括

NAND Flash充当硬盘的角色,NAND Flash主要分为以下两类,
SLC(single level cell):单层式存储
MLC(multi level cell):多层式存储
MLC对比SLC
SLC访问速度一般比MLC快三倍以上 SLC可以进行十万次的擦写,MLC可以进行一万次,MLC功耗比SLC高15%左右
访问方式内存采用的是统一编址,NAND Flash采用的是独立编址,第一传地址给CPU控制器,第二传命令给控制器,第三传数据给控制器

二 NAND Flash驱动设计_读

根据NAND Flash的芯片手册,可以看出页读中I/Ox的编码步骤
这里写图片描述
首先发送命令00h,然后发送地址,发送地址先发送列地址,后发送行地址。其次发送命令0x30,等待RnB信号,最后读取数据。除此之外,还需要加入一些通用步骤,选中NAND Flash芯片,清除RnB信号,在最后需要取消选中NAND Flash芯片。所以基本步骤是
1 选中芯片
2 清除RnB
3 发出命令
4 发出列地址
5 发出行地址
6 发出命令
7 等待RnB信号
8 读数据
9 取消片选
这里写图片描述

如何选中NAND Flash芯片

这里写图片描述
这里写图片描述
选中NAND Flash芯片,就是往NFCONT这个寄存器中第一位写入0。

void select_ship(void){    NFCONT &= ~(1<<1); }

如何发送命令

NFCMMD(八位)寄存器就是存放发送给NAND Flash的命令的,命令本身传进来后送到NFCMMD寄存器中。

void nand_cmd(unsigned char cmd){    NFCMMD = cmd;   }

如何发送地址

NFADDR(八位)往这个寄存器中写入地址,按页读没有偏移,所以列地址为0,有两个列地址都为0。有三个行地址。由READ OPERATION时序图中看出有两个列地址和三个行地址。

void nand_addr(unsigned char addr){    NFADDR = addr;}/*********************************/        /* 发出列地址 */        nand_addr(0x00);        nand_addr(0x00);        /* 发出行地址 */        nand_addr(addr&0xff);        nand_addr((addr >>8 ) & (0xff));        nand_addr((addr >>16 ) & (0xff));

如何清除RnB信号

在NFSTAT寄存器中,当RnB信号从低变成高电平的时候,第4位自动设置为1,检查这位有没有变成1,首先要将其擦除清零才能检查。
这里写图片描述
这里写图片描述
清零就是要写入这个寄存器的第四位为0, 此时根据To clear this write‘1’,可知不是直接写0,而是写成1。

void clean_RnB(){    NFSTAT |= (1<<4);} 

发送完30h 信号后,需要等待RnB信号结束,只要RnB信号没有从低电平到高电平,就需要等。

void wait_RnB(void){    while(!(NFSTAT & 0x1));}

如何取消选中

在NFCONT第一位写入1即可。

void delselect_ship(void){    NFCONT |= (1<<1);}

如何读取数据?

这里写图片描述
NFDATA是读取数据用到的寄存器,由图可知,一页上有2K的空间所以 读取数据的时候一般大于2048,这里选择为4096。

 for(i = 0; i<1024*4; i++)        {            buff[i] = NFDATA;        }
至此,按页读的步骤就结束了。但是,这只是nandflash读功能的实现,初始化工作还没有完成,我们还需要初始化NFCONF,NFCONT和复位。

如何初始化NFCONF

这里写图片描述
上图可得到三个重要的时间:1 TWP 2 TCLS-TWP 3 TCLH。由下表可知,由于3.3V为工作电压,所以TWP最小时间为12ns,TCLS-TWP是0ns,tclh为5ns,要保证nandflash正常工作,需要将其配置不小于最低时间。这里写图片描述

这里写图片描述
根据上图时序图,可以得出TACLS为TCLS-TWP,TWRPH0为TWP ,TWRPH1为TCLH
由于NandFlash使用的是HCLK,100MHZ,故周期为10ns,在Nand Flash Configuration这个寄存器中去修改相应位的值,由手册可知,TACLS只要大于0即可,根据公式HCLK*TACLS>0,在这里设置TACLS为1,TWRPH0大于12ns,同理这里设置TWRPH0为2(1也可以),TWRPH1要大于5ns,这里设置TWRPH1为1(0也可以)。这样NFCONF寄存器就设置好了。
这里写图片描述

如何初始化NFCONT

这里只要设置两个位。
这里写图片描述

#define TACLS  1#define TWRPH0 2#define TWRPH1 1    NFCONF &= ~((7<<12)|(7<<8)|(7<<4));    NFCONF |= (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);    /* 使能 nandflash controller*/    NFCONT = 1 | (1<<1);

如何初始化复位

这里写图片描述
这里有以下几个步骤,选中flash,清除RnB信号,发送0xff命令,等到RnB,取消选中flash。

NAND Flash驱动设计_写

之前选择的是按页读,所以这里选择的是按页写(还有一种是随机写)
这里写图片描述
这里还是按照和读方式一样的思路去设计,首先是发送命令0x80,其次是发送列地址,行地址,然后是写入数据,再次发送命令0x10,等待RnB信号发生变化,最后发送命令0x70,读取写入结果。
除此之外,还要加入通用操作,清除RnB,选中Flash芯片,在最后取消flash芯片的选中。

int NF_WritePage(unsigned long addr,unsigned char* buff){    int ret,i;    //选中flash芯片    select_ship();    //清除RnB    clean_RnB();    //发送命令80    nand_cmd(0x80);    //发送列地址(2个周期)    nand_addr(0x00);        nand_addr(0x00);    //发送行地址(3个周期)    nand_addr(addr&0xff);        nand_addr((addr >>8 ) & (0xff));        nand_addr((addr >>16 ) & (0xff));    //写入数据    for(i=0;i<1024*4;i++)    {        NFDATA = buff[i];       }    //发送命令10    nand_cmd(0x10);    //等待RnB    wait_RnB();    //发送命令70    nand_cmd(0x70);    //读取写入结果    ret = NFDATA;    //取消选中flash芯片    delselect_ship();    return ret;}

在写入NAND Flash之前需要做擦除的工作
这里写图片描述
擦除的时候,不是按照页来擦除,首先发送命令0x60,然后发送三个行地址,发送命令0xd0,等待RnB信号,通过发送命令0x70读取发送结果,同样加入三个通用流程,选中(选中flash芯片),清除(清除RnB信号),取消(取消片选)。

int NF_Erase(unsigned long addr){    int ret;    //选中flash芯片    select_ship();    //清除RnB    clean_RnB();    //发送命令60    nand_cmd(0x60);    //发送行地址(3个周期)    nand_addr(addr&0xff);        nand_addr((addr >>8 ) & (0xff));        nand_addr((addr >>16 ) & (0xff));    //发送命令D0    nand_cmd(0xD0);    //等待RnB    wait_RnB();    //发送命令70    nand_cmd(0x70);    //读取擦除结果    ret = NFDATA;    //取消选中flash芯片    delselect_ship();    return ret;}