目录
描述
-
1
实现 nand 测试菜单中的 [r]Read nand flash
-
2
读 OOB 检测坏块, 改进 nand_read 实现碰到坏块就跳过
-
3
改进 nand_write 实现碰到坏块就跳过
-
4
百度了解一下 NAND ECC
解答
-
1
在 switch函数 中调用函数 do_read_nand_flash()
switch (c)
{
case 'q':
case 'Q':
return;
break;
case 's':
case 'S':
nand_chip_id();
break;
case 'e':
case 'E':
do_erase_nand_flash();
break;
case 'w':
case 'W':
do_write_nand_flash();
break;
case 'r':
case 'R':
do_read_nand_flash();
break;
default:
break;
}
void do_read_nand_flash(void)
{
unsigned int addr;
volatile unsigned char *p;
int i, j;
unsigned char c;
unsigned char str[16];
unsigned char buf[64];
/* 获得地址 */
printf("Enter the address to read: ");
addr = get_uint();
nand_read(addr, buf, 64);
p = (volatile unsigned char *)buf;
printf("Data : \n\r");
/* 长度固定为64 */
for (i = 0; i < 4; i++)
{
/* 每行打印16个数据 */
for (j = 0; j < 16; j++)
{
/* 先打印数值 */
c = *p++;
str[j] = c;
printf("%02x ", c);
}
printf(" ; ");
for (j = 0; j < 16; j++)
{
/* 后打印字符 */
if (str[j] < 0x20 || str[j] > 0x7e) /* 不可视字符 */
putchar('.');
else
putchar(str[j]);
}
printf("\n\r");
}
}
-
2
检测坏块函数 nand_bad()
int nand_bad(unsigned int addr)
{
unsigned int col = 2048;
unsigned int page = addr / 2048;
unsigned char val;
/* 1. 选中 */
nand_select();
/* 2. 发出读命令00h */
nand_cmd(0x00);
/* 3. 发出地址(分5步发出) */
nand_col(col);
nand_page(page);
/* 4. 发出读命令30h */
nand_cmd(0x30);
/* 5. 判断状态 */
nand_wait_ready();
/* 6. 读数据 */
val = nand_data();
/* 7. 取消选中 */
nand_deselect();
if (val != 0xff)
return 1; /* bad blcok */
else
return 0;
}
在 nand_read() 读之前,检测坏块,碰到就跳过
void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{
int col = addr % 2048;
int i = 0;
while (i < len)
{
if (!(addr & 0x1FFFF) && nand_bad(addr)) /* 一个block只判断一次 */
{
addr += (128*1024); /* 跳过当前block */
continue;
}
/* 1. 选中 */
nand_select();
/* 2. 发出读命令00h */
nand_cmd(0x00);
/* 3. 发出地址(分5步发出) */
nand_addr(addr);
/* 4. 发出读命令30h */
nand_cmd(0x30);
/* 5. 判断状态 */
nand_wait_ready();
/* 6. 读数据 */
for (; (col < 2048) && (i < len); col++)
{
buf[i] = nand_data();
i++;
addr++;
}
col = 0;
/* 7. 取消选中 */
nand_deselect();
}
}
-
3
检测坏块函数 nand_bad()
int nand_bad(unsigned int addr)
{
unsigned int col = 2048;
unsigned int page = addr / 2048;
unsigned char val;
/* 1. 选中 */
nand_select();
/* 2. 发出读命令00h */
nand_cmd(0x00);
/* 3. 发出地址(分5步发出) */
nand_col(col);
nand_page(page);
/* 4. 发出读命令30h */
nand_cmd(0x30);
/* 5. 判断状态 */
nand_wait_ready();
/* 6. 读数据 */
val = nand_data();
/* 7. 取消选中 */
nand_deselect();
if (val != 0xff)
return 1; /* bad blcok */
else
return 0;
}
在 nand_write() 写之前,检测坏块,碰到就跳过
void nand_write(unsigned int addr, unsigned char *buf, unsigned int len)
{
unsigned int page = addr / PAGE_SIZE;
unsigned int col = addr & (PAGE_SIZE-1);
unsigned int i = 0;
while(1)
{
if(!(addr & 0x1ffff) && nand_bad(addr))
{
addr += (128* 1024);
continue;
}
nand_select();
nand_cmd(CMD_WRITE_1);
nand_col(col);
nand_page(page);
while((col < PAGE_SIZE) && (i<len))
{
nand_write_data_byte(buf[i++]);
}
nand_cmd(CMD_WRITE_2);
nand_wait_ready();
nand_deselect();
if(i==len)
break;
else
{
col = 0;
page++;
}
}
}
-
4
ECC 的全称是 Error Checking and Correction ,是一种用于Nand的差错检测和修正算法。如果操作时序和电路稳定性不存在问题的话,NAND Flash出错的时候一般不会造成整个Block或是Page不能读取或是全部出错,而是整个Page(例如512Bytes)中只有一个或几个bit出错。ECC能纠正1个比特错误和检测2个比特错误,而且计算速度很快,但对1比特以上的错误无法纠正,对2比特以上的错误不保证能检测。
校验码生成算法:ECC校验每次对256字节的数据进行操作,包含列校验和行校验。对每个待校验的Bit位求异或,若结果为0,则表明含有偶数个1;若结果为1,则表明含有奇数个1。列校验规则如表1所示。256字节数据形成256行、8列的矩阵,矩阵每个元素表示一个Bit位。
其中CP0 ~ CP5 为六个Bit位,表示Column Parity(列极性),
CP0为第0、2、4、6列的极性,CP1为第1、3、5、7列的极性,
CP2为第0、1、4、5列的极性,CP3为第2、3、6、7列的极性,
CP4为第0、1、2、3列的极性,CP5为第4、5、6、7列的极性。
用公式表示就是:CP0=Bit0^Bit2^Bit4^Bit6, 表示第0列内部256个Bit位异或之后再跟第2列256个Bit位异或,再跟第4列、第6列的每个Bit位异或,这样,CP0其实是256*4=1024个Bit位异或的结果。CP1 ~ CP5 依此类推。行校验如下图所示
综上所述,对256字节的数据共生成了6个Bit的列校验结果,16个Bit的行校验结果,共22个Bit。在Nand中使用3个字节存放校验结果,多余的两个Bit位置1。存放次序如下表所示: