faking a delay for LED blink by a counting loop does not work

hi,
I just came upon this issue by incident -
in the following code the LED does not blink :o
what do I miss ?
first I thought is was a compiler optimization thing, but the program works faulty even after I made the variables “volatile” :confused:
(IDE 1.6.5, Arduino Mega)

void setup(){
   pinMode(13, OUTPUT);  
}

void loop(){
     volatile uint32_t  i, b;   
     
     b=0;
     digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
     for( i = 0; i < 2147483647 ; i++){   b++;}             // wait.. a little longer...?
     digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
     b=0;
     for( i = 0; i < 2147483647 ; i++){   b++;}             // wait
}

My guess, without actually doing a disassembly on the ELF created by your code, is that just incrementing b++ does not fool the compiler. Try actually doing something with 'b' after the last loop...

Serial.print(b); // should do the trick.

But using for-next loops for delay is a very, very poor practice unless you are just playing around out of curiosity.

Ray My Stuff

it's just for experimental reasons, and my question is not about workarounds, just that issue is actually the issue ;) Because the point is: the compiler must not care if variables are "volatile" ! So actually the code had to be compiled without out-optimizing the loops, and therefore I expected the LED to blink! 8-)

It should work but the period is tooooo looong. Try smaller constant about 500 000, it will blink in 1s interval. It does on my 24MHz arduino.

BTW: Arduino uses optimizing during compilation by default so it means that the "for" cycles will be removed if the nonvolatile variable like "b" stays unused.

ArthurD:
it’s just for experimental reasons, and my question is not about workarounds, just that issue is actually the issue :wink:
Because the point is:
the compiler must not care if variables are “volatile” !
So actually the code had to be compiled without out-optimizing the loops, and therefore I expected the LED to blink! :sunglasses:

Obviously, you do not understand the deep workings of the compiler and how short-circuit situations are identified and optimized. The compiler is far smarter than I as I have been proven wrong more than a few times when I second-guessed what is happening.

IMO, just using volatile as an attribute does not imply that the compiler must execute a loop incrementing the variable if the variable is not subsequently referenced outside the loop… hence, why I suggested you print it.

When is a Volatile Object Accessed?

C has the concept of volatile objects. These are normally accessed by pointers and used for accessing hardware or inter-thread communication. The standard encourages compilers to refrain from optimizations concerning accesses to volatile objects, but leaves it implementation defined as to what constitutes a volatile access. The minimum requirement is that at a sequence point all previous accesses to volatile objects have stabilized and no subsequent accesses have occurred. Thus an implementation is free to reorder and combine volatile accesses that occur between sequence points, but cannot do so for accesses across a sequence point. The use of volatile does not allow you to violate the restriction on updating objects multiple times between two sequence points.

https://gcc.gnu.org/onlinedocs/gcc/Volatiles.html

I don't want to use Serial, I just want to make the compiler compile the code "the way it is", i.e. performing the for-loops.

So how can I make the compiler generating code performing the for-loops? Forbid optimization...: how?

update: I now tried 500000 - now it works as expected, no optimization issue!

ArthurD: update: I now tried 500000 - now it works as expected, no optimization issue!

Hallelujah.

IMO, just using volatile as an attribute does not imply that the compiler must execute a loop incrementing the variable if the variable is not subsequently referenced outside the loop... hence, why I suggested you print it.

The volatile keyword tells to the compiler that the variable must be read from the memory before and write back after any operation to avoid miss the change on data from parallel computing as it is from the interrupt routine etc. This operation cannot be removed by optimizing so in this case it does imply that the compiler must execute a loop. In opposite case the nonvolatile variable can be kept in register during whole time spent in a function because there is guaranteed no other data changes and such variable can be optimized if it is not used (just value change it does not mean using). In this case we have no other things in the loop so the whole loop could be removed by optimizing process.

I disassembled your example, and it had perfectly reasonable code for actually incrementing the variables and looping. With a count of 2^31-1, I estimate a time to execute each loop of more than 3000 seconds. How long did you wait? (even if the loop was one machine cycle, executing 2B times would take over 100s.)

I think it was more than 3000s. It was 44 ticks in one loop as i remember, it means 3937s for my 24MHz arduino and 5905s for standard 16Mz. :)

yesyesyes, we all know, it was a mental arithmetic issue by 1000x :-/ (OTOH, I was not the only one... )

but the "volatile" thing indeed is essential-