dsPIC上的EEPROM读/写错误


8

我正在运行Microchip dsPIC30F6012a。我在多个运行相同软件的PCB上安装了该芯片,并在所有PCB上观察到相同的问题。这意味着系统性问题,而不是一次性生产问题。这个问题也是可以重现的,这意味着如果我知道在哪里看,我应该可以杀死它。但是我仍然很难调试应用程序。

被测板接受24V,通过V7805降压至5V。该芯片在带有16x PLL的内部振荡器上运行,运行速度约为29.5 MIPS。该板上的相关代码本质上非常简单:唤醒,从EEPROM读取数据,然后进入无限循环。每毫秒中断一次,观察一些环境数据,并将更新的值写入EEPROM。还有其他事情,但是即使不相关的代码被注释掉,问题仍然会发生,因此我可以肯定地确定它与当前的问题无关。

在一般情况下,板卡有95%的时间以正确的内存值唤醒,然后继续其业务。但是,其他5%的时间会以错误的值唤醒。具体来说,它会以本应具有的数据的位翻转版本唤醒。我正在看的是一个四字节的无符号长整数,长整数的高位或低位字都可能被翻转。例如,10变成2 ^ 16-10,之后变成2 ^ 32-10。我可以通过手动重启数十次来重现故障,但这并不是很一致,并且我的开关手指已经磨损了。

为了以受控方式重现该问题,我制作了第二块板,该板驱动被测板的24V电源。(另一个dsPIC驱动达林顿光电耦合器。)测试板将24V关断1.5秒(足够长的时间使5V电源轨降到基本为0并停留在那里一秒钟),然后将24V开通一段可配置的时间长度。凭借大约520 mS的接通时间,我每次都能在五个电源周期内重现该EEPROM故障。

5V电源轨表现合理。假设我可以相信我的示波器,它会在开机1毫秒内稳定在5V,可能会有0.4V的过冲。关断时,它以指数方式衰减至0V,在50 mS内达到1V。我没有看似相关的构建警告,只有未使用的变量和文件末尾缺少换行符。

我已经尝试了几件事:

  • 启用/禁用MCLR
  • 启用/禁用WDT
  • 启用/禁用代码保护
  • 启用/禁用/更改掉电检测电压
  • 启用/禁用/更改开机定时器
  • 主内部振荡器上的不同PLL设置
  • 连接/断开我的PICkit 3编程器
  • 在5V电压轨上增加470 uF的电容
  • 在我的MCLR引脚上的4.7k上拉电阻上添加/移除0.1 uF
  • 禁用代码中的所有中断,并且在主循环中仅保留EEPROM更新
  • 开始读取EEPROM之前,在启动例程中增加了1.5秒的延迟

我还编写了单独的测试代码,除了继续将值写入EEPROM然后再将它们读回以确保该值没有更改外,它什么也没做。数以万计的迭代没有出错。我所能得出的结论是,EEPROM读取或写入出现问题,特别是在上电/掉电时。

自2007年以来,我一直在使用相同的EEPROM库。我偶尔看到故障,但没有可重复的内容。相关代码可以在这里找到:http:
//srange.net/code/eeprom.c
http://srange.net/code/readEEByte.s
http://srange.net/code/eraseEEWord.s
http:/ /srange.net/code/writeEEWord.s

我以前在其他应用程序中曾见过EEPROM错误,但始终都是一次过的小故障,没有任何可重复的或一致的。

有人知道发生了什么吗?我没办法尝试了。


请参阅此处以获取有关解决此问题的最新信息:electronics.stackexchange.com/questions/38083/…–
Stephen Collings,

Answers:


3

我想到两件事:

首先,根据数据手册,擦除-写周期至少需要0.8ms,最多需要2.6ms。您说您每隔1毫秒就有一个中断,这可能会导致写操作。我在代码中看到,您禁用了部分擦除和部分写入功能的中断。但是您仍然可能对函数调用进行有趣的交织。在禁用整个擦除和写入序列的中断时,可能会有所帮助?

其次-您可能想在电源下降时进行写操作,而EEPROM的写操作恰好在电源电压低于工作电压的那一刻发生。您可以尝试监视电源电压,并在低于4.5V时拒绝写入。假定它在2.7V(最小工作电压)以上保持足够长的时间,并且欠压检测设置为仅在该点以下触发。


你近了!周期为擦除->写入,因此如果在擦除和写入之间掉电,则会丢失数据。我的第一个解决方案是将EEPROM分成多个冗余副本,这些副本将自动检查是否存在不一致。但是由于那只占了我EEPROM的3/4,所以我将其替换为一个简单的写缓冲区。缓冲区将是一个特殊的EEPROM块,其中包含要写入的数据,要写入的地址以及指示写入尚未完成的标志。这样可以解决问题,同时占用更少的空间。
史蒂芬·柯林斯

现在,我可以确认我的基于缓冲区的方法有效,并且不会由于擦除和写入之间的异步掉电而遭受数据丢失。
史蒂芬·科林斯

5

您已经研究了许多可能的硬件问题。很好,但这很可能是固件错误。

不幸的是,您的源代码没有很好地记录,并且格式难以视觉化。您的第一个文件在顶部包含外部例程的声明:

void readEEByte(unsigned int,unsigned int,void *);
void deleteEEWord(unsigned int,unsigned int);
void writeEEWord(unsigned int,unsigned int,void *);

将这样的声明放在客户端模块中不仅是一个坏主意,而且看不到任何注释!我们只能从它们的名称中猜出这些例程打算做什么,并且调用参数是完全未记录的。此外,在该文件中,您还有以“ //”开头的各行和一整行等号。这些增加了视觉上的混乱,使尝试遵循该代码变得非常麻烦。

您可能会说,这与代码的操作无关。但是,像这样的不良编程习惯确实很重要。它们导致代码编写不当,使发现错误甚至代码应该执行的工作变得困难。所有这些都会导致您难以发现所发现的问题。您甚至说自己,自2007年以来,您偶尔会看到该代码的故障。这应该是错误的有力线索,甚至可能是整体设计不佳的线索。

修复问题,正确记录所有接口,并将公共声明放入您一次编写的包含文件中,然后在需要时进行引用。另外,您关于我没有似乎相关的构建警告的声明是一个巨大的危险信号。再次,修复混乱。调试时,请始终先解决容易产生和修复的问题。有时,这些实际上是造成棘手问题的原因,或者有时,在解决这些问题时,您会发现其他问题的原因。编译器警告您银盘松懈。您还想要什么?您不应该使用未使用的变量,因为它们会使试图理解您的代码的人感到困惑,并且根本没有借口错过任何新行。同样,修复它们明显的混乱,尤其是在要求其他人查看您的代码之前。

整洁和对细节的注意。很多。

 


您对代码非常正确。可以这样说,我很清楚,我是五年前开始使用此代码的,但是是其他人编写的。我不会写类似这样的东西。我仍然应该修复它,但我没有这样做是不好的。只是为了让我看起来不像QUITE那么大。:-)
史蒂芬·科林斯

2
访问内部EEPROM很容易。对于这种简单的东西,编写自己的代码比尝试弄清楚别人的错误软件的工作方式然后将其修补直到看起来可行要容易得多。阅读数据表并编写代码。一个小时之内就可以完成。
奥林·拉斯洛普

我在这里同意Olin的观点,因为它很可能是固件。该部分勘误没有提及是腥与EEPROM。
亚当·劳伦斯

2
@Madmad-勘误表可能不会说零件有些腥,但他们永远不会说它没腥:-)
stevenvh 2012年

1
@stevenvh我与Microchip及其FAE的往来基本上是积极的。我一直在使用的零件的勘误表准确无误,它们可以帮助我们解决问题,经常为我们找到解决方法。
亚当·劳伦斯

0

我在4个dsPIC30F6014A上有相同的行为(在过去几个月中使用了大约10个。.),避免断电期间零星数据损坏的唯一方法是在关机前将MCLR设置为零。

显然,这在实践中是不可行的,因此,如果有人有其他解决方案,我选择替换“错误的” dsPIC。


3
为什么那不可行?即使在最后一个毫秒将数据保存到EEPROM时,也要进行很多次断电检测。
stevenvh 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.