Electronic – Audio PWM on atmega644

avrcpwm

I'm trying to generate audio through a 3.5mm jack using an atmega644. I tried following this tutorial, but even with the sampling provided, I only get a high-pitched whine. I did a lot of reading in the datasheet and came up with this code:

#define F_CPU 1000000
#include <stdint.h>
#include <avr/io.h>
#include "pcm_sample.h"
#include <avr/interrupt.h>
#define SAMPLE_RATE 8000;

volatile uint16_t sample = 0;

ISR(TIMER1_OVF_vect) {
    if (sample >= pcm_length) {
        sample = 0;
    }
    OCR1A = pcm_samples[sample++];
}

void init(void) {
    DDRD = (1<<PD5); // OCR1A

    // Fast PWM Mode 14, TOP=ICR1(0x7D), toggle OC1A on compare match
    TCCR1A = (1<<COM1A1) |  (1<<WGM11); 
    TCCR1B = (1<<CS10) | (1<<WGM12) | (1<<WGM13);
    TIMSK1 = (1<<TOIE1); // Interrupt on overflow
    // Timer ticks at 1us, samples every 125us, so overflow every 125us
    ICR1 = 0x7D; // Overflow at 125
    OCR1A = pcm_samples[0]; // Set initial duty
    sei();
}

int main(void) {
    init();
    while (1);
}

But then nothing comes out of the headphone jack. My first thought was that the interrupt isn't firing, but I'm pretty sure it's set up right. Any ideas?

EDIT: The WGM12 bit is in the TCCR1B register and timer 1 needs a clock source, as Bruce Abbot pointed out below. I've changed this in the code and now the interrupt fires, however it still doesn't play the sound. Instead I get a high pitched whine and occasionally broken by a thumping noise.

Also, I realized that the timing was probably off, so I've changed I did some maths and came up with the above (hopefully it's correct). It required I be able to set when Timer 1 overflowed, so I've change from using Mode 5 to Mode 14. After correcting some math mistakes, it is improving: fuzzy noise instead of a high-pitched whine.

The solution to this was a combination of the below answers and comments. The code above is working, although it's pretty low quality you can clearly hear "It's working" (for this application, I'm not bothered about the quality, but I assume to fix that you just need to look into a higher sample rate as Chris Stratton mentions below). Thanks to all those who helped.

Best Answer

Your interrupt vector is incorrect. The ISR routine looking for TIMER0_1VF_vect although you never set up the TIMER0 timer and TIMER0_1VF_vect isn't a valid vector according to atmels list.

You set up the TIMER1 to interrupt on overflow so you should use the TIMER1_OVF_vect instead which will trigger on TIMER1 overflow