nanosecond delay functions - playing with volatile

Today I played with the delayMicroseconds() function - http://arduino.cc/forum/index.php/topic,132983.0.html - It seems to be difficult to get delays of 1 and 2 usec right. So I tried to make a function that delayed for exactly 1 usec and started experimenting with the volatile keyword in (for me) new ways.

This way I "fabricated" 4 functions:

  • delay125ns();
  • delay250ns();
  • delay500ns();
  • delay1000ns();

The timings are approx within 1% tested on a 16Mhz Duemillanove. I tested these functions by running them in a loop, first with one call , and then a second loop with 2 calls, so the difference is the time used by the functions as the loop overhead is subtracted too.

Note: There are better ways to implement these functions - using asm("nop"); - but this was just fun! :slight_smile:

The functions:

void delay125ns()
{
  volatile uint8_t x=0;
  return;
}

void delay250ns()
{
  volatile int x=0;
  return;
}

int delay500ns()
{
  volatile int x=0;
  return x;
}

int delay1000ns()
{
  volatile int x = 0;
  volatile int y = 0;
  return x+y;
}

// profi way to implement such delay functions
void d250ns()
{
  asm("nop");
  asm("nop");
  asm("nop");
  asm("nop");
}

The testprogram with functions:

void setup()
{
  Serial.begin(9600);
  Serial.println("start...");
  
  unsigned long m;
  unsigned long n;
  
  
  Serial.println("delay125ns");
  m = micros();
  for (unsigned int i=0; i<16000; i++) delay125ns();
  m = micros() - m;
  n = micros();
  for (unsigned int i=0; i<16000; i++)
  {
    delay125ns();
    delay125ns();
  }
  n = micros() - n;
  Serial.print("Extra 1000 calls take: ");
  Serial.println((n-m)/16);

  Serial.println("delay250ns");
  m = micros();
  for (unsigned int i=0; i<16000; i++) delay250ns();
  m = micros() - m;
  n = micros();
  for (unsigned int i=0; i<16000; i++)
  {
    delay250ns();
    delay250ns();
  }
  n = micros() - n;
  Serial.print("Extra 1000 calls take: ");
  Serial.println((n-m)/16);


  Serial.println("delay500ns");
  m = micros();
  for (unsigned int i=0; i<16000; i++) delay500ns();
  m = micros()- m;
  n = micros();
  for (unsigned int i=0; i<16000; i++)
  {
    delay500ns();
    delay500ns();
  }
  n = micros()- n;
  Serial.print("Extra 1000 calls take: ");
  Serial.println((n-m)/16);


  Serial.println("delay1000ns");
  m = micros();
  for (unsigned int i=0; i<16000; i++) delay1000ns();
  m = micros() - m;
  n = micros();
  for (unsigned int i=0; i<16000; i++)
  {
    delay1000ns();
    delay1000ns();
  }
  n = micros() - n;
  Serial.print("Extra 1000 calls take: ");
  Serial.println((n-m)/16);
}

void loop()
{}

void delay125ns()
{
  volatile uint8_t x=0;
  return;
}

void delay250ns()
{
  volatile int x=0;
  return;
}

int delay500ns()
{
  volatile int x=0;
  return x;
}

int delay1000ns()
{
  volatile int x = 0;
  volatile int y = 0;
  return x+y;
}

Does the presence or absence of the return statement make any difference? I typically do not include a return statement in a function of type void, since it will return anyway.

PaulS:
Does the presence or absence of the return statement make any difference? I typically do not include a return statement in a function of type void, since it will return anyway.

I think that robtillaart has based its counting mechaninsm on the declaration of variables and the usage of return statement.
If you look at his code, every function has a different combination of variable declaration and value returned.

If you look at his code, every function has a different combination of variable declaration and value returned.

You mean the voids returned by delay125ns(), delay250ns(), and d250ns()?

leo72:

PaulS:
Does the presence or absence of the return statement make any difference? I typically do not include a return statement in a function of type void, since it will return anyway.

I think that robtillaart has based its counting mechaninsm on the declaration of variables and the usage of return statement.
If you look at his code, every function has a different combination of variable declaration and value returned.

That's how I took it. A dump of the generated object code would show the actual instructions generated that make up the specific delay values sought.

Lefty

FYI, I focused more on the initialization of the volatile vars, and sought different ways to add cycles. Without volatile the compiler optimizes the functions away.

I will look if I can do a dump of the assembly/obj tonight but the forum is soooo sloooow at the moment.

For those interested, the output of objdump -d -S testDelayNanoSeconds.cpp.o is in the zip file attached.

have fun :wink:

objdump.zip (3.48 KB)

robtillaart:
For those interested, the output of objdump -d -S testDelayNanoSeconds.cpp.o is in the zip file attached.

have fun :wink:

Interesting :wink: