新闻中心

EEPW首页 > 网络与存储 > 设计应用 > SigmaStar的SSD20x处理器Nand Flash读写问题排查

SigmaStar的SSD20x处理器Nand Flash读写问题排查

作者:物联网全栈开发 时间:2026-01-26 来源:今日头条 收藏

一批用SSD20X开发的设备在用SD卡升级之后变砖,无法启动linux操作系统;

设备升级的日志表明,设备在擦除Nand Flash时报了E_Fail的错误;

芯片厂家反馈应该是Nand Flash不支持,应该换成华邦1G的Nand Flash,

这个...,我们已经出货了上万套设备了...

正在进行的生产被紧急叫停,几千台设备堆在产线等着出货;

在这危急关头,我硬着头皮顶上排查问题根源,

根据我的理解,我花了半天做了一些测试,据此推测可能的根源并与厂家沟通如下:

可能是因为这个nand flash出厂就有坏块,

用专门的下载工具可以检测到两个坏块,可能uboot在擦除flash时检测不到这个坏块,

没有跳过坏块区,仍然去擦,没办法从0擦成1,

所以报了E_Fail的擦除错误,

在uboot中运行nand bad,打印的信息没有提示有坏块;

深入函数打印日志,nand_block_isbad->nand_block_bad函数没有判断到坏块;、

最终是通过HAL_SPINAND_Read的读取oob数据,根据第一个字节是否是0来判断坏块;

在这个函数把读取到的64个字节的oob 数据打印出来,

发现基本上全都是ff,有大概8个page,是 ff ff ff ff 00 ff …,即第5个字节是00,也不是坏块所定义的第1个字节为00;

HAL_SPINAND_Read函数读取spare区的oob数据有问题?

按照nand flash的规格书,坏块标志00应该在每一个block的第一个page的oob的第一个字节;

厂家提供了最新V55版本的SDK, 并表示,可能是Nand flash存在坏块在出厂时没被标识,专用工具可以识别被标识,但是SSD20X不能识别,

我的意见:

两个可能,一个是没有标注坏块,另一个有标注坏块,SSD20x判断错了,误认为不是坏块;

Nand Flash的规格书中有这么一句话:

NAND Flash devices are shipped from the factory erased. The factory identifies invalid

blocks before shipping by attempting to program the bad-block mark into every location in the first page of each invalid block. It may not be possible to program every location in an invalid block with the bad-block mark. However, the first spare area location

in each bad block is guaranteed to contain the bad-block mark. This method is compliant with ONFI factory defect mapping requirements. See the following table for the

bad-block mark.

规格书上明确说了,nand flash会做坏块标识,用专用工具能显示坏块,用nand bad没有显示坏块,这肯定是有问题,顺着这个问题往下查找,应该就能解决问题了。

第二天一上班,我再次仔细分析HAL_SPINAND_Read函数代码,有了新的发现;

1. 修改的代码

HAL_SPINAND_Read函数有问题!

读nand flash page的函数,根据规格书的说明,首先是发命令0x13给nand flash把数据搬到cache,然后再从cache读取数据和spare区;

因为这个flash是两个plane,需要根据page选择plane;

看上去应该是地址线12选择plane,在读数据的时候有或plane选择位,但是读spare区的时候并没有或plane选择位,

我加上图示的红色框内的代码,或上plan选择位;

再运行nand bad,可以正常检测到坏块,用SD卡升级程序,可以正常启动内核;

除此之外,HAL_SPINAND_Read还存在另一个问题,

图2. Nand Flash规格书中关于Page Read的时序说明

发送完13h之后,nand flash需要时间把数据搬到cache,

需要通过GET Features得到的状态判断是否搬移完成,但是程序没有做这样的判断,可能导致数据没准备好就去读,从而得到错误的数据;

一、升级变砖问题

改之前:

HAL_SPINAND_Read(pSpiNandDrv->tSpinandInfo.u16_PageByteCnt...

改之后:

HAL_SPINAND_Read(u16ColumnAddr | pSpiNandDrv->tSpinandInfo.u16_PageByteCnt...

Spare区数据读错,奇数plane的数据错读偶数plane的Spare区数据,使得坏块标识和ECC都错误;

厂家曾经发2023年3月份左右发布patch修正这一问题,但是当时提到的是ECC算错的低概率的问题,并没有提高坏块标识检测不到的问题;没有合并该patch,而且厂家提供的V55版本的SDK也没有合并该patch;

二、开机LOGO显示错乱的问题

V55版本的SDK和V30版本的相比,除了plane标志位的区别,还有就是QUAD读写的一些配置上的区别,比如bootdriversmstarspinandincconfiginfinity2mdrvSPINAND_uboot.h中的宏定义SUPPORT_SPINAND_QUAD。

这个定义按我的理解是使能QUAD SPI的读写方式,也就是用1根的SPI数据线还是4根SPI数据线;

V30是定义为0,也就是使用1根数据线,

V55是定义为1,也就是使用4根数据线, 这两个配置SPI的读写速度完全不一样,

当把这个宏定义改为1时,也就是用4根数据线时,开机LOGO在启动内核前消失的一瞬间显示错乱;

在cmd_nand中,对nand bad命令的执行统计执行时间并打印出来,当宏义为1时,执行时间为150us,当定义为0时,执行时间为400us。

uboot启动内核的脚 本:

bootlogo 0 1 0 0 0;

nand read.e 0x22000000 KERNEL 0x500000;

bootm 0x22000000;

改成以下的启动代码,LOGO显示不错乱:

run_command("bootlogo 0 1 0 0 0", 0);

udelay(1000);

run_command("nand read.e 0x22000000 KERNEL 0x500000", 0);

run_command("bootm 0x22000000", 0);

改成以下的启动代码,LOGO显示延时3秒,并且不错乱:

run_command("bootlogo 0 1 0 0 0", 0);

run_command("nand read.e 0x22000000 KERNEL 0x500000", 0);

udelay(3000 * 1000);

run_command("bootm 0x22000000", 0);

说明,显示LOGO正在刷新之时,改成QAUD读NAND之后,read kernel加快,使得LOGO的刷新与启动KERNEL时的display的关闭冲突了。

bootm运行到以下代码,把延时放在后面,LOGO就不延时显示,说明boot_selected_os是kernel提供的启动函数,在这里对硬件做了重新初始化,使得LOGO显示错乱。

ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO, images, boot_fn);

udelay(3000 * 1000);

三、Feature, status的in process标志的问题

根据nand flash的时序要求:

Following successful completion of PAGE READ, the READ FROM CACHE command must be issued to read data out of cache.

The command sequence is as follows to transfer data from array to output:

• 13h (PAGE READ command to cache)

• 0Fh (GET FEATURES command to read the status)

• 03h or 0Bh (READ FROM CACHE)

实际的代码并没有读取status状态,进行inprocess的判断,如果数据搬移到cache比较慢,可能出现数据还没有准备好就去读的情况,造成读错;

U32 MDrv_SPINAND_Read这个函数增加数据ready的判断,不会出现LOGO错乱的问题;

u32Ret = HAL_SPINAND_RFC(u32_PageIdx, &u8Status);if(u32Ret != ERR_SPINAND_SUCCESS){	return u32Ret;
}
u16Counter = 0;do{
u32Ret = MDrv_SPINAND_ReadStatusRegister(&u8Status, SPI_NAND_REG_STAT);  if(u32Ret == ERR_SPINAND_SUCCESS){    if(0 == (u8Status & 0x1)){    break;
   }else{    printf("%s, %d, read busy, counter=%dn", __func__, __LINE__, u16Counter);
   }
 }
 u16Counter++;
}while(u16Counter < 100);

没有发现有打印busy的日志,可能是cache搬移比较快,不会出现这一情况,从可靠性的角度出发,应该加上status的判断;

另外,加上status的in process标志位判断,开机LOGO显示不再错乱;

四、Quad SPI读写的问题

#define SUPPORT_SPINAND_QUAD (1) 配置成1使用QUAD读nand

通过以下代码测试时间:

if (strcmp(cmd, "bad") == 0) {	printf("nDevice %d bad blocks:n", dev);
start = get_timer(0); for (off = 0; off < nand->size; off += nand->erasesize) if (nand_block_isbad(nand, off)) printf(" %08llxn", (unsigned long long)off); unsigned long elapsed = get_timer(start); // get elapsed time in us
printf("Elapsed time: %lu usn", elapsed); return 0;
}

Quad read以及增加数据ready的判断耗时为330us;

不验证status的in process标志,耗时325 us

#define SUPPORT_SPINAND_QUAD (0) 配置成0使用单线读nand flash并且验证ready, 耗时821us;

不验证status的in process标志,耗时817 us

可见,在显示开机LOGO和运行kernel启动函数之间增加几百us以上的延时就可以解决LOGO错乱的问题


关键词:

评论


相关推荐

技术专区

关闭