读书频道 > 系统 > 其他综合 > 嵌入式系统设计与实践
3.6.2 闪存测试范例
2013-06-21 09:41:26     我来说两句 
收藏    我要投稿   

本文所属图书 > 嵌入式系统设计与实践

O’Reilly Media通过图书、杂志、在线服务、调查研究和会议等方式传播创新知识。自1978年开始,O’Reilly一直都是前沿发展的见证者和推动者。超级极客们正在开创着未来,而我们关注真正重要的技术趋势...  立即去当当网订购

闪存是一种非易失性内存(因此,当电源关闭时其中的内容不会被清除)。其他一些类型的非易失性内存包括ROM(只读存储器)和电子可擦除可编程只读存储器(EEPROM)。

注意: 易失性内存在系统重启后不保留其中存储的数据。有多种不同类型的易失性内存,但它们都是某种形式的RAM(随机访问存储器)。

像EEPROM一样,闪存可被擦除和写入。然而,大多数的EEPROM只能一次擦除和写入一字节。使用闪存,可以一次写一字节,但为了做到这一点,必须首先擦除整个扇区。扇区的大小取决于闪存(通常是较大的闪存,每个扇区也较大)。对于测试器件,一个扇区是65 536字节,整个芯片包含8Mb(1MB或16个扇区)。闪存通常比EEPROM有更大的存储空间,但耗电量却比较小。然而,EEPROM尺寸较小,因此它们仍然是有用的。

在我们写调试测试程序的时候,闪存芯片中没有什么需要予以保留。而对于加电自检(POST),我们则不应该修改闪存中的内容,因为系统可能会使用它(用于存储版本和图形数据)。对于单元测试,我们就让其保留测试后的状态,但可能设置一些限制。

测试通常需要三个参数:目标闪存地址,这样测试就可以运行在没有被占用(或不重要)的扇区;一个内存指针和内存长度。内存长度是闪存测试将保留在RAM中的数据量。如果内存长度与扇区大小相同,则闪存不会丢失任何数据。下面的原型说明了三种类型的测试:综合测试运行其他测试(并返回遇到的错误数);试图从闪存读取数据的测试(返回实际读取的字节数);尝试写入到闪存的测试(返回写入的字节数)。

int FlashTest(uint32_t address, uint8_t *memory, uint16_t memLength);

uint16_t FlashRead(uint32_t addr, uint8_t *data, uint16_t dataLen);

uint16_t FlashWrite(uint32_t addr, uint8_t *data, uint16_t dataLen);

我们将在调试期间广泛使用FlashTest,然后把它加到单元测试中,并在发生改变或在发布之前根据需要将它打开。我们不打算让这个测试成为加电自检(POST)的一部分。闪存在经过一定数量的写周期之后将会发生损坏(通常是100 000次,这个信息可以从数据表中找到),而且这些测试至少有两个对数据来说有可能是破坏性的。

而且,我们也不需要在启动的时候运行这个测试。如果处理器原本就可以和闪存通信,那么就有理由相信闪存是正常工作的。(可以通过在闪存中存入一个头信息以检查基本的通信,头信息包含一个已知的关键字、一个版本号和一个校验位)。

有两种方式来访问闪存:字节和多字节块。当运行代码时,使用更快的块访问方式。在刚开始的调试和测试阶段,可以从比较简单的字节方式开始,以便为驱动程序建立一个良好的基础。

测试1:读退出数据

测试从闪存读取的数据实际上的验证了,输入/输出线配置为一个SPI端口、SPI端口配置正确,以及正确理解了闪存命令协议的基本原理。

对于这个测试,我们将尽可能多的数据从扇区读取出来,这样可以稍后把它再写回去。这里是FlashTest的开始:

// Test 1: Read existing data in a block just to make sure it is possible 

dataLen = FlashRead(startAddress, memory, memLength); 

if (dataLen != memLength) {

   // read less than desired, note error

   Log(LogUnitTest, LogLevelError, "Flash test: truncation on byte read"); 
 
   memLength = dataLen;

   error++;

}

请注意,这里没有对数据进行验证,因为我们不知道此函数是否运行一个空的闪存芯片。如果正在写加电自检(POST),那么可以读然后检查数据是有效的(然后停止测试,因为这对加电自检来说已经足够了)。

测试2:字节访问

下一个测试从擦除扇区的数据开始。然后,将闪存填满数据,每次写入一字节。我们希望在写的时候做一些变化,以确保写命令是有效的。我将基于地址的一个偏移量对它进行写。(偏移量告诉我,我不是偶然地将该地址数据读回。)

FlashEraseSector(startAddress);

// want to put in an incrementing value but don't want it to be the address 

addValue = 0x55; 

for (i=0; i< memLength; i++) {

   value = i + addValue;

   dataLen = FlashWrite(startAddress + i, &value, 1);

   if (dataLen != 1) {

      Log (LogUnitTest, LogLevelError, "Flash test: byte write error."); 

      error++;

   } 

}

要完成这个检查,只需要逐字节地将数据读回,并验证每个地址(address + addValue)的数据与预期值是一致的。

测试3:块访问

既然闪存包含了我们新写的数据,那么为了确认块访问是没有问题的,可以把原始数据再写回去。这意味着再次从擦除扇区开始:

FlashEraseSector(startAddress); 

dataLen = FlashWrite(startAddress, memory, memLength); 

if (dataLen != memLength) {

  LogWithNum(LogUnitTest, LogLevelError,   

    "Flash test: block write error, len ", dataLen);

  error++; 

}

最后,用另一个逐字节读验证数据。我们已经知道这对测试2来说是可行的。如果这个结果是好的,那么我们就知道本测试的块写入与测试1中的块读取都是没有问题的。错误数将被返回到上一层的验证代码。

注意: 这也测试了闪存驱动程序软件。它不检查闪存没有黏性位(即那些应该改变而永远不会改变的位)。生产测试可以确认所有的位都改变了,但大多数闪存在到你手里之前都以这种方式验证过了。

测试总结

如果电路板通过了这三项测试,那么我们就可以相信,闪存的硬件和软件都没有问题,满足调试测试和单元测试的需要。

对于大多数形式的存储器,我们这里看到的模式是一个比较好的开端:

1. 读取原始数据。

2. 写一些变化的,但公式化的数据。

3. 验证数据。

4. 重新写回原始数据。

5. 验证原始数据。

然而,还有许多其他类型的外部设备,比这里能够讨论的要多很多。尽管自动化测试是最好的,但有时候还是需要一些外部验证。例如,LCD需要通过获取一种颜色和线条的模式来验证其驱动程序。有些测试需要模拟的外部输入,以便对敏感元素进行检查。

对于每一个外部设备和软件子系统,要搞清楚哪些测试将给我们足够的信心去相信它可以如预期的那样工作,并且可靠。这听起来并不困难,但实现起来有时候却很难。设计良好的测试,是让软件更卓越的方法之一。

点击复制链接 与好友分享!回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:3.6.1 构建测试
下一篇:3.6.3 命令和响应
相关文章
图文推荐
2.7.12 使用仿真器查
2.7.11 栈和寄存器组
2.7.8 出栈
2.7.7 压栈
排行
热门
文章
下载
读书

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做最好的IT技术学习网站