Chinaunix首页 | 论坛 | 博客
  • 博客访问: 306347
  • 博文数量: 63
  • 博客积分: 1482
  • 博客等级: 上尉
  • 技术积分: 1185
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-12 19:06
个人简介

hello world!

文章分类

全部博文(63)

分类: LINUX

2011-04-09 15:48:10

接下来主要采用页操作Nand Flash,并检查坏块,采读写ECC(错误

纠错码)校验 。主要有以下几部分:nand_check_badlock(),nand_erase_blcok(),

nand_writePage(),nand_readPage(),Testpage_NAND_FLASH()。

NAND Flash 控制器包括4 个ECC(错误接错码)模块。两个模块

(一个用于data[7:0],一个用于data[15:8])可以被用于(上限)2048bytes

的ECC 奇偶码的生成,另外两个模块(一个用于data[7:0],一个用于data[15:8])

可以被用于(上限)16bytes 的ECC 奇偶校验码的生成。

28 位ECC 奇偶码=22 位行奇偶+6 位列奇偶

14 位ECC 奇偶码=8 位行奇偶+6 位列奇偶

ScreenShot001

1ECC 模块特点

ECC 生成由控制寄存器的ECC 锁位(主ECC 锁、空闲ECC 锁)来控制。

2ECC 寄存器配置(大小端),K9F2G08UXA为8bit。

clip_image004

3ECC 编程指引

(1)在软件模式下,ECC 模块为所有的读写数据生成ECC 奇偶码。因此你

通过写InitECC位(NFCONT[4])置1 来重置ECC 的值,且在读写数据之前清0

theMainECCLock 位(NFCONT[15])。

(2)不管读还是写数据,ECC 模块在寄存器NFMECC0/1 上生成ECC 奇偶码。

(3)在你完整的读写一页后(不包括空闲区域数据),theMainECCLock 位置1

(锁定)。ECC奇偶码被锁定且ECC 状态寄存器的值不会被改变。

(4)生成空闲区域ECC 奇偶码,清0(非锁定)SpareECCLock 位(NFCONT[6])

(5)不管读还是写数据,空闲区域ECC 模块在寄存器NFSECC 上生成ECC 奇偶码

(6)在你完整的读写空闲区域后,SpareECCLock 位置1(锁定)。ECC 奇偶

码被锁定且ECC状态寄存器的值不会被改变

(7)一旦完成你可以使用这些值去记录到空闲区域或检查位错误。

注:NFSECCD 是为空闲区域的ECC 服务(通常,用户写主数据区域的ECC 值到空闲

区域,这些值和NFMECC0/1 中的值一样)且从主数据区域中生成。

4、nand_check_badlock()

  1. static inline int nand_check_badblock(U32 addr)
  2. {
  3.     U32 sector = addr >> 11;
  4.     U8 bad_value;

  5.     nand_reset();//nand flash 复位
  6.     NF_nFCE_L(); //选择芯片
  7.     NF_CLEAR_RB();
  8.     NF_CMD(0x0);//读命令
  9.     
  10.     NF_ADDR(2048 & 0xFF); //读一页中的2048地址处保存的坏块标志地址,分5次送出一个完整地址
  11.     NF_ADDR((2048 >>8) & 0xff);
  12.     NF_ADDR(sector & 0xff);
  13.     NF_ADDR((sector >> 8) & 0xff);
  14.     NF_ADDR((sector >> 16) & 0xff);
  15.     
  16.     NF_CMD(0x30);
  17.     NF_DETECT_RB();

  18.     bad_value = NF_RDDATA8();

  19.     NF_nFCE_H();

  20.     if (bad_value == 0xFF) {
  21.         return 1; //good
  22.     }

  23.     return 0;
  24. }

5、nand_erase_block()

  1. /*****************************************
  2.            块擦除
  3. ******************************************/
  4. int nand_erase_block (U32 addr)
  5. {
  6.     unsigned int stat;
  7.     unsigned long bi;

  8.     for(;;){
  9.         if(nand_check_badblock(addr))
  10.         {
  11.             break;
  12.         }
  13.         bi = addr>>17;
  14.         printf("%d is bad block.\r\n",(int)bi);
  15.         addr += (1<<17);//跳过此块
  16.     }
  17.     
  18.     nand_reset();
  19.     NF_nFCE_L();

  20.     //发送指令60h块擦除设置指令
  21.     NFCMD = 0x60;

  22.     //发送三次行地址
  23.     NFADDR = (addr >> 11) & 0xff;
  24.     NFADDR = (addr >> 19) & 0xff;
  25.     NFADDR = (addr >> 27) & 0x1;
  26.     
  27.    //nandflash ready
  28.     //发送d0擦除指令
  29.     NFCMD = 0xd0;

  30.     //等待忙状态
  31.     while(!(NFSTAT & 0x1));

  32.     // 发送70h读状态指令
  33.     NFCMD = 0x70;

  34.     //读取数据
  35.     stat = NF_RDDATA8();

  36.    //最后一位判断成功与否
  37.     if(stat & 0x1){
  38.         Uart_SendString("erase nand flash device err\r\n");
  39.          NF_nFCE_H();
  40.         return 0;
  41.     }
  42.     bi = addr>>17;
  43.     printf("erase %d is succes\r\n",(int)bi);
  44.     NF_nFCE_H();

  45.     return 1;
  46. }

6、nand_writePage()

  1. /*****************************************
  2.            按块写数据
  3. ******************************************/
  4. int nand_writePage(U8 *buf, U32 addr)
  5. {
  6.     U32 sector,i, mecc0, secc;
  7.     U32 bi;
  8.     U8 ECCBuf[6],stat;

  9.     for(;;){
  10.         if(nand_check_badblock(addr))
  11.         {
  12.             break;
  13.         }
  14.         bi = addr>>17;
  15.         printf("%d is bad block,skip this block.\r\n",bi);
  16.         addr += (1<<17);//跳过此块
  17.     }

  18.     sector = addr >> 11;

  19.     nand_reset();

  20.     NF_ECC_RST();
  21.     NF_MECC_UnLock();

  22.     NF_nFCE_L();

  23.     NF_CLEAR_RB();
  24.     NF_CMD(0x80); //页写命令周期1

  25.     NF_ADDR(0x00);
  26.     NF_ADDR(0x00);
  27.     NF_ADDR(sector & 0xff);
  28.     NF_ADDR((sector >> 8) & 0xff);
  29.     NF_ADDR((sector >> 16) & 0xff);

  30.     //write a page data
  31.     for(i = 0; i < (2048); i++)
  32.     {
  33.         NF_RDDATA8() = buf[i];
  34.     }


  35.     NF_MECC_Lock();
  36.     mecc0=NFMECC0; //读取main区的ECC校验码
  37.     
  38.     //把ECC校验码由字型转换为字节型,并保存到全局变量数组ECCBuf中
  39.     ECCBuf[0]=(U8)(mecc0&0xff);
  40.     ECCBuf[1]=(U8)((mecc0>>8) & 0xff);
  41.     ECCBuf[2]=(U8)((mecc0>>16) & 0xff);
  42.     ECCBuf[3]=(U8)((mecc0>>24) & 0xff);
  43.     
  44.     NF_SECC_UnLock();                 //解锁spare区的ECC
  45.     
  46.     NF_RDDATA8() = 0xff;             //标记此为好块
  47.     //把main区的ECC值写入到spare区的前4个字节地址内,即第2049~2052地址
  48.     for(i=0;i<4;i++)
  49.     {
  50.         NF_RDDATA8() = ECCBuf[i];
  51.     }
  52.     
  53.     NF_SECC_Lock();                 //锁定spare区的ECC值
  54.     secc=NFSECCD;                    //读取spare区的ECC校验码

  55.     //把ECC校验码保存到全局变量数组ECCBuf中
  56.     ECCBuf[4]=(U8)(secc&0xff);
  57.     ECCBuf[5]=(U8)((secc>>8) & 0xff);

  58.     //把spare区的ECC值继续写入到spare区的第2053~2054地址内
  59.     for(i=4;i<6;i++)
  60.     {
  61.      NF_RDDATA8() = ECCBuf[i];
  62.     }

  63.      //发送10h写指令
  64.     NF_CMD(0x10);              //页写命令周期2        
  65.     
  66.      //等待忙状态
  67.     while(!(NFSTAT & 0x1));
  68.     
  69.      // 发送70h读状态指令
  70.     NF_CMD(0x70);                //读状态命令

  71.     NF_DETECT_RB();
  72.     stat = NF_RDDATA8();
  73.     
  74.      //最后一位判断成功与否
  75.      if(stat & 0x1){
  76.          Uart_SendString("write nand flash device err\r\n");
  77.          NF_nFCE_H();
  78.          return 0;
  79.      }
  80.     bi = addr>>17;
  81.     printf("write %d is success,good block!!\r\n",bi);
  82.     NF_nFCE_H();
  83.     return 1;
  84. }

7、nand_readPage()

  1. /*****************************************
  2.            按块读数据
  3. ******************************************/
  4. int nand_readPage(U8 *buf, U32 addr)
  5. {
  6.     U32 sector,i, mecc0, secc;
  7.     U32 bi;

  8.     for(;;){
  9.         if(nand_check_badblock(addr))
  10.         {
  11.             break;
  12.         }
  13.         bi = addr>>17;
  14.         printf("%d is bad block,skip this block.\r\n",bi);
  15.         addr += (1<<17);//跳过此块
  16.     }

  17.     sector = addr >> 11; //page_number

  18.     nand_reset();

  19.     NF_ECC_RST();
  20.     NF_MECC_UnLock();

  21.     NF_nFCE_L();

  22.     NF_CLEAR_RB();
  23.     NF_CMD(0x00);            //页读命令周期2

  24.     NF_ADDR(0x00);
  25.     NF_ADDR(0x00);
  26.     NF_ADDR(sector & 0xff);
  27.     NF_ADDR((sector >> 8) & 0xff);
  28.     NF_ADDR((sector >> 16) & 0xff);

  29.     NF_CMD(0x30);             //页读命令周期2

  30.     NF_DETECT_RB();

  31.     //nandflash 数据准备
  32.     for(i = 0; i < (2048); i++)
  33.     {
  34.        buf[i] = NF_RDDATA8();
  35.     }


  36.     NF_MECC_Lock();
  37.     NF_SECC_UnLock(); //解锁spare区ECC

  38.     mecc0=NF_RDDATA8(); //0xff好块标志读出
  39.     mecc0=NF_RDDATA32(); //读spare区的前4个地址内容,即第2049~2052地址,
  40.                                  //这4个字节为main区的ECC

  41.     //把读取到的main区的ECC校验码放入NFMECCD0/1的相应位置内
  42.     NFMECCD0=((mecc0&0xff00)<<8)|(mecc0&0xff);
  43.     NFMECCD1=((mecc0&0xff000000)>>8)|((mecc0&0xff0000)>>16);
  44.     
  45.     NF_SECC_Lock(); //锁定spare区的ECC值
  46.     secc=NF_RDDATA32();             //继续读spare区的4个地址内容,即第2053~2056地址,
  47.                                  //其中前2个字节为spare区的ECC值

  48.     //把读取到的spare区的ECC校验码放入NFSECCD的相应位置内
  49.     NFSECCD=((secc&0xff00)<<8)|(secc&0xff);


  50.     NF_nFCE_H();
  51.     
  52.     //判断所读取到的数据是否正确
  53.     if ((NFESTAT0&0xf) == 0x0)
  54.     {
  55.         Uart_SendString("read a page finish,good block!\r\n");    
  56.         return 1;                  //正确
  57.     }
  58.      else
  59.          return 0;                  //错误

  60. }

8、Testpage_NAND_FLASH()

  1. void Testpage_NAND_FLASH()
  2. {
  3.     int i;
  4.     unsigned char buf[10];
  5.     unsigned int addr;
  6.     addr =0x5000000;
  7.     
  8.     NandInit();

  9.     for(i=0;i<10;i++)
  10.     {
  11.         buf[i] = 'd';
  12.     }
  13.     nand_erase_block(addr);
  14.     nand_writePage(buf,addr);
  15.     //Uart_SendString("write nand flash device success\n");

  16.     for(i=0;i<10;i++)
  17.     {
  18.         buf[i] = '0';
  19.     }

  20.     nand_readPage(buf,addr);
  21.   // Uart_SendString("read nand flash device success\r\n");    

  22.     for(i=0;i<10;i++)
  23.     {
  24.         printf(" %c ",buf[i]);
  25.     }
  26.     Uart_SendString("\r\n");

  27.     nand_erase_block(addr);

  28. /*
  29.     nand_erase_block(addr);

  30.     nand_readPage(buf,addr);
  31.     Uart_SendString("read nand flash device success\r\n");        
  32.     for(i=0;i<10;i++)
  33.     {
  34.         printf(" %c ",buf[i]);
  35.     }    
  36. */
  37.    return ;
  38. }

运行结果

ScreenShot005

640到643坏块是由于程序初始调试时并未写好,每写一个数据后,

此块就变成坏块。经过分析,是由于写时产生的ECC覆盖了坏块标志。

将ECC校正码保存地址移后4字节即可。

        二进制代码下载至Nand Flash起始处运行即可:

 all_ts.rar   

阅读(2268) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~