Exactly... How fast is Arduino?

I'm implementing a PID controller (similar to this one Arduino Playground - BarebonesPIDForEspresso) on my Arduino and I'd like to use a sampling time of 1ms (frequency = 1 kHz).

I've read that Arduino runs at 16 MHz (btw is that true?) and I thought it would not be a problem to execute (more or less) 60 float operations every 1 ms: it indeed is a problem and I have to slow down to 250 Hz (once every 4 ms).

Do you think that this is an expected result?
Thanks :slight_smile:

Hello

Why would you not believe it runs at 16MHz? :slight_smile:

If you are using an original arduino you can see by yourself by looking at the quartz next to the processor.
It should say S16B00K7 the 16 means 16MHz

in terms of floating point speed it all depends on the quality of the software implementation as the processor doesn't have a floating point coprocessor

we are using the one that comes with avr-gcc so you should check if there is any indication on the avr-libc website

massimo

Hello
Why would you not believe it runs at 16MHz? :slight_smile:

Simply because I didn't read it on the datasheet... but I guess I can trust Massimo! :wink:

If you are using an original arduino you can see by yourself by looking at the quartz next to the processor.
It should say S16B00K7 the 16 means 16MHz

Nice!

in terms of floating point speed it all depends on the quality of the software implementation as the processor doesn't have a floating point coprocessor
we are using the one that comes with avr-gcc so you should check if there is any indication on the avr-libc website

The question is... how may cycles might it take to sum or multiply two floats?
I've found a few documents (page 34 of http://manet.die.udec.cl/~biomedica/senales/avr-libc-user-manual-1.6.1.pdf and avr-libc: <math.h>: Mathematics) but they're not useful for my purpose.

...Any idea?

PS: I thought I might calculate how much time it takes for two floats to be added or multiplied but I need a more precise version of the millis() function... does a version of millis() that work with microseconds (instead of milliseconds) exist?
Thank you.

PS: I thought I might calculate how much time it takes for two floats to be added or multiplied but I need a more precise version of the millis() function... does a version of millis() that work with microseconds (instead of milliseconds) exist?
Thank you.

You can use timer1 which can be accurate to a fraction of a microsecond but its easier just doing a big loop of floating points and using millis. If you do a say ten thousand fp operations you should get a pretty good estimate of how long one would take

You can use timer1 which can be accurate to a fraction of a microsecond but its easier just doing a big loop of floating points and using millis. If you do a say ten thousand fp operations you should get a pretty good estimate of how long one would take

I used a program to separately calculate ADD and MULT time.
The results were: 12 microseconds and 5 microseconds respectively.

My code has 28 multiplies and 36 sums for a total of 572 microseconds.
In addition it must be considered that I'm working with matrixes and that I'm handling 4 PWM outputs and one analog input.

...Is it enough to exceed 3 milliseconds?

PS:
This is the code I wrote (the printDouble function was created by mem!):

float val = 0.03;
float add = 0.012;
float mult = 1.008;
float time = 0;
int prec = 30000;
long start = 0;
long end = 0;
long total = 0;

void setup() {
  digitalWrite(13, HIGH);
}


void loop() {
  
  //ADD
  start =  millis();
  for( int i = 1;  i < prec;  i++ ) {
    val = val + add;
  }
  end = millis();
  total = end - start;
  
  Serial.begin(9600);
  Serial.print("It has taken ");
  Serial.print( total );
  Serial.println(" milliseconds in total.");
  time = (total*1000)/prec;
  printDouble( time, 6 );
  Serial.println(" microseconds per one ADD");
  
  
  //MULTIPLY
  start =  millis();
  for( int i = 1;  i < prec;  i++ ) {
    val = val*mult;
  }
  end = millis();
  total = end - start;
  
  Serial.begin(9600);
  Serial.print("It has taken ");
  Serial.print( total );
  Serial.println(" milliseconds in total.");
  time = (total*1000)/prec;
  printDouble( time, 6 );
  Serial.println(" microseconds per one MULT");
  
  
  digitalWrite(13, LOW);
  while(1);
}


void printDouble( double val, byte precision){
  // prints val with number of decimal places determine by precision
  // precision is a number from 0 to 6 indicating the desired decimial places
  // example: printDouble( 3.1415, 2); // prints 3.14 (two decimal places)

  Serial.print (int(val));  //prints the int part
  if( precision > 0) {
    Serial.print("."); // print the decimal point
    unsigned long frac;
    unsigned long mult = 1;
    byte padding = precision -1;
    while(precision--)
       mult *=10;
       
    if(val >= 0)
      frac = (val - int(val)) * mult;
    else
      frac = (int(val)- val ) * mult;
    unsigned long frac1 = frac;
    while( frac1 /= 10 )
      padding--;
    while(  padding--)
      Serial.print("0");
    Serial.print(frac,DEC) ;
  }
}

This may or may not be a valid thought, but doesn't using a for loop add overhead, so you're not getting an accurate result for how long it takes to do a multiple or add?

The overhead will only be a few hundred nanoseconds per iteration.

Ah, well never mind then! :slight_smile:

It's definitely good to consider things like that to make sure that your estimates are reliable. If he was trying to time how long it takes to add and multiply integers, the overhead of the for loop would be significant. In this case it seems the overhead is maybe about 5 - 10% of the total time, so it can be safely ignored if all we care about is an order of magnitude estimate.

  • Ben

Basic for loops generally take two instructions (not sure about the ATmega, I could be off +/- one instruction). This doesn't account for compiler optimization games like loop unrolling.

Speaking of unrolling, you can stuff more work into your loop to mitigate the loop overhead. For example:

float f1=0.0, f2=0.0, f3=0.0, f4=0.0, f5=0.0;
int i;

long start, end;

start = millis();

for (i=0; i<10000; i++)
{
   f1 += 3.14159;
   f2 += 3.14159;
   f3 += 3.14159;
   f4 += 3.14159;
   f5 += 3.14159;
}

end = millis() - start;
...

-j

This may or may not be a valid thought, but doesn't using a for loop add overhead, so you're not getting an accurate result for how long it takes to do a multiple or add?

I get your point but in my program (the one described in the first post) all the operations happen inside for loops, so I guess that in this case it's important not to mitigate the loop overhead.

Thanks for all the replies :slight_smile:

I doubt that worrying about the time spent in the for loop is the right place for your efforts to improve speed. I think you would get a far greater performance improvement if you can do the math using longs rather than floats. In many applications one can scale floats to longs with sufficient precision and if yours is one than you will considerably speed up your execution time. You can probably find a number of examples of how to do this on these and other AVR forums.

I doubt that worrying about the time spent in the for loop is the right place for your efforts to improve speed.

Thanks for the hint; actually I don't want to improve (250 Hz should be enough) but I want to better understand how things are working.