Attiny2313 Pulse Width Modulation

Go To Last Post
3 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello Avrfreaks community,

the last two days I tried to come up with a working pwm code in C for the Attiny2313. I connected a led to pb2 of the µC and made up this little piece of code:

#include 
#include 

void Init_Timer(void);

int main(void)
{
	/* insert your hardware initialization here */
	DDRB |= (1<<PB2);	// OC0A as output
	
	Init_Timer();    
	
	sei();	// enable global interrupts
	
    for(;;){
        /* insert your main loop code here */
    }
    return 0;   /* never reached */
}

void Init_Timer(void) {
	TCCR0A |= (1<<COM0A1)	// Clear OC0A on Compare Match, set OC0A at TOP
			| (1<<WGM01)|(1<<WGM00);	// Fast PWM
	TCCR0B = 0x00;
	TCCR0B |= (1<<WGM02)	// OCR0A = TOP
			| (1<<CS02)|(1<<CS00);	// clkI/O/1024 (From prescaler)
	OCR0A = 0x7f;	// Output Compare Register
	TCNT0 = 0x00;	// Reset Timer
}

Somehow the intensity of the LED doesn't change when I change the OCR0A Register.

I looked at other codes but I was not able to figure out the mistake I made. Can you spot it and point me into right direction?

Thanks in advance,

Flops

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Flops, DON'T put comments between code assignments, put them at the END, you make it hard to read a line. DO this:

  TCCR0A =(1<<COM0A1)|(1<<WGM01) |(1<<WGM00);	// Fast PWM, MODE 3
  TCCR0B = (1<<CS02)|(1<<CS00); // clkI/O/1024 (From prescaler)
  OCR0A = 0x7f;   // Output Compare Register
  TCNT0 = 0x00;   // Reset Timer

2 numbers are needed to do PWM, a period register and a duty cycle register:

1) Number 1, TOP : it's the PERIOD ( TOP ), so it sets freq.
2) Number 2, OCR : sets the duty cycle and obviously these numbers can't be in the same register. In your code you use OCR0A as TOP, so you'd have to use OCR0B as duty, or a version like mine. Read the PWM tutorials in that forum ( hit the "forum" button in the upper left area of this site and you'll see every forum on this site ).

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Many thanks I didn't know I am using the wrong Timer mode. Here is the code I made up, it works very well (just in case someone has the same problem I had):

#include 
#include 

void Init_Timer(void);

int main(void)
{
	/* insert your hardware initialization here */
	DDRB |= (1<<PB2);	// OC0A as output
	
	Init_Timer();    
	
	sei();	// enable global interrupts
	
    for(;;){
        /* insert your main loop code here */
    }
    return 0;   /* never reached */
}

void Init_Timer(void) {
	TCCR0A |= (1<<COM0A1)| (1<<WGM01)|(1<<WGM00);	// Clear OC0A on Compare Match, set OC0A at TOP; Fast PWM
	TCCR0B = 0x00;
	TCCR0B |= (1<<CS01)|(1<<CS00);	// clkI/O/(No prescaling)
	OCR0A = 0x00;	// Output Compare Register
	TCNT0 = 0x00;	// Reset Timer
	
	TIMSK |= (1<<OCIE0A);
}

ISR(TIMER0_COMPA_vect) {
	OCR0A++;
}

Thanks again,
Flops