Go Down

Topic: How exactly slow is digitalRead()? (Read 19824 times) previous topic - next topic


Jul 24, 2015, 08:36 pm Last Edit: Jul 24, 2015, 08:37 pm by jboyton
It depends, doesn't it? In isolation it's just one cycle. And if you do the same thing but address the port indirectly instead it's going to take longer, at least with an AVR processor.

I have some code that I originally wrote to use pin numbers defined in the library header file. That way the port accesses would be via immediate values. But in the Arduino environment having values in the header files makes it hard to go from one sketch to the next where the pins might different. So I rewrote it to use values passed in the constructor. That ultimately meant that the ports were addressed indirectly, even though technically the pin numbers were known at compile time -- just not library compile time. And it affected the performance.


Jul 28, 2015, 05:43 pm Last Edit: Jul 28, 2015, 05:45 pm by SukkoPera
To sample at that speed I would consider a faster MCU/clock speed as you won't have much time to do anything else. If you supply more details of what you need/want then maybe we can suggest options.
Sorry for the delay, but I have some news!

First of all, what I'm doing is snooping the NES Controller Protocol (Which is based on a CD4021 shift register as probably everybody knows, see here: http://www.mit.edu/~tarvizo/nes-controller.html). I'm not just trying to drive a pad connected to the Arduino, I'm rather intercepting the signals while the console is running, and they're pretty fast.

I have no problems doing that on a 16 MHz Arduino, even digitalRead() works fine (provided that I use an interrupt to detect clock transitions) but my final objective is to create a sort of modchip to install in the console, so the least components, the better. This means that I would happily avoid the crystal, so I am trying to get things running fine at 8 MHz. It would even be better to use a smaller MCU in the end, my ideal target being the ATtiny84.

But at 8 MHz detection isn't reliable. I have tried different strategies (direct port manipulation, register variables, different interrupts, etc...), but it seems that the code is always too slow and drags behind the strict timing required. The best result I could get was getting only the first 4 buttons read correctly (over 8 ).

But yesterday I discovered SPI! I spent some time with it and got it working easily on the '328. I used the much neglected (on the Arduino) slave mode, since everything is being driven by the console. Then I switched to the '84 and I found out that there's no ready-made library and that it doesn't have real hardware SPI, then I found Atmel's Technical Note about USI and managed to get something working on the '84 as well. It's not complete yet, and I'm not sure it will work 100% (it's hard to debug without a Serial Console), but results are promising so far.

So I guess we are a bit out of topic by now, but anyway... Any hints?
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E


The tiny85 has a PLL clock mode so you can run it at something around 16MHz with no external xtal. Maybe it will do the job or another similar mode chip?
Don't PM me for help as I will ignore it.


Interesting! But the '84 doesn't have that, right? Too bad, I already had in mind a version for the '85 but I don't think I will be able to squeeze all the features in :smiley-confuse:.

What do you mean with "another similar mode chip"?
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E


The ATtiny84 doesn't have that PLL, but you can rev up the internal oscillator to around 14MHz, give or take:

The Tiny chips also lack a MUL instruction. Depending on what you're doing that can have a noticeable effect on execution time.


If you really need more performance, I'd advise you switch to using an ARM based processor

Arduino have recently released the Zero, and the Due has been around for ages, both of which are significantly faster than the 16Mhz AVR's

There are also various other third party options including the Teensy, STM32F103 based boards and also PIC32, all of which have options to develop using the Arduino IDE

However, one note of caution, ARM boards are 3.3V and also, not all libraries have been ported to ARM (though Teensy have a lot of libs ported by Paul who developed the Teensy)

My personal favourite in terms for value for money is the STM32 Maple Mini board.
Freelance developer and IT consultant


Jul 29, 2015, 10:52 am Last Edit: Jul 29, 2015, 10:56 am by SukkoPera
@rogerClark: Thanks for your advice, but if you read my last post you'll see that a Due doesn't meet basically any of my requirements :D.

@jboyton: I don't use MUL, so it will be fine.

Anyway I've experimented a bit more with USI/SPI on the '84 at 8 MHz and it's working really really well, *never* missing a shot. It actually works much better than I expected, and I wonder how this can be possible for at least two reasons:

  • My understanding is that I would need SPI mode 2, but USI only supports modes 0 and 1. So I thought I would invert the clock with a 7404, but I actually forgot to do it and apparently it works flawlessly. I still have to check that all bits are actually read correctly, but I'm inclined to say so.
  • I can't find any information on how SPI handles "synchronization", but it seems it is pretty steady. I mean: I can power down the '84 and then power it back up at any time with the console running and it seems it always syncs to the first clock pulse of the batch correctly. I thought that since it always expects 8 clock cycles, if the reading starts for example halfway through a transfer it would read data from two different cycles, but this does not seem to happen, unless I have been so lucky to always power it back up at the beginning of a transfer like 30 times 8)

BTW, the '84 with its USI even has some advantage over the full SPI implementation of the '328 for me as I actually have no SS signal: USI does not implement SS, so it just works, but on the '328 you actually have to bring down SS to let the hardware do the job. The only signal I can use for the matter is the LATCH signal, which goes UP and just for a BIT at the beginning of a transfer (while SS is active low and should be kept low for the whole transfer), so I have to catch it with an interrupt and drive SS through another pin, which means more connections and more work!
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E


Jul 30, 2015, 04:59 pm Last Edit: Jul 30, 2015, 05:01 pm by eddiea6987
you can blink an led with no delay with arduino code  and check it out with a scope...
then do the same via direct port manipulation and check that out with a scope ...

then multiply the frequency reading  by two since its one command to turn on and one to turn off ..
 then you can get a more real world idea of the speed difference .

If you do go into ARM i recommend using Atmel Studio , their ASF makes using the Cortex very easy and a lot less overhead then Arduino code . Its a good way to get to learn the chip
I could print the Arduino logo on a box of cereal and sell it as "Arduin-O's"


Here is a video of the blink led and measuring the frequency ... YOUTUBE 
he starts at around 4 minutes or something
I could print the Arduino logo on a box of cereal and sell it as "Arduin-O's"

Go Up