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
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
Simply because I didn't read it on the datasheet... but I guess I can trust Massimo!
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
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?
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.
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;
...
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.
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.