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) ;
}
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 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);
}
}