util/delay.h compiler problem

Hi,

I'm using Arduino IDE 1.8.1 on windows 10 and I'm getting something very strange.
The problem only happens if using util/delay.h and the _delay_ms(), _delay_us() functions.
Removing the include and F_CPU #define and using delay() and delayMicroseconds() solved the problem.
But, as this code will (probably) evolve to an ISR routine I might need to use util/delay.h, I have used it several times, but this is the first time I use _delay_us(), is it broken ???

The code bellow fails to compile with the following errors

C:\Users\Antonio\Documents\Arduino\nano-waves-01\nano-waves-01.ino:1:0: warning: "F_CPU" redefined
 #define F_CPU 16000000UL
 ^
<command-line>:0:0: note: this is the location of the previous definition

c:\users\antonio\appdata\local\arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2\avr\include\util\delay.h: In function 'triang.constprop':

c:\users\antonio\appdata\local\arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2\avr\include\util\delay.h:276:40: error: __builtin_avr_delay_cycles expects a compile time integer constant

  __builtin_avr_delay_cycles(__ticks_dc);
                                        ^

c:\users\antonio\appdata\local\arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2\avr\include\util\delay.h:276:40: error: __builtin_avr_delay_cycles expects a compile time integer constant

  __builtin_avr_delay_cycles(__ticks_dc);
                                        ^

lto-wrapper: C:\Users\Antonio\AppData\Local\Arduino15\packages\arduino\tools\avr-gcc\4.9.2-atmel3.5.4-arduino2/bin/avr-gcc returned 1 exit status

c:/users/antonio/appdata/local/arduino15/packages/arduino/tools/avr-gcc/4.9.2-atmel3.5.4-arduino2/bin/../lib/gcc/avr/4.9.2/../../../../avr/bin/ld.exe: error: lto-wrapper failed

collect2.exe: error: ld returned 1 exit status
exit status 1
Error compiling for board Arduino Nano.

However, this only happens if I have more than one call to function triang() anywhere in the program, being it inside loop() or setup() and ONLY if the call is made with different parameters.

triang(432,500,128);
triang(432,500,128);

compiles ok

triang(432,499,128);
triang(432,500,128);

does NOT compile.

At first I thought that it happens if I have more than one call to triang() but no, it only happens if any of the parameters is different.

#define F_CPU 16000000UL
#include <util/delay.h>

#define pin 5

void triang(float, int, int);

void setup() {
  Serial.begin(9600);
  pinMode(pin, OUTPUT);
}

void loop() {
  int f;
  
  for(f=0;f<10;f++)
  {
    Serial.print("["); Serial.print(f); Serial.print("]");

    triang(432, 500, 256);
    triang(432, 500, 128);
    tone(pin,432);
    _delay_ms(500);
    noTone(pin);
    _delay_ms(1000);
  }
  
  while(1);
}

void triang(float freq, int dur, int stp)
{
  int f;
  double  T;
  unsigned long int t_us;
  unsigned long int then;
  char buf[64];
 
  then=micros()+(dur*1000UL);
  T=1/freq;
  t_us=((T/(stp*2))*1000000UL);

  dtostrf(T, 16, 8, buf);
  Serial.print("T=");
  Serial.println(buf);
  
  while(micros()<then)
  {
    for(f=0;f<256;f+=(256/stp))
    {
      analogWrite(pin, f);
      _delay_us(t_us);
    }
    for(f=255;f>0;f-=(256/stp))
    {
      analogWrite(pin, f);
      _delay_us(t_us);
    }
  }
  analogWrite(pin,0);
}

Ah!
I found this in delay.h

note In order for these functions to work as intended, (...), and the delay time must be an expression that is a known constant at compile-time. If these requirements are not met, the resulting delay will be much longer (and basically unpredictable), and applications that otherwise do not use floating-point calculations will experience severe code bloat by the floating-point library routines linked into the application.

So this means that _delay_ms() and _delay_us() cannot be used with variables. Right?

  1. My guess is the compiler optimization removes the delay except with multiple calls.

  2. Hopefully you are not performing a delay inside of an ISR.

ocsav:
So this means that _delay_ms() and _delay_us() cannot be used with variables. Right?

Correct.

You could try the Arduino core delay() and delayMicroseconds() functions. They work fine on non-constant values.

1 Like

johnwasser:
You could try the Arduino core delay() and delayMicroseconds() functions. They work fine on non-constant values.

Yes they do.
I was using delay.h because the standard delay() gets confused when you start to mess with the timers, and this program may well go in that direction. I had no idea that such limitation existed with _delay_ms() and _delay_us().

But the fact that a program compiles if there is ONE call to a function, and do not compile if there is more than one was... shocking...