【问题标题】:Schrödinger bug disappearing when breakpoint is set设置断点时薛定谔错误消失
【发布时间】:2012-02-29 15:37:54
【问题描述】:

我的代码中有一个奇怪的错误,当我尝试调试它时它消失了。

在我的计时器中断(始终运行系统代码)中,我有这样的事情:

 if (a && lot && of && conditions)
 {
     some_global_flag = 1;                   // breakpoint 2
 }

在我的主循环中

 if (some_global_flag)
 {
     some_global_flag = 0;
     do_something_very_important();   // breakpoint 1
 }

当计时器中的条件(我认为)满足时,永远不会调用主循环中的这个条件。条件是外部的(端口引脚、ADC 结果等)。 首先我在位置 1 放了一个断点,它永远不会被触发。

为了检查它,我把断点 nr. 2 在some_global_flag = 1; 行上,在这种情况下代码有效:当条件为真时触发两个断点。

更新 1:

为了研究是否是某些计时条件造成的,如果不调试就永远不会进入计时器中的if,我在我的计时器中添加了以下内容:

 if (a && lot && of && conditions)
 {
     some_global_flag = 1;                   // breakpoint 2
 }


 if (some_global_flag)
 {
     #asm("NOP");    // breakpoint 3
 }

该标志不在代码中的其他任何地方使用。它在RAM中,并且在开始时RAM被清零。

现在,当所有断点都被禁用时(或者只启用main中的断点1),代码不能正常工作,函数没有执行。但是,如果我只启用 NOP 上的断点 3,代码就可以工作!断点被触发,继续后,函数被执行。 (它有可见和可听的输出,所以如果它运行起来就很明显了)

更新 2:

定时器中断是可中断的,在其开始时通过一个“SEI”。我删除了该行,但行为并没有以任何明显的方式改变。

更新 3:

我没有使用任何外部存储器。 由于我非常接近闪存中的限制,因此我在编译器中进行了大小优化。

编译器(CodeVision)能负责吗,还是我做错了什么?

【问题讨论】:

  • 有什么方法可以尝试添加某种日志记录,而不是设置断点?我通常会犹豫是否建议这样做,但在这种情况下,它可能对系统的干扰较小。特别是,我要记录的是每次通过定时器中断代码时的条件状态。
  • some_global_flag 是如何定义的?你在用volatile int some_global_flag吗?
  • 您使用的是外部存储器吗?还是只是内部SRAM?你具体用的是什么芯片?
  • @DipSwitch:我只是在使用一个全局的unsigned char some_global_flag;,它只在一个源文件中使用。以前我使用了一个位变量,但改变了它以使调试更容易。我非常接近闪光灯的极限。使用 volatile 并没有改变行为。
  • 由于您正在处理中断和并发执行,因此调试器对代码执行的影响是不可忽视的。这不是解决您的问题的方法,而是解释为什么这种行为(错误消失)是完全正常的,而不是使用的工具的缺陷,而是您的应用程序的缺陷(除非您知道自己在做什么,我不知道) t假设)。

标签: c embedded atmega jtag


【解决方案1】:

我在这里可能错了,但是如果您使用调试器连接到有问题的电路板并在它应该运行的硬件上调试程序,我认为它可以在执行连接时改变微控制器的行为....除此之外和上面建议的 volatile 关键字我没有任何线索。

【讨论】:

  • 奇怪的是,使用调试器的时候,正确的功能就实现了。
【解决方案2】:

这可能是一个典型的优化/调试错误。确保 some_global_flag 被标记为 volatile。这可能是一个 int uint8 uint64 随便你...

volatile int some_global_flag

这样你告诉编译器不要对 some_global_flag 的值做任何假设。您必须这样做,因为编译器/优化器看不到对您的中断例程的任何调用,因此它假定 some_global_flag 始终为 0(初始状态)并且从未改变。

抱歉误读了您已经尝试过的部分...

你可以尝试用avr-gcc编译代码,看看是否有同样的行为...

【讨论】:

  • 我用 volatile 试了一下,结果没有改变。
【解决方案3】:

调试器可以/确实改变处理器运行和代码执行的方式,所以这不足为奇。

分而治之。开始删除东西,直到它工作。与此并行的是,只在主循环中添加定时器中断和几行代码,其中 do_something_very_important() 很简单,比如闪烁 LED 或从 uart 中吐出一些东西。如果这不起作用,您将无法使用更大的应用程序。如果这确实有效,则开始在您的中断中添加初始化代码和更多条件,但不要使主循环比描述的几行更复杂。通过添加更多代码来增加中断处理程序条件,直到它失败。

当您到达可以添加一个东西并失败并删除它而不失败的边界时,请进行一些反汇编以查看它是否是编译器的东西。如果不是很明显,这可能需要另一个 SO 票,“为什么我的 avr 中断处理程序在我添加时中断......”

如果您能够将其简化为十几行主要代码和几条中断行,请将其发布,以便其他人可以在自己的硬件上尝试它,也许可以并行解决。

【讨论】:

    【解决方案4】:

    这可能看起来很奇怪,但最终证明它是由其中一条输入线路上的强瞬变引起的(它为系统供电,但它的 ADC 测量也被用作条件)。

    系统会出现周期性的短时间断电,重要的临时数据保存在内部SRAM的一部分,启动后不清理,设计保留数据(长达10分钟以上)在 CPU 欠压时使用一个小电容器。

    我没有在问题中发布此内容,因为我测试了系统的这一部分并且运行良好,所以我不想让你偏离正题。

    最后我发现,在一个产生非常强瞬变的环境中使用了一项新功能,而我的问题中的一个条件取决于一个状态,该状态取决于“永久”中的这些变量之一RAM”,最后使用断点使我摆脱了瞬态的影响。

    最后通过调整时间问题解决了。

    编辑:帮助我找到问题所在的原因是我在“永久 RAM”区域中记录了我最重要的变量的值,并且可以看到其中一些变量已损坏。

    【讨论】:

    • 这实际上是此类问题的一般原因——调试往往会以某种方式扰乱时序,如果您遇到对时序问题敏感的情况,那么调试肯定会影响它。但是,在调试如何影响它方面通常没有太多有意义的信息(部分原因是很难判断调试如何影响时序)。
    • 我认为在这个答案中添加一点描述您最终如何诊断问题以及您发现了什么会很有趣。此外,由于您知道这是正确答案,因此您应该接受它以确保其完整性。 :)
    • 很好,你解决了它。从中产生了一些好处:您在全局标志中添加了 volatile(如果您没有添加它,请添加它,它确实应该存在)。
    • @Gauthier:不,我在寄存器中为它做了一个永久的位置,作为一个位变量。因为它在寄存器中,所以默认情况下它是 volatile 的。
    • @vsz,Brooks Moses 给出了一般性答案:调试会影响时间。建议您添加备注。
    【解决方案5】:

    这是在假设 ARM 处理器的情况下编写的。

    使用断点(RAM 或 ROM bkpoint)强制处理器在断点处从运行模式切换到调试模式(停止模式或监控模式)并强制它以调试速度运行或运行中止处理程序,因此基于 JTAG 的调试基本上是侵入式调试。

    ETM(嵌入式跟踪宏单元),特别是在 ARM(或其他类型的总线仪器)中,被设计为非侵入式的,可以实时记录指令和数据,以便我们检查实际发生的情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-19
      • 1970-01-01
      相关资源
      最近更新 更多