1

I'm working on a Arduino-based synthesizer using this tutorial, specifically using a wavetable and 1-bit DAC. I understand that the value for OCR2A register sets the frequency, but how do I calculate the value?

I've seen this list of notes which is great, but I want arbitrary frequencies in Hz...

Here's the code I'm working from:

#include <avr/interrupt.h>
// sinewave parameters
#define FREQ 18
#define PI2 6.283185 // 2*PI saves calculation later
#define AMP 127 // scaling factor for sine wave
#define OFFSET 128 // offset shifts wave to all >0 values
#define LENGTH 256 // length of the wave lookup table
byte wave[LENGTH]; // wavetable
void setup() {
 // populate wavetable
 for (int i = 0; i < LENGTH; i++) {
 float v = (AMP * sin((PI2 / LENGTH) * i));
 wave[i] = int(v + OFFSET);
 }
 // set timer1 for 8-bit fast PWM output
 pinMode(9, OUTPUT); // make timer’s PWM pin an output
 TCCR1B = (1 << CS10); // set prescaler to full 16MHz
 TCCR1A |= (1 << COM1A1); // pin low when TCNT1=OCR1A
 TCCR1A |= (1 << WGM10); // use 8-bit fast PWM mode
 TCCR1B |= (1 << WGM12);
 // set up timer2 to call ISR
 TCCR2A = 0; // no options in control register A
 TCCR2B = (1 << CS21); // set prescaler to divide by 8
 TIMSK2 = (1 << OCIE2A); // call ISR when TCNT2 = OCRA2
 OCR2A = FREQ; // set frequency of generated wave
 sei(); // enable interrupts to generate waveform!
}
void loop() {
 // nothing to do here!
}
// called every time TCNT2 = OCR2A
ISR (TIMER2_COMPA_vect) { // called when TCNT2 == OCR2A
 static byte index = 0; // points to each table entry
 OCR1AL = wave[index++]; // update the PWM output
 asm("NOP; NOP"); // fine tuning
 TCNT2 = 6; // timing to compensate for ISR run time
}
asked Jan 25, 2016 at 15:57
7
  • Shouldn't this be in Arduino.SE? Commented Jan 25, 2016 at 16:09
  • Perhaps, didn't realize there was a separate forum. Happy to migrate if that's appropriate. Commented Jan 25, 2016 at 16:10
  • Whoever wrote the code for that tutorial needs their head examining. asm("NOP; NOP"); and TCNT2 = 6; are total nonsense and should be removed, as should the sei(); line from setup (it's unnecessary). Also, the LENGTH #define is totally ignored in the ISR, so if it was ever set to something other than 256 the code would break. >_< Commented Jan 25, 2016 at 16:46
  • Hmm, I tried it without TCNT2=6 and got a lot more high-freq partials. With TCNT2=6 but no asm("NOP;NOP") I get no audio, just buzzing. It seems to be fine without sei(), but (obviously) my timer programming is really bad, and I don't entirely understand what they do. Commented Jan 25, 2016 at 16:51
  • Well the asm() statement that according to the comments adds two nops only adds one, so... Commented Jan 25, 2016 at 17:00

1 Answer 1

4

The equation to calculate it is given in the first article you linked:

From linked Makezine article "Advanced Arduino Sound Synthesis"

The 2MHz value comes from the factor of 8 prescale on the 16MHz clock and 256 is the size of the lookup table specified by your LENGTH define. If you start from a frequency you want to synthesize, just use the above equation to solve for the necessary value of OCR2A. Note that since you have to input integer values to OCR2A, you can't really achieve arbitrary frequencies, but you're certainly not locked in to the values given in the supplemental musical note PDF you reference.

So, to solve for OCR2A:

OCR2A = TCNT2_rate / (desiredFreq * wavetableLength);
answered Jan 25, 2016 at 16:23
5
  • Thanks! It took me a while to figure out that the equation told me that! So, my math is really terrible: how do I swap the equation to get me OCR2A from frequency? :) Commented Jan 25, 2016 at 16:31
  • 1
    @JeffThompson just swap them over in the equation (stick frequency where OCR2A is, and vice versa) Commented Jan 25, 2016 at 16:35
  • Sorry, feeling really stupid: so OCR2A = TCNT2/(freq*tableLen)? Commented Jan 25, 2016 at 16:41
  • 1
    @JeffThompson Yep, that's correct. Commented Jan 25, 2016 at 16:45
  • 1
    As Cheibriados said, you won't get arbitrary frequencies. From the table you linked you can see that OCR2A of 15 gives you a frequency of 523.25 Hz, and making it 16 gives you a frequency of 493.88 Hz. Thus you cannot get any frequencies in-between. Commented Jan 25, 2016 at 21:19

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.