## PWM generation mode of CPP

### PWM Mode

#### PWM Mode Block Diagram

In Pulse-Width Modulation (PWM) mode, the CCPx pin produces up to a 10-bit resolution PWM output. Since the CCP2 pin is multiplexed with a PORTB or PORTC data latch, the appropriate TRIS bit must be cleared to make the CCP2 pin an output.Figure shows a simplified block diagram of the CCP module in PWM mode. For a step-by-step procedure on how to set up the CCP module for PWM operation, see Section “Setup for PWM Operation”.

#### PWM Mode block Diagram and Explanation

##### PWM period

It is specified by writing to the PR2 register. The PWM period can be calculated using the following formula:

PWM Period=[(PR2)+1]• 4 • TOSC • (TMR2 Prescale Value)

##### PWM frequency

It is defined as 1/[PWM period]. When TMR2 is equal to PR2, the following three events occur on the next increment cycle:

PWM frequency= 1/ [PWM period]

• TMR2 is cleared
• The CCPx pin is set (exception: if PWM duty cycle = 0%, the CCPx pin will not be set)
• The PWM duty cycle is latched from CCPRxL into CCPRxH
##### PWM DUTY CYCLE

The PWM duty cycle is specified by writing to the CCPRxL register and to the CCPxCON<5:4> bits. Up to 10-bit resolution is available.
The CCPRxL contains the eight MSbs and the CCPxCON<5:4> bits contain the two LSbs.
This 10-bit value is represented by CCPRxL:CCPxCON<5:4>. The following equation is used to calculate the PWM duty cycle in time

PWM Duty Cycle = (CCPRXL:CCPXCON<5:4>) • TOSC • (TMR2 Prescale Value)

##### Set-Up for PWM Operation

CCPRxL and CCPxCON<5:4> can be written to at any time, but the duty cycle value is not latched into CCPRxH until after a match between PR2 and TMR2 occurs (i.e., the period is complete). In PWM mode, CCPRxH is a read-only register.
The following steps should be taken when configuring the CCP module for PWM operation:

1. Set the PWM period by writing to the PR2 register.
2. Set the PWM duty cycle by writing to the CCPRxL register and CCPxCON<5:4> bits.
3. Make the CCPx pin an output by clearing the appropriate TRIS bit.
4. Set the TMR2 prescale value, then enable Timer2 by writing to T2CON.
5. Configure the CCPx module for PWM operation.

#### Numerical -1

##### Program:- Write an embedded C program to generate PWM waveform of 1Khz frequency with 25%,50%,75%,100% Duty cycle. Assume XTAL= 4 MHz and Prescaler = 4.Observe the output on Digital oscilloscope
Solution :-
Given XTAL= = fosc   i.e.    4 MHz
Prescaler i.e. N = 4
fpwm = 1 KHz
Duty cycle = 25% , 50%, 75%, 100%
i) Value to be loaded in Period Register2 (PR2) = [  (fOSC ) / 4X fPWM  x N ] -1  =249

Case-1  For 25% Duty cycle
ii) Value to be loaded in Duty cycle register (CCPRxL) = %Duty Cycle x PR2 Value

= 0.25 x 249
= 62.25
= 62 Integer value                {0.25 value after decimal point will be loaded by Duty cycle bits from CCPxCON Register}
iii) Value to be loaded in CCPxCON = 0x1C    // 0.25 value after decimal point , PWM mode of operation of CCP module
Case-2  For 50% Duty cycle

ii) Value to be loaded in Duty cycle register (CCPRxL) = %Duty Cycle x PR2 Value
= 0.5 x 249
= 124.50
= 124 Integer value                {0.50 value after decimal point will be loaded by Duty cycle bits from CCPxCON Register}
iii) Value to be loaded in CCPxCON = 0x2C // 0.50 value after decimal point , PWM mode of operation of CCP module
Case-3  For 75% Duty cycle

ii) Value to be loaded in Duty cycle register (CCPRxL) = %Duty Cycle x PR2 Value
= 0.75 x 249
= 186.75
= 186 Integer value                {0.75 value after decimal point will be loaded by Duty cycle bits from CCPxCON Register}
iii) Value to be loaded in CCPxCON = 0x3C // 0.75 value after decimal point , PWM mode of operation of CCP module
Case-4  For 100% Duty cycle

ii) Value to be loaded in Duty cycle register (CCPRxL) = %Duty Cycle x PR2 Value
= 1 x 249
= 249.00
= 249 Integer value                {0.00 value after decimal point will be loaded by Duty cycle bits from CCPxCON Register}
iii) Value to be loaded in CCPxCON = 0x0C // 0.00 value after decimal point , PWM mode of operation of CCP module

##### Embedded C Program

#include<p18f458.h>
#pragma config OSC=HS
#pragma config PWRT=OFF
#pragma config WDT=OFF
#pragma config DEBUG=OFF, LVP=OFF
void DELAY();
void main()
{
TRISC=0x00;   ///RC2 pin as PWM output pin
PR2=249;      ////PR2=(Fosc/4xNxFpwm)
T2CON=0X01;  ///Prescaler=4
while(1)      ///forever loop
{
CCPR1L=62;       //25% Duty cycle
CCP1CON=0X1C;    ///PWM mode, DCB1:DCB0=0.25 Decimal points
DELAY();
CCPR1L=124;       //50% Duty cycle
CCP1CON=0X2C;///PWM mode, DCB1:DCB0=0.50 Decimal points
DELAY();
CCPR1L=186;     //75% Duty cycle
CCP1CON=0X3C;///PWM mode, DCB1:DCB0=0.75 Decimal points
DELAY();
CCPR1L=249;           //100% Duty cycle
CCP1CON=0X0C;///PWM mode, DCB1:DCB0=0.00 Decimal points
DELAY();
PIR1bits.TMR2IF=0;        //Clear interrupt flag
T2CONbits.TMR2ON=1;        //start timer 2
while(PIR1bits.TMR2IF==0);  ///monitor TMR2 interrupt flag
}
}

void DELAY()
{
unsigned int i,j;
for(i=0;i<100;i++)
for(j=0;j<100;j++);
}

#### Numerical-2

##### Program:- Write an embedded C program to generate PWM waveform of 2.5 KHz and 75% Duty cycle with N=4, XTAL=10 MHz
Solution :-
Given XTAL= = fosc   i.e.    10 MHz
Prescaler i.e. N = 4
fpwm = 2.5 KHz
Duty cycle =75%
i) Value to be loaded in Period Register2 (PR2) = [  (fosc ) / 4X fpwm  x N ] -1  = 249

Case-  For 75% Duty cycle

•     ii) Value to be loaded in Duty cycle register (CCPRxL) = %Duty Cycle x PR2 Value

= 0.75 x 249
= 186.75
= 186 Integer value          {0.75 value after decimal point will be loaded by Duty cycle bits from CCPxCON Register}
iii) Value to be loaded in CCPxCON = 0x3C // 0.75 value after decimal point , PWM mode of operation of CCP module

##### Embedded C program
#include<p18f458.h>
#pragma config OSC=HS
#pragma config PWRT=OFF
#pragma config WDT=OFF
#pragma config DEBUG=OFF, LVP=OFF
void DELAY();
void main()
{
TRISC=0x00;   ///RC2 pin as PWM output pin
PR2=249;      ////PR2=(Fosc/4xNxFpwm)
T2CON=0X01;  ///Prescaler=4
while(1)      ///forever loop
{
CCPR1L=186;     //75% Duty cycle
CCP1CON=0X3C;///PWM mode, DCB1:DCB0=0.75 Decimal points
DELAY();
PIR1bits.TMR2IF=0;        //Clear interrupt flag
T2CONbits.TMR2ON=1;        //start timer 2
while(PIR1bits.TMR2IF==0);  ///monitor TMR2 interrupt flag
}
}

void DELAY()
{
unsigned int i,j;
for(i=0;i<100;i++)
for(j=0;j<100;j++);
}

#### References

• Created and Developed by Sujit wagh, SKNCOE
• WikiNote Foundation