接下来主要采用页操作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 位列奇偶
1、ECC 模块特点
ECC 生成由控制寄存器的ECC 锁位(主ECC 锁、空闲ECC 锁)来控制。
2、ECC 寄存器配置(大小端),K9F2G08UXA为8bit。
3、ECC 编程指引
(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()
- static inline int nand_check_badblock(U32 addr)
- {
- U32 sector = addr >> 11;
- U8 bad_value;
- nand_reset();//nand flash 复位
- NF_nFCE_L(); //选择芯片
- NF_CLEAR_RB();
- NF_CMD(0x0);//读命令
-
- NF_ADDR(2048 & 0xFF); //读一页中的2048地址处保存的坏块标志地址,分5次送出一个完整地址
- NF_ADDR((2048 >>8) & 0xff);
- NF_ADDR(sector & 0xff);
- NF_ADDR((sector >> 8) & 0xff);
- NF_ADDR((sector >> 16) & 0xff);
-
- NF_CMD(0x30);
- NF_DETECT_RB();
- bad_value = NF_RDDATA8();
- NF_nFCE_H();
- if (bad_value == 0xFF) {
- return 1; //good
- }
- return 0;
- }
5、nand_erase_block()
- /*****************************************
- 块擦除
- ******************************************/
- int nand_erase_block (U32 addr)
- {
- unsigned int stat;
- unsigned long bi;
- for(;;){
- if(nand_check_badblock(addr))
- {
- break;
- }
- bi = addr>>17;
- printf("%d is bad block.\r\n",(int)bi);
- addr += (1<<17);//跳过此块
- }
-
- nand_reset();
- NF_nFCE_L();
- //发送指令60h块擦除设置指令
- NFCMD = 0x60;
- //发送三次行地址
- NFADDR = (addr >> 11) & 0xff;
- NFADDR = (addr >> 19) & 0xff;
- NFADDR = (addr >> 27) & 0x1;
-
- //nandflash ready
- //发送d0擦除指令
- NFCMD = 0xd0;
- //等待忙状态
- while(!(NFSTAT & 0x1));
- // 发送70h读状态指令
- NFCMD = 0x70;
- //读取数据
- stat = NF_RDDATA8();
- //最后一位判断成功与否
- if(stat & 0x1){
- Uart_SendString("erase nand flash device err\r\n");
- NF_nFCE_H();
- return 0;
- }
- bi = addr>>17;
- printf("erase %d is succes\r\n",(int)bi);
- NF_nFCE_H();
- return 1;
- }
6、nand_writePage()
- /*****************************************
- 按块写数据
- ******************************************/
- int nand_writePage(U8 *buf, U32 addr)
- {
- U32 sector,i, mecc0, secc;
- U32 bi;
- U8 ECCBuf[6],stat;
- for(;;){
- if(nand_check_badblock(addr))
- {
- break;
- }
- bi = addr>>17;
- printf("%d is bad block,skip this block.\r\n",bi);
- addr += (1<<17);//跳过此块
- }
- sector = addr >> 11;
- nand_reset();
- NF_ECC_RST();
- NF_MECC_UnLock();
- NF_nFCE_L();
- NF_CLEAR_RB();
- NF_CMD(0x80); //页写命令周期1
- NF_ADDR(0x00);
- NF_ADDR(0x00);
- NF_ADDR(sector & 0xff);
- NF_ADDR((sector >> 8) & 0xff);
- NF_ADDR((sector >> 16) & 0xff);
- //write a page data
- for(i = 0; i < (2048); i++)
- {
- NF_RDDATA8() = buf[i];
- }
- NF_MECC_Lock();
- mecc0=NFMECC0; //读取main区的ECC校验码
-
- //把ECC校验码由字型转换为字节型,并保存到全局变量数组ECCBuf中
- ECCBuf[0]=(U8)(mecc0&0xff);
- ECCBuf[1]=(U8)((mecc0>>8) & 0xff);
- ECCBuf[2]=(U8)((mecc0>>16) & 0xff);
- ECCBuf[3]=(U8)((mecc0>>24) & 0xff);
-
- NF_SECC_UnLock(); //解锁spare区的ECC
-
- NF_RDDATA8() = 0xff; //标记此为好块
- //把main区的ECC值写入到spare区的前4个字节地址内,即第2049~2052地址
- for(i=0;i<4;i++)
- {
- NF_RDDATA8() = ECCBuf[i];
- }
-
- NF_SECC_Lock(); //锁定spare区的ECC值
- secc=NFSECCD; //读取spare区的ECC校验码
- //把ECC校验码保存到全局变量数组ECCBuf中
- ECCBuf[4]=(U8)(secc&0xff);
- ECCBuf[5]=(U8)((secc>>8) & 0xff);
- //把spare区的ECC值继续写入到spare区的第2053~2054地址内
- for(i=4;i<6;i++)
- {
- NF_RDDATA8() = ECCBuf[i];
- }
- //发送10h写指令
- NF_CMD(0x10); //页写命令周期2
-
- //等待忙状态
- while(!(NFSTAT & 0x1));
-
- // 发送70h读状态指令
- NF_CMD(0x70); //读状态命令
- NF_DETECT_RB();
- stat = NF_RDDATA8();
-
- //最后一位判断成功与否
- if(stat & 0x1){
- Uart_SendString("write nand flash device err\r\n");
- NF_nFCE_H();
- return 0;
- }
- bi = addr>>17;
- printf("write %d is success,good block!!\r\n",bi);
- NF_nFCE_H();
- return 1;
- }
7、nand_readPage()
- /*****************************************
- 按块读数据
- ******************************************/
- int nand_readPage(U8 *buf, U32 addr)
- {
- U32 sector,i, mecc0, secc;
- U32 bi;
- for(;;){
- if(nand_check_badblock(addr))
- {
- break;
- }
- bi = addr>>17;
- printf("%d is bad block,skip this block.\r\n",bi);
- addr += (1<<17);//跳过此块
- }
- sector = addr >> 11; //page_number
- nand_reset();
- NF_ECC_RST();
- NF_MECC_UnLock();
- NF_nFCE_L();
- NF_CLEAR_RB();
- NF_CMD(0x00); //页读命令周期2
- NF_ADDR(0x00);
- NF_ADDR(0x00);
- NF_ADDR(sector & 0xff);
- NF_ADDR((sector >> 8) & 0xff);
- NF_ADDR((sector >> 16) & 0xff);
- NF_CMD(0x30); //页读命令周期2
- NF_DETECT_RB();
- //nandflash 数据准备
- for(i = 0; i < (2048); i++)
- {
- buf[i] = NF_RDDATA8();
- }
- NF_MECC_Lock();
- NF_SECC_UnLock(); //解锁spare区ECC
- mecc0=NF_RDDATA8(); //0xff好块标志读出
- mecc0=NF_RDDATA32(); //读spare区的前4个地址内容,即第2049~2052地址,
- //这4个字节为main区的ECC
- //把读取到的main区的ECC校验码放入NFMECCD0/1的相应位置内
- NFMECCD0=((mecc0&0xff00)<<8)|(mecc0&0xff);
- NFMECCD1=((mecc0&0xff000000)>>8)|((mecc0&0xff0000)>>16);
-
- NF_SECC_Lock(); //锁定spare区的ECC值
- secc=NF_RDDATA32(); //继续读spare区的4个地址内容,即第2053~2056地址,
- //其中前2个字节为spare区的ECC值
- //把读取到的spare区的ECC校验码放入NFSECCD的相应位置内
- NFSECCD=((secc&0xff00)<<8)|(secc&0xff);
- NF_nFCE_H();
-
- //判断所读取到的数据是否正确
- if ((NFESTAT0&0xf) == 0x0)
- {
- Uart_SendString("read a page finish,good block!\r\n");
- return 1; //正确
- }
- else
- return 0; //错误
- }
8、Testpage_NAND_FLASH()
- void Testpage_NAND_FLASH()
- {
- int i;
- unsigned char buf[10];
- unsigned int addr;
- addr =0x5000000;
-
- NandInit();
- for(i=0;i<10;i++)
- {
- buf[i] = 'd';
- }
- nand_erase_block(addr);
- nand_writePage(buf,addr);
- //Uart_SendString("write nand flash device success\n");
- for(i=0;i<10;i++)
- {
- buf[i] = '0';
- }
- nand_readPage(buf,addr);
- // Uart_SendString("read nand flash device success\r\n");
- for(i=0;i<10;i++)
- {
- printf(" %c ",buf[i]);
- }
- Uart_SendString("\r\n");
- nand_erase_block(addr);
- /*
- nand_erase_block(addr);
- nand_readPage(buf,addr);
- Uart_SendString("read nand flash device success\r\n");
- for(i=0;i<10;i++)
- {
- printf(" %c ",buf[i]);
- }
- */
- return ;
- }
运行结果
640到643坏块是由于程序初始调试时并未写好,每写一个数据后,
此块就变成坏块。经过分析,是由于写时产生的ECC覆盖了坏块标志。
将ECC校正码保存地址移后4字节即可。
二进制代码下载至Nand Flash起始处运行即可:
all_ts.rar
阅读(2261) | 评论(0) | 转发(0) |