1.电路的制做工艺错误:在焊接电路的时候,可能会出现焊锡飞溅的状况,使得两个引脚短路,这样的后果是,当你对存储器进行操做的时候,就会数据重叠,甚至于说,出现没法读取的数据;焊接操做不当或者铜板刻制出错,出现开路的状况,可能会出现对存储器没法操做或者数据操做不成功的状况。
2.电路的电容性:假设使用的芯片频率足够快,你进行一个写操做,为了检验,你再进行一个读操做,那么问题来了,若是电容性,虽然你可能检测到的数据是你想要的,可是这时这个数据是因为读写操做太快,而来不及反翻转,那么这样的芯片其实是不能存储你检测到的那么多的数据的。
3.存储芯片错误放置,其实这样的状况很容易避免的,这样的问题,进行检测的时候,都会自动的检测出来。函数
如今介绍三种检测方法,数据总线检测,地址总线检测,设备检测。
数据存取正常是在控制总线(地址总线)正常的状况下进行的,而设备检测须要肯定地址总线和数据总线已经正常工做了。
1.数据总线检测,一般采用的方法使用0~1对存储的每个bit位进行遍历,
每次的读写操做,每一个数据位之间都是独立的。如图所示,好像“1”从右边走到了左边,因此这种方法也叫做“walking 1”.测试
typedef unsigned char datum; /* 设置数据总线宽度为8bit */ /********************************************************************** * * 函数名: memTestDataBus * * 函数内容: 在指定的地址下,用walking 1的方法对数据总线进行检测 * 地址经过函数参数指定。 * * 输入参数: address 须要检测的内存地址 * * 返回值: 返回'0',则没有问题,若是返回其余值, * 则说明检测失败有数据位操做有问题 * **********************************************************************/ datum memTestDataBus(volatile datum * address) { datum pattern; /* * 在指定的地址下执行对数据线进行walking 1检测 */ for (pattern = 1; pattern != 0; pattern <<= 1) { /* * 写入检测数据 */ *address = pattern; /* * 读回数据 */ if (*address != pattern) { return (pattern); } } return (0); } /* memTestDataBus() */
2.地址总线检测:对芯片的每个地址进行写0和1,同时肯定引脚之间相互独立。code
这个和数据总线检测的walking 1的方法是相似(对一个16bit的总线来讲,地址能够是0000H,0001H,0002H,0004H,0008H,0010H,0020H,0080H等等),而且在你写入的同时,你须要检测其余的地址没有被重写。blog
可是不是全部的地址线能够经过这样的方法检测,好比你的地址总线宽度是32bit,寻址空间是4GB,若是你要测试128K的内存块,那么其实只有17根总线用到了, 仍有15根总线没有用到。ip
肯定两个存储之间没有重叠内存
/********************************************************************** * * 函数名: memTestAddressBus() * * 函数描述: 这个测试能够找出某个bit位上的错误,好比,卡高,卡低 * 短路。基础地址和区域大小能够由函数参数指定。 * 输入参数: 基础地址, * * 返回值 : 若是地址总线没有,返回空值。 * 返回的非零的结果,是函数执行时碰见的第一个出现地址 * 重叠的。经过检查存储的内容,能够知道关于这个存储问 * 题是卡高,卡低,短路。 * **********************************************************************/ datum * memTestAddressBus(volatile datum * baseAddress, unsigned long nBytes) { unsigned long addressMask = (nBytes/sizeof(datum) - 1); unsigned long offset; unsigned long testOffset; datum pattern = (datum) 0xAAAAAAAA; datum antipattern = (datum) 0x55555555; /* * 在每个偏置电源下,对每个地址位写初值操做 */ for (offset = 1; (offset & addressMask) != 0; offset <<= 1) { baseAddress[offset] = pattern; } /* * 检查地址位卡低 */ testOffset = 0; baseAddress[testOffset] = antipattern; for (offset = 1; (offset & addressMask) != 0; offset <<= 1) { if (baseAddress[offset] != pattern) { return ((datum *) &baseAddress[offset]); } } baseAddress[testOffset] = pattern; /* * 检查地址位卡高 */ for (testOffset = 1; (testOffset & addressMask) != 0; testOffset <<= 1) { baseAddress[testOffset] = antipattern; if (baseAddress[0] != pattern) { return ((datum *) &baseAddress[testOffset]); } for (offset = 1; (offset & addressMask) != 0; offset <<= 1) { if ((baseAddress[offset] != pattern) && (offset != testOffset)) { return ((datum *) &baseAddress[testOffset]); } } baseAddress[testOffset] = pattern; } return (NULL); } /* memTestAddressBus() */
3.设备检测,存储器中每一位均可以存储0或1,虽然这句话很简单,很粗暴,可是所花的时间比前面两个多了很多。
在设备检测过程当中,你须要对全部的内存空间进行两次读写操做,第一次将一个随机数写读该地址,第二次将这个随机数取反再次写读。在检测中经常使用的方法是,随着地址的变化,存储的值逐渐增长。
以下图所示:it
第一列和第二列是地址和数据的变化,第三列是数据取反以后的变化。取数值的方式有不少种,可是这种顺序变化的方式更加的容易计算。class
/********************************************************************** * * 函数名: memTestDevice() * * 函数描述: 用数据递增/递减的方式检测整个物理存储区域。 * 在这个过程当中设备里的每个存储位用bit1或者bit0进行 * 检测。经过形参传递基础地址和检测区域大小。 *输入参数: 基础地址 baseAddress,检测区域大小 * * 返回值: 若是检测成功,则返回空值。 * 若是检测失败,会返回一个第一次检测失败的内存地址。同时 * 检测内存内容,能够获得这个问题更多详细信息。 * **********************************************************************/ datum * memTestDevice(volatile datum * baseAddress, unsigned long nBytes) { unsigned long offset; unsigned long nWords = nBytes / sizeof(datum); datum pattern; datum antipattern; /* * 用已知的数据 */ for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++) { baseAddress[offset] = pattern; } /* * 检测每个存储位置,并进行每一个bit位进行翻转 */ for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++) { if (baseAddress[offset] != pattern) { return ((datum *) &baseAddress[offset]); } antipattern = ~pattern; baseAddress[offset] = antipattern; } /* * 检测存储器中每一个已经翻转的bit位,同时将全部内存置零 */ for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++) { antipattern = ~pattern; if (baseAddress[offset] != antipattern) { return ((datum *) &baseAddress[offset]); } } return (NULL); } /* memTestDevice() */
好吧,到了三剑合一的时候了
说了那么多,咱们如今来说点实际的。假设如今咱们须要检测一个地址00000000H,大小是64K的内存块。咱们如今以咱们刚刚说的顺序对三个函数进行调用。对咱们的内存进行检测,获得的代码以下。test
int memTest(void) { #define BASE_ADDRESS (volatile datum *) 0x00000000 #define NUM_BYTES (64 * 1024) if ((memTestDataBus(BASE_ADDRESS) != 0) || (memTestAddressBus(BASE_ADDRESS, NUM_BYTES) != NULL) || (memTestDevice(BASE_ADDRESS, NUM_BYTES) != NULL)) { return (-1); } else { return (0); } } /* memTest() */
在检测中,你能够用一个LED的亮灭来表示内存的检测的结果,若是返回值不为空,则亮起红灯。若是返回值为空,则亮起绿灯。基础