Use of timer2 and SPI at the same time on Arduino Uno


I am starting to mess around with timers on the Arduino Uno.
I have a building a project that uses a SRAM, connected with SPI to the board and I am using timer2 at the same time.
After looking around internet and the ATmega328 datasheet, I understood that Arduino pins 11 and 3 are controlled by timer2.

In my case, I want to use pin 11 as MISO pin for the SPI communication.

So is it possible to control only pin 3 with timer2 so that pin 11 is reserved for the SPI communication? Or should I think of changing timer, timer0 for example, in order to avoid conflict on pin 11?
My thoughts would be that when initialising the timer2 registers (DDxn bit in the DDRx Registers, p.76 of ATmega328 datasheet), it is possible to only use one over the 2 dedicated pins. Am I right?

Thank you for your answers.

I understood that Arduino pins 11 and 3 are controlled by timer2.

PWM on pins 11 and 3 is controlled by timer 2.

In my case, I want to use pin 11 as MISO pin for the SPI communication.

Which does not involve PWM.

So, go for it.

Its the call to analogWrite () that enables timer control of each PWM output pin - so long as you don’t call analogWrite () the SPI hardware should have control (it might have precedence anyway - have to read the right bit of the datasheet to find out).

If you’ve called analogWrite() on a pin then digitalWrite() will reset it and cancel PWM control of that pin - you can look at wiring_digital.c and wiring_analog.c to see how this happens BTW (/hardware/arduino/core/arduino/wiring_analog.c etc)

Thanks for your answers MarkT and PaulS, it's all clear now (I hope :))


In my case, I want to use pin 11 as MISO pin for the SPI communication.

Which does not involve PWM.

Glad I saw this post - I was about to abandon thoughts of using the rather neat looking timer1 library because I saw this issue:

The TimerOne library can’t be used together with either the Servo or the SPI library.
In the case of Servo, TimerOne wins, whereas in the case of SPI, SPI wins and TimerOne won’t function.

**EDIT/UPDATE:**I can answer my own question and save anyone else confusion - it DOES work.
OK, to clarify, using the attachInterrupt function of this library appears to work fine with SPI. Try this code… timer1_and_spi.ino · GitHub

And the reason it didn’t work first time? Turned out the slave select wire to the slave was loose! As soon as I stuck the logic analyzer on it, I saw the problem, and everything fine!

I also found this forum post:

SPI in loop() working fine, but not in ISR TIMER 1 interrupt

“I might be wrong, but does the spi library rely on interrupts ? If so it will not work inside an interrupt service routine because interrupts are disabled temporarily while an isr runs”.

Is he wrong? and

If you use SPI both in an ISR and in the loop() function then you must disable interrupts around all uses of SPI not in the ISR

Is that correct?


The Timer1 is triggering the interrupt at just the right times, and everything is looking good.

Except, I am seeing corruption on the SPI. I can only assume that it is due to the interrupt for Timer1 firing during the SPI transfer. If I disable the timer and its interrupt I get no problems with the SPI transfer at all.

In my case, I’m not trying to use any of the PWM pins or functions, simply:

attachInterrupt(function, period)
Calls a function at the specified interval in microseconds.

I just want to use attachInterrupt to trigger SPI to poll for some data on a slave Arduino ten times a second (ie: 10Hz). As you say, there’s no PWM involved, so this should be fairly safe to use, yes?

Before anyone points out the obvious: Yes, I could do it in the loop.

Or I could use a library like Metro:

“Because Metro does not use interrupts, you have to “check” the Metro regularly (at least every millisecond).”

Or SimpleTimer.

The base goal is to be able to execute a particular piece of code every n milliseconds, without using interrupts.

The algorithm looks like this:

lastMillis = 0
forever do:
if (millis() - lastMillis > n)
call the particular piece of code
lastMillis = millis()

Or Simon Monk’s Timer library.
All of which use “the loop”.

But I don’t want to block a dynamically updating LCD display (which isn’t time sensitive and uses no delays - only “read busy flag” before anyone asks!). And I also need to be sending and receiving UART serial data. Possibly even a little RTC module. Yeah, pushing those pins to the limit. Again, before anyone asks - I’m using a Pro Mini so got two extra pins A6 and A7 to play with.

In fact, do I even need a whole library? I’d be happy using timer0 if it could help me do the following:

In the background, there’s a 100x32 OLED scrolling information. To scroll, I need to send it a full display-worth of 400 bytes about 30 times a second.
As I’m using direct port manipulation, I can get the whole display written in a few milliseconds.
While that’s going on, I need to poll another Arduino somewhere around 10 to 25 times a second. I’m doing that at 2Mhz SPI setting to get it done quickly, and when the byte arrives, a simple lookup array converts that byte into one of a selection of predefined messages, then updates the OLED with the new message after grabbing the current time from the RTC.

Working as fast as it’ll go with no delays, my OLED is scrolling slightly faster than I need it, so I figure using something efficient like an interrupt will naturally induce a delay just enough to make it readable, once I’ve taken my lookup array function into account (which includes a “if 0x00 then do nothing” part).

But I thought that if had a “runEvery…” type function being polled every single loop, that would be enough to visibly slow the display down again. As I say, I had to get right into port manipulation for every single pin otherwise the display was “tearing”, so don’t want to undo that if there’s a nice timer that’ll take the load off the CPU checking millis() all the time.

Am I on the right track here, or on a hiding to nothing? Incidentally, in case anyone asks if I’ve done my homework, here’s where I’ve been over the last couple of days.

I’m pasting this here because although some of it isn’t directly relevant to this subject, it all relates to timers and PWM and some cool related stuff I only found out about by stumbling on it. Here we go…

Nick Gammons pages on … Interrupts , SPI and Timers and counters , in which I found, as a nice bonus… Tone library for timers

The small library below simplifies generating tones with the hardware timers. Unlike the “Tone” library that comes with the Arduino this one directly uses the outputting capability of the hardware timers, and thus does not use interrupts.

More things I found and read:
Timer1- the library I hope to use.
Arduino 101: Timers and Interrupts
Secrets of Arduino PWM

If you used a 16 bit timer (e.g. timer 1, or timers 3,4,5 on '1280), you could generate “tones” down to 1/8 Hz (one cycle every 8 seconds), although the library only accepts integers for frequency.

Overriding Arduino interrupt handlers
Adjusting PWM frequencies

Surprisingly, the polling function outperforms the interrupt request by almost a factor of 2! In hindsight this result might not be so surprising. SPI in this case works at half the CPU frequency, which means that the CPU can only execute less than 16 instructions per byte sent. The polling loop wastes less time per transfer than an overhead of an interrupt call.

Varying the pwm frequency for timer 0 or timer 2?

If you change TCCR0B, it affects millis() and delay(). They will count time faster or slower than normal if you change the TCCR0B settings. Below is the adjustment factor to maintain consistent behavior of these functions:

Default: delay(1000) or 1000 millis() ~ 1 second

0x01: delay(64000) or 64000 millis() ~ 1 second
0x02: delay(8000) or 8000 millis() ~ 1 second
0x03: is the default
0x04: delay(250) or 250 millis() ~ 1 second
0x05: delay(62) or 62 millis() ~ 1 second
(Or 63 if you need to round up. The number is actually 62.5)

Also, the default settings for the other timers are:
TCCR1B: 0x03
TCCR2B: 0x04

Hope these notes help other wanderers on this long journey!