本帖最后由 破风者 于 2018-12-19 10:30 编辑
[mw_shl_code=c,true]//读取NAND Flash的指定页指定列的数据(main区和spare区都可以使用此函数)
//PageNum:要读取的页地址,范围:0~(block_pagenum*block_totalnum-1)
//ColNum:要读取的列开始地址(也就是页内地址),范围:0~(page_totalsize-1)
//*pBuffer:指向数据存储区
//NumByteToRead:读取字节数(不能跨页读)
//返回值:0,成功
// 其他,错误代码
u8 NAND_ReadPage(u32 PageNum,u16 ColNum,u8 *pBuffer,u16 NumByteToRead)
{
vu16 i=0;
u8 res=0;
u8 eccnum=0; //需要计算的ECC个数,每NAND_ECC_SECTOR_SIZE字节计算一个ecc
u8 eccstart=0; //第一个ECC值所属的地址范围
u8 errsta=0;
u8 *p;
*(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_AREA_A;
//发送地址
*(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)ColNum;
*(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(ColNum>>8);
*(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)PageNum;
*(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(PageNum>>8);
*(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(PageNum>>16);
*(vu8*)(NAND_ADDRESS|NAND_CMD)=NAND_AREA_TRUE1;
//下面两行代码是等待R/B引脚变为低电平,其实主要起延时作用的,等待NAND操作R/B引脚。因为我们是通过
//将STM32的NWAIT引脚(NAND的R/B引脚)配置为普通IO,代码中通过读取NWAIT引脚的电平来判断NAND是否准备
//就绪的。这个也就是模拟的方法,所以在速度很快的时候有可能NAND还没来得及操作R/B引脚来表示NAND的忙
//闲状态,结果我们就读取了R/B引脚,这个时候肯定会出错的,事实上确实是会出错!大家也可以将下面两行
//代码换成延时函数,只不过这里我们为了效率所以没有用延时函数。
res=NAND_WaitRB(0); //等待RB=0
if(res)return NSTA_TIMEOUT; //超时退出
//下面2行代码是真正判断NAND是否准备好的
res=NAND_WaitRB(1); //等待RB=1
if(res)return NSTA_TIMEOUT; //超时退出
if(NumByteToRead%NAND_ECC_SECTOR_SIZE)//不是NAND_ECC_SECTOR_SIZE的整数倍,不进行ECC校验
{
//读取NAND FLASH中的值
for(i=0;i<NumByteToRead;i++)
{
*(vu8*)pBuffer++ = *(vu8*)NAND_ADDRESS;
}
}else
{
eccnum=NumByteToRead/NAND_ECC_SECTOR_SIZE; //得到ecc计算次数
eccstart=ColNum/NAND_ECC_SECTOR_SIZE;
p=pBuffer;
for(res=0;res<eccnum;res++)
{
FMC_Bank2_3->PCR3|=1<<6; //使能ECC校验
for(i=0;i<NAND_ECC_SECTOR_SIZE;i++) //读取NAND_ECC_SECTOR_SIZE个数据
{
*(vu8*)pBuffer++ = *(vu8*)NAND_ADDRESS;
}
while(!(FMC_Bank2_3->SR3&(1<<6))); //等待FIFO空
nand_dev.ecc_hdbuf[res+eccstart]=FMC_Bank2_3->ECCR3; 读取200-711的硬件 ECC
FMC_Bank2_3->PCR3&=~(1<<6); //禁止ECC校验
}
i=nand_dev.page_mainsize+0X10+eccstart*4; //从spare区的0X10位置开始读取之前存储的ecc值
NAND_Delay(NAND_TRHW_DELAY);//等待tRHW
*(vu8*)(NAND_ADDRESS|NAND_CMD)=0X05; //随机读指令
//发送地址
*(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)i;
*(vu8*)(NAND_ADDRESS|NAND_ADDR)=(u8)(i>>8);
*(vu8*)(NAND_ADDRESS|NAND_CMD)=0XE0; //开始读数据
NAND_Delay(NAND_TWHR_DELAY);//等待tWHR
pBuffer=(u8*)&nand_dev.ecc_rdbuf[eccstart];
for(i=0;i<4*eccnum;i++) //读取保存的ECC值
{
*(vu8*)pBuffer++= *(vu8*)NAND_ADDRESS; 读取保存的0-511 ECC
}
for(i=0;i<eccnum;i++) //检验ECC
{
if(nand_dev.ecc_rdbuf[i+eccstart]!=nand_dev.ecc_hdbuf[i+eccstart])//不相等,需要校正
{
printf("err hd,rd:0x%x,0x%x
",nand_dev.ecc_hdbuf[i+eccstart],nand_dev.ecc_rdbuf[i+eccstart]);
printf("eccnum,eccstart:%d,%d
",eccnum,eccstart);
printf("PageNum,ColNum:%d,%d
",PageNum,ColNum);
res=NAND_ECC_Correction(p+NAND_ECC_SECTOR_SIZE*i,nand_dev.ecc_rdbuf[i+eccstart],nand_dev.ecc_hdbuf[i+eccstart]);//ECC校验
if(res)errsta=NSTA_ECC2BITERR; //标记2BIT及以上ECC错误
else errsta=NSTA_ECC1BITERR; //标记1BIT ECC错误
}
}
}
if(NAND_WaitForReady()!=NSTA_READY)errsta=NSTA_ERROR; //失败
return errsta; //成功
} [/mw_shl_code]
比如ColNum为200,NumByteToRead为512,nand_dev.ecc_hdbuf是200-711的硬件 ECC,nand_dev.ecc_rdbuf是保存的0-511 ECC。
是我理解错了还是程序有bug?
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
版主,就像楼主说的,这个在写入的时候ecc是按照512字节存4组,那么读取的时候,如果是从页中开始读取,例如页地址700读512个字节,那么读取时计算的ecc是地址700到700+511的,这个怎么和之前写入时的ecc比较呢?
一周热门 更多>