ATtiny10 PWM generation

Hi all,
Could you give me some advice on generating 20KHz PWM? I tried to use Timer0 with no prescaler but the interrupt triggers around 4us (4*256) which is too long for a 50us period (20kHz ~ 50us/cycle)
my example code at 8MHz

// interrupt for Compare A

#define DUTY_CYCLE (255/2)  // testing purpose
ISR(TIM0_COMPA_vect)
{
	// turn on/off according to PWM value
	if (pwmCount > DUTY_CYCLE) {
		PORTB &= ~(1 << PB1);
	}
	else {
		PORTB |= (1 << PB1);
	}

	// increment PWM count
	pwmCount++;

}

void setup()
{
	// Set CPU speed by setting clock prescaler:
	// CCP register must first be written with the correct signature - 0xD8
	CCP = 0xD8;
	//  CLKPS[3:0] sets the clock division factor
	CLKPSR = 0;

	// set up Output Compare A
	// WGM[3:0] is set to 0010
	// prescaler is set to clk/1 (001)
	TCCR0A = 0;
	TCCR0B = (1 << CS00) | (1 << WGM02);
	// set Output Compare A value
	OCR0A = 1;
	// enable Output Compare A Match interrupt
	TIMSK0 |= (1 << OCIE0A); 
	
	// enable interrupts
	sei();
	
	// set pin directions as output
	DDRB |=  (1 << PB1) ;
	
}

Thank you in advance.

I moved your topic to an appropriate forum category @r0ck1.

In the future, please take some time to pick the forum category that best suits the subject of your topic. There is an "About the _____ category" topic at the top of each category that explains its purpose.

This is an important part of responsible forum usage, as explained in the "How to get the best out of this forum" guide. The guide contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.

1 Like

Please post the code, using code tags, and specify the CPU clock rate.

Using the 8 MHz internal RC clock, the base overflow rate of Timer0 in 8 bit mode is 31 kHz.

Please see the code above, which I have just modified. Thanks

To achieve or exceed 20 kHz PWM with an 8 MHz clock, you need to use 8 bit fast PWM or CTC mode with 8 bits as TOP.

The choices are limited, as 8 MHz/256 = 31250 Hz.

1 Like

This will give you a 20KHz PWM on PB0 (OC0A output)

Lowering ICR0 value will increase the PWM frequency, so you can change that to tune it to the exact frequency you need. (e.g. mine needed 387 to get 20KHz in my frequency counter).

Changing OCR0A sets the duty-cycle

I used inverted PWM mode, or you will have problems switching the pin off completely. Now the pin is off at TOP value. You will see that in the demo, where I keep it "off" for about a second. After that it turns fully on and fades away.

#include <avr/delay.h>
int main(void){
  // Set CPU speed by setting clock prescaler:
  // CCP register must first be written with the correct signature - 0xD8
  CCP = 0xD8;
  //  CLKPS[3:0] sets the clock division factor
  CLKPSR = 0;
  DDRB |=  _BV(PB0) ;  // Set OC0A pin as output
  ICR0 = 400; //  8Mhz / 20KHz = 400 (400 as top will generate 20KHz PWM)
  // Set OC0A on Compare Match, clear OC0A at BOTTOM (inverting mode)
  // Also set WGM01 bit as part of selecting fast PWM mode 
  TCCR0A = _BV(COM0A1) | _BV(COM0A0) | _BV(WGM01); 
  // set clock to no prescaling and select other 2 WGM bits for fast PWM mode with ICR0 as TOP
  TCCR0B = _BV(CS00) | _BV(WGM03) | _BV(WGM02); 
 while (1){
  OCR0A++;
  if (OCR0A == ICR0) {
  _delay_ms(1000);
    OCR0A = 0;
  }
  _delay_ms(5);
 }
}
1 Like

@hmeijdam Thank you, able to gen 20kHZ on PB1

That's just a small change as PB1 is OCR0B.
Below sketch generates 20KHz PWM with 50% duty-cycle on PB1

int main(void){ 
  CCP = 0xD8;
  CLKPSR = 0;
  DDRB |= _BV(PB1);
  ICR0 = 400; 
  OCR0B = ICR0 / 2; // 50% dutycycle
  TCCR0A = _BV(COM0B1) | _BV(COM0B0) | _BV(WGM01); 
  TCCR0B = _BV(CS00) | _BV(WGM03) | _BV(WGM02);
  }

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.