Electrical – How to manipulate timer1 / timer2 in arduino nano to get HS PWM


I'm new to arduino but have coded a few projects in AVR ASM years ago.

Now I'd like to manipulate t1/t2 to get high speed pwm. I can lower the resolution from 511(?) to 63. And maybe mess with the prescaler. It would be nice if millis() are left intact. Can it be done, or do I need to get out of the arduino umbrella?

Best Answer

I assume that "an arduino" refers to an ATmega328 -based arduino board.

The arduino initializes timer 0 for keeping count of elapsed microseconds/milliseconds, allowing us to use timer 1 and timer 2 as we please.

Since you asked if the resolution can be set to 511, we have to use the 16-bit timer 1 which can count from 0 to 65535 (actually 65536 steps, not 65535 as your thinking seems to imply). Timer 2 is an 8-bit timer, so it can only count from 0 to 255 (256 steps). You can configure either timer to restart counting at any arbitrary value.

//the timer outputs have to be set explicitly as outputs
pinMode(9, OUTPUT); 
//pinMode(10, OUTPUT);
TCCR1B = (1 << WGM13) | (1 << WGM12);//waveform generation mode 1110: fast (single  
TCCR1A = (1 << WGM11) | (0 << WGM10) //..slope) PWM, counter TOP (resolution) = 1 + ICR1
       | (0b10 << COM1A0)  //output compare A PWM output enabled, non-inverting (pin ~9)
       | (0b00 << COM1B0); //output compare B output disabled (pin ~10)
TCNT1 = 0; //reset the current count to 0, just in case
ICR1 = 510; //set the timer TOP value (resolution to 510 + 1)
OCR1A = 0; //set the output compare unit A duty cycle to 0
//OCR1B = 0; //set the output compare unit B duty cycle to 0. 
//Finally start the timer by selecting a clock sourve
TCCR1B |= (0b001 << CS10); //timer 1 clock source = CLKio / 1 (no prescaling), 16 MHz

In this configuration the timer is in fast PWM mode. The timer counts up from 0. After the counter value matches with TOP(ICR1 in this configuration), the next cycle will set the timer to 0 instead of incrementing it.

The current setup would produce a 31311.15 kHz PWM output. If you want a lower frequency, you could set the prescaler to a higher value, but it would lower the resolution. It makes more sense to just increase the TOP value. For example, ICR1 = 15999 would produce a 1 kHz output with a resolution of 16000 steps, no prescaling required.

The output duty cycle is controlled by the respective output compare registers. The value can range anywhere from 0 to TOP (inclusive), but going higher would cause the output to never reset. For example, to generate a 10% duty cycle at 20 kHz you would set ICR1 to 799 and OCR1A to 80.

For more in-depth information, refer to the datasheet