On the Atmel ATmega328P (datasheet), there are three timers available for PWM generation (timer0, timer1, and timer2).
I already have what I need using the 8-bit timer2, I am just concerned with using different timer instad of timer2, because timer2 is used in various libraries, and I'd like to have more granularity. Thus I'd like to use the 16-bit timer1.
Here is what I am using to generate a 25 kHz, variable duty cycle using timer2. For this example, lets consider a 35% duty cycle:
void setup()
{
/*
16*10^6/ [prescalar] / ([OCR2A]) / 2 = [desired frequency]
16*10^6/ 8 / [OCR2A] / 2 = 25*10^3
Prescalar table for Timer2 (from datasheet section 17-9):
CS22 CS21 CS20
0 0 0 = No clock source (Timer/couter stopped)
0 0 1 = clkT2S/(No prescaling)
0 1 0 = clkT2S/8 (From prescaler)
0 1 1 = clkT2S/32 (From prescaler)
1 0 0 = clkT2S/64 (From prescaler)
1 0 1 = clkT2S/128 (From prescaler)
1 1 0 = clkT2S/256 (From prescaler)
1 1 1 = clkT2S/1024 (From prescaler)
*/
pinMode(3, OUTPUT);
TCCR2B = _BV(WGM22) | _BV(CS21);
TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(COM2B0) | _BV(WGM20);
OCR2A = 40;
OCR2B = 16; //40*0.35=16
}
void loop()
{
}
To get the same result using timer1 must be incredibly simple, however I'm not familiar with these registers. I have been looking around for explanations outside the datasheet. I have found this post: Secrets of Arduino PWM, however it only covers the use of timer2.
I have tried the following as per Stephan's suggestion, however it just leads to both outputs (D9 and D10) being held HIGH:
void setup()
{
pinMode(9, OUTPUT); //D9
pinMode(10, OUTPUT); //D10
// Set GPIO for timer1 output for OC1A and OC1B
//DDRB |= (1 << DDB1) | (1 << DDB2);
ICR1 = 0xFFFF;
// 25% duty cycle
OCR1A = 0x0009;
// 75% duty cycle
//OCR1B = 0xBFFF;
//20.14.1, pg170
// set none-inverting mode
TCCR1A |= ((1 << COM1A1) | (1 << COM1B1));
//Table 20-6, pg171
// Fast PWM mode
TCCR1A |= (1 << WGM11);
TCCR1B |= (1 << WGM12) | (1 << WGM13);
// START the timer with no prescaler
TCCR1B |= (1 << CS10);
}
void loop()
{
}
I tried changing everything (ICR1, OCR1A, TCCR1A), but the only combination that did anything different was the following, which gives a 25kHz frequency on D10, and D9 held HIGH, but the HIGH duration is stuck at 4μs regardless of the registers. (I just guessed and checked with OCR1A to get 25kHz. I'm not sure why that works.)
void setup()
{
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
// Set GPIO for timer1 output for OC1A and OC1B
//DDRB |= (1 << DDB1) | (1 << DDB2);
ICR1 = 0xFFFF;
// 25% duty cycle
OCR1A = 0x0009;
// 75% duty cycle
//This line causes both outputs to be held HIGH
//OCR1B = 0xBFFF;
//20.14.1, pg170
// set none-inverting mode
TCCR1A |= ((1 << COM1A1) | (1 << COM1B1));
//Table 20-6, pg171
// Fast PWM mode
TCCR1A |= (1 << WGM11);
TCCR1B |= (1 << WGM12) | (1 << WGM13);
// START the timer with no prescaler
TCCR1B |= (1 << CS10);
}
void loop()
{
}
I'm using an Arduino Nano breakout board for prototyping, with D9 and D10 being the timer1 output pins:
(Image from https://bigdanzblog.wordpress.com)
I've tried changing the board but I have the same result.
Here is relevant information from the datasheet: