mini2440硬件篇之Nand Flash
来源:互联网 发布:淘宝pkpm激活码多少钱 编辑:程序博客网 时间:2024/05/21 10:16
1. 硬件原理
Nand Flash在对大容量的数据存储中发挥着重要的作用。相对于Nor Flash,它具有一些优势,但它的一个劣势是很容易产生坏块,因此在使用Nand Flash时,往往要利用校验算法发现坏块并标注出来,以便以后不再使用该坏块。Nand Flash没有地址或数据总线,如果是8位Nand Flash,那么它只有8个IO口,这8个IO口用于传输命令、地址和数据。Nand Flash主要以page(页)为单位进行读写,以block(块)为单位进行擦除。每一页中又分为main区和spare区,main区用于正常数据的存储,spare区用于存储一些附加信息,如块好坏的标记、块的逻辑地址、页内数据的ECC校验和等。
1.1. 坏块管理
由于NAND Flash的工艺不能保证NAND的Memory Array在其生命周期中保持性能的可靠,因此,在NAND的生产中及使用过程中会产生坏块。坏块的特性是:当编程/擦除这个块时,不能将某些位拉高,这会造成Page Program和Block Erase操作时的错误,相应地反映到Status Register的相应位。
(1)固有坏块,这是生产过程中产生的坏块,一般芯片原厂都会在出厂时都会将坏块第一个page的spare area的第6个bit标记为不等于0xff的值。
(2)使用坏块,这是在NAND Flash使用过程中,如果Block Erase或者Page Program错误,就可以简单地将这个块作为坏块来处理,这个时候需要把坏块标记起来。为了和固有坏块信息保持一致,将新发现的坏块的第一个page的spare area的第6个Bit标记为非0xff的值。
(3)坏块管理
根据上面的这些叙述,可以了解NAND Flash出厂时在spare area中已经反映出了坏块信息,因此,如果在擦除一个块之前,一定要先check一下spare area的第6个bit(512)或第1个bit(2k)是否是0xff,如果是就证明这是一个好块,可以擦除;如果是非0xff,那么就不能擦除。
当然,这样处理可能会犯一个错误―――“错杀伪坏块”,因为在芯片操作过程中可能由于电压不稳定等偶然因素会造成NAND操作的错误。但是,为了数据的可靠性及软件设计的简单化,我们就要奉行“蒋委员长”的“宁可错杀一千,也决不放过一个”的宗旨。
(4)需要对前面由于Page Program错误发现的坏块进行一下特别说明。如果在对一个块的某个page进行编程的时候发生了错误就要把这个块标记为坏块,首先就要把其他好的page里面的内容备份到另外一个空的好块里面,然后,把这个块标记为坏块。
当然,这可能会犯“错杀”之误,一个补救的办法,就是在进行完页备份之后,再将这个块擦除一遍,如果Block Erase发生错误,那就证明这个块是个真正的坏块,那就毫不犹豫地将它打个“戳”吧!
(2)可能有人会问,为什么要使用spare area的第六个bit作为坏块标记。这是NAND Flash生产商的默认约定。
2. 芯片手册
K9F2G08U0B
2.1. 特性
容量256MB
一页2k+64;一块128k+4k;
2.2. 引脚描述
见手册
2.3. 指令集
2.4. 读
2.5. 编程
2.6. 擦除
2.7. 读ID
3. mini2440电路图
4. S3C2440寄存器
4.1. 控制器特性
1、支持读/写/编程 NAND FLASH内存
2、系统复位后nand flash的前4k代码自动copy到内部sram,copy完 成后从sram启动,此时内部sram被映射为nGCS0。(当OM[1:0] = 00时使能NAND FLASH 启动模式)
3、支持硬件ECC校验
4、系统启动后内部ram可以用做其他的用途。
4.2. 操作Nand方法
1、设置nand flash配置寄存器NFCONF
2、向命令寄存器NFCMD写入操作命令
3、向地址寄存器NFADDR写入地址
4、读/写数据前要读取状态寄存器NFSTAT来判断nand flash是否处于忙状态。
4.3. ECC奇偶校验
S3C2440在读/写操作时,自动生成2048字节的奇偶校验码。
Nand Flash的页为2048B。在读写的时候每页会产生4个bit大小的ECC校验码。
28bit ECC校验码=22bit线校验码+6bit列校验码
ECC产生模块执行以下步骤:
1:当MCU写数据到NAND时,ECC产生模块生成ECC码。
2:当MCU从NAND读数据时,ECC产生模块生成ECC码同时用户程序将它与先前写入时产生的ECC码作比较。
在自动引导模式下,不进行ECC检测。因此,NAND FLASH的前4KB应确保不能有位错误(一般NAND FLASH厂家都确保)。
nand.h
/******************************************************************* * Copyright (C),2011-2012, XXX. * FileName: nand.h * Author:HuangYinqing * Version:1.0 * Date::2012-04-22 * Description:nand flash驱动. * Function List: * History: ******************************************************************/#ifndef __NAND_H__#define __NAND_H__/*nand flash调试等级*/#define DBG_NAND_LEVEL 1/*nand flash信息*/#define NAND_PAGE_SIZE(2*1024) //==1页2k#define NAND_BLOCK_SIZE(NAND_PAGE_SIZE*64) //==1块128k#define NAND_SIZE(256*1024*1024)//==容量256M/*操作命令*/#define CMD_READ1 0x00 //页读命令周期1#define CMD_READ2 0x30 //页读命令周期2#define CMD_READID 0x90 //读ID命令#define CMD_WRITE1 0x80 //页写命令周期1#define CMD_WRITE2 0x10 //页写命令周期2#define CMD_ERASE1 0x60 //块擦除命令周期1#define CMD_ERASE2 0xd0 //块擦除命令周期2#define CMD_STATUS 0x70 //读状态命令#define CMD_RESET 0xff //复位#define CMD_RANDOMREAD1 0x05//随意读命令周期1#define CMD_RANDOMREAD2 0xE0//随意读命令周期2#define CMD_RANDOMWRITE 0x85//随意写命令/*NFCONF设置时序*/#define TACLS1#define TWRPH02#define TWRPH10/*NFCONT片选*/#define NF_nFCE_L() {rNFCONT &= ~(1<<1); }//==打开片选#define NF_nFCE_H() {rNFCONT |= (1<<1); }//==关闭片选/*读写数据*/#define NF_CMD(data) {rNFCMD = (data);} //传输命令#define NF_ADDR(addr) {rNFADDR = (addr);} //传输地址#define NF_RDDATA() (rNFDATA) //读32位数据#define NF_RDDATA8() (rNFDATA8) //读8位数据#define NF_WRDATA(data) {rNFDATA = (data);} //写32位数据#define NF_WRDATA8(data) {rNFDATA8 = (data);} //写8位数据/*NFSTAT的第0位可以用于判断nandflash是否在忙,第2位用于检测RnB引脚信号*/#define NF_WAITRB() {while(!(rNFSTAT&(1<<0)));} //等待nandflash不忙#define NF_CLEAR_RB() {rNFSTAT |= (1<<2); } //清除RnB信号#define NF_DETECT_RB() {while(!(rNFSTAT&(1<<2)));} //等待RnB信号变高,即不忙/*ECC*/#define NF_RSTECC() {rNFCONT |= (1<<4); } //复位ECC#define NF_MECC_UnLock() {rNFCONT &= ~(1<<5); } //解锁main区ECC#define NF_MECC_Lock() {rNFCONT |= (1<<5); } //锁定main区ECC#define NF_SECC_UnLock() {rNFCONT &= ~(1<<6); } //解锁spare区ECC#define NF_SECC_Lock() {rNFCONT |= (1<<6); } //锁定spare区ECC/*函数*/void NandTest(void);void NandInit(void);#endifnand.c
/******************************************************************* * Copyright (C),2011-2012, XXX. * FileName: nand.h * Author:HuangYinqing * Version:1.0 * Date::2012-04-22 * Description:nand flash驱动. * Function List: * History: ******************************************************************/#include "common.h"#include "core.h"#include "nand.h"/********************************************************************函数功能:nand flash初始化。入口参数:无。返 回:无。备 注:无。********************************************************************/ void NandInit(void){rGPACON = (rGPACON &~(0x3f<<17)) | (0x3f<<17); //配置芯片引脚/*TACLS=1、TWRPH0=2、TWRPH1=0,8位IO*/rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);/*非锁定,屏蔽nandflash中断,初始化ECC及不锁定main区和spare区ECC,使能nandflash片选及控制器*/rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(1<<1)|(1<<0);}/********************************************************************函数功能:nand flash复位。入口参数:无。返 回:无。备 注:无。********************************************************************/ void NandReset(void){int i;NF_nFCE_L(); //打开nandflash片选NF_CLEAR_RB();//清除RnB信号for ( i=0; i<10; i++);NF_CMD(CMD_RESET);//写入复位命令NF_DETECT_RB();//等待RnB信号变高,即不忙NF_nFCE_H(); //关闭nandflash片选}/********************************************************************函数功能:nand flash读ID。入口参数:无。返 回:设备ID。备 注:无。********************************************************************/ char NandReadID(void){char pMID;char pDID;char cyc3, cyc4, cyc5; NF_nFCE_L(); //打开nandflash片选// NF_CLEAR_RB(); //清RnB信号NF_CMD(CMD_READID); //读ID命令NF_ADDR(0x0); //写0x00地址// for ( i=0; i<10; i++);//读五个周期的IDpMID = NF_RDDATA8(); //厂商ID:0xECpDID = NF_RDDATA8(); //设备ID:0xDAcyc3 = NF_RDDATA8(); //0x10cyc4 = NF_RDDATA8(); //0x95cyc5 = NF_RDDATA8(); //0x44NF_nFCE_H(); //关闭nandflash片选DbgPrintX( DBG_NAND_LEVEL, "\rMID=%2x,DID=%2x,3r=%2x,4r=%2x,5r=%2x\n",pMID,pDID,cyc3,cyc4,cyc5);return pDID;}/********************************************************************函数功能:nand flash检查坏块。(大页2k)入口参数:ulBlockNum:待检查块索引返 回:1:坏块;0:好块。备 注:无。********************************************************************/ int NandIsBadBlockPage2048(U32 ulBlockNum){ U32 ulPageNum;U8 bBadBlockFlag; ulPageNum = ulBlockNum << 6;//==1块=128k=64页 NF_nFCE_L(); NF_CLEAR_RB(); NF_CMD(0x00);NF_ADDR(0);NF_ADDR((2048>>8)&0xff); NF_ADDR(ulPageNum&0xff); NF_ADDR((ulPageNum>>8)&0xff); NF_ADDR((ulPageNum>>16)&0xff); NF_CMD(0x30); NF_DETECT_RB(); bBadBlockFlag = NF_RDDATA8(); NF_nFCE_H(); return (bBadBlockFlag != 0xff);}/********************************************************************函数功能:检查坏块。入口参数:ulBlockNum:待检查块索引;bIsLargerPage:1:大页;0:小页返 回:1:坏块;0:好块。备 注:无。********************************************************************/ int NandIsBadBlock(U32 ulBlockNum, U8 bIsLargePage){switch(bIsLargePage) {case 0://return Nand_IsBadBlockPage512(ulBlockNum);case 1:return NandIsBadBlockPage2048(ulBlockNum);}return 0;}/********************************************************************函数功能:读nand flash一页数据。(大页2k)入口参数:ulPageNum:页索引pucBuffer:缓冲区返 回:成功:读取字节数备 注:无。********************************************************************/ U32 NandReadPage2048(U32 ulPageNum, U8 *pucBuffer){U32 i;NF_nFCE_L(); //打开nandflash片选NF_CLEAR_RB(); //清RnB信号NF_CMD(CMD_READ1); //页读命令周期1//写入5个地址周期NF_ADDR(0x00); //列地址A0~A7NF_ADDR(0x00); //列地址A8~A11NF_ADDR((ulPageNum) & 0xff); //行地址A12~A19NF_ADDR((ulPageNum >> 8) & 0xff); //行地址A20~A27NF_ADDR((ulPageNum >> 16) & 0xff); //行地址A28NF_CMD(CMD_READ2); //页读命令周期2NF_DETECT_RB(); //等待RnB信号变高,即不忙//读取一页数据内容for (i = 0; i < 2048; i++){*pucBuffer++ = NF_RDDATA8();} NF_nFCE_H(); //打开nandflash片选 return i;}/********************************************************************函数功能:读nand flash一页数据。入口参数:ulPageNum:页索引pucBuffer:缓冲区bIsLargerPage:1:大页;0:小页返 回:读取字节数。备 注:无。********************************************************************/ int NandReadPage(U32 ulPageNum, U8 *pucBuffer, U8 bIsLargePage){switch(bIsLargePage) {case 0://return Nand_ReadSectorPage512(ulPageNum, buffer);case 1:return NandReadPage2048(ulPageNum, pucBuffer);}return 0;}/********************************************************************函数功能:读nand flash数据。入口参数:ulAddr:从哪个地址读ulSize:要读取的字节数pucBuffer:缓冲区返 回:成功:读取字节数;其他:出错。备 注:无。********************************************************************/ int NandRead(U32 ulAddr, U32 ulSize, U8 *pucBuffer){int i, j;/*检查参数*/if ( (ulAddr & (NAND_PAGE_SIZE-1)) || (ulSize & (NAND_PAGE_SIZE-1)) ){return ERR_PARAMETER;/* invalid alignment */}/*每次读一页*/for (i=ulAddr; i < (ulAddr + ulSize);) {if (i & (NAND_BLOCK_SIZE-1)== 0) //==如果是块首,要检查坏块。{if ( NandIsBadBlock(i/NAND_BLOCK_SIZE, 1) ) {/* Bad block */i += NAND_BLOCK_SIZE;ulSize += NAND_BLOCK_SIZE;continue;}}j = NandReadPage(i/NAND_PAGE_SIZE, pucBuffer, 1);i += j;pucBuffer += j;}return ERR_SUCCESS;}/********************************************************************函数功能:写nand flash一页数据。(大页)入口参数:ulPageNum:页索引pucBuffer:缓冲区返 回:成功:读取字节数备 注:无。********************************************************************/ U32 NandWritePage2048(U32 ulPageNum, U8 *pucBuffer){U32 i;NF_nFCE_L(); //打开nandflash片选NF_CLEAR_RB(); //清RnB信号NF_CMD(CMD_WRITE1); //页读命令周期1 //写入5个地址周期NF_ADDR(0x00); //列地址A0~A7NF_ADDR(0x00); //列地址A8~A11NF_ADDR((ulPageNum) & 0xff); //行地址A12~A19NF_ADDR((ulPageNum >> 8) & 0xff); //行地址A20~A27NF_ADDR((ulPageNum >> 16) & 0xff); //行地址A28//读取一页数据内容for (i = 0; i < 2048; i++){ NF_WRDATA8(*pucBuffer++);} NF_CMD(CMD_WRITE2); //页读命令周期2udelay(200);#if 0NF_CMD(CMD_STATUS); //读状态命令//判断状态值的第6位是否为1,即是否在忙,该语句的作用与NF_DETECT_RB();相同do{stat = NF_RDDATA8();}while(!(stat&0x40));#endif NF_DETECT_RB(); //等待RnB信号变高,即不忙NF_nFCE_H(); //打开nandflash片选 return i;}/********************************************************************函数功能:写nand flash一页数据。入口参数:ulPageNum:页索引pucBuffer:缓冲区bIsLargerPage:1:大页;0:小页返 回:读取字节数。备 注:无。********************************************************************/ int NandWritePage(U32 ulPageNum, U8 *pucBuffer, U8 bIsLargerPage){switch(bIsLargerPage) {case 0://return Nand_ReadSectorPage512(ulPageNum, buffer);case 1:return NandWritePage2048(ulPageNum, pucBuffer);}return 0;}/********************************************************************函数功能:写nand flash数据。入口参数:ulAddr:写到哪个地址ulSize:要写的字节数pucBuffer:缓冲区返 回:成功:编程字节数;其他:出错。备 注:无。********************************************************************/int NandWrite(U32 ulAddr, U32 ulSize, U8 *pucBuffer){int i, j;/*检查参数*/if ( (ulAddr & (NAND_PAGE_SIZE-1)) || (ulSize & (NAND_PAGE_SIZE-1)) ){return ERR_PARAMETER;/* invalid alignment */}/*每次写一页*/for (i=ulAddr; i < (ulAddr + ulSize);) {if (i & (NAND_BLOCK_SIZE-1)== 0) //==如果是块首,要检查坏块。{if ( NandIsBadBlock(i/NAND_BLOCK_SIZE, 1) ) {/* Bad block */i += NAND_BLOCK_SIZE;ulSize += NAND_BLOCK_SIZE;continue;}}j = NandWritePage(i/NAND_PAGE_SIZE, pucBuffer, 1);i += j;pucBuffer += j;}return ERR_SUCCESS;}/********************************************************************函数功能:擦除nand flash数据。入口参数:ulBlock:块索引返 回:成功:0;其他:出错。备 注:无。********************************************************************/ int NandErase(U32 ulBlockNum){if( NandIsBadBlock(ulBlockNum, 1) ){return ERR_ERASE_NANDFLASH;}NF_nFCE_L(); //打开nandflash片选NF_CLEAR_RB(); //清RnB信号NF_CMD(CMD_ERASE1); //页读命令周期1NF_ADDR((ulBlockNum <<6 ) & 0xff); //行地址A12~A19NF_ADDR((ulBlockNum >> 2) & 0xff); //行地址A20~A27NF_ADDR((ulBlockNum >> 10) & 0xff); //行地址A28NF_CMD(CMD_ERASE2); //页读命令周期2udelay(200);#if 0NF_CMD(CMD_STATUS); //读状态命令//判断状态值的第6位是否为1,即是否在忙,该语句的作用与NF_DETECT_RB();相同do{stat = NF_RDDATA8();}while(!(stat&0x40));#endif NF_DETECT_RB(); //等待RnB信号变高,即不忙NF_nFCE_H(); //打开nandflash片选 return ERR_SUCCESS;}/********************************************************************函数功能:测试nand flash。入口参数:无。返 回:无。备 注:无。********************************************************************/ void NandTest(void){int ret;unsigned char data[4][1024];memset(data, 0x86, 4*1024);NandInit();NandReset();NandReadID();ret = NandErase(2);if(ret != ERR_SUCCESS){ DbgPrintX( DBG_NAND_LEVEL, "\rnand erase err=%2x\n",ret);return;}ret = NandWrite( 0x50000, 4*1024, (unsigned char *)data );if(ret != ERR_SUCCESS){ DbgPrintX( DBG_NAND_LEVEL, "\rnand write err=%2x\n",ret);return;}ret = NandRead(0x50000, 4*1024, (unsigned char *)0x31000000);if(ret != ERR_SUCCESS){ DbgPrintX( DBG_NAND_LEVEL, "\rnand read err=%2x\n",ret);return;}}
- mini2440硬件篇之Nand Flash
- mini2440硬件篇之Nor Flash
- mini2440之nand flash 分析(1)
- mini2440 nand flash
- Mini2440 NAND FLASH驱动
- NAND Flash硬件原理
- mini2440硬件篇之GPIO
- mini2440硬件篇之SDRAM
- mini2440硬件篇之MMU
- mini2440硬件篇之中断
- mini2440硬件篇之看门狗
- mini2440硬件篇之DMA
- mini2440硬件篇之UART
- mini2440硬件篇之IIC
- mini2440硬件篇之LCD
- mini2440硬件篇之RTC
- mini2440硬件篇之IIS
- mini2440硬件篇之SPI
- 右键弹出菜单和快捷键的设置
- 人生四项原则
- iframe url传参
- PL/SQL --> 包的创建与管理
- 模板设计
- mini2440硬件篇之Nand Flash
- 名词解释备忘录
- 缺省的servlet
- 深入理解PHP内存管理
- Magento后台订单页面增加邮箱项
- 我还是愿意尊它为龙书
- 黑马IOS - OC protocol与Delegate 理解
- Spring MVC 环境搭建
- 配置iis支持.json格式的文件