Wednesday, August 25, 2021

ATMega16 Timer/Counter0 Phase Correct PWM

 

Introduction

In previous post we demonstrate how to program for fast PWM waveform creates by Timer/Counter0 peripheral module. Beside of fast PWM waveform generation, Timer/Counter0 offers another more precise PWM mode – phase correct PWM.

ATMega16 Timer/Counter0 Phase Correct PWM

Phase Correct PWM Mode

As mentioned in previous post, fast PWM mode waveform has only 8-bit counting register. However a phase correct PWM offer a higher resolution as twice compares to fast PWM mode. This mode is preferred for a precise motor control application.

Operation Of Phase Correct PWM



A high resolution of waveform generation of this mode make by a two-direction countering of Timer/Counter0 register (TCNT0).

ATMega16 Timer/Counter0 Phase Correct PWM
Timing diagram of phase correct PWM mode from device’s datasheet
OC0 flag is set for both counting direction, TCNT0 up counting reaches MAX and TCNT0 down counting reaches BOTTOM.

Waveform generation of this PWM mode has two polarities – non-inverting and inverting output at OC0 pin. A non-inverting waveform generation occurs when up counting (BOTTOM to MAX) that TCNT0 compares with OCR0, and clear OC0 flag at compare match . OC0 flag is set when down counting (MAX to BOTTOM), and it’s clear at compare match.

An inverting phase correct PWM waveform generation its operation is inverse. These two type of waveform creation selected in Timer Control Register (TCCR0).

We can find its output frequency as follow,

ATMega16 Timer/Counter0 Phase Correct PWM
Phase correct PWM output frequency’s equation

Interfacing And Programming

It’s similar to fast PWM mode programming in previous post. However it’s different in register setting and its output frequency. I keep the hardware schematic and connection the same to the previous one’s.

Hardware Interfacing

There’s no change in hardware connection for this tutorial, as it’s already worked in previous tutorial for fast PWM mode.

ATMega16 Timer/Counter0 Phase Correct PWM
Circuit Diagram

ATMega16 supplies at +5V, clocks at 16MHz DC. The odd one’s is its output frequency at OC0/PB3 pin of Port B.



Registers Setting

There are some bits setting in Timer/Counter Control Register (TCCR0).

ATMega16 Timer/Counter0 Phase Correct PWM
Timer/Counter0 Control Register (TCCR0)

In the Waveform Generation Mode Bit, the software must set the WGM00 to force Timer/Counter0 works in phase correct PWM mode.

ATMega16 Timer/Counter0 Phase Correct PWM
Waveform Generation Mode Bit

Output Compare Register (OCR0) is also limit duty cycle of PWM waveform in this mode. Beside crystal oscillator frequency of microcontroller, Clock Select Bit define the PWM output frequency.

ATMega16 Timer/Counter0 Phase Correct PWM
Clock Select Bit of Timer/Counter0 Control Register (TCCR0)

 Polarity of waveform for this PWM mode is selected in Compare Output Mode bit.

ATMega16 Timer/Counter0 Phase Correct PWM
Compare Output Mode for Phase Correct PWM

In this tutorial I preferred a non-inverting phase correct PWM mode. Thus COM01 must be putted to ‘1’.



AVR GCC Programming for Phase Correct PWM

In this tutorial, the microcontroller generate a PWM waveform with a frequency of 122.54Hz. Since microcontroller clock is 16MHz, I set Clock Select Bit to 1:256. Phase correct PWM output frequency is calculated by,

ATMega16 Timer/Counter0 Phase Correct PWM
Calculation for frequency in phase correct PWM mode

To get a 1:256 clock prescaler, the software must set CS02=1. AVR GCC of this minor example is written in Atmel Studio 7 IDE.

  1. /*
  2.  * m16_phaseCorrectPwm.c
  3.  *
  4.  * Created: 12/14/2020 10:15:22 AM
  5.  * Author : admin
  6.  */
  7.  
  8. #include <avr/io.h>
  9.  
  10. int main(void)
  11. {
  12. /*phase correct PWM mode, Non-inverting,
  13.   1:256 Prescaler*/
  14. TCCR0=(1<<WGM00)|(1<<COM01)|(1<<CS02);
  15. /*Set duty cycle to 50%*/
  16. OCR0=127;
  17. /*OC0 outputs PWM waveform*/
  18. DDRB=(1<<3);
  19. /*Main loop do nothing*/
  20. while (1)
  21. {
  22. }
  23. }

We can see the result in Proteus simulator below.

ATMega16 Timer/Counter0 Phase Correct PWM
Simulation result in Proteus simulator

 The output frequency is 122Hz. However we can create a lower frequency using this PWM mode. Click here to download zip file of this working tutorial.

Adjusting Its Duty Cycle

Since Output Compare Register (OCR0) is changeable during run-time, the user can modify its duty cycle of phase correct PWM waveform using this register.



Adding Two Adjusting Buttons

We use two user’s input push button to increase and decrease duty cycle of phase correct PWM waveform. These two buttons change the duty cycle of PWM waveform with a rate of 15.

A button connects to PD2 decrease duty cycle while another one’s connects to PD3 increase its duty cycle.

ATMega16 Timer/Counter0 Phase Correct PWM
Proteus simulation of adjusting duty cycle of phase correct PWM mode

Its frequency remains 122Hz. It excepts its variable duty cycle of waveform.

AVR GCC Source Code



There are some additional lines of code to handle input button events. Main program loop keeps track of input changes of these two buttons, connect to PD2 and PD3.

  1. /*
  2.  * m16_phaseCorrectPwm_btn.c
  3.  *
  4.  * Created: 12/14/2020 10:33:50 AM
  5.  * Author : admin
  6.  */
  7.  
  8. #include <avr/io.h>
  9.  
  10. /*Buttons to change PWM duty cycle*/
  11. #define lower ((PIND&0x04)==0)
  12. #define higher ((PIND&0x08)==0)
  13.  
  14. int main(void)
  15. {
  16. /*phase correct PWM mode, Non-inverting,
  17.   1:256 Prescaler*/
  18. TCCR0=(1<<WGM00)|(1<<COM01)|(1<<CS02);
  19. /*Zero duty cycle*/
  20. OCR0=0;
  21. /*OC0 Pin Output*/
  22. DDRB=(1<<3);
  23. /*PD2 and PD3 as input*/
  24. DDRD&=(1<<2);
  25. DDRD&=(1<<3);
  26. /*Turn PD2 and PD3 High*/
  27. PORTD=(1<<3)|(1<<2);
  28. while (1)
  29. {
  30. /*Decreasing PWM Duty Cycle*/
  31. if (lower)
  32. {
  33. /*Wait Until PD2 released*/
  34. while(lower);
  35. /*Decrease Duty Cycle By 15*/
  36. if(OCR0>0) OCR0-=15;
  37. }
  38. /*Increasing PWM Duty Cycle*/
  39. if (higher)
  40. {
  41. /*Wait Until PD3 released*/
  42. while(higher);
  43. /*Increase Duty Cycle By 15*/
  44. if(OCR0<250) OCR0+=15;
  45. }
  46. }
  47. }
  48.  
  49.  

There’s no need to test this program on AVR development board due to duplication, as a similar work was already done in previous article. Click here to download zip file of this working example.



No comments:

Post a Comment

Labels

ADC (10) Analog (14) Arduino (12) Atmega16 (19) Audio (2) AVR (20) Charger (1) Cortex-M0 (1) Counter (10) CPLD (25) Digital I/O (22) Display (34) EEPROM (2) Environment Sensor (1) esp8266 (2) Experiment Board (10) I2C (4) Interrupt (7) LCD (1) LDmicro (29) measurement and instrumentation (7) Microchip Studio (3) MikroC (1) One-Shot (3) OpAmp (1) PCB (31) PIC16 Microcontrollers (16) PIC16F877A (2) PIC16F887 MikroC (22) PLC (35) PWM (11) Regulator (1) RTC (2) Sensor (8) Shift Registers (5) SPI (5) Timer (34) UART (2) ultra-sonic sensor (1) USB (1) VHDL (21) xc8 (1) XC95108 (9) XC9536 (15) XC9572 (1) Xilinx (23) Xilinx ISE (22)