The impossible is happening....IF statement violation

I'm observing an IF statement violation...what I'm going to show is extremely strange. Let me describe the situation. All the variables below are GLOBAL and declared "volatile unsigned long". All the variables can be changed only in an interrupt routine (except G_Hall_counts_previous....which doesn't matter). The below code runs in the main loop. It should only execute if G_delta_HALL_time>120.

This is the print out from the serial monitor:

**** MAIN LOOP *****
G_Hall_counts=348
G_delta_HALL_time=0

How is it possible this was printed by the Serial monitor when G_delta_HALL_time=0 !!!!!! G_delta_HALL_time needs to be >120 to execute the code after the IF.

BTW I'm running this on an ESP32 Wrover Module.

Thanks in advance for the help.

///////////////////////////// code below ////////////////////////////////////////

noInterrupts();

if ((G_Hall_counts_previous != G_Hall_counts) && (G_delta_HALL_time > 120) )  
{
	G_Hall_counts_previous = G_Hall_counts;
	
	Serial.println(F("**** MAIN LOOP  *****"));
	Serial.print(F("G_Hall_counts="));
	Serial.println(G_Hall_counts);
	Serial.print(F("G_delta_HALL_time="));
	Serial.println(G_delta_HALL_time);
	Serial.println(F(""));
}
interrupts();

I'm observing an IF statement violation

Extremely unlikely. It is almost certainly a bug, or misunderstanding on your part about what is supposed to happen.

You did not provide full code, only a snippet. So your question can't be answered. Please post either the complete sketch, or better, an MRE (minimal reproducible example) that demonstrates the problem.

Trust me, the impossible is not happening.

By the way, you are not allowed to call Serial functions with interrupts disabled. That is because Serial is interrupt driven.

Always post all the code.

Turn the interrupts back on, and maybe the code will work.

If G_Hall_counts is being modified by an interrupt routine, the correct way to protect that variable for printing is to make a copy with the interrupts off, turn the interrupts back on and print the copy.

Something like:

noInterrupts();
G_Hall_counts_copy=G_Hall_counts;
interrupts();
Serial.println(G_Hall_counts_copy);
1 Like

I doubt it. In 40 years of doing software I have never encountered such a trivial compiler bug. We need to see your entire sketch in order to help.

Don't use Serial.print() within a "no interrupts" group because this itself uses interrupts. The ESP32 is a 32 bit processor so actions on unsigned long variables are anyway atomic.

Edit
On the ESP32 the F() macro does nothing useful.
Did you get any compiler warnings ?

(Hardware serial actually knows how to handle printing when interrupts are blocked on AVR)

On an ESP32 you want to use a mutex/semaphore/… for your critical sections - don’t suspend interrupts it won’t do what you want.

Also always flush your prints when timing might be critical

1 Like

In what way is the if statement being violated?
What makes you think it is happening?

Thanks for your input. I'm not familiar with "mutex/semaphore" or how to "flush" my print statements? Please elaborate on how to modify my code. I'm programming using Arduino.

My code already turns off interrupts. Its the first line I showed.

Glad you noticed that! Did you read any of the posts explaining your mistake?

My code already turns off interrupts. Its the first line I showed.

No compiler warnings. I have found the F() does help with memory issues.

It is possible that the value of G_delta_HALL_time changed in the interrupt routine after the if statement was evaluated but before the Serial.println statements were executed in the main loop. This is because the variable is declared as "volatile", which tells the compiler that the variable can be modified by an external source (e.g. an interrupt) and therefore should not be optimized by the compiler.

To verify this, you can add a print statement in the interrupt routine to check the value of G_delta_HALL_time when it changes. Alternatively, you can add a delay before the Serial.println statements in the main loop to ensure that enough time has passed for the interrupt routine to complete and for any changes to G_delta_HALL_time to be reflected.

A complete solution was posted in reply #3.

As previously stated, I'm using ESP32 Wrover Module. The full code isn't needed. The problem is well defined by my post. You would not be able to run my code as the interrupt is driven by a HALL sensor which detects rotation of the system I'm developing. G_delta_HALL_time is modified in the interrupt routine. My best guess as to the problem is that, for whatever reason, Serial.println(G_delta_HALL_time); does not correctly print G_delta_HALL_time....I don't know why? G_HALL_counts prints correctly and it is also modified in the interrupt routine.

Thanks for your help.

And it was clearly explained to you what is wrong with the snippet. Fix that problem and get on with your life.

No it isn't. I already have interrupts turned off for my code. I turn them back on after. See the code I posted.

THAT IS THE PROBLEM.

My mistake....you are correct. Your solution worked. Thanks for your help and patience.

Glad you got it working!

As @6v6gt pointed out, on the ESP32 there is no problem with integers being corrupted by interrupt/main access conflict, so you don't need to turn the interrupts off at all.

You do need to do so with 8 bit processors.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.