# PWM for crude DAC from the PIC18F47J53

#### spinnaker

Joined Oct 29, 2009
7,835
I am trying to create a crude DAC by using PWM on the PIC18F47J53.

The datasheet says the following:

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

But then goes on to say:

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

I am really confused at how to generate say 10%, 20, % 30%, 40%, 50% etc etc duty cycle.

Do I also need to manipulate the prescaler?

Currently all I am doing is to manipulate CCPR4L and CCP4CONbits.DC4B to change my duty cycle.

Below is my code.. I am using Timer4. Changing the period on Timer 2 seems to be affect the baudrate of my EUSART for some reason but the datasheet does not seem to mention T2 is used for baudrate and least not from what I am understanding.

I am getting PWM out but I can't seem to make sense of how to control my duty cycle.

My chip is currently running ant 8MHZ on the internal oscillator.

Code:
void pwm_init()
{
T4CONbits.TMR4ON = 0;  // STOP TIMER2 registers to POR state
PR4 = 0;  // Set period

// Set prescaler
T4CONbits.T4CKPS0 = 0;
T4CONbits.T4CKPS1 = 0;

TRISBbits.TRISB4 = 0;  // Set B4 to output
TRISBbits.TRISB5 = 0;  // Set B5 to output
TRISBbits.TRISB6 = 0;  // Set B6 to output

CCP4CON = 0b0111100;  // Set CCP4 to PWM

CCP5CON = 0b0001100;  // Set CCP5 to PWM
CCP6CON = 0b0001100;  // Set CCP6 to PWM

CCPR4L = 0;
CCPR5L = 0;
CCPR6L = 0;

CCPTMRS1 = 1;  //Set clock to T4 for all CCP registers

T4CONbits.TMR4ON = 1;  // Turn on T2

}

void pwm_setDuty4(unsigned duty)
{
CCPR4L = (unsigned char)duty & 0x00ff;
CCP4CONbits.DC4B = ((duty & 0xff00) >> 8);

}

#### be80be

Joined Jul 5, 2008
2,022
PWM Period = [(PR2) + 1] • 4 • T OSC •
(TMR2 Prescale Value)
Timer 2 set's the frequency
Use timer1 for uart

Last edited:

#### spinnaker

Joined Oct 29, 2009
7,835
PWM Period = [(PR2) + 1] • 4 • T OSC •
(TMR2 Prescale Value)
Timer 2 set's the frequency
Use timer1 for uart

I can read the datasheet and you are pretty much parroting what is in the datasheet. So I don't see how this answers my question.

As far as I know you can't choose the timer to be used for aync UART so I don't know what you are trying to say either.

Last edited:

#### be80be

Joined Jul 5, 2008
2,022
The peripherals managed by the PPS are all digital
only peripherals. These include general serial commu-
nications (UART and SPI), general purpose timer clock
inputs, timer-related peripherals (input capture and
output compare) and external interrupt inputs. Also
included are the outputs of the comparator module,
since these are discrete digital signals.

Guess you read that too sorry for trying to point you to the right parts.

#### spinnaker

Joined Oct 29, 2009
7,835
I found this:

The peripherals managed by the PPS are all digital
only peripherals. These include general serial commu-
nications (UART and SPI), general purpose timer clock
inputs, timer-related peripherals (input capture and
output compare) and external interrupt inputs. Also
included are the outputs of the comparator module,
since these are discrete digital signals.

Guess you read that too sorry for trying to point you to the right parts.

#### be80be

Joined Jul 5, 2008
2,022
Don't worry I'm not you always had something to say so not much sense trying to help you.
You just reminded me why I stopped posting here long ago have a good go with this.

#### spinnaker

Joined Oct 29, 2009
7,835
OK Update. First I was incorrect on my FOSC. It is not 8MHZ but 2MHZ.

I think my baud rate issues are unrelated to my timer. I am seeing the same issues using T4 too. I think it might just be a flaky HC05.

I found this post;

http://thelast16bits.blogspot.com/2011/12/pulse-width-modulation-pwm-calculations.html

It explains the math pretty well and how to figure out the value for duty cycle. So based on that article I put together the attached spreadsheet (hopefully everyone has Open Office).

If I did my math correctly at an 2MHZ clock and a 50Khz for my PWM and a 1 in the prescaler my PR2 register would be loaded with a 24.

To get a 50% duty cycle I would load with a 50. When I do that I get what looks to be 100% duty cycle. In fact I can't load much more than a 30.

This is with 12 in CCPR4L. That looks pretty close to 50% to me so either my math is off or my FSOC is not running at what I think it is running.

Here is my osc setup. That should be 2MHZ according to the datasheet. Unless I am reading it wrong.
Code:
OSCCONbits.IRCF0 = 1;
OSCCONbits.IRCF1 = 0;
OSCCONbits.IRCF2 = 1;

Code:
void pwm_init()
{
T2CONbits.TMR2ON = 0;  // STOP TIMER2 registers to POR state
PR2 =24;  // Set period

// Set prescaler
T2CONbits.T2CKPS0 = 1;
T2CONbits.T2CKPS1 = 0;

TRISBbits.TRISB4 = 0;  // Set B4 to output
TRISBbits.TRISB5 = 0;  // Set B5 to output
TRISBbits.TRISB6 = 0;  // Set B6 to output

CCP4CON = 0b0001100;  // Set CCP4 to PWM

CCP5CON = 0b0001100;  // Set CCP5 to PWM
CCP6CON = 0b0001100;  // Set CCP6 to PWM

CCPR4L = 50;
CCPR5L = 0;
CCPR6L = 0;

CCPTMRS1 = 0;  //Set clock to T2 for all CCP registers

T2CONbits.TMR2ON = 1;  // Turn on T2

}

Last edited:

#### OBW0549

Joined Mar 2, 2015
3,295
If I'm remembering correctly, the PWM operates at oscillator speed, not CPU clock speed; so you should be seeing it run at 4X the speed you expected here:

This is with 12 in CCPR4L. That looks pretty close to 50% to me so either my math is off or my FSOC is not running at what I think it is running.
If you've loaded 24 into the period register, then loading 12 into the CCPR4L:CCP4CON<5:4> registers would give you a 50% duty cycle (12/24) as you've observed. Loading 6 into CCPR4L:CCP4CON<5:4> would give you 25% (6/24); loading 18 would give you 75% (18/24), and so forth.

The prescaler doesn't affect the % duty cycle, only the frequency of the PWM output. If you want a fast PWM, use 1 for the prescaler; if you want slower, use a higher number (4, 16 or whatever).

Last edited:

#### MMcLaren

Joined Feb 14, 2010
842
Your PRx setting of 25-1 should allow you to set duty cycle in 1% increments using duty cycle values of 0 to 100. If you don't want to mess with those two least significant duty cycle bits you could use a PRx value of 100-1 and simply update CCPRxL with a value of 0 to 100.

Hope this helps.

Cheerful regards, Mike

#### spinnaker

Joined Oct 29, 2009
7,835
If I'm remembering correctly, the PWM operates at oscillator speed, not CPU clock speed; so you should be seeing it run at 4X the speed you expected here:

If you've loaded 24 into the period register, then loading 12 into the CCPR4L:CCP4CON<5:4> registers would give you a 50% duty cycle (12/24) as you've observed. Loading 6 into CCPR4L:CCP4CON<5:4> would give you 25% (6/24); loading 18 would give you 75% (18/24), and so forth.

The prescaler doesn't affect the % duty cycle, only the frequency of the PWM output. If you want a fast PWM, use 1 for the prescaler; if you want slower, use a higher number (4, 16 or whatever).

Ahh yes FOSC is actually OSC/4. Man do I feel stupid. I have been away from this stuff for a while and I am getting old and I forget stuff easily.

OK it is late and I am really brain dead now. How do I calculate the value for CCPR4L:CCP4CON for a 50% duty cycle?

Is it not (TOSC*prescaler)/.5 ??

#### spinnaker

Joined Oct 29, 2009
7,835
The prescaler doesn't affect the % duty cycle, only the frequency of the PWM output. If you want a fast PWM, use 1 for the prescaler; if you want slower, use a higher number (4, 16 or whatever).
According to the datasheet it does

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

Which isn't making sense when I do the math. Assuming I am doing it right.

#### spinnaker

Joined Oct 29, 2009
7,835
Your PRx setting of 25-1 should allow you to set duty cycle in 1% increments using duty cycle values of 0 to 100. If you don't want to mess with those two least significant duty cycle bits you could use a PRx value of 100-1 and simply update CCPRxL with a value of 0 to 100.

Hope this helps.

Cheerful regards, Mike

With what in the prescale registers?

with a 0 in prescale and a 24 in PR2, I get 50% at around 13.

Code:
T2CONbits.TMR2ON = 0;  // STOP TIMER2 registers to POR state
PR2 =24;  // Set period

// Set prescaler
T2CONbits.T2CKPS0 = 0;
T2CONbits.T2CKPS1 = 0;

#### MMcLaren

Joined Feb 14, 2010
842
According to the datasheet it does

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

Which isn't making sense when I do the math. Assuming I am doing it right.
That formula is for calculating the PWM duty cycle in TIME. Duty cycle percentage is the duty cycle "on" time divided by the period x 100...

#### MMcLaren

Joined Feb 14, 2010
842
With what in the prescale registers?

with a 0 in prescale and a 24 in PR2, I get 50% at around 13.

Code:
T2CONbits.TMR2ON = 0;  // STOP TIMER2 registers to POR state
PR2 =24;  // Set period

// Set prescaler
T2CONbits.T2CKPS0 = 0;
T2CONbits.T2CKPS1 = 0;
The timer prescaler doesn't affect duty cycle.

If you're putting 13 in CCPRxL and ignoring the two least significant duty cycle bits, that's about right (52%). You see a duty cycle value of 52 in binary is '110100' and after you stuff the two least significant bits into CCPxCON you're left with the most significant bits '1101' (13) for the CCPRxL register. Yes, no?

Use a value of 25 ('11001') for a 25% duty cycle. That's CCPRxL = '110' (6d) and CCPxCON-DCxB<1:0> = '01'.

Use a value of 10 ('1010') for a 10% duty cycle. That's CCPRxL = '10' (2d) and CCPxCON-DCxB<1:0> = '10'.

As I mentioned earlier, if you don't want to hassle with the two least significant duty cycle bits in CCPxCON-DCxB<1:0>, just use a value of 100-1 in the PRx period register and use values of 0 through 100 in the CCPRxL register for 0% to 100% duty cycles.

Last edited:

#### spinnaker

Joined Oct 29, 2009
7,835
If I use a PWM frequency of 5K then I get a 50% duty cycle with 50 in CCPR2L My FOSC is actually 200K not 2MHZ as I mention above. But also corrected above.

Why too late now to crunch math. I can barely type.

#### MMcLaren

Joined Feb 14, 2010
842
get some rest and take a fresh look in the mornin'...

#### OBW0549

Joined Mar 2, 2015
3,295
Ah. I see the problem: two different meanings of the term "duty cycle."

When you or I or anyone else in the civilized world think "duty cycle", we're referring to the percentage of time during which the PWM output is high. That's the "normal" way of using the term.

But Microchip isn't normal. When they say "duty cycle", they mean something entirely different: they're referring to the number of counts the PWM output is high, out of the total number of counts in each PWM cycle.

So their formula for duty cycle,

PWM Duty Cycle = (CCPR4L:CCP4CON<5:4>) • TOSC • (TMR2 Prescale Value)​

is correct according to their meaning of the term "duty cycle," but not when talking about percentage duty cycle, which is

% Duty Cycle = (CCPR4L:CCP4CON<5:4>) / PR2​

Tosc and the Prescaler have no effect on the % Duty Cycle; they only affect the PWM frequency.

I hope what I wrote isn't too rambling; I just got up and I still haven't finished my first cup of coffee.

Last edited:

#### spinnaker

Joined Oct 29, 2009
7,835
I updated the spreadsheet with what was learned here. I have included both ODS and XLS file formats.

#### Attachments

• 16.9 KB Views: 2

#### OBW0549

Joined Mar 2, 2015
3,295
I updated the spreadsheet with what was learned here. I have included both ODS and XLS file formats.
I must be missing something. What spreadsheet?