Back to the original question of how to test the speed of a digitalRead function and compare it with something faster like direct manipulation of port bits.
Looking at things on a 'scope is "easy" according to the Original Poster (although there might be some question about whether the observed pulse width includes loop overhead and so forth), but, in my opinion, the way to compare two operations is to use two timed loops and let the program tell you.
Now as far as a digital read statement, we really don't want to know just what the execution time is for the function, but what the execution time is for getting the value and storing it, right? And, in particular, we want to compare the speed of the assignment using some kind of "fast" method with one that uses the Arduino user-friendly-but-less-than-fast digitalRead function.
//
// A program to compare execution time for a "faster" pin
// reading function with the more convenient Arduino
// digitalRead function.
//
// davekw7x
//
//
// If you are really interested a "faster" way,
// don't shift, but do an "and" operation in-place. The
// return value will be zero or non-zero, depending
// on the state. In many cases, this is all you need
// to be able to use it in your program.
//
// Anyhow, for now, I'll just compare execution time
// for the exact replacement for digitalRead
//
//
// I make a macro here just so it won't clutter
// up the code in the loop. If you want
// to use some other pin, then you have to look
// up the port number and pin number to see what
// to define here.
// Arduino pin 14 is pin 6 on Port B
// Here's how to get a value (0 or 1) that
// shows the state of pin 6 on Port B
//
#define readPin14 ((PINB >> PINB6) & 1)
void setup()
{
Serial.begin(9600);
delay(1000);
}
void loop()
{
volatile byte x, y;
unsigned long num = 100000L;
unsigned long t1, t2, t3, t4;
t1 = micros();
for (unsigned long i = 0; i < num; i++) {
x = readPin14;
}
t2 = micros();
// Put print stuff here if you want to see actual times
t3 = micros();
for (unsigned long i = 0; i < num; i++) {
x = digitalRead(14);
}
t4 = micros();
unsigned long loop1Time = t2 - t1;
unsigned long loop2Time = t4 - t3;
// Put print stuff here if you want to see actual times. Note
// that these times include loop overhead and the time to call micros().
Serial.print("Loop 1 time = ");Serial.print(loop1Time);Serial.println(" usec");
Serial.print("Loop 2 time = ");Serial.print(loop2Time);Serial.println(" usec");
// This is what we are really after
unsigned long diffTime = loop2Time - loop1Time;
Serial.print("Difference between direct pin manipulation and digitalRead is approximately ");
Serial.print(diffTime / (float)num);
Serial.println(" usec"); Serial.println();
Serial.print("(Ignore this junk: ");
Serial.print(x, DEC);Serial.print(y, DEC);Serial.println(")");
Serial.println();
delay(1000);
}
Output:
[color=blue]Loop 1 time = 301804 usec
Loop 2 time = 471580 usec
Difference between direct pin manipulation and digitalRead is approximately 1.70 usec[/color]
In general: If we put some stuff in loop1 and some other stuff in loop 2, this shows how to compute the difference in execution time in microseconds.
So, for example, if we want to know the absolute execution time of "something," put "something" in loop 1 and put two "somethings" in loop 2. Then let the program show the difference.
Warning: Beware of compiler optimization. Here are a couple of hints:
- If you just do something like an assignment statement in the loops and if you don't do anything with the values stored, the compiler may (or may not) optimize away the entire loop. (So do a junky print or some such thing after the loops.)
Furthermore...
- Function calls will not be optimized away, but if you just store something in a variable in a loop and print its value after the loop, the loop may (or may not) be optimized down to one execution unless the variable is declared volatile (or unless it is extern).
A final note:
This program does not take the execution time of Timer 0 interrupt servicing into account. The actual ISR doesn't happen often enough to skew the results in any meaningful way. Or so I claim. See Footnote
Regards,
Dave
Footnote:
By my reckoning, for a 16 MHz Arduino board, the Timer 0 interrupt service routine takes something like 3 microseconds every millisecond or so, which I neglect in this simple program. (If my reckoning is incorrect, maybe someone can enlighten us all.)