I need to generate PWM signal with PIC18F2550 microcontroller at near 20kHz. I read the datasheet, I found it too complex and confusing, then I started to search for a sample code on the net to finally see this PWM tool.

I used it with parameters \$ F_{OSC} \$=20MHz and \$ F_{PWM} \$=20kHz to generate these two different codes for corresponding two different duty cycle percentages.

// Duty cycle = 0%
PR2 = 0b11111001 ;
T2CON = 0b00000100 ;
CCPR1L = 0b00000000 ;
CCP1CON = 0b00001100 ;

// Duty cycle = 100%
PR2 = 0b11111001 ;
T2CON = 0b00000100 ;
CCPR1L = 0b11111001 ;
CCP1CON = 0b00111100 ;

The datasheet tells me that the 4th and 5th bits of the CCP1CON register are the LSBs of the "PWM duty cycle with" value, and its MSBs are stored in the CCPR1L register, isn't it?

That makes, for 0% duty cycle, the 10-bit PWM duty cycle timing is,

00000000 + 00 = 0x000

And for 100% duty cycle,

11111001 + 11 = 0x3E7

So, according to this tool, I must set the values between 0x000 and 0x3E7 to the relevant PWM registers to have duty cycle ratios between 0% and 100%. At this point I become confused and the following questions arise in my mind:

  • What is this 0x3E7 value? How is it calculated? How would I find it myself if I hadn't had such an online tool?
  • What is the resolution of this PWM signal (i.e.; what is the time difference of length of two duty cycles for two sequential values like 0x3E6 and 0x3E7)?
  • Why can't I load higher values to the CCPR1L register like all ones (0xFF); that would make 0x3FF for the overall PWM duty cycle length value. What happens if I do so?
  • The tool says that, I can use PWM feature only with 9-bit resolution with the working parameters I specified. So, why the number 0x3E7 is a 10-bit number? Is the "9-bit" comes from integer truncated value of \$log_2(0x3E7)\$?

This happened to be a long question, but it would help me greatly if someone kindly explains me the overall steps and logic of PWM signal creation with PIC microcontrollers.



I know it's a bit late, but I've just got this sabe doubt. After looking around, I've come across this Microchip Doc that shows some examples.

First, we calculate \$\text{PR2}\$. From this formula,

$$ F_\text{PWM} = \dfrac{1}{(\text{PR2} + 1) \times 4 \times T_\text{OSC} \times \text{T2CKPS}} $$

we get

$$ \text{PR2} = \dfrac{1}{F_\text{PWM} \times 4 \times T_\text{OSC} \times \text{T2CKPS}} - 1 $$

where \$T_\text{OSC} = 1/F_\text{OSC}\$, and \$\text{T2CKPS}\$ is the Timer2 prescaler value (1, 4 or 16).

Therefore, if we want \$F_\text{PWM} = 20\text{kHz}\$, and choosing \$\text{T2CKPS} = 1\$, we get \$\text{PR2} = 249\$. We should choose higher values for \$\text{T2CKPS}\$ only if \$\text{PR2}\$ exceeds 8 bits (\$\text{PR2} \gt 255\$) for the given prescale.

Now we calculate the max PWM resolution for the given frequency:

$$ \text{max PWM resolution} = \log_2(\;\dfrac{F_\text{OSC}}{F_\text{PWM}}\;) $$

That gives us \$9.9658\$ bits (I know, it sounds weird, but we'll use it like that later).

Now, let's calculate the PWM duty cycle. It is specified by the 10-bit value \$\text{CCPRxL:DCxB1:DCxB0}\$, that is, \$\text{CCPRxL}\$ bits as the most significant part, and \$\text{DCxB1}\$ and \$\text{DCxB0}\$ (bits 5 and 4 of \$\text{CCPxCON}\$) the least significant bits. Let's call this value \$\text{DCxB9:DCxB0}\$, or simply \$\text{DCx}\$. (x is the CCP number)

In our case, since we have a max PWM resolution of \$9.9658\$ bits, the PWM duty cycle (that is, the value of \$\text{DCx}\$) must be a value between \$0\$ and \$2^{9.9658} - 1 = 999\$. So, if we want a duty cycle of 50%, \$\text{DCx} = 0.5 \times 999 = 499.5 \approx 500\$.

The formula given on the datasheet (also on the linked doc),

$$\text{duty cycle} = \text{DCx} \times T_\text{OSC} \times \text{T2CKPS}$$

gives us the pulse duration, in seconds. In our case, it's equal to \$25\text{ns}\$. Since \$T_\text{PWM} = 50\text{ns}\$, it's obvious that we have a 50% duty cycle.

That said, to calculate DCx in terms of duty cycle as \$r \in [0,1]\$, we do:

$$ \text{DCx} = \dfrac{r \times T_\text{PWM}}{T_\text{OSC} \times \text{T2CKPS}} = \dfrac{r \times F_\text{OSC}}{F_\text{PWM} \times \text{T2CKPS}} $$

Answering your other questions:

2) The resolution of your PWM pulse with period \$T_\text{PWM}\$ is

$$ \dfrac{T_\text{PWM}}{2^\text{max PWM res}} $$

3) Because CCPRxL, along with DCxB1 and DCxB0, determine the pulse duration. Setting CCPRxL with a higher value than \$2^\text{max PWM res} - 1\$ means a pulse duration higher than the PWM period, and therefore you'll get a flat \$V_{DD}\$ signal.


When using a 1:1 prescalar on TMR2, the CCPR1L value represents the whole number of CPU cycles of "on time" for each PWM cycle. With a 4:1 prescalar, it represents the number of four-cycle count increments, etc.

Bit 0 of the CCP1CON register delays each turn-off cycle by 1/4 of a count increment; bit 1 deelays it by 1/2. The effects are cumulative. Note that on older PICs these bits have no effect if CCPR1L is zero; if the output never turns on, delaying the turn-off won't have any effect.

The value in PR2 sets the interval between the start of one PWM cycle and the start of the next. If one sets PR2 to a value of 99 and selects a 1:1 prescalar, then a PWM cycle will start every 100 clock cycles (one larger than the programmed value). If one sets CCPR1L to 12 and sets the two lower bits of CCP1CON to '1','0', then every 100 CPU cycles the PWM output will be high for twelve full CPU cycles plus an additional half cycle, for a net duty cycle of 1/8.

  • \$\begingroup\$ what does resolution mean in PWM? and how does it change as the value of PR2 register value? \$\endgroup\$ – noufal Oct 11 '13 at 10:42

Not the answer you're looking for? Browse other questions tagged or ask your own question.