Go Down

Topic: Microcontroller I/O & ADC Benchmarks (Read 6665 times) previous topic - next topic

spirit

hi.

i did also make a sketch to benchmark the IO/analog speed. on a DUE

here are the results:
Code: [Select]
Digital IO results
Pin.no / DigitalWrite / WriteReg / DigitalRead / ReadReg / PWM
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Pin 0|| Pin 1|| Pin 2|| Pin 3|| Pin 4|| Pin 5|| Pin 6|| Pin 7|| Pin 8|| Pin 9|| Pin10|| Pin11|| Pin12|| Pin13|| Pin14|| Pin15|| Pin16|| Pin17|| Pin18|| Pin19|| Pin20|| Pin21|| Pin22|| Pin23|| Pin24|| Pin25|| Pin26|| Pin27|| Pin28|| Pin29|| Pin30|| Pin31|| Pin32|| Pin33|| Pin34|| Pin35|| Pin36|| Pin37|| Pin38|| Pin39|| Pin40|| Pin41|| Pin42|| Pin43|| Pin44|| Pin45|| Pin46|| Pin47|| Pin48|| Pin49|| Pin50|| Pin51|| Pin52|| Pin53|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 1.23 || 1.15 || 1.40 || 1.35 || 1.35 || 1.27 || 1.40 || 1.35 || 1.35 || 1.27 || 1.40 || 1.35 || 1.35 || 1.27 || 1.28 || 1.23 || 1.23 || 1.15 || 1.28 || 1.23 || 1.35 || 1.27 || 1.40 || 1.35 || 1.35 || 1.27 || 1.40 || 1.35 || 1.35 || 1.27 || 1.40 || 1.35 || 1.35 || 1.27 || 1.40 || 1.35 || 1.35 || 1.27 || 1.40 || 1.35 || 1.35 || 1.27 || 1.40 || 1.35 || 1.35 || 1.27 || 1.40 || 1.35 || 1.35 || 1.27 || 1.40 || 1.35 || 1.35 || 1.15 |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 1.09 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0.14 || 0.14 || 0.13 || 0.14 || 0.13 || 0.14 || 0.14 || 0.14 || 0.13 || 0.13 || 0.13 || 0.13 || 0.14 || 0.13 || 0.14 || 0.13 || 0.13 || 0.14 || 0.13 || 0.14 || 0.13 || 0.13 || 0.14 || 0.13 || 0.14 || 0.13 || 0.13 || 0.14 || 0.13 || 0.14 || 0.13 || 0.13 || 0.14 || 0.13 || 0.14 || 0.13 || 0.13 || 0.14 || 0.13 || 0.14 || 0.13 || 0.13 || 0.14 || 0.13 || 0.14 || 0.13 || 0.13 || 0.14 || 0.13 || 0.14 || 0.13 || 0.13 || 0.14 || 0.13 |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 3.92 || 3.91 || 3.84 || 3.91 || 2.76 || 2.76 || 2.76 || 2.76 || 3.84 || 3.91 || 3.84 || 3.84 |
------------------------------------------------------------------------------------------------
Analog / Digital IO results
Pin.no / DigitalWrite / WriteReg / DigitalRead / ReadReg / AnalogRead 8bit / AnalogRead 10bit / AnalogRead 12bit
--------------------------------------------------------------------------------------------------------------------------------
| Pin 0|| Pin 1|| Pin 2|| Pin 3|| Pin 4|| Pin 5|| Pin 6|| Pin 7|| Pin 8|| Pin 9|| Pin10|| Pin11|| Pin12|| Pin13|| Pin14|| Pin15|
--------------------------------------------------------------------------------------------------------------------------------
| 1.41 || 1.36 || 1.36 || 1.28 || 1.41 || 1.36 || 1.36 || 1.28 || 1.41 || 1.36 || 1.36 || 1.28 || 1.29 || 1.36 || 1.25 || 1.16 |
--------------------------------------------------------------------------------------------------------------------------------
| 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 || 0.05 |
--------------------------------------------------------------------------------------------------------------------------------
| 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 || 1.13 || 1.08 || 1.08 || 1.04 |
--------------------------------------------------------------------------------------------------------------------------------
| 0.12 || 0.12 || 0.12 || 0.12 || 0.12 || 0.12 || 0.12 || 0.12 || 0.12 || 0.12 || 0.12 || 0.12 || 0.12 || 0.12 || 0.12 || 0.12 |
--------------------------------------------------------------------------------------------------------------------------------
| 3.39 || 3.38 || 3.38 || 3.38 || 3.38 || 3.38 || 3.38 || 3.38 || 3.38 || 3.38 || 3.38 || 3.38 |
------------------------------------------------------------------------------------------------
| 3.47 || 3.47 || 3.47 || 3.47 || 3.47 || 3.47 || 3.47 || 3.47 || 3.47 || 3.47 || 3.47 || 3.47 |
------------------------------------------------------------------------------------------------
| 3.40 || 3.40 || 3.40 || 3.40 || 3.40 || 3.40 || 3.40 || 3.40 || 3.40 || 3.40 || 3.40 || 3.40 |
------------------------------------------------------------------------------------------------

all are 50000 Iterations.

and for WriteReg and ReadReg i used this code:
Code: [Select]
inline void digitalWriteDirect(int pin, boolean val) {
  if (val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
  else    g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}

inline int digitalReadDirect(int pin) {
  return !!(g_APinDescription[pin].pPort -> PIO_PDSR & g_APinDescription[pin].ulPin);
}

DrDiettrich

I had noticed the Mega seemed slower at digital I/O but never bothered to investigate as it was analogue I was interested in. Maybe it's due to core differences in how pins are read/written as pin 9 is PWM on both UNO & MEGA and don't seem to serve as multi function pins (I2C, SPI, UART etc.) that may slow things down. The only other possibility I can think of is interrupt overheads as I don't disable them for testing but analogue read is the same between both UNO & Mega.
The Mega has at least one overly bloated #define for the digitalPinToPCICRbit macro, in the 1.6.7 version. The 6 comparisons of the pin number could be reduced to 2, which yield a result different from zero.

Dunno if that (all those #defines in pins_arduino.h) affects digital I/O timing, though. The mapping of pins to ports and bits is straight forward (array index), no comparisons there.

Mike44449

#17
Jul 06, 2016, 06:04 am Last Edit: Jul 06, 2016, 06:07 am by Mike44449
I do not know if people will see this, but I ran the benchmark on the Arduino 101, using the IDE 1.6.9. I also added the feature to time an analog-write / PWM on pin 9 and I compensated for the time it took to map the values (by timing them as well).

These are my results for the Arduino 101, doing 5000 iterations as well:

Digital Write:                     1.5634 Microseconds (.31 nanoseconds per execution)
Digital Read:                      1.3131 Microseconds (.26 nanoseconds per execution)
Analog Read:                    27.9999 Microseconds (5.59 nanoseconds per execution)
Analog Write (PWM):           2.2391 Microseconds (.44 nanoseconds per execution)
Mapping 0-5000 to 0-255:     1.9063 Microseconds (.38 nanoseconds per execution)

This is the code I used, after modifying it for the mapping and PWM timers. Credit goes to the original Author Riva.

Code: [Select]
/* Benchmark V2.0 02-June-2015  */

#define targetBoard "Arduino 101"
#define ideVersion "Arduino IDE v1.6.9"
#define analoguePin A0
#define digitalPin 9
#define ledPin 1

#define loopCount 50000   // Max 65535

void setup() {
  Serial.begin(115200);
  while (!Serial) ;
  pinMode(ledPin,OUTPUT);
  digitalWrite(ledPin,LOW);
 
  pinMode(analoguePin,INPUT);
}

void loop() {
  unsigned long startTime;
  unsigned long totalTime;
  unsigned int x;
  int ar;
  int y;
 
  Serial.print(F(targetBoard));
  Serial.print(F(" I/O Speed Tests Over "));
  Serial.print(loopCount, DEC);
  Serial.print(F(" Iterations. Compiled Using "));
  Serial.println(F(ideVersion));
  Serial.flush();
  delay(1000);
 
  // Digital Write
  pinMode(digitalPin,OUTPUT);
  digitalWrite(ledPin,HIGH);
  startTime = micros();
  for (x = 0; x < loopCount; x++){
    digitalWrite(digitalPin,HIGH);
    digitalWrite(digitalPin,LOW);
  }
  totalTime = micros() - startTime;
  digitalWrite(ledPin,LOW);
  Serial.print(F("Digital Pin Write Takes About "));
  //Serial.print(totalTime / 2);
  //Serial.print(F(" Microseconds And Each 'digitalWrite' Took About "));
  Serial.print((float)totalTime / (float)loopCount / 2.0, 4);
  Serial.println(F(" Microseconds."));
  Serial.flush();
  delay(1000);
 
  // Digital Read
  pinMode(digitalPin,INPUT);
  digitalWrite(ledPin,HIGH);
  startTime = micros();
  for (x = 0; x < loopCount; x++){
    ar = digitalRead(digitalPin);
  }
  totalTime = micros() - startTime;
  digitalWrite(ledPin,LOW);
  Serial.print(F("Digital Pin Read  Takes About "));
  Serial.print((float)totalTime / (float)loopCount, 4);
  Serial.println(F(" Microseconds."));
  Serial.flush();
  delay(1000);
 
  // Analogue
  digitalWrite(ledPin,HIGH);
  startTime = micros();
  for (x = 0; x < loopCount; x++){
      ar = analogRead(analoguePin);
  }
  totalTime = micros() - startTime;
  digitalWrite(ledPin,LOW);
  Serial.print(F("Analogue Pin Read Takes About "));
  //Serial.print(totalTime / 2);
  //Serial.print(F(" Microseconds And Each 'digitalWrite' Took About "));
  Serial.print((float)totalTime / (float)loopCount, 4);
  Serial.println(F(" Microseconds."));
  Serial.flush();
  delay(1000);

  //AnalogWrite
  digitalWrite(ledPin, HIGH);
  startTime = micros();
  for (x = 0; x < loopCount; x++){
    analogWrite(9, map(x, 0, loopCount, 0, 255));
  }
  totalTime = micros() - startTime;
  digitalWrite(ledPin, LOW);
  Serial.print(F("PWM Write Takes About "));
  //Serial.print(totalTime / 2);
  //Serial.print(F(" Microseconds And Each 'digitalWrite' Took About "));
  Serial.print((float)totalTime / (float)loopCount, 4);
  Serial.println(F(" Microseconds."));
  Serial.println();
  Serial.flush();
  delay(1000);

  //mapping
  startTime = micros();
  for (x = 0; x < loopCount; x++)
  {
    y = map(x, 0, loopCount, 0, 255);
  }
  totalTime = micros() - startTime;
  Serial.print(F("Mapping Takes About "));
  //Serial.print(totalTime / 2);
  //Serial.print(F(" Microseconds And Each 'digitalWrite' Took About "));
  Serial.print((float)totalTime / (float)loopCount, 4);
  Serial.println(F(" Microseconds."));
  Serial.println();
  Serial.flush();
  delay(1000);   
 
}
There is no "It will" in robotics or code, there is only "It should."

DrDiettrich

Provided that the system clock of the 101 is 32MHz, your times can not be correct. When one instruction takes at least 30ns, how can anything execute faster than that, by a factor of 100?

Mike44449

I ran the benchmark through 5000 iterations, that is the number on the left, to run through the entire loop. I then proceeded to divide each result by 5000 to get the number on the right. I have not made up any numbers (not implying you are saying that). The numbers above are what I received over serial.
There is no "It will" in robotics or code, there is only "It should."

westfw

Quote
Digital Write:                     1.5634 Microseconds (.31 nanoseconds per execution)
Did you divide by 5000 twice?  1.5634 Microseconds has to be a divided quantity, because nothing measures less than 1us...

Also, your output file doesn't match your source code.

Code: [Select]
  Serial.print(F("Digital Pin Write Takes About "));
  //Serial.print(totalTime / 2);
  //Serial.print(F(" Microseconds And Each 'digitalWrite' Took About "));
  Serial.print((float)totalTime / (float)loopCount / 2.0, 4);

vs
Quote
Digital Write:           1.5634  Microseconds to loop;            0.00031 Microseconds per execution.

DrDiettrich

What's the time for an empty loop? This time should be subtracted from the totalTime of the statements to benchmark.

Also check: will a different loopCount (e.g. 100 or 10000) change the times?

I could imagine that the compiler optimized every loop into a single assignment to x, and a single execution of the loop body. Only a look into the generated assembly code can reveal what's really going on.

As is, the times are bogus :-(

Mike44449

Also, your output file doesn't match your source code.

It's just a file that I typed up from looking at the Serial monitor.


Did you divide by 5000 twice?
The only explanation I can find is that the sketch is already dividing, I divided each number that I received by the loop count, to get a number like 0.00032, which is .32 nano seconds. I obviously did not go through the program well enough.

As is, the times are bogus :-(
I am quite aware of that
There is no "It will" in robotics or code, there is only "It should."

Mike44449

#23
Jul 07, 2016, 06:12 am Last Edit: Jul 07, 2016, 06:20 am by Mike44449 Reason: Fixed Formatting
I had some time to go through, so I corrected my mistakes, with much greater detail.

- I have made my own benchmark sketch, using parts from Riva's code (so some credit goes to Riva)
- I have made a much more detailed file, which includes actual serial output
- I tested 10, 5k, and 10k iterations
- The file has the details at the top, then serial output at the bottom. It is very long so I labeled the line that each set of iterations begins on

The Table:

Code: [Select]
Board: Arduino 101 @ 32 MHz
IDE:   v1.6.9
Buad Rate of Serial: 115,200
Iterations per benchmark: 10 | 5,000 | 10,000

=====Digital Reading====

Iterations: 10
Digital Read of Pin 5 (total)  :         20.000 Microseconds
Digital Read of Pin 5 (per)  :            2.000 Microseconds

Iterations: 5,000
Digital Read of Pin 5 (total)  :      8,920.000 Microseconds
Digital Read of Pin 5 (per)  :            1.784 Microseconds

Iterations: 10,000
Digital Read of Pin 5 (total)  :     17,836.000 Microseconds
Digital Read of Pin 5 (per)  :            1.784 Microseconds

Average Time per Read  :                  1.856 Microseconds

====Digital Writing====

Iterations: 10
Digital Write of Pin 5 (total)  :        18.500 Microseconds
Digital Write of Pin 5 (per)  :           1.850 Microseconds

Iterations: 5,000
Digital Write on Pin 5 (total) :      8,758.000 Microseconds
Digital Write on Pin 5 (per)  :           1.757 Microseconds

Iterations: 10,000
Digital Write on Pin 5 (total)  :    17,514.000 Microseconds
Digital Write on Pin 5 (per)  :           1.751 Microseconds

Average Time per Write  :                 1.786 Microseconds

====Analog Reading====

Iterations: 10
Analog Read on Pin A0 (total)  :        273.000 Microseconds
Analog Read on Pin A0 (per)  :           27.300 Microseconds

Iterations: 5,000
Analog Read on Pin A0 (total) :     140,082.000 Microseconds
Analog Read on Pin A0 (per)  :           28.016 Microseconds

Iterations: 10,000
Digital Read of Pin A0 (total)  :   280,365.000 Microseconds
Digital Read of Pin A0 (per)  :          28.036 Microseconds

Average Time per Read  :                 27.784 Microseconds

====PWM Writing (un-adjusted)====

Iterations: 10
PWM Write of Pin 5 (total)  :            52.500 Microseconds
PWM Write of Pin 5 (per)  :               5.250 Microseconds

Iterations: 5,000
PWM Write on Pin 5 (total)  :        23,805.000 Microseconds
PWM Write on Pin 5 (per)  :               4.761 Microseconds

Iterations: 10,000
Digital Write on Pin 5 (total)  :    47,605.000 Microseconds
Digital Write on Pin 5 (per)  :           4.761 Microseconds

Average Time per Write  :                 4.924 Microseconds

====PWM Writing (adjusted)====

Iterations: 10
PWM Write of Pin 5 (total)  :            28.000 Microseconds
PWM Write of Pin 5 (per)  :               2.800 Microseconds

Iterations: 5,000
PWM Write on Pin 5 (total)  :        12,389.000 Microseconds
PWM Write on Pin 5 (per)  :               2.479 Microseconds

Iterations: 10,000
Digital Write on Pin 5 (total)  :    24,777.000 Microseconds
Digital Write on Pin 5 (per)  :           2.478 Microseconds

Average Time per Write  :                 2.586 Microseconds
  
====Empty Loop====

Iterations: 10
Empty Loop (total)  :                     2.000 Microseconds
Empty Loop (per)  :                       0.200 Microseconds

Iterations: 5,000
Empty Loop (total)  :                   471.000 Microseconds
Empty Loop (per)  :                       0.094 Microseconds

Iterations: 10,000
Empty Loop (total)  :                   938.500 Microseconds
Empty Loop (per)  :                       0.094 Microseconds

Average Time per Loop  :                  0.130 Microseconds

====Mapping 0-5000 to 0-255====

Iterations: 10
Mapping (total)  :                       24.000 Microseconds
Mapping (per)  :                          2.400 Microseconds

Iterations: 5,000
Mapping (total)  :                   11,415.000 Microseconds
Mapping (per)  :                          2.283 Microseconds

Iterations: 10,000
Mapping (total)  :                   22,828.000 Microseconds
Mapping (per)  :                          2.282 Microseconds

Average Time per Map  :                   2.322 Microseconds




The code to get the information:

Code: [Select]

const uint16_t ITERATIONS = 10000;
const uint8_t DIGITAL_PIN = 5;
const uint8_t ANALOG_PIN = A0;

uint32_t startTime, totalTime;
uint16_t loopCount, d_read, a_read, map_test;

const uint16_t SESSION_LENGTH = 401;
uint16_t cycleCount = 0;

void setup() {
  Serial.begin(115200);
  while (!Serial);

  pinMode(ANALOG_PIN, INPUT);
}

void loop() {
  for (int x = 0; x < SESSION_LENGTH; x++)
  {
    TEST_D_READ();
    TEST_D_WRITE();
    TEST_A_READ();
    TEST_A_WRITE();
    TEST_LOOP();
    TEST_MAP();
    
    //delay(500);
    
    cycleCount++;
    Serial.print("Cycle: ");
    Serial.println(cycleCount);    
    Serial.println();
  }
  
  for(;;)
  {}

  
}

void TEST_D_READ() {
  startTime = micros();
  
  for (loopCount = 0; loopCount < ITERATIONS; loopCount++) {
    d_read = digitalRead(DIGITAL_PIN);
  }
  
  totalTime = micros() - startTime;

  Serial.print("Digital Read: ");
  Serial.print((float)totalTime, 4);
  Serial.println(" Microseconds");
  Serial.flush();
}

void TEST_D_WRITE() {
  startTime = micros();
  
  for (loopCount = 0; loopCount < ITERATIONS; loopCount++) {
    digitalWrite(DIGITAL_PIN, HIGH);
    digitalWrite(DIGITAL_PIN, LOW);
  }
  
  totalTime = micros() - startTime;

  Serial.print("Digital Write: ");
  Serial.print((float)totalTime / 2.0, 4);
  Serial.println(" Microseconds");
  Serial.flush();  
}

void TEST_A_READ() {
  startTime = micros();
  
  for (loopCount = 0; loopCount < ITERATIONS; loopCount++) {
    a_read = analogRead(ANALOG_PIN);
  }
  
  totalTime = micros() - startTime;

  Serial.print("Analog Read: ");
  Serial.print((float)totalTime, 4);
  Serial.println(" Microseconds");  
  Serial.flush();  
}

void TEST_A_WRITE() {
  startTime = micros();
  
  for (loopCount = 0; loopCount < ITERATIONS; loopCount++) {
    analogWrite(DIGITAL_PIN, map(loopCount, 0, ITERATIONS, 0, 255));
  }
  
  totalTime = micros() - startTime;

  Serial.print("PWM Write (not adjusted for mapping time): ");
  Serial.print((float)totalTime, 4);
  Serial.println(" Microseconds");
  Serial.flush();  
}

void TEST_LOOP() {
  startTime = micros();
  
  for (loopCount = 0; loopCount < ITERATIONS; loopCount++) {
    
  }
  
  totalTime = micros() - startTime;

  Serial.print("Empty Loop: ");
  Serial.print((float)totalTime, 4);
  Serial.println(" Microseconds");
  Serial.flush();  
}

void TEST_MAP() {
  startTime = micros();
  
  for (loopCount = 0; loopCount < ITERATIONS; loopCount++) {
    map_test = map(loopCount, 0, ITERATIONS, 0, 255);
  }
  
  totalTime = micros() - startTime;

  Serial.print("Mapping: ");
  Serial.print((float)totalTime, 4);
  Serial.println(" Microseconds");
  Serial.flush();  
}

There is no "It will" in robotics or code, there is only "It should."

westfw

Quote
The only explanation I can find is that the sketch is already dividing
Yes, it is:

Code: [Select]
 Serial.print((float)totalTime / (float)loopCount / 2.0, 4);
The first numbers:
Quote
Digital Write:                     1.5634 Microseconds
Digital Read:                      1.3131 Microseconds
Analog Read:                    27.9999 Microseconds
Analog Write (PWM):           2.2391 Microseconds
Mapping 0-5000 to 0-255:     1.9063 Microseconds
Are pretty reasonable looking for a single execution.

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy