嵌入式 uboot中mtest测试内存

原创 2013年12月02日 14:54:35

在U-Boot中,Denx(U-Boot的开发商)针对常见的DDR内存故障进行了严格的检测处理,下图描述了该检测处理过程的三个步骤:检测数据线、地址线和DDR物理存储部件,主要涉及这三个步骤的处理过程和方法,对于DDR子系统,是很容易出故障并且是很难debug检测出来的,而Denx所针对DDR内存故障设计的检测方法是非常严谨,值得学习研究的。

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

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

因为如果数据线是断开的,那么一切无从谈起!接下来是检测地址线,只有数据线和地址线都通过,检测内存的存储单元才有意义,这样的流程也利于分割定位问题。上面testingsequence框图将整个检测过程分成三大步,用三个虚线方框表示。

2、数据线的连接错误

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

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

Denx设计的数据线检测算法还是很Tricky和精秒的,整个处理流程如下例子:如果是两根数据线,只需要写入并读出一个pattern=0b01(0b开头表示二进制数)就能判断它们是否短路或断开。很明显,大部分的嵌入式平台不止两根数据线,我们以64位地址线为例,pattern= 0b101010101010101010....能检测出奇偶位之间的数据错误。如果这个错误被排除,每两根数据线组成一组(这是理解下一个pattern的关键),再用相同的办法,检测每相邻两组之间是否有短路,就得到第二个pattern,就是0b110011001100...... 依次类推,以4根数据线为一组,8根线为一组,相继得到共6个pattern,分别是0xaaaaaaaaaaaaaaaa,0xcccccccccccccccc,0xf0f0f0f0f0f0f0f0,0xff00ff00ff00ff00,0xffff0000ffff0000,0xffffffff00000000。只要相继写入并读出这6个pattern就能验证是否存在数据线交叉短路错误。

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

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

5、什么是floating buses错误

floatingbuses会“欺骗”测试软件,如果测试软件写入并很快读出一个值的时候,写操作会跟数据线上的电容充电,总线会短暂的保持它的状态。当测试软件读操作时,总线会返回刚写入的值,即使实际上该数据线是断路的。

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

检测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)、mtest addr lenth pattern

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

2)、复制NOR flash的内容到内存中,如 cp.b 0x20080000 0x7fc020000,然后比较 cmp.b 0x20080000 0x7fc0 20000。

3)、下载kernel image到内存中,copy NOR flash或tftp都行,然后调用iminfo LOAD_ADDR 检测CRC错误。

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

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


具体代码实现如下:

  1. static voidmove64(unsigned long long *src, unsigned long long*dest)
  2. {
  3. *dest= *src;
  4. }
  5. const static unsignedlong long pattern[] = {
  6. 0xaaaaaaaaaaaaaaaaULL,
  7. 0xccccccccccccccccULL,
  8. 0xf0f0f0f0f0f0f0f0ULL,
  9. 0xff00ff00ff00ff00ULL,
  10. 0xffff0000ffff0000ULL,
  11. 0xffffffff00000000ULL,
  12. 0x00000000ffffffffULL,
  13. 0x0000ffff0000ffffULL,
  14. 0x00ff00ff00ff00ffULL,
  15. 0x0f0f0f0f0f0f0f0fULL,
  16. 0x3333333333333333ULL,
  17. 0x5555555555555555ULL
  18. };
  19. const unsigned longlong otherpattern = 0x0123456789abcdefULL;
  20. static intmemory_post_dataline(unsigned long long * pmem)
  21. {
  22. unsigned longlong temp64 = 0;
  23. int num_patterns= sizeof(pattern)/ sizeof(pattern[0]);
  24. inti;
  25. unsigned int hi, lo,pathi, patlo;
  26. int ret= 0;
  27. for (i= 0;i <</FONT> num_patterns; i++)
  28. {
  29. move64((unsigned longlong *)&(pattern[i]), pmem++);
  30. move64((unsigned longlong *)&otherpattern, pmem--);
  31. move64(pmem,&temp64);
  32. #ifdefINJECT_DATA_ERRORS
  33. temp64 ^=0x00008000;
  34. #endif
  35. if (temp64 !=pattern[i])
  36. {
  37. pathi =(pattern[i]>>32)& 0xffffffff;
  38. patlo = pattern[i]& 0xffffffff;
  39. hi =(temp64>>32)& 0xffffffff;
  40. lo = temp64&0xffffffff;
  41. post_log ("Memory (dateline) error at x, "
  42. "wrote xx, read xx!\n",
  43. pmem, pathi, patlo, hi,lo);
  44. ret =-1;
  45. }
  46. }
  47. returnret;
  48. }
  49. static intmemory_post_addrline(ulong *testaddr, ulong *base, ulongsize)
  50. {
  51. ulong*target;
  52. ulong*end;
  53. ulongreadback;
  54. ulongxor;
  55. int ret= 0;
  56. end = (ulong*)((ulong)base + size);
  57. xor = 0;
  58. for(xor= sizeof(ulong);xor > 0; xor <</SPAN><</SPAN>=1)
  59. {
  60. target = (ulong*)((ulong)testaddr ^ xor);
  61. if((target>=base) && (target <</FONT> end))
  62. {
  63. *testaddr= ~*target;
  64. readback =*target;
  65. #ifdefINJECT_ADDRESS_ERRORS
  66. if(xor==0x00008000)
  67. {
  68. readback =*testaddr;
  69. }
  70. #endif
  71. if(readback== *testaddr)
  72. {
  73. post_log ("Memory(address line) error at x<</SPAN>->x,"
  74. "XOR value x!\n",
  75. testaddr, target,xor);
  76. ret =-1;
  77. }
  78. }
  79. }
  80. returnret;
  81. }
  82. static intmemory_post_test1 (unsigned long start,
  83. unsigned longsize,
  84. unsigned longval)
  85. {
  86. unsigned longi;
  87. ulong*mem = (ulong *)start;
  88. ulongreadback;
  89. int ret= 0;
  90. for(i = 0;i <</FONT> size /sizeof (ulong); i++) {
  91. mem[i] =val;
  92. if (i %1024== 0)
  93. WATCHDOG_RESET();
  94. }
  95. for(i = 0;i <</FONT> size /sizeof (ulong) && ret== 0; i++){
  96. readback = mem[i];
  97. if (readback != val){
  98. post_log ("Memory errorat x, "
  99. "wrote x, read x!\n",
  100. mem + i, val,readback);
  101. ret =-1;
  102. break;
  103. }
  104. if (i %1024== 0)
  105. WATCHDOG_RESET();
  106. }
  107. returnret;
  108. }
  109. static intmemory_post_test2 (unsigned long start, unsigned longsize)
  110. {
  111. unsigned longi;
  112. ulong*mem = (ulong *)start;
  113. ulongreadback;
  114. int ret= 0;
  115. for(i = 0;i <</FONT> size /sizeof (ulong); i++) {
  116. mem[i] = 1<</SPAN><</SPAN> (i % 32);
  117. if (i %1024== 0)
  118. WATCHDOG_RESET();
  119. }
  120. for(i = 0;i <</FONT> size /sizeof (ulong) && ret== 0; i++){
  121. readback = mem[i];
  122. if (readback !=(1 <</SPAN><</SPAN> (i % 32))) {
  123. post_log ("Memory errorat x, "
  124. "wrote x, read x!\n",
  125. mem + i, 1<</SPAN><</SPAN> (i % 32),readback);
  126. ret =-1;
  127. break;
  128. }
  129. if (i %1024== 0)
  130. WATCHDOG_RESET();
  131. }
  132. returnret;
  133. }
  134. static intmemory_post_test3 (unsigned long start, unsigned longsize)
  135. {
  136. unsigned longi;
  137. ulong*mem = (ulong *)start;
  138. ulongreadback;
  139. int ret= 0;
  140. for(i = 0;i <</FONT> size /sizeof (ulong); i++) {
  141. mem[i] =i;
  142. if (i %1024== 0)
  143. WATCHDOG_RESET();
  144. }
  145. for(i = 0;i <</FONT> size /sizeof (ulong) && ret== 0; i++){
  146. readback = mem[i];
  147. if (readback != i){
  148. post_log ("Memory errorat x, "
  149. "wrote x, read x!\n",
  150. mem + i, i,readback);
  151. ret =-1;
  152. break;
  153. }
  154. if (i %1024== 0)
  155. WATCHDOG_RESET();
  156. }
  157. returnret;
  158. }
  159. static intmemory_post_test4 (unsigned long start, unsigned longsize)
  160. {
  161. unsigned longi;
  162. ulong*mem = (ulong *)start;
  163. ulongreadback;
  164. int ret= 0;
  165. for(i = 0;i <</FONT> size /sizeof (ulong); i++) {
  166. mem[i] =~i;
  167. if (i %1024== 0)
  168. WATCHDOG_RESET();
  169. }
  170. for(i = 0;i <</FONT> size /sizeof (ulong) && ret== 0; i++){
  171. readback = mem[i];
  172. if (readback != ~i){
  173. post_log ("Memory errorat x, "
  174. "wrote x, read x!\n",
  175. mem + i, ~i,readback);
  176. ret =-1;
  177. break;
  178. }
  179. if (i %1024== 0)
  180. WATCHDOG_RESET();
  181. }
  182. returnret;
  183. }
  184. static intmemory_post_tests (unsigned long start, unsigned longsize)
  185. {
  186. int ret= 0;
  187. if (ret== 0)
  188. ret = memory_post_dataline((unsigned long long*)start);
  189. WATCHDOG_RESET();
  190. if (ret== 0)
  191. ret = memory_post_addrline((ulong *)start, (ulong *)start,size);
  192. WATCHDOG_RESET();
  193. if (ret== 0)
  194. ret = memory_post_addrline((ulong *)(start + size -8),
  195. (ulong *)start,size);
  196. WATCHDOG_RESET();
  197. if (ret== 0)
  198. ret = memory_post_test1(start, size,0x00000000);
  199. WATCHDOG_RESET();
  200. if (ret== 0)
  201. ret = memory_post_test1(start, size,0xffffffff);
  202. WATCHDOG_RESET();
  203. if (ret== 0)
  204. ret = memory_post_test1(start, size,0x55555555);
  205. WATCHDOG_RESET();
  206. if (ret== 0)
  207. ret = memory_post_test1(start, size,0xaaaaaaaa);
  208. WATCHDOG_RESET();
  209. if (ret== 0)
  210. ret = memory_post_test2(start,size);
  211. WATCHDOG_RESET();
  212. if (ret== 0)
  213. ret = memory_post_test3(start,size);
  214. WATCHDOG_RESET();
  215. if (ret== 0)
  216. ret = memory_post_test4(start,size);
  217. WATCHDOG_RESET();
  218. returnret;
  219. }

相关文章推荐

uboot 中内存测试,内存检测方法

DDR内存子系统常见硬件错误及Uboot中检测流程 在 U-Boot中,Denx(U-Boot的开发商)针对常见的DDR内存故障进行了严格的检测处理,下图描述了该检测处理过程的三个步骤:检测...

uboot 中内存测试,内存检测方法

DDR内存子系统常见硬件错误及Uboot中检测流程 在 U-Boot中,Denx(U-Boot的开发商)针对常见的DDR内存故障进行了严格的检测处理,下图描述了该检测处理过程的三个步骤:...
  • evenness
  • evenness
  • 2012年08月01日 15:54
  • 10784

uboot使用

我一贯认为:对于一个技术类的东西,你连用都不会用,那根本就不可能会开发。就好像一个人连Linux不会用,那还谈何开发Linux程序呢?     同样的要开发和移植U-boot,首先要对U-boot有...

uboot中的内存测试方法

1. Denx的UBOOT针对DDR内存的检测过程              从上图,可以看出要经过3个阶段:          (1) 检测数据线                  如果数据线是断开...

U-boot移植及测试

6.1. U-boot 移植准备 6.1.1. 创建开发板移植目录结构 首先我们创建开发板移植相关的目录结构,除了移植 u-boot 的 u-boot 以外,我们还将今 后移植的 Linux 内核,...
  • LYX_WIN
  • LYX_WIN
  • 2016年07月18日 19:56
  • 771

u-boot 串口乱码问题的解决

 1:时钟问题,  以前总是一知半解,这次彻底搞明白了,2440的PLL分为两种,MPLL和UPLL,MPLL用来做系统时钟,UPLL则是USB时钟(必须为48M),两种时钟的计算方法一样:     ...

AT91RM9200开发历程(转)

AT91RM9200开发历程 2008-11-26 16:13 420人阅读 评论(1) 收藏 举报 flashimagelinux编译器systemmakefile 一、ARM9+LI...

嵌入式 hi3518c裸板烧写uboot简记以及内存初始化寄存器修改技巧

7、加载uboot.bin  J-Link>loadbin g:\3518\uboot_tools\3518a.bin 0x80800000  Loading binary file... [g:...
  • skdkjxy
  • skdkjxy
  • 2014年04月20日 13:49
  • 1131

嵌入式学习-uboot-lesson7-内存初始化

6410所使用的内存为DDR 210使用的是DDR2 2440使用的是SDRAM,关于他们之间的区别,我在以前的文章中ok6410内存及启动流程简单介绍过,有兴趣的可以看看。1. 地址空间S3C641...

嵌入式内存测试

  • 2011年10月13日 10:09
  • 275KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:嵌入式 uboot中mtest测试内存
举报原因:
原因补充:

(最多只允许输入30个字)