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 TACLS   1
#define TWRPH0  2
#define TWRPH1  0/*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);#endif 

nand.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));
#endifNF_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));
#endifNF_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相关推荐

  1. mini2440硬件篇之Nor Flash

    1. 硬件原理 1.1. Nor Flash简介 NOR Flash是Intel在1988年推出的一款商业性闪存芯片,它需要很长的时间进行抹写,大半生它能够提供完整的寻址与数据总线,并允许随机存取存储 ...

  2. mini2440硬件篇之开篇词

    对于以前玩单片机的人来说,对裸机编程一直都情有独钟,到了ARM9以上的cpu后,基本都跑操作系统,主流的是Linux,A8以后基本都跑Android,那么有没有必要再写裸机程序,这是一个争议的话题.以 ...

  3. s3c2440 移值u-boot-2016.03 第2篇 支持Nand flash启动

    1, 要求:在4K 的代码以内,完成 NOR NAND 类型判断,初始化 NAND 复制自身到 SDRAM ,重定向. 2, 在 /arch/arm/cpu/arm920t/ 文件夹里 添加一个 in ...

  4. mini2440硬件篇之IIC

     1. 硬件原理 I2C总线是PHLIPS公司推出的一种串行总线,是具备多主机系统所需的包括总线裁决和高低速器件同步功能的高性能串行总线. I2C总线只有两根双向信号线.一根是数据线SDA,另一根 ...

  5. PXA270-基于ARM9内核Processor外部NAND FLASH的控制实现

    于ARM9内核Processor外部NAND FLASH的控制实现 夏 涛 (上海交通大学微电子学院 上海 200030) 1 NAND FLASH NAND写回速度快.芯片面积小,特别是大容量使其优 ...

  6. DM365视频处理流程/DM368 NAND Flash启动揭秘

    DM365的视频处理涉及到三个相关处理器,分别是视频采集芯片.ARM处理器和视频图像协处理器(VICP),整个处理流程由ARM核协调.视频处理主要涉及三个处理流程,分别是视频采集.视频编码和对编码后的 ...

  7. nand flash 个人觉得写得比较好的文章

    [详解]如何编写Linux下Nand Flash驱动 版本:v2.2.1 Crifan Li 摘要 本文先解释了Nand Flash相关的一些名词,再从Flash硬件机制开始,介绍到Nand Flas ...

  8. nand flash 经典 全面 ------如何编写Linux下Nand Flash驱动

    Crifan Li 摘要 本文先解释了Nand Flash相关的一些名词,再从Flash硬件机制开始,介绍到Nand Flash的常见的物理特性,且深入介绍了Nand Flash的一些高级功能,然后开 ...

  9. 【详解一】Nand Flash 编写驱动之前要了解的知识

    1.1. 一些相关的名词的解释 1.1.1. Non-Volatile Memory非易失性存储器 NVM,即NV (RAM)Memory,断电数据也不会丢失的存储器,比如Nand Flash,Nor ...

最新文章

  1. 啊D扫肉鸡+无远控双开XP3389 termsrvhack.dll_本地测试
  2. UIProgressView(进度条控件)
  3. putty完全使用手册--多窗口---git提交---连接数据库--自动日志显示
  4. github本地文件和远端文件的协同
  5. HDOJ 4876 ZCC loves cards
  6. linux动态库符号检查,写 Linux 动态库的最佳实践
  7. python中协程与函数的区别_python 协程与go协程的区别
  8. 容器,VM和Docker的初学者友好介绍
  9. .net 实现微信公众平台的用户信息获取
  10. 华为云PB级数据库GaussDB(for Redis)揭秘第七期:高斯Redis与强一致
  11. win11如何加快搜索速度 Windows11更改文件索引加快搜索速度的设置方法
  12. 常去的国外网站一览表
  13. robbe+base64+Mysql简易有效的php全文索引实现
  14. java docx4j 目录,docx4j项目(包括jar包、javadoc文档、源码及示例)
  15. 龙卷风路径_“龙卷风”:预判路径 减轻灾害
  16. niosii spi 外部_NIOS2随笔——SD卡之SPI操作
  17. 计算机编辑功能在哪,win10系统本地组策略编辑器在哪的具体步骤
  18. 从核酸检测平台崩盘看性能工程的范围
  19. php header 生成pdf,PHP如何生成PDF文档
  20. 第一次向git.oschina.net提交项目

热门文章

  1. 一维数组新老数据对比修改字段
  2. dos2unix 解决脚本执行过程中的莫名错误 “not found”
  3. C语言代码(打印国际象棋棋盘)
  4. 重磅!Amazon发布个人免费的AI编程助手:CodeWhisperer !
  5. 苹果胜三星震惊国产手机
  6. 【敬伟ps教程】图层相关知识
  7. 记录学习Java HttpServletRequests报错The server encountered an internal error that prevented it from fulfil
  8. STEM创新教育-热量与马铃薯含水量之间的关系
  9. 常见开关电源优缺点对比
  10. 深度揭秘阿里云函数计算异步任务能力