How to: Phase and Frequency correct PWM on ATtiny461A

How to: Phase and Frequency correct PWM on ATtiny461A

Just thought I’d share how I achieved phase and frequency correct PWM on the ATtiny461A using Atmel Studio 6.2.

I really haven’t the required knowledge or time to explain everything, but I highly suggest reading Introduction to AVR timers.

The phase and frequency correct PWM counts up from the bottom to the top. When it rises above and below the threshold, the OC1A pin goes from high to low or low to high depending on the settings of the COM1A1:0 bit. In the above code, the bits are Cleared on Compare Match when up-counting, and Set on Compare Match when down-counting. See page 113 on the ATtiny461A datasheet for clarification.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//define the frequency of the cpu
#define F_CPU 8000000

//requred includes
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

//function declaration(prototype)
void pwm_init();

int main(void) //this is our main loop
{
pwm_init(); //call our function to initialize the pwm
while(1) //start an infinite loop
{
for(uint8_t i = 1;i<100;i++){ OCR1A = i; _delay_ms(50); } for(uint8_t i = 99;i>0;i--){
OCR1A = i;
_delay_ms(50);
}
}
}

void pwm_init(){
//Set OC1A pin as output pin port b1
DDRB |= (1<<PB1);

//Set waveform generation to frequency and phase correct pwm.. page 118-119
TCCR1D |= (1<<WGM10);

//Set appropriate prescaler divider - page 116 on datasheet
//1 tick = 8MHZ / 1 = 125nS!
TCCR1B |= (<<CS10); //no prescaler used, one tick is 125 nanoseconds!!

//Set comparator A output module to toggle on every compare match
//This is what automatically toggles our OC1A pin -- see page 113 on datasheet
TCCR1A |= (1<<COM1A0);

//Set to 1 enables PWM mode based on comparator OCR1A
TCCR1A |= (1<<PWM1A);

//top of 100 = 25uS OR 40khz
OCR1C = 100;

OCR1A = 50; //this is what *should* determine the duty cycle

TCNT1 = 0; //reset the thing

}

The OCR1C represents the top of the counter (e.g. what the counter counts up to) and the OCR1A variable is the threshold. The bottom is zero. TCNT1 is the counter’s current value.. we set it to zero so when we exit the pwm_init function, it will not be at some arbitrary value, since it actually started counting when we set the prescaler value TCCR1B |= (1<<CS10)

Since the counter counts to the top (in this case 100) and back to the bottom, zero, then there are 200 steps at 125 nanoseconds each (since we are using a prescaler of 1/1). 125 nanoseconds * 200 = 25 microSeconds. Frequency = 1/25uS = 40000, or 40khz.

My intent with all this is to eventually make a class d amplifier using the timer as the triangle wave compared with the signal (OCR1A!) to output a frequency modulated signal to the power stage of an amplifier then low pass filter through a speaker…. fingers crossed.

The only problem here is the frequency, as 40khz is not nearly enough for a class D. Lowering the top value below 100 will speed it up, but will cause us to loose resolution…. it’s all about the tradeoffs.