日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/20 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 uboot 中内存测试,内存检测方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

DDR內存子系統常見硬件錯誤及Uboot中檢測流程

在 U-Boot中,Denx(U-Boot的開發商)針對常見的DDR內存故障進行了嚴格的檢測處理,下圖描述了該檢測處理過程的三個步驟:檢測數據線、地址線和DDR物理存儲部件,主要涉及這三個步驟的處理過程和方法,對于DDR子系統,是很容易出故障并且是很難debug檢測出來的,而Denx所針對 DDR內存故障設計的檢測方法是非常嚴謹,值得學習研究的。

下面主要是相關的檢測處理思路及問題:

1、為什么先檢測數據線?

因為如果數據線是斷開的,那么一切無從談起!接下來是檢測地址線,只有數據線和地址線都通過,檢測內存的存儲單元才有意義,這樣的流程也利于分割定位問題。上面testing sequence框圖將整個檢測過程分成三大步,用三個虛線方框表示。

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個paatern的反碼,總共12個pattern就能檢測到每一位都可以寫入和讀出0和1。

5、什么是floating buses錯誤

floating buses會“欺騙”測試軟件,如果測試軟件寫入并很快讀出一個值的時候,寫操作會跟數據線上的電容充電,總線會短暫的保持它的狀態。當測試軟件讀操作時,總線會返回剛寫入的值,即使實際上該數據線是斷路的。

6、如何檢測數據線的floating buses錯誤

檢測floating buses錯誤的算法不復雜,在寫入和讀回之間再插入一次對不同地址寫入不同值的操作。例如,X寫入X1位置,Y寫入Y1位置,再從X1位置讀出X值則表示floating buses錯誤不存在。

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的代碼和堆、??臻g0x10000000處開始,這些空間是不能被刷的,否則就掛死了。

2)、復制NOR flash的內容到內存中,如 cp.b 0x20080000 0x7fc0 20000,然后比較 cmp.b 0x20080000 0x7fc0 20000。

3)、下載kernel image到內存中,copy NOR flash 或tftp都行,然后調用iminfo LOAD_ADDR 檢測CRC錯誤。

第一種方法是用特定的pattern去刷DDR的空閑空間,第二種和第三種方法可以說Pattern的隨機性更大一些。

當然最徹底的檢測方法當然是長時間跑Linux系統,上面的方法更適用于系統不穩定時定位錯誤。

內存檢測方法 2011年07月14日 星期四 20:59

內存檢測方法

針對常見的DDR內存故障進行了嚴格的檢測處理,下圖描述了該檢測處理過程的三個步驟:檢測數據線、地址線和DDR物理存儲部件,主要涉及這三個步驟的處理過程和方法。

下面主要是相關的檢測處理思路及問題:

1、為什么先檢測數據線?

因為如果數據線是斷開的,那么一切無從談起!接下來是檢測地址線,只有數據線和地址線都通過,檢測內存的存儲單元才有意義,這樣的流程也利于分割定位問題。上面testing sequence框圖將整個檢測過程分成三大步,用三個虛線方框表示。

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錯誤

floating buses會“欺騙”測試軟件,如果測試軟件寫入并很快讀出一個值的時候,寫操作會對數據線上的電容充電,總線會短暫的保持它的狀態。當測試軟件進行讀操作時,總線會返回剛寫入的值,即使實際上該數據線是斷路的。

6、如何檢測數據線的floating buses錯誤

檢測floating buses錯誤的算法不復雜,在寫入和讀回之間再插入一次對不同地址寫入不同值的操作。例如,a寫入A位置,b寫入B位置,再從A位置讀出a值則表示floating buses錯誤不存在。

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的代碼和堆、??臻g0x10000000處開始,這些空間是不能被刷的,否則就掛死了。

2)復制NOR flash的內容到內存中,如cp.b 0x20080000 0x7fc0 20000,然后比較cmp.b 0x20080000 0x7fc0 20000。

3)下載kernel image到內存中,copy NOR flash?或tftp都行,然后調用iminfo LOAD_ADDR?檢測CRC錯誤。

第一種方法是用特定的pattern去刷DDR的空閑空間,第二種和第三種方法可以說Pattern的隨機性更大一些。

當然最徹底的檢測方法當然是長時間跑Linux系統,上面的方法更適用于系統不穩定時定位錯誤。

?? ? ?具體代碼實現如下:


static void move64(unsigned long long *src, unsigned long long *dest)

{

*dest = *src;

}

?

/*

?* This is 64 bit wide test patterns. ?Note that they reside in ROM

?* (which presumably works) and the tests write them to RAM which may

?* not work.

?*

?* The "otherpattern" is written to drive the data bus to values other

?* than the test pattern. ?This is for detecting floating bus lines.

?*

?*/

const static unsigned long long pattern[] = {

0xaaaaaaaaaaaaaaaaULL,

0xccccccccccccccccULL,

0xf0f0f0f0f0f0f0f0ULL,

0xff00ff00ff00ff00ULL,

0xffff0000ffff0000ULL,

0xffffffff00000000ULL,

0x00000000ffffffffULL,

0x0000ffff0000ffffULL,

0x00ff00ff00ff00ffULL,

0x0f0f0f0f0f0f0f0fULL,

0x3333333333333333ULL,

0x5555555555555555ULL

};

const unsigned long long otherpattern = 0x0123456789abcdefULL;

?

/* 數據線檢測 */

static int memory_post_dataline(unsigned long long * pmem)

{

unsigned long long temp64 = 0;

int num_patterns = sizeof(pattern)/ sizeof(pattern[0]);

int i;

unsigned int hi, lo, pathi, patlo;

int ret = 0;

?

for ( i = 0; i < num_patterns; i++)?

{

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

/*

* Put a different pattern on the data lines: otherwise they

* may float long enough to read back what we wrote.

*/

/* 預防floating buses錯誤 */

move64((unsigned long long *)&otherpattern, pmem--);

move64(pmem, &temp64);

?

#ifdef INJECT_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 (date line) error at %08x, "

?"wrote %08x%08x, read %08x%08x !\n",

?pmem, pathi, patlo, hi, lo);

ret = -1;

}

}

return ret;

}

?

/* 地址線檢測 */

static int memory_post_addrline(ulong *testaddr, ulong *base, ulong size)

{

ulong *target;

ulong *end;

ulong readback;

ulong xor;

int ? ret = 0;

?

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

xor = 0;

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

{

/* 對測試的地址的某一根地址線的值翻轉 */

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

if((target >= base) && (target < end))?

{

/* 由于target是testaddr某一根地址線的值翻轉得來

? ?故testaddr != target,下面賦值操作后

? ?應有*testaddr != *target */

*testaddr = ~*target;

readback ?= *target;

?

#ifdef INJECT_ADDRESS_ERRORS

if(xor == 0x00008000)?

{

readback = *testaddr;

}

#endif

?? ? ? ? ? ? ? ? ? ? /* 出現此種情況只有testaddr == target,即某根地址線翻轉無效 */

if(readback == *testaddr)?

{

post_log ("Memory (address line) error at %08x<->%08x, "

?"XOR value %08x !\n",

testaddr, target, xor);

ret = -1;

}

}

}

return ret;

}

?

static int memory_post_test1 (unsigned long start,

? ? ?unsigned long size,

? ? ?unsigned long val)

{

unsigned long i;

ulong *mem = (ulong *) start;

ulong readback;

int ret = 0;

?

for (i = 0; i < size / sizeof (ulong); i++) {

mem[i] = val;

if (i % 1024 == 0)

WATCHDOG_RESET ();

}

?

for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) {

readback = mem[i];

if (readback != val) {

post_log ("Memory error at %08x, "

?"wrote %08x, read %08x !\n",

?mem + i, val, readback);

?

ret = -1;

break;

}

if (i % 1024 == 0)

WATCHDOG_RESET ();

}

?

return ret;

}

?

static int memory_post_test2 (unsigned long start, unsigned long size)

{

unsigned long i;

ulong *mem = (ulong *) start;

ulong readback;

int ret = 0;

?

for (i = 0; i < size / sizeof (ulong); i++) {

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

if (i % 1024 == 0)

WATCHDOG_RESET ();

}

?

for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) {

readback = mem[i];

if (readback != (1 << (i % 32))) {

post_log ("Memory error at %08x, "

?"wrote %08x, read %08x !\n",

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

?

ret = -1;

break;

}

if (i % 1024 == 0)

WATCHDOG_RESET ();

}

?

return ret;

}

?

static int memory_post_test3 (unsigned long start, unsigned long size)

{

unsigned long i;

ulong *mem = (ulong *) start;

ulong readback;

int ret = 0;

?

for (i = 0; i < size / sizeof (ulong); i++) {

mem[i] = i;

if (i % 1024 == 0)

WATCHDOG_RESET ();

}

?

for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) {

readback = mem[i];

if (readback != i) {

post_log ("Memory error at %08x, "

?"wrote %08x, read %08x !\n",

?mem + i, i, readback);

?

ret = -1;

break;

}

if (i % 1024 == 0)

WATCHDOG_RESET ();

}

?

return ret;

}

?

static int memory_post_test4 (unsigned long start, unsigned long size)

{

unsigned long i;

ulong *mem = (ulong *) start;

ulong readback;

int ret = 0;

?

for (i = 0; i < size / sizeof (ulong); i++) {

mem[i] = ~i;

if (i % 1024 == 0)

WATCHDOG_RESET ();

}

?

for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) {

readback = mem[i];

if (readback != ~i) {

post_log ("Memory error at %08x, "

?"wrote %08x, read %08x !\n",

?mem + i, ~i, readback);

?

ret = -1;

break;

}

if (i % 1024 == 0)

WATCHDOG_RESET ();

}

?

return ret;

}

?

static int memory_post_tests (unsigned long start, unsigned long size)

{

int ret = 0;

?

if (ret == 0)

ret = memory_post_dataline ((unsigned long long *)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 ();

?

return ret;

}

總結

以上是生活随笔為你收集整理的uboot 中内存测试,内存检测方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 91丝袜| 中文字幕一区二区三区门四区五区 | 日韩一区二区中文字幕 | 日本黄色动态图 | 在线你懂得 | 伊人久久大香线蕉av一区 | 尤物在线精品 | 欧亚在线视频 | 亚洲人成免费 | 国内精品久| 国产精品伦理一区 | 成人动漫视频在线观看 | 欧美日韩资源 | 九九这里只有精品视频 | 成人午夜视频免费观看 | 成人黄色短视频在线观看 | 色男人天堂av | 天天干天天舔 | 欧美极品jizzhd欧美 | 依依激情网 | 天天摸天天 | 国产成人亚洲一区二区 | 性一交一乱一色一视频麻豆 | 成人一级大片 | 国产不卡在线观看 | 国产情侣免费视频 | 瑟瑟视频在线免费观看 | 国产一区二区a | 日韩欧美国产一区二区三区 | 国产伦精品一区二区免费 | 国产吞精囗交免费视频 | 色屁屁网站 | 男女做爰猛烈高潮描写 | 在线免费看黄色片 | 操女人免费视频 | 在线cao | 精品福利视频一区二区 | 精品久久久一区二区 | 国产精品网站免费 | 爱情岛论坛亚洲自拍 | 欧美一区二区三区电影 | 黄色的网站免费看 | 亚洲色图另类小说 | 欧美色图俺去了 | 成人在线视频观看 | 91免费版视频 | 99精彩视频| 午夜激情在线播放 | 日韩在线观看视频一区二区 | 三级网站免费 | 欧美色综合网站 | 亚洲丁香网 | 福利精品视频 | 午夜精品久久久久久久91蜜桃 | 第一章激情艳妇 | wwwwxxxx欧美 | 国产精品激情偷乱一区二区∴ | 国产精品一区在线看 | 久久人妻一区二区 | 日韩一中文字幕 | 久久九九国产精品 | 在线观看小视频 | 欧美成人a交片免费看 | 久久看片| 欧美乱码精品 | 性歌舞团一区二区三区视频 | 伊人55 | 黄色www视频| 草久在线 | 永久免费看黄网站 | 欧美激情专区 | 国产第一页精品 | 国产精品自拍一区 | 韩国女主播裸体摇奶 | 午夜精品福利一区二区三区蜜桃 | 淫片在线 | av最新版天堂资源在线 | 污网站免费看 | 91福利一区 | 人人爱人人草 | 99蜜桃臀久久久欧美精品网站 | 日韩欧美精品久久 | 在线观看你懂的视频 | 激情网av | 熟女熟妇伦久久影院毛片一区二区 | 呦呦色 | 美女131爽爽爽做爰视频 | 国产中文在线视频 | 国产第99页| 厕拍极品| 久久久888 | 亚洲天堂一区二区在线 | 五月六月丁香 | 亚洲国产日本 | 日韩女优网站 | a级黄色小说 | 久久你懂的 | 国产一区二区电影 | 精品人妻一区二区三区三区四区 |