# Setting the frequency of a timer interrupt

The concept:

Play a sine wave saved as a character array in PROGMEM through an 8-bit DAC connected to the PORTC pins on the Arduino Mega.

This works:

// File just defines an array and a size

#include "sine440.h"

int i = 0;
void setup() {
DDRC = B11111111;
}

void loop() {
if(i >= sine_size){
i = i - sine_size;
}

delayMicroseconds(60);
}

The above code produces a sine wave of about 440 Hz, exactly what I wanted. Now, I'd like to move this into an interrupt routine, as follows:

### This doesn't work

#include "sine440.h"

int i = 0;
void setup() {
DDRC = B11111111;
TCCR5B = (1 << WGM52) | (1 << CS50 );
OCR5A =  16000000/16000;
TIMSK5 = (1 << OCIE5A);
}

ISR(TIMER5_COMPA_vect){
if(i >= sine_size){
i = i - sine_size;
}
}

void loop() {

}

The above code produces a sine wave of 1721 Hz. I know that this means it's iterating through the array too fast, but I don't know how to change it. In order for it to produce 440 Hz, it needs to be preforming 16,000 iterations per second, which is what I believe OCR5A = 16000000/16000; does. But it doesn't appear that changing the value of OCR5A does anything at all. Giving it the max value of 65,535 still produces a 1721 Hz sine wave...

So what am I doing wrong here? How do I change the speed of this timer interrupt?

• Try setting TCCR5A = 0 explicitly, maybe arduino has WGM51 or WGM50 set at startup for some reason. Jun 11, 2016 at 23:34

I second BrettAM's comment. The Arduino IDE sets most of all the timers up for PWM, and I had to comment out a section once to use my own ISR with Timer 3 on a 32u4, because no matter where or how I set it, the CTC interrupt never went. The WGM50 and CS51 are set at the start of the Arduino files basically, so that messes with your settings.

You will need go into the Arduino core files. This is \$install_path/arduino-1.x.x/hardware/arduino/avr/cores/arduino/, and under that directory you need to find file wiring.c. This file contains all the setup of the timers for PWM and the millis() or micros() functions.

Go to line 342. Located there is this:

#if defined(TCCR5B) && defined(CS51) && defined(WGM50)

sbi(TCCR5B, CS51);           //set ter 5 prescale factor to 64
sbi(TCCR5B, CS50);
sbi(TCCR5A, WGM50);         // put timer 5 in 8-bit phase correct pwm mode

#endif

Here you can place another #if defined() macro around this, resulting in:

#if !defined(doNotSetTimer5)

#if defined(TCCR5B) && defined(CS51) && defined(WGM50)

sbi(TCCR5B, CS51);           //set ter 5 prescale factor to 64
sbi(TCCR5B, CS50);
sbi(TCCR5A, WGM50);         // put timer 5 in 8-bit phase correct pwm mode

#endif

#endif

Now when you want to use your custom settings, you will put the following at the top of your .ino file:

#define doNotSetTimer5
#include <wiring.c>

That does not block the Arduino environment from setting up Timer 5 when compiled with other code, but only when you want to use custom settings (changed because of @Gerben's suggestion). When you change these settings you will lose PWM on 3 pins: 44 45 46. But you will be able to make use of setting your own PWM up or a CTC ISR().

This doesn't mess with anything else and is the easiest way to do it.

• Wouldn't it be better to use a !defined(...), as to not break existing code? Something like #if !defined(doNotSetTimer5). That way you need to set the flag only if you want the no-standard settings. Jun 12, 2016 at 14:04
• @Gerben that's a good point, I will change it to that rather then. Will be more compatible with stuff. +1
– RSM
Jun 12, 2016 at 15:42
• Hey, thanks. I actually found a thread yesterday before seeing BretAm's comment that addressed this issue with a different timer. So i tried it out and it worked. But this did a great job in explaining WHY it was happening.
– Dave
Jun 12, 2016 at 20:50
• @Dave pleasure, maybe just add that link as a comment here or something to have another way too.
– RSM
Jun 13, 2016 at 6:15