Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Schrödinger bug disappearing when breakpoint is set

I have a strange bug in my code which disappears when I try to debug it.

In my timer interrupt (always running system ticker) I have something like this:

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

in my main loop I have

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

This condition in the main loop is never called when the conditions in the timer are (I think) fulfilled. The conditions are external (portpins, ADC results, etc). First I put a breakpoint at the position 1, and it is never triggered.

To check it, I put breakpoint nr. 2 on the line some_global_flag = 1;, and in this case the code works: both breakpoints are triggered when the conditions are true.

Update 1:

To research whether some timing condition is responsible, and the if in the timer is never entered if running without debugging, I added the following in my timer:

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


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

The flag is not used anywhere else in the code. It is in RAM, and the RAM is cleared to zero at the beginning.

Now, when all the breakpoints are disabled (or only breakpoint 1 in the main is enabled), the code does not work correctly, the function is not executed. However, if I enable only the breakpoint 3 on the NOP, the code works! The breakpoint is triggered, and after continuing, the function is executed. (It has visible and audible output, so it's obvious if it runs)

Update 2:

The timer interrupt was interruptible, by means of a "SEI" at its beginning. I removed that line, but the behavior is not changed in any noticeable way.

Update 3:

I'm not using any external memory. As I'm very close to the limit in the flash, I have size optimization in the compiler on maximum.

Can the compiler (CodeVision) be responsible, or did I do something very wrong?

like image 273
vsz Avatar asked Feb 08 '12 07:02

vsz


2 Answers

Debuggers can/do change the way the processor runs and code executes so this is not surprising.

divide and conquer. Start removing things until it works. In parallel with that start with nothing add only the timer interrupt and the few lines of code in the main loop with do_something_very_important() being something simple like blinking an led or spitting something out the uart. if that doesnt work you wont get the bigger app to work. If that does work start adding init code and more conditions in your interrupt, but do not complicate the main loop any more than the few lines described. Increase the interrupt handler conditions by adding more of the code back in until it fails.

When you reach the boundary where you can add one thing and fail and remove it and not fail then do some disassembly to see if it is a compiler thing. this might warrant another SO ticket if it is not obvious, "why does my avr interrupt handler break when I add ..."

If you are able to get this down to a small number of lines of code a dozen or so main and just the few interrupt lines, post that so others can try it on their own hardware and perhaps figure it out in parallel.

like image 63
old_timer Avatar answered Oct 02 '22 22:10

old_timer


This is probably an typical optimizing / debugging bug. Make sure that some_global_flag is marked as volatile. This may be an int uint8 uint64 whatever you like...

volatile int some_global_flag

This way you tell the compiler not to make any assumptions on what the value of some_global_flag will be. You must do this because the compiler/optimizer can't see any call to your interrupt routine, so it assumes some_global_flag is always 0 (the initial state) and never changed.

Sorry misread the part where you already tried it...

You can try to compile the code with avr-gcc and see if you have the same behavior...

like image 40
DipSwitch Avatar answered Oct 03 '22 00:10

DipSwitch