内存测试三步法.docx

上传人:b****2 文档编号:17024012 上传时间:2023-07-21 格式:DOCX 页数:14 大小:66.20KB
下载 相关 举报
内存测试三步法.docx_第1页
第1页 / 共14页
内存测试三步法.docx_第2页
第2页 / 共14页
内存测试三步法.docx_第3页
第3页 / 共14页
内存测试三步法.docx_第4页
第4页 / 共14页
内存测试三步法.docx_第5页
第5页 / 共14页
内存测试三步法.docx_第6页
第6页 / 共14页
内存测试三步法.docx_第7页
第7页 / 共14页
内存测试三步法.docx_第8页
第8页 / 共14页
内存测试三步法.docx_第9页
第9页 / 共14页
内存测试三步法.docx_第10页
第10页 / 共14页
内存测试三步法.docx_第11页
第11页 / 共14页
内存测试三步法.docx_第12页
第12页 / 共14页
内存测试三步法.docx_第13页
第13页 / 共14页
内存测试三步法.docx_第14页
第14页 / 共14页
亲,该文档总共14页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

内存测试三步法.docx

《内存测试三步法.docx》由会员分享,可在线阅读,更多相关《内存测试三步法.docx(14页珍藏版)》请在冰点文库上搜索。

内存测试三步法.docx

内存测试三步法

DDR内存子系统常见硬件错误及Uboot中检测流程

在U-Boot中,Denx(U-Boot的开发商)针对常见的DDR内存故障进行了严格的检测处理,下图描述了该检测处理过程的三个步骤:

检测数据线、地址线和DDR物理存储部件,主要涉及这三个步骤的处理过程和方法,对于DDR子系统,是很容易出故障并且是很难debug检测出来的,而Denx所针对DDR内存故障设计的检测方法是非常严谨,值得学习研究的。

下面主要是相关的检测处理思路及问题:

1、为什么先检测数据线?

因为如果数据线是断开的,那么一切无从谈起!

接下来是检测地址线,只有数据线和地址线都通过,检测内存的存储单元才有意义,这样的流程也利于分割定位问题。

上面testingsequence框图将整个检测过程分成三大步,用三个虚线方框表示。

2、数据线的连接错误

数据线的连接可能存在两种错误,一种是被断开,另一种布线或生产造成互相短路。

3、如何检测数据线的连接错误

Denx设计的数据线检测算法还是很Tricky和精秒的,整个处理流程如下例子:

如果是两根数据线,只需要写入并读出一个pattern=0b01(0b开头表示二进制数)就能判断它们是否短路或断开。

很明显,大部分的嵌入式平台不止两根数据线,我们以64位地址线为例,pattern=0b1101010....能检测出奇偶位之间的数据错误。

如果这个错误被排除,每两根数据线组成一组(这是理解下一个pattern的关键),再用相同的办法,检测每相邻两组之间是否有短路,就得到第二个pattern,就是0b110011001100......依次类推,以4根数据线为一组,8根线为一组,相继得到共6个pattern,分别是0xaaaaaaaaaaaaaaaa,0xcccccccccccccccc,0xf0f0f0f0f0f0f0f0,0xff00ff00ff00ff00,0xffff0000ffff0000,0xffffffff00000000。

只要相继写入并读出这6个pattern就能验证是否存在数据线交叉短路错误。

4、如何检测数据线与板上其它信号线交叉短路或断路

取以上6个pattern的反码,总共12个pattern就能检测到每一位都可以写入和读出0和1。

5、什么是floatingbuses错误

floatingbuses会“欺骗”测试软件,如果测试软件写入并很快读出一个值的时候,写操作会给数据线上的电容充电,总线会短暂的保持它的状态。

当测试软件读操作时,总线会返回刚写入的值,即使实际上该数据线是断路的。

6、如何检测数据线的floatingbuses错误

检测floatingbuses错误的算法不复杂,在写入和读回之间再插入一次对不同地址写入不同值的操作。

例如,X写入X1位置,Y写入Y1位置,再从X1位置读出X值则表示floatingbuses错误不存在。

7、地址线的错误

如果地址线存在错误,其症状是地址空间中的两个不同位置被映射到同一物理存储位置。

更通俗地讲,就是写一个位置却“改变”了另一个位置。

8、地址线的错误检测

地址线的错误检测相对简单,其算法是:

1)、将地址的值作为内容写入该地址处,汇编的表示方法是(addr)=addr。

即将地址值写到地址对应的空间里,这样确保每一个位置的内容不同。

2)、依次将内存基地址的某一根地址线的值翻转(flip/toggle)得到某个地址,从该地址取值,如果该值和基地址的值相等,则表示某一位地址线有问题。

这个算法的特点是每次只检测一根地址线,方法简单有效。

9、存储单元的错误

以上数据线和地址线的检测都是检测布线或工厂生产的错误,而存储单元的检测则是真正对DDR内存芯片的检测。

内存芯片的常见错误是bit-stuck,简而言之,就是让它是0,它偏为1,让它为1,它偏为0,检测方法也很简单,就是用不同的pattern去写尽可能所有的地址并读回比较。

有一些常用的pattern如0x5555,0xAAAA等。

10、几个简单的检测DDR故障的方法

上面的DDR检测算法,虽然全面,但是耗时比较长,常常需要好几个小时,在Uboot命令行下也有几个简单的命令可以检测常见内存故障,如下所示:

1)、mtestaddrlenthpattern

这个命令需要注意,DDR在Uboot启动后被映射到了0地址,但是uboot的代码和堆、栈空间0x10000000处开始,这些空间是不能被刷的,否则就挂死了。

2)、复制NORflash的内容到内存中,如cp.b0x200800000x7fc020000,然后比较cmp.b0x200800000x7fc020000。

3)、下载kernelimage到内存中,copyNORflash或tftp都行,然后调用iminfoLOAD_ADDR检测CRC错误。

第一种方法是用特定的pattern去刷DDR的空闲空间,第二种和第三种方法可以说Pattern的随机性更大一些。

当然最彻底的检测方法当然是长时间跑Linux系统,上面的方法更适用于系统不稳定时定位错误。

内存检测方法程序示例

staticvoidmove64(unsignedlonglong*src,unsignedlonglong*dest)

{

*dest=*src;

}

 

/*

 *Thisis64bitwidetestpatterns. NotethattheyresideinROM

 *(whichpresumablyworks)andthetestswritethemtoRAMwhichmay

 *notwork.

 *

 *The"otherpattern"iswrittentodrivethedatabustovaluesother

 *thanthetestpattern. Thisisfordetectingfloatingbuslines.

 *

 */

conststaticunsignedlonglongpattern[]={

0xaaaaaaaaaaaaaaaaULL,

0xccccccccccccccccULL,

0xf0f0f0f0f0f0f0f0ULL,

0xff00ff00ff00ff00ULL,

0xffff0000ffff0000ULL,

0xffffffff00000000ULL,

0x00000000ffffffffULL,

0x0000ffff0000ffffULL,

0x00ff00ff00ff00ffULL,

0x0f0f0f0f0f0f0f0fULL,

0x3333333333333333ULL,

0x5555555555555555ULL

};

constunsignedlonglongotherpattern=0x0123456789abcdefULL;

 

/*数据线检测*/

staticintmemory_post_dataline(unsignedlonglong*pmem)

{

unsignedlonglongtemp64=0;

intnum_patterns=sizeof(pattern)/sizeof(pattern[0]);

inti;

unsignedinthi,lo,pathi,patlo;

intret=0;

 

for(i=0;i

{

move64((unsignedlonglong*)&(pattern[i]),pmem++);

/*

*Putadifferentpatternonthedatalines:

otherwisethey

*mayfloatlongenoughtoreadbackwhatwewrote.

*/

/*预防floatingbuses错误*/

move64((unsignedlonglong*)&otherpattern,pmem--);

move64(pmem,&temp64);

 

#ifdefINJECT_DATA_ERRORS

temp64^=0x00008000;

#endif

 

if(temp64!

=pattern[i])

{

pathi=(pattern[i]>>32)&0xffffffff;

patlo=pattern[i]&0xffffffff;

 

hi=(temp64>>32)&0xffffffff;

lo=temp64&0xffffffff;

 

post_log("Memory(dateline)errorat%08x,"

 "wrote%08x%08x,read%08x%08x!

\n",

 pmem,pathi,patlo,hi,lo);

ret=-1;

}

}

returnret;

}

 

/*地址线检测*/

staticintmemory_post_addrline(ulong*testaddr,ulong*base,ulongsize)

{

ulong*target;

ulong*end;

ulongreadback;

ulongxor;

int ret=0;

 

end=(ulong*)((ulong)base+size);/*pointerarith!

*/

xor=0;

for(xor=sizeof(ulong);xor>0;xor<<=1) 

{

/*对测试的地址的某一根地址线的值翻转*/

target=(ulong*)((ulong)testaddr^xor);

if((target>=base)&&(target

{

/*由于target是testaddr某一根地址线的值翻转得来

  故testaddr!

=target,下面赋值操作后

  应有*testaddr!

=*target*/

*testaddr=~*target;

readback =*target;

 

#ifdefINJECT_ADDRESS_ERRORS

if(xor==0x00008000) 

{

readback=*testaddr;

}

#endif

           /*出现此种情况只有testaddr==target,即某根地址线翻转无效*/

if(readback==*testaddr) 

{

post_log("Memory(addressline)errorat%08x<->%08x,"

 "XORvalue%08x!

\n",

testaddr,target,xor);

ret=-1;

}

}

}

returnret;

}

 

staticintmemory_post_test1(unsignedlongstart,

   unsignedlongsize,

   unsignedlongval)

{

unsignedlongi;

ulong*mem=(ulong*)start;

ulongreadback;

intret=0;

 

for(i=0;i

mem[i]=val;

if(i%1024==0)

WATCHDOG_RESET();

}

 

for(i=0;i

readback=mem[i];

if(readback!

=val){

post_log("Memoryerrorat%08x,"

 "wrote%08x,read%08x!

\n",

 mem+i,val,readback);

 

ret=-1;

break;

}

if(i%1024==0)

WATCHDOG_RESET();

}

 

returnret;

}

 

staticintmemory_post_test2(unsignedlongstart,unsignedlongsize)

{

unsignedlongi;

ulong*mem=(ulong*)start;

ulongreadback;

intret=0;

 

for(i=0;i

mem[i]=1<<(i%32);

if(i%1024==0)

WATCHDOG_RESET();

}

 

for(i=0;i

readback=mem[i];

if(readback!

=(1<<(i%32))){

post_log("Memoryerrorat%08x,"

 "wrote%08x,read%08x!

\n",

 mem+i,1<<(i%32),readback);

 

ret=-1;

break;

}

if(i%1024==0)

WATCHDOG_RESET();

}

 

returnret;

}

 

staticintmemory_post_test3(unsignedlongstart,unsignedlongsize)

{

unsignedlongi;

ulong*mem=(ulong*)start;

ulongreadback;

intret=0;

 

for(i=0;i

mem[i]=i;

if(i%1024==0)

WATCHDOG_RESET();

}

 

for(i=0;i

readback=mem[i];

if(readback!

=i){

post_log("Memoryerrorat%08x,"

 "wrote%08x,read%08x!

\n",

 mem+i,i,readback);

 

ret=-1;

break;

}

if(i%1024==0)

WATCHDOG_RESET();

}

 

returnret;

}

 

staticintmemory_post_test4(unsignedlongstart,unsignedlongsize)

{

unsignedlongi;

ulong*mem=(ulong*)start;

ulongreadback;

intret=0;

 

for(i=0;i

mem[i]=~i;

if(i%1024==0)

WATCHDOG_RESET();

}

 

for(i=0;i

readback=mem[i];

if(readback!

=~i){

post_log("Memoryerrorat%08x,"

 "wrote%08x,read%08x!

\n",

 mem+i,~i,readback);

 

ret=-1;

break;

}

if(i%1024==0)

WATCHDOG_RESET();

}

 

returnret;

}

 

staticintmemory_post_tests(unsignedlongstart,unsignedlongsize)

{

intret=0;

 

if(ret==0)

ret=memory_post_dataline((unsignedlonglong*)start);

WATCHDOG_RESET();

if(ret==0)

ret=memory_post_addrline((ulong*)start,(ulong*)start,size);

WATCHDOG_RESET();

if(ret==0)

ret=memory_post_addrline((ulong*)(start+size-8),

  (ulong*)start,size);

WATCHDOG_RESET();

if(ret==0)

ret=memory_post_test1(start,size,0x00000000);

WATCHDOG_RESET();

if(ret==0)

ret=memory_post_test1(start,size,0xffffffff);

WATCHDOG_RESET();

if(ret==0)

ret=memory_post_test1(start,size,0x55555555);

WATCHDOG_RESET();

if(ret==0)

ret=memory_post_test1(start,size,0xaaaaaaaa);

WATCHDOG_RESET();

if(ret==0)

ret=memory_post_test2(start,size);

WATCHDOG_RESET();

if(ret==0)

ret=memory_post_test3(start,size);

WATCHDOG_RESET();

if(ret==0)

ret=memory_post_test4(start,size);

WATCHDOG_RESET();

 

returnret;

}

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2