3

Consider the following code:

void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {
    // turn LED on:
    digitalWrite(ledPin, HIGH);
  }
  else {
    // turn LED off:
    digitalWrite(ledPin, LOW);
  }
}

The line buttonState = digitalRead(buttonPin); checks the input voltage.

But how is that checked internally?

I mean at what rate the input is checked?

5
  • The check is performed in one single cycle, but the whole routine takes WAY longer. It's not clear what you are asking. For info: jeelabs.org/2010/01/06/pin-io-performance Summary: "digitalRead() takes 3712 ns, direct port read takes 151 ns, a ratio of 25:1
    – FarO
    Jan 23 '17 at 14:19
  • So it is roughly 0.3MHz right? That could be the answer to my question?
    – user16307
    Jan 23 '17 at 14:50
  • As I said it's not clear what you ask: your input is checked once every loop, meaning that you need the time for one digitalRead, one IF, one digitalWrite, one JUMP to the beginning othe next loop. DigitalRead COULD work at 0.3 MHz if you call it continuously, but you are doing more stuff.
    – FarO
    Jan 23 '17 at 15:39
  • Add a delay at the end of the loop and measure micros() once at the beginning of the loop, once at the end before the delay, and send via Serial.println(microsAfter-microsBefore).
    – FarO
    Jan 23 '17 at 15:41
  • I did some benchmarking on the cost of Arduino - in that case for digital write. I can easily do so for digital read as well. When I get time, I will provide more definitive answers. It is sufficient to say now that the cost in performance is quite substantial in avrs and considerably less on stm32.
    – dannyf
    Jan 23 '17 at 16:52
3

When I get time, I will provide more definitive answers.

I did follow through with this, and the result is here, towards the end of the page: https://dannyelectronics.wordpress.com/2016/05/01/the-price-of-avr-arduino/

the short answer is: digitalRead() takes 4.9us to execute on a 16MIPS Arduino Uno, or 79 ticks (=instructions).

the fastest you can read digitalRead() is then 200KHz (= 1/4.9us).

Hope it helps.

3

It read a port just like it reads memory (to which it's mapped.) So speed is how fast an instruction can read memory. EEPROM is a different animal.

Might get it a little faster by replacing

buttonState = digitalRead(buttonPin);
with
buttonState = PORTB & _BV(buttonPin);

Assuming it's PORTB that you are using. This will alleviate at least one function call, I would think, and will generate a single instruction to read the port into the variable. It may require an instruction to load the variable address, but that's up to the compiler. The replacement may be more trouble porting to other micros. Normally you don't see a variable as a parameter although legal, usually a constant in a #define.

_BV(INPUT_PIN_X) is a macro (BV is for 'bit value') that expands to
(1 << INPUT_PIN_X)

dannyf times seem quick to me, but it sounds like he's done the testing. Is he taking into account the complete function call as part of the time? I run at 1Mhz normally, so it's more difficult to relate.

Take Majenko advice and start reading the generated assembler :)

Best of luck.

2
  • For pins above 7, won't, for example _BV(13) give you masks like B1000000000000 and not work sensibly with PORTA or PORTB? Wouldn't buttonState = *portInputRegister(digitalPinToPort(buttonPin)) & digitalPinToBitMask(buttonPin); be more robust?
    – Dave X
    Apr 14 at 19:34
  • Ack -- digitalRead(buttonPin) gives a 1 or 0, while PORTB & _BV(buttonPin) could give you 0,1,2,4,8,16,32,64,128 depending on the state of the pin and which pin on the port you are looking at.
    – Dave X
    Apr 14 at 19:52
2

That depends on the frequency your Arduino runs at.

It's basically once per iteration of the loop, and that depends on everything that is happening in the loop.

You can examine the assembly language output of the compiler (disassemble the .elf file using avr-objdump -h -S <elf file>) and count the number of clock cycles per iteration (the datasheet has the number of clock cycles per instruction). However that is tedious.

If you want to read the input at a specific frequency then you should do it using a timer interrupt.

3
  • Can you give a rough number for a short code like in my example?
    – user16307
    Jan 23 '17 at 14:16
  • No, I can't. Not just like that. You could toggle an IO pin each iteration of your loop and read the frequency using an oscilloscope, then double it. That is how fast the loop is running at that moment in time.
    – Majenko
    Jan 23 '17 at 14:24
  • It is based on the frequency of the arduino and the 'amount' of operations in loop() and serial_event() methods, is it not? More operations in the loop, lower the read frequency.
    – Divisadero
    Jan 23 '17 at 15:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.