WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决

WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决

 

之前在U0D上正常工作,现在换为U0E后在烧录系统的时候,系统加载时无法正常启动,停在下面的串口信息处:

WindowsCE Kernel for ARM (Thumb Enabled) Built on Oct 20 2009 at 18:39:19

INFO:OALLogSetZones:dpCurSettings.ulZoneMask: 0xb

DCache:128 sets, 4 ways, 32 line size, 16384 size

ICache:128 sets, 4 ways, 32 line size, 16384 size

FCLK:400000000,HCLK:133333333, PCLK:66666666

+OALArgsInit()

Argumentsarea has some values

-OALArgsInit()

OEM:Force clean boot.

-OEMInit

+OEMSetRealTime(2008/6/112:0:0.000)

####FMD_DRIVER:::FMD_OEMIoControl IOCTL (0x71f8c).

FMD_OEMIoControl:IOCTL_FMD_GET_INTERFACE

####FMD_DRIVER:::FMD_INIT

 (NAND ID:0xecd3) --> OK.

 NUM_OF_BLOCKS    = 8192

 PAGES_PER_BLOCK  = 64

 SECTORS_PER_PAGE = 4

NUMBLOCKS: 8192(0x2000), SECTORSPERBLOCK = 64(0x40), BYTESPERSECTOR = 2048(0x800)

####FMD_DRIVER:::FMD_OEMIoControl IOCTL (0x71c24).

FMD_OEMIoControl:unrecognized IOCTL (0x71c24).

MECCUncorrectable error(0x4246)

FMD_LB_ReadSector()startSectorAddr=0x4246

MECCUncorrectable error(0x4246)

FMD_LB_ReadSector()startSectorAddr=0x4246

OEM:Clearing storage registry hive

MECCUncorrectable error(0x1fc)

FMD_LB_ReadSector()startSectorAddr=0x1fc

MECCUncorrectable error(0x1fc)

FMD_LB_ReadSector()startSectorAddr=0x1fc

MECCcorrectable error(0x44da). Byte:117, bit:7

MECCcorrectable error(0x44da). Byte:327, bit:6

MECCcorrectable error(0x44da). Byte:161, bit:2

MECCcorrectable error(0x44da). Byte:219, bit:0

MECCcorrectable error(0x44da). Byte:117, bit:7

MECC correctableerror(0x44da). Byte:327, bit:6

MECCcorrectable error(0x44da). Byte:161, bit:2

MECCcorrectable error(0x44da). Byte:219, bit:0

MECCcorrectable error(0x4398). Byte:384, bit:1

MECCUncorrectable error(0x4626)

FMD_LB_ReadSector()startSectorAddr=0x4626

MECCUncorrectable error(0x4626)

FMD_LB_ReadSector()startSectorAddr=0x4626

OEM: Notclearing storage

MECCUncorrectable error(0x4246)

FMD_LB_ReadSector()startSectorAddr=0x4246

MECCUncorrectable error(0x4246)

FMD_LB_ReadSector()startSectorAddr=0x4246

 

其中最后的信息是在FMD_LB_ReadSector函数读取数据后调用ECC_CorrectData进行ECC校验出错时输出的。

 

1.      U0D和U0E的异同

对比了U0D和U0E的功能方块图和阵列组织图是一样的,如下图:

WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决_第1张图片

图1

K9K8G08U0D和U0E一片是8192blocks。

 

经过仔细对比,还发现下面的一些差别:

 

(1)    页编程、块擦除等参数的差别

WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决_第2张图片

图2

 

 

(2)    NOP由最大有4个周期变为1个周期

WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决_第3张图片

图3

 

(3)    交互操作(Interleave Operation)

 

U0E支持交互操作,相关的其中一部分如下图:

WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决_第4张图片

图4

这里可以看出U0E和U0D都支持interleave operation,但为什么U0D数据手册中没有说明了,我怀疑是U0E这里描述有问题,也就是说U0D并不支持Interleave Operation的。

 

还可以看出Interleave page proam设计目的是为了系统吞吐量的,而且是非Interleave page program的两倍。

 

(4)     

 

2.      解决此问题的过程

 

下面是解决问题的确认

2.1  TACLS、TWRPH0和TWRPH1参数的确定

 

先来看S3C2451的相关时序部分:

WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决_第5张图片

图5

由图7可知TACLS、TWRPH0和TWRPH1是对COMMAND/ADDRESS操作时序的描述,再来看K9K8G08U0E此部分的时序图:

WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决_第6张图片

图6

结合图7和图8可知,TACLS:表示CLT和ALE的建立时间(setup time) =tCLS/tALS-tWP;TWRPH0表示nWE的脉冲宽度=tWP;TWRPH0表示CLE和ALE维持时间,我们来看K9K8G08U0E数据手册这几个参数的具体要求:

WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决_第7张图片

图7

我们HCLK=400M/3=133MHZ,相当于一个HCLK时钟需要7.5ns,在这里我们的取值是:

#defineTACLS                    7  //7 //1

#defineTWRPH0                        7  //7 //6

#defineTWRPH1                        7  //7 //2

这三个参数取值都为7,都是能够设置的最大值,比如对于TACLS=7来说,标明NAND控制TACLS=7*7.5=52.5n,是满足图6给出的参数的。而且对比了K9K8G08U0D这部分时序参数,没有差别。

 

 

2.2  降低HCLK

 

因为NAND控制器是由HCLK提供时钟的,由于U0E速度下来了,想通过降低HCLK来看能否解决此问题,寄存器定义了HCLK时钟的控制,如下图:

WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决_第8张图片

图8

目前我们CLKDIV0寄存器相关配置在SMDK2450\SRC\INC\S3c2450.inc中,如下图:

WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决_第9张图片

图9

由上图可知目前的HCLK=PREDIV_CLK/2=(MPLL/3)/2=(800MHZ/3)/2=133MHZ,目标是直接降为67MHZ,需要修改的地方如下:

(1)    SMDK2450\SRC\INC\S3c2450.inc

如图8所示需要把Startup_HCLKdiv的值改为3,也就是HCLK=PREDIV_CLK/4,但由于PCLK是由HCLK分频的,这样改之后PCLK=HCLK/2也相应降低了,从而导致调试串口输出乱码,为确保调试串口输出正常,我们同时把Startup_PCLKdiv改为0,也就PCLK=HCLK,这样就不会输出乱码了。

 

(2)    SRC\OAL\OALLIB\startup.s

 

SMDK2450\SRC\COMMON\TIMER\timer_fixedtick.c,此文件的ChangeSystemStateDVS函数下面通过调用HCLK_DOWNTO_PCLK函数也修改到HCLK和PCLK,HCLK_DOWNTO_PCLK函数在SMDK2450\SRC\OAL\OALLIB\startup.s文件中实现,如下:

    LEAF_ENTRY    HCLK_DOWNTO_PCLK

    ldr       r0, =vCLKDIV0            ;    Set Clock Divider

    ldr       r1, [r0]

    bic       r1,    r1,    #0x7            ; clear PCLKDIV, HCLKDIV

    ldr       r2, =((0<<PCLKDIV_bit)+(3<<HCLKDIV_bit));

    orr       r1, r1, r2

    str       r1, [r0]

mov       pc, lr

可以看出来,这里并没有采用S3c2450.inc中定义的Startup_HCLKdiv和Startup_PCLKdiv,这样的风格很不好,如果不仔细查找,不容易找到这里的,但经过确认ChangeSystemStateDVS函数暂时没有用到,所以可以不管这里。

 

2.3  U0E支持的interleave operation

根据图4中U0E支持的interleave operation修改了驱动代码,但还是不行。

 

2.4  NOP

Number ofPartial Program Cycles,见图3,可知U0D支持的NOP最大是4个周期,而U0E支持的NOP最大是1个周期,后来也看到老外在I.MX35+Linux平台上也提到NOP

https://community.freescale.com/thread/319855

回到FMD_LB_WriteSector函数中,我们增加下面的调试信息:

RETAILMSG(1,(TEXT("FMD_LB_WriteSector: %08x, %08x, %08x\r\n"),

startSectorAddr,(DWORD)pSectorBuff, (DWORD)pSectorInfoBuff));

见相关代码:

WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决_第10张图片

图10

 

依次输出页地址,保存页数据buffer的地址,保存SectorInfo结构体数据的buffer地址,相关的输出信息如下:

Windows CE Kernel for ARM(Thumb Enabled) Built on Oct 20 2009 at 18:39:19

INFO:OALLogSetZones:dpCurSettings.ulZoneMask: 0xb

DCache: 128 sets, 4 ways,32 line size, 16384 size

ICache: 128 sets, 4 ways,32 line size, 16384 size

FCLK:400000000,HCLK:133333333, PCLK:66666666

+OALArgsInit()

Arguments area has somevalues

-OALArgsInit()

-OEMInit

+OEMSetRealTime(2008/6/112:0:0.000)

####FMD_DRIVER:::FMD_OEMIoControl IOCTL (0x71f8c).

FMD_OEMIoControl:IOCTL_FMD_GET_INTERFACE

#### FMD_DRIVER:::FMD_INIT

 (NAND ID:0xecdc) --> OK.

 NUM_OF_BLOCKS    = 4096

 PAGES_PER_BLOCK  = 64

 SECTORS_PER_PAGE = 4

NUMBLOCKS : 4096(0x1000),SECTORSPERBLOCK = 64(0x40), BYTESPERSECTOR = 2048(0x800)

####FMD_DRIVER:::FMD_OEMIoControl IOCTL (0x71c24).

FMD_OEMIoControl:unrecognized IOCTL (0x71c24).

OEM: Not clearing storage

FMD_LB_WriteSector:000001c0, 00000000, d023eb2c

FMD_LB_WriteSector:000001c0, d0370000, d023eb2c

FMD_LB_WriteSector:000001c1, 00000000, d023eb2c

FMD_LB_WriteSector:000001c1, d0370800, d023eb2c

FMD_LB_WriteSector:000001c2, 00000000, d023eb2c

FMD_LB_WriteSector:000001c2, d0371000, d023eb2c

FMD_LB_WriteSector:000001c3, 00000000, d023eb2c

FMD_LB_WriteSector:000001c3, d0371800, d023eb2c

…………………………

可以看出来,相同的startSectorAddr地址,发现调用FMD_LB_WriteSector函数两次,第1次的pSectorBuff的值是00000000,这次直接调用NAND_LB_WriteSectorInfo函数后就返回了,第2次的值比如是d0370000,才是执行FMD_LB_WriteSector后面的部分。

 

为了验证是否是NOP的问题,这里我们注释掉对NAND_LB_WriteSectorInfo函数的调用,这样系统就可以正常跑起来了,这样就验证了是U0ENOP最大支持1个周期,所以对于支持最大为4NOPU0D就没有问题。

 

但是我发现有个问题,先从SD卡启动,在eboot中依次操作a---f---9---s后,然后改为从NAND启动,就看不到任何串口输出信息,如果改为依次操作f---9---s(少了a操作)后,从NAND可以正常启动,奇怪啊。为了搞清楚这几个问题,先来看看a和f对应的操作

 

A对应的操作:

WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决_第11张图片

图11

很简单,就是发送擦除命令擦除所有的块。

 

F对应的操作:

WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决_第12张图片

图12

 

下面来介绍为什么执行了a操作后,重启无法完成启动的:

(1)    A:把所有的block重置,包括spare区的数据.

(2)    F:调用FMD_WriteSector(i, NULL, &si,1)把SectorInfo数据写入到spare区,但因为注释掉NAND_LB_WriteSectorInfo函数,所以无法把SectorInfo数据写入到spare区

(3)    系统重启,stepldr\nand.c的NF_ReadPage函数在读取数据时,这样在重启的时候,根据下面的判断


图13

因为第(2)没有把有效的SectorInfo数据写入到spare区,所以这里直接返回return nRet,也就是返回FALSE,所以nboot无法读取eboot,所以没有看到串口输入任何串口信息

 

要解决此问题,就是bootloader阶段调用NAND_LB_WriteSectorInfo,系统阶段,不调用NAND_LB_WriteSectorInfo,但这样做还不知道是否有哪些风险,麻烦知道的朋友告知,谢谢了,接下来测试,也希望此总结对大家有帮忙

 

int NF_ReadPage(UINT32 block,UINT32 sector,UINT8 *buffer)
{
	register UINT8 * bufPt=buffer;
	unsigned int RowAddr, ColAddr;
	DWORD MECCBuf, rddata1, rddata2;
	UINT32 nRetEcc;
	int nRet = FALSE;
	int nSectorLoop;

	NF_nFCE_L();	

	for (nSectorLoop = 0; nSectorLoop < (bLARGEBLOCK==TRUE?4:1); nSectorLoop++)
	{
		ColAddr = nSectorLoop * 512;

		NF_CMD(CMD_READ);   // Read command

		if (bLARGEBLOCK == TRUE)
		{
			RowAddr = (block<<6) + sector;
			
			NF_ADDR((ColAddr)   &0xff);    // 1st cycle
			NF_ADDR((ColAddr>>8)&0xff);    // 2nd cycle
			NF_ADDR((RowAddr)   &0xff);    // 3rd cycle
			NF_ADDR((RowAddr>>8)&0xff);    // 4th cycle
			if (LB_NEED_EXT_ADDR)
				NF_ADDR((RowAddr>>16)&0xff);    // 5th cycle
		}
		else
		{
			RowAddr = (block<<5) + sector;
			
			NF_ADDR((ColAddr)   &0xff);    // 1st cycle
			NF_ADDR((RowAddr)   &0xff);    // 2nd cycle
			NF_ADDR((RowAddr>>8)&0xff);    // 3rd cycle
			if (SB_NEED_EXT_ADDR)
				NF_ADDR((RowAddr>>16)&0xff);    // 4th cycle
		}

		NF_CLEAR_RB();
		NF_CMD(CMD_READ3);   // Read command
		NF_DETECT_RB();
		//NF_WAITRB();

		NF_RSTECC();	// Initialize ECC

		NF_MECC_UnLock();
		
		__RdPage512(bufPt+nSectorLoop*512);		// Read 512 bytes.

		NF_MECC_Lock();

		if (bLARGEBLOCK == TRUE)
		{
			ColAddr = 2048;

			NF_CMD(CMD_RDO);		// Random Data Output In a Page, 1st Cycle
			NF_ADDR((ColAddr)   &0xff);    // 1st cycle
			NF_ADDR((ColAddr>>8)&0xff);    // 2nd cycle
			NF_CMD(CMD_RDO2);		// Random Data Output In a Page. 2nd Cycle
		}

		rddata1 = NF_RDDATA32();  // check bad block
		rddata2 = NF_RDDATA32();

		if (bLARGEBLOCK == TRUE)
		{
			if (((rddata1 & 0xff) != 0xff) && (((rddata2>>8) & 0xff) != 0x03)) return nRet;  // bad block && !(OEM_BLOCK_RESERVED | OEM_BLOCK_READONLY)
		}
		else if ((((rddata2>>8) & 0xff) != 0xff) && ((rddata2 & 0xff) != 0x03)) return nRet;  // bad block && !(OEM_BLOCK_RESERVED | OEM_BLOCK_READONLY)

		if (bLARGEBLOCK == TRUE)
		{
			ColAddr = 2048 + 8 + nSectorLoop*4;

			NF_CMD(CMD_RDO);		// Random Data Output In a Page, 1st Cycle
			NF_ADDR((ColAddr)   &0xff);    // 1st cycle
			NF_ADDR((ColAddr>>8)&0xff);    // 2nd cycle
			NF_CMD(CMD_RDO2);		// Random Data Output In a Page. 2nd Cycle
		}

		MECCBuf = NF_RDDATA32();

		NF_WRMECCD0( ((MECCBuf&0x0000ff00)<<8) | ((MECCBuf&0x000000ff)    ) );
		NF_WRMECCD1( ((MECCBuf&0xff000000)>>8) | ((MECCBuf&0x00ff0000)>>16) );

		nRetEcc = rNFECCERR0;

		nRet = ECC_CorrectData(RowAddr, bufPt+nSectorLoop*512, nRetEcc, ECC_CORRECT_MAIN);

		if (!nRet) return nRet;
	}

	NF_nFCE_H();	

	return nRet;
}

相关链接:

此问题csdn帖子:

K9K8G08U0D-SCB0升级为K9K8G08U0E时系统起不来

http://bbs.csdn.net/topics/390762117

 

你可能感兴趣的:(WINCE6.0+S3C2451K9K8G08U0D升级为U0E遇到的问题及解决)