Search This Blog

Saturday, December 3, 2011

Pulse Width Modulation (PWM) Calculations for PIC Micros

   Pic micros are really awesome little chips, and Microchip does a really good job documenting them.  Usually.  Sometimes, though, their docs assume something that I just completely fail to know about.  One such area was using their built in PWM on the CCP modules.  I could get them working.  I just cheated and used this Pic PWM Calculator.  But, reading their data sheets, I could never understand how the values were computed.  Tonight, I finally took some time to get it.  Here are the fruits of my labors.

   First, a review.  PWM wants to set up a period and a duty cycle.  The period is the length of time of one pulse cycle.  The duty cycle is the percentage of time in the period that the pulse will be high.  For Pic micros, the period is set with register PR2.  The duty cycle is a bit more complex.  It is shared between a register, such as CCPRnL and two bits in a control register such as CCPCONn<5:4>.  The lease significant bits are stored in the CCPCON<5:4> bits.  I'll talk about the simple Pic16F88.  It only has one CCP module, so the CCP register is CCPR1L and the control register is CCPCON. 

   First, the period must be set in register PR2.  For this example, we will set a 38 kHz period for a Pic16F88, running at 8 MHz.  The data sheet says that:

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

A bit of algebra turns that into:

       PR2 = ( PWM Period / ( TOsc x 4 x TMR2 Prescaler ) ) - 1

Definitions:
       PWM Period = 1 / PWM frequency
       TOsc = 1 / MCU clock frequency

So, this looks like this for our 8 MHz Pic for a 38 kHz PWM:

       PR2 = ( ( 1/pulse frequency in Hz ) / ( 1/clock speed x 4 x prescaler value ) ) - 1
       PR2 = ( ( 1/38,000 ) / ( 1/8,000,000 ) x 4 x 1 ) ) - 1
       PR2 = ( ( .0000263 ) / ( .000000125 ) x 4 x 1 ) - 1
       PR2 =  52.6 - 1
       PR2 =  51.6 ( use 52 )

So, PR2 will get the value decimal 52 ( 0x34 ).  The prescaler worked with a simple x1 modifier, so TM2Con will be 0x04 ( 0b00000100 ).  If the value had been greater than 255, the TMR2 prescaler allows values of 1, 4, and 16.  Plug each value into the equation to get a PR2 value between 1 and 255.  If the value is still out of range, the PWM module cannot provide that frequency.  This is especially true of low frequencies needed for servo control.  It is fairly easy to implement those in software.  I've written code that controls 16 servos in software with interrupts.  I'll post that at some point.

    Now, for the duty cycle.  This is the part that drove me nuts.  The data sheet states that the duty cycle is:

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

   I couldn't for the life of me get this to translate into sensible values.  I used the PWM calculator to reverse engineer the equation.  Here are the definitions I came up with.

    Duty Cycle = ( 1/ pwm freq ) x percentage
    TOsc = 1 / clock freq.

    So, if I have a FOsc of 8 MHz and want 38 kHz at 50% duty cycle:

    Duty Cycle = ( 1 / 38,000 ) x .50 = .0000132
    TOsc = .000000125
    (CCPR1L:CCP1CON<5:4>) = .0000132 / .000000125 = 105.6
    use 106, in binary = 0b1101010
    So CCPR1L gets 0b11010 and CCP1CON<5:4> gets the lsbs: 0b10

   No matter what, the least significant bits go into CCP1CON<5:4>.  The rest goes into CCPR1L.  Note that the value for duty cycle is only 7 bits long, so my resolution is 7 bits for 38 kHz at 8 MHz.  That's it!

EDIT:
   I've been looking this over again.  The Duty Cycle is the percentage of the period frequency.  So, 50% of 38KHz is:
1/38000*.5 = 1.3157e-5 or ~ 0.00001316
0.0000132 * 8e6 = 105.6

This seems easier to think about.  It's just 1/pwm freq. * percentageAsDecimal * FOsc / prescaler.





13 comments:

  1. I was having exactly the same problem with the pic 18f4550, thank you dude!

    ReplyDelete
  2. Hey! Glad it helped. That is my current favorite Pic to use!

    ReplyDelete
  3. awesome i too was very confused to find duty cycle....thanks!!!

    ReplyDelete
  4. Thanks a lot man. U did awesome job.

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. This is a God-Send!! The Datasheet is too cryptic to decipher and understand..

      Delete
  6. This is a God-Send!! The Datasheet is too cryptic to decipher and understand.. Thanks a million, Tom! Scored the internet and most of the implementors point to some sort of calculator and use those to fill in the registers and some calculations done on the internet are more cryptic than the datasheet itself! I was totally frustrated and overwhelmed.. Thanks again for simplifying it ..

    ReplyDelete
  7. good stuff for explanation the calulation for the pwm signal very useful to my report

    thanks the fruits of your labors :D :D :D

    ReplyDelete
  8. Please can you do calculation for dspic30f2010 with clock frequency of 6.144mhz to generate 19.8khz.

    ReplyDelete
  9. THANKS YOU!

    I've been banging my head against the wall trying to decipher the duty cycle for a little while now.....

    So much help :)

    ReplyDelete
  10. weird i put the values into my pic12f1840 and its does not reproduce the required frequency, Its odd how the CCP1CON register is a configuration register not a setting register so it fails.

    ReplyDelete