While working on a recent project I needed to generate a PWM signal from my ATMEGA644P in order to operate a
SN754410 motor driver as a speed controller.
To generate the PWM I used the ATMEGA's 8-bit Timer/Counter 2 configured for fast PWM mode. Fast PWM works as follows:
The timer will continually count up from 'bottom' to 'top'. When 'top' is reached the counter will then wrap around and begin counting up from 'bottom' again. In this case we are using an 8 bit timer so 'bottom' will be equal to 0 and top will be equal to 255 decimal or FF hex. When the counter reaches the 'compare' value an output pin will be set. This pin will then reset when the counter wraps around to 'bottom'. We are able to vary the value of 'compare' in order to generate a fixed frequency PWM signal with a variable duty cycle.
In order to set up the timer its registers need to be configured as follows:
Set the Data direction for timer pin set as output
I am using timer 2 output A so pin 7 port D (PD7 OC2A/PCINT31) needs to be set as output:
DDRD |= (1 << PD7)
Set waveform generation mode
Waveform generation mode is set in the two registers TCCR2A and TCCR2B, Timer/Counter Control Registers A and B. I need Fast PWM counting from 0 to 0xFF so I set the registers as:
TCCR2A |= (1 << WGM0)
TCCR2A |= (1 << WGM1)
Set compare output mode
Compare output mode is set in the TCCR2A register:
TCCR2A |= (1 << COM2A0)
TCCR2A |= (1 << COM2A1)
Clock selection
Clock selection is set in the TCCR2B register. I am not concerned about the frequency of the PWM signal so I just select the AVR's clock as without any prescalling.
TCCR2B |= (1 << CS20)
Set the output compare
Lastly the fast PWM's duty cycle needs to be set by adjusting the compare value. This is set in the OCR2A, Output Compare Register A. This register can be written to in any point in software to vary the duty cycle of the output PWM signal.
OCR2A = duty_cycle