ATTiny85 Sine Wave Gen

Hi I found this article on using the ATTiny85 as a function generator using a interrupt-routine and a PWM output. http://www.technoblogy.com/show?QVN

I'd like to output a sine wave, but I can't visualize how to write the code inside the interrupt routine program-loop. I want to read the amplitude values from a wave table (as suggested in the article). I get that I need to scroll through array-indexes of my wave table periodically, but how would I do the frequency calculation? Taking the wave table length, the Interrupt routine call frequency (20kHz) and a frequency division variable into account. Would it be as simple as this?

(Interrupt Frequency * clock divisor variable) / (Wave table length)

I've added a sine wave table below for reference.

const unsigned char sine[256] = { 131,132,135,137,140,143,146,149,152,155,157,160,163,166,168,171, 174,176,179,181,184,186,189,191,194,196,198,200,202,205,207,209, 211,212,214,216,218,219,221,223,224,226,227,228,229,231,232,233, 234,234,235,236,237,237,238,238,239,239,239,239,240,240,240,239, 239,239,239,238,238,237,237,236,236,235,234,233,232,231,230,229, 227,226,225,223,222,220,219,217,216,214,212,210,208,206,204,202, 200,198,196,194,192,189,187,185,182,180,177,175,173,170,167,165, 162,160,157,154,152,149,146,144,141,138,135,133,130,127,124,122, 119,116,113,111,108,105,103,100, 97, 95, 92, 89, 87, 84, 82, 79, 77, 74, 72, 69, 67, 64, 62, 60, 58, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 36, 34, 32, 31, 29, 28, 26, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 15, 14, 13, 13, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 19, 21, 22, 23, 24, 26, 27, 29, 30, 32, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 56, 58, 60, 63, 65, 68, 70, 73, 75, 78, 81, 83, 86, 89, 92, 94, 97, 100,103,106,108,111,114,117,120,123,126,129,130};

I intend to use this as a Low Frequency Oscillator (0.5Hz - 10Hz) and it would be neat to be able to control the sine wave frequency with one of the analog inputs. Would I need to lower the interrupt frequency in order to give the chip time to read the analog input every cycle?

Thank you for any help!

Writing the thread made things a little clearer.

Would something like this work, or am I making it too complicated?

ISR(TIMER0_COMPA_vect) {
Acc += 1;
OCR1B = sine[((Acc / Note) % WaveLength)]; // int-division (freq div) & modulo-division (stay within array len)
}

EDIT: I guess this will cause trouble on Acc rollover? Maybe this would be better?

ISR(TIMER0_COMPA_vect) {
Acc = (Acc + 1) % (65535 - (65535 % Note));
OCR1B = sine[((Acc / Note) % WavetableLength)];
}

I think you want:

ISR(TIMER0_COMPA_vect) {  
  Acc = (Acc + 1) % WavetableLength;
  OCR1B = sine[Acc]; 
}

If WavetableLength is 256 you can simplify to:

ISR(TIMER0_COMPA_vect) {  
  static unsigned char Acc = 0;
  OCR1B = sine[Acc++]; 
}

johnwasser: I think you want:

ISR(TIMER0_COMPA_vect) {  
  Acc = (Acc + 1) % WavetableLength;
  OCR1B = sine[Acc]; 
}

If WavetableLength is 256 you can simplify to:

ISR(TIMER0_COMPA_vect) {  
  static unsigned char Acc = 0;
  OCR1B = sine[Acc++]; 
}

Thanks for your reply, but this way I won't be able to adjust the frequency of the wave.

Anyways I think there is something wrong with the code on the linked site. I'm able to upload it to the ATTiny85, but it does not output any waveform.

knutolai:
Anyways I think there is something wrong with the code on the linked site. I’m able to upload it to the ATTiny85, but it does not output any waveform.

It doesn’t give you a Middle-C (261.625565 Hz) square wave on pin 3? Could you be using it on an ATtiny that is NOT set for an 8MHz clock? Do you get anything on pin 3?

/*
 Generating a tone using DDS
*/
float Freq = 261.625565;  // Middle C
volatile unsigned int Incr;
const unsigned char sine[256] =  {
  131, 132, 135, 137, 140, 143, 146, 149, 152, 155, 157, 160, 163, 166, 168, 171,
  174, 176, 179, 181, 184, 186, 189, 191, 194, 196, 198, 200, 202, 205, 207, 209,
  211, 212, 214, 216, 218, 219, 221, 223, 224, 226, 227, 228, 229, 231, 232, 233,
  234, 234, 235, 236, 237, 237, 238, 238, 239, 239, 239, 239, 240, 240, 240, 239,
  239, 239, 239, 238, 238, 237, 237, 236, 236, 235, 234, 233, 232, 231, 230, 229,
  227, 226, 225, 223, 222, 220, 219, 217, 216, 214, 212, 210, 208, 206, 204, 202,
  200, 198, 196, 194, 192, 189, 187, 185, 182, 180, 177, 175, 173, 170, 167, 165,
  162, 160, 157, 154, 152, 149, 146, 144, 141, 138, 135, 133, 130, 127, 124, 122,
  119, 116, 113, 111, 108, 105, 103, 100, 97, 95, 92, 89, 87, 84, 82, 79,
  77, 74, 72, 69, 67, 64, 62, 60, 58, 55, 53, 51, 49, 47, 45, 43,
  41, 39, 37, 36, 34, 32, 31, 29, 28, 26, 25, 24, 22, 21, 20, 19,
  18, 17, 16, 15, 15, 14, 13, 13, 12, 12, 12, 11, 11, 11, 11, 11,
  11, 11, 11, 12, 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 19, 21,
  22, 23, 24, 26, 27, 29, 30, 32, 33, 35, 37, 39, 41, 43, 45, 47,
  49, 51, 53, 56, 58, 60, 63, 65, 68, 70, 73, 75, 78, 81, 83, 86,
  89, 92, 94, 97, 100, 103, 106, 108, 111, 114, 117, 120, 123, 126, 129, 130
};
void setup() {
  Incr = 20000 * (Freq / 65536.0);
  // Enable 64 MHz PLL and use as source for Timer1
  PLLCSR = 1 << PCKE | 1 << PLLE;
  // Set up Timer/Counter1 channel B for 8-bit PWM output
  TIMSK = 0;                     // Timer interrupts OFF
  TCCR1 = 1 << CS10;             // 1:1 prescale
  GTCCR = 1 << PWM1B | 2 << COM1B0; // PWM B, clear on match
  pinMode(4, OUTPUT);            // Enable PWM output pin
  // Set up Timer/Counter0 for a 20kHz interrupt to output samples.
  TCCR0A = 3 << WGM00;           // Fast PWM
  TCCR0B = 1 << WGM02 | 2 << CS00;// 1/8 prescale
  TIMSK = 1 << OCIE0A;           // Enable compare match, disable overflow
  OCR0A = 49;                    // Divide again by 50 to get 1/400  (1/8 * 1/50)
}
void loop() { }
ISR(TIMER0_COMPA_vect) {
  static unsigned int acc;
  acc += Incr;
  OCR1B = sine[acc >> 8];
}

Just reuploaded the code and got it working for some explainable reason. The Square, Sawtooth and triangle waves are all fine, but I’m still having trouble with the sine wave table.

I get it “working” with this code:

Acc = (Acc + 1) % (65535 - (65535 % Note));
OCR1B = sina[((Acc / Note) % wavetablelengt)];

The code below does not work properly as the counter skips in the wavetable when Acc reaches 65535 and starts back at 0. I’m using the waveform for a LFO (0.5Hz - 15Hz) and the skip is quite noticable.

Acc = (Acc + 1);
OCR1B = sina[((Acc / Note) % wavetablelengt)];

A problem is that I don’t get nearly the same frequency range as with the square, sawtooth and triangle codes from the article. (listed below). I can make it very slow, but it wont go any faster than ~3Hz.

ISR(TIMER0_COMPA_vect) {
  Acc = Acc + Note;
  OCR1B = (Acc >> 8) & 0x80;
}

ISR(TIMER0_COMPA_vect) {
  Acc = Acc + Note;
  OCR1B = Acc >> 8;
}

ISR(TIMER0_COMPA_vect) {
  signed char Temp, Mask;
  Acc = Acc + Note;
  Temp = Acc >> 8;
  Mask = Temp >> 15;
  OCR1B = Temp ^ Mask;
}

Is there any way to alter the sinewave code so that it outputs the same frequency as the other waveshapes? Also, the way I’ve written my code the frequency decreases as int Note increases. It’s the other way around for the other waveshapes. Any thoughts?