Arduino digitalRead and interrupt speed improvements

Having thought I’d almost nailed my ignition timing problems, I tried testing at higher engine speeds (up to 6000 RPM) only to find that the ignition timing began to become erratic again.


This again was due to the time spent servicing the interrupt routine for the crank position sensor. Although I had optimised this to some level, it turns out that I need to squeeze a bit more out of it. I have already removed most of the complex operations from the routine, and so had to begin looking more deeply. I considered the ordering of the logic inside my if statements, and reordered some of the code, but without much success. I then remembered back to a similar problem I had with programming a PIC18, where the library function for reading and writing to the timer registers were much much slower than writing them directly (and no less complex).

I was already writing the Arduino timer registers directly but was using the built in functions to read and write the digital pins. A quick Google turned up a few results relating to problems of digitalRead and digitalWrite being slower than dealing with the ports directly. JeeLabs provides a pretty good analysis of the problem, and although doesn’t manage to define an exact speed difference, it certaintly is orders of magnitude slower to use the built in functions.

Therefore, I replaced the digitalRead(13) function with bitRead( PORTB, 7) which is the method for reading a particular bit from a register (perhaps it would be even quicker to do this using bitwise logic). I had to look in the Arduino source code to find the port and bit number which corresponded to the GPIO pin 13 on my AtMega1280 Arduino, this is easy to find in the Arduino folder wherever you installed it to. On my machine it was here:

E:\Program Files\arduino-1.0.5\hardware\arduino\variants\mega\pins_arduino.h

The new function solved my timing issues, and now my max. engine speed is around 6500 RPM. I did test changing my crank sensor interrupt to trigger on the falling edge instead of on change which would give me an interrupt every 6 degrees instead of 3 and hence more time between interrupts. This allowed me to push the engine speed up to around 10,000 RPM. If I wanted to go higher, I could probably make a couple more optimisations, but I think it would be pushing it, and perhaps another micro would be more suited.

Fortunately my test engine is limited to around 5000RPM and I don’t think I’ll get a chance to use this on an F1 engine any time soon! This is also currently only designed to handle one cylinder, although in theory adding more cylinders shouldn’t cause too big a problem, as long as enough timers are available on the micro.

3 thoughts on “Arduino digitalRead and interrupt speed improvements

  1. Ed

    I enjoy reading these posts, keep up the good work! When you get it running smoothly you should post a video of the setup.

    Reply
    1. Scott Snowden Post author

      Thanks! It’s going well so far, and I will post some videos, and a link to the code when I’m happy that it at least works to some extent.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *