Microcontroller I/O & ADC Benchmarks

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.

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.

  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

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

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 :frowning:

westfw:
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.

westfw:
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.

DrDiettrich:
As is, the times are bogus :frowning:

I am quite aware of that

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:

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:

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();  
}

Arduino 101 Proper Benchmark.txt (314 KB)

_101_Benchmark.ino (2.6 KB)

The only explanation I can find is that the sketch is already dividing

Yes, it is:

  Serial.print((float)totalTime / (float)loopCount / 2.0, 4);

The first numbers:

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.

Hi Riva,

These are interesting information.

You did tested for Nucleo STM32F401 board which I also intent to buy this one. But I still confuse that whether this board can be official Arduino supported (the official means that the Arduino core is developed by Arduino or TI)?

Thank you in advance.

Regards,

Hi KatyaS.

Your confusion must be greater than you realise yourself.

STMxxxxxx are STMicro products.
TI has nothing to do with that.
Most Arduino products are based on Atmel ARM technology, but there are different tastes.
There are even Intel based products.

I can understand one would like a single IDE to be used for different products, but how smart would it be to do that ?
You still need to take the chips possibilities in consideration, and how well would an IDE create code if it has to work well with all types of chips ?

I don't know whether there are extensions so the Arduino IDE will work with STM products, but such extensions do exist (You already found out about ESP and such).

KatyaS:
You did tested for Nucleo STM32F401 board which I also intent to buy this one. But I still confuse that whether this board can be official Arduino supported (the official means that the Arduino core is developed by Arduino or TI)?

As MAS3 says TI do not do the STM32 series of MCU but it is done by STMicroelectronics.
Alas the STM32401 series of MCU is not well supported on the Arduino with a custom core so I wrote the benchmark above using it's native mbed core. There are several other variants of the STM32 that are better supported on the Arduino and I suggest you have a look here for more information on what cores are best supported. The STM32 board are usually incredibly cheap to buy and can offer a great performance boost compared to the AVR chips used in a lot of Arduinos.

The Arduino.org "Star Otto" board uses a STM32F469 - that should be similar to the STM32F401...
(exact status from an availability or "supported by working software" point of view is ... a bt murky.)

Put together admittedly terrible comparison graphs of the processor performance, definitely best viewed on a computer screen. Arduino Compatible Processor Comparison - Google Sheets

Managed to get my hands on a SAMD21 Zero clone and run the benchmark in #1 after converting references of Serial to SerialUSB and am surprised at how slow it is, especially the analogRead.
I have added results to the first post but for reference here, they are repeated.

Arduino Zero I/O Speed Tests Over 50000 Iterations. Compiled Using Arduino IDE v1.8.7
Digital Pin Write Takes About 1.6234 Microseconds.
Digital Pin Read  Takes About 1.0264 Microseconds.
Analogue Pin Read Takes About 423.2541 Microseconds.

it would be interesting to see some comparison between the new nanos and the ESP8266/ESP32...
is there something like this on the net, can't find it?

Have just done the test on an ESP32

ESP32 DoIt ESP32 Devkit V1 (80MHz) I/O Speed Tests Over 50000 Iterations. Compiled Using Arduino IDE v1.8.9 and 1.0.2 Core
Digital Pin Write Takes About 0.1199 Microseconds.
Digital Pin Read  Takes About 0.1642 Microseconds.
Analogue Pin Read Takes About 10.3027 Microseconds.

is there some benchtmark with the new arduinos?

sblantipodi:
is there some benchtmark with the new arduinos?

I don't have any of the newer Arduino's. Maybe someone who has can run the benchmark sketch from #4 and post the results here.

Riva:
While trying to determine the most suitable MCU for a project that needs fast analogue read I decided to knock up a quick bench-test sketch and run it on some of the various MCU's I have kicking around.
Hope the info is helpful and maybe others can add new MCU's or tests.

Interesting. Do you have any idea why the analog read is so slow for the Zero?

Do you have any idea why the analog read is so slow for the Zero?

Apparently the SAMD ADC is configured with a very large "sample time" in addition to the conversion time.
Arduino Zero ADC Sample Time Too Long · Issue #327 · arduino/ArduinoCore-samd · GitHub (reported nearly 2 years ago. Has the look of one of those "oops, we made a mistake, but we're afraid to change it for fear of breaking something" bugs :frowning: )
Adafruit improved it for their boards: Speed up ADC (especially for SAMD51!) · Issue #51 · adafruit/ArduinoCore-samd · GitHub

Teensy 4.0 at several speed settings (needed to change to nanoseconds)

Teensy 4.0 (600MHz) I/O Speed Tests Over 50000 Iterations.
Digital Pin Write Takes About 35.50 nanoseconds.
Digital Pin Read  Takes About 33.34 nanoseconds.
Analogue Pin Read Takes About 18623.44 nanoseconds.

Teensy 4.0 (150MHz) I/O Speed Tests Over 50000 Iterations.
Digital Pin Write Takes About 142.00 nanoseconds.
Digital Pin Read  Takes About 132.32 nanoseconds.
Analogue Pin Read Takes About 19351.30 nanoseconds.

Teensy 4.0 (24MHz) I/O Speed Tests Over 50000 Iterations.
Digital Pin Write Takes About 896.50 nanoseconds.
Digital Pin Read  Takes About 834.44 nanoseconds.
Analogue Pin Read Takes About 22173.00 nanoseconds.

STM32 Blue Pill (STM32F103C8T6/72 MHz) using Arduino IDE 1.8.2 and STM32 Core by STMMicroelectronics version 1.9.0:

STM32 Bluepill (STM32F103C8T6/72 MHz) I/O Speed Tests Over 50000 Iterations.
Digital Pin Write Takes About 0.50 Microseconds.
Digital Pin Read  Takes About 0.98 Microseconds.
Analogue Pin Read Takes About 63.30 Microseconds.

Using Arduino IDE 1.8.2 and STM32duino core:

STM32 "Blue Pill" (STM32F103C8T6 / 72 MHz) I/O Speed Tests Over 50000 Iterations.
Digital Pin Write Takes About 0.50 Microseconds.
Digital Pin Read  Takes About 0.78 Microseconds.
Analogue Pin Read Takes About 7.02 Microseconds.