1

When I generate PWM on CCP1 only, I am able to get SPWM of 50HZ with 10kHz switching frequency. When I enable the PWM on CCP2 for another SPWM, the frequency of both SPWMs changes. But if I generate it on either 1 of the outputs, it works fine. I am trying to produce 2 SPWMs with 90 degrees phase shift, for sin and cos, both at 50Hz and 10kHz switching frequency.

   void main(void)
{
    ANSELD=0X00;
    ANSELC=0X00;
    PORTD = 0;
    TRISD = 0;
    TMR2 = 0;

    PR2 = 199;   // PWM period = (PR2+1) * prescaler * Tcy
    CCPR1L = 0;
    CCPR2L = 0;
    TRISC = 0; //0b11111011;     // Make pin 17 (RC1/CCP2) an output
    T2CON = 0b00000100;     // Enable TMR2 with prescaler = 1
    CCP1CON = 0b00001100;   // Enable PWM on CCP1
    CCP2CON = 0b00001100;
    PIR1.TMR2IF = 0;
    T2CON.TMR2ON = 1;
    j = i+50;

    while(1)
    {
            PIR1.TMR2IF = 0;

            while( PIR1.TMR2IF ==0);

            CCPR1L = 0.99*sin_table[i];
            CCPR2L = 0.99*sin_table[j];

             i = i+2;
             j = j+2;

             if(i==100)
             {
              i=0;
             }

             if(j==100)
             {
              j=0;
             }

    }
}
Ken Adams
  • 11
  • 1

1 Answers1

2

The issue is the shared use of timer 2. From the manual page 181), three actions happen once the timer is equal to the PRx register. They are:

  1. TMRx is cleared
  2. The CCPx pin is set.
  3. The PWM duty cycle is latched from CCPRxL into CCPRxH.

Because TMRx (TMR2 in your case) is cleared, that resets the period of both outputs. There are other slight issues, such as you didn't specifically write to the "CCPTMRSx" register which assigns what timer to use, & I assume you deleted writing to PR1 to test just the 2nd output, but you need to write to both PR1 and PR2 to set the periods.

Solution should be to assign TMR2 to CCP1 and TMR4 to CCP2 if you want true independent PWMs

Joe Thomas
  • 325
  • 1
  • 7
  • I tried that too. Using TMR2 and TMR4 also causes a slight change in the frequency and the phase difference is also disrupted in this case. – Ken Adams Apr 11 '18 at 20:48
  • do you have the full code listing with both PWMs enabled that you can post? – Joe Thomas Apr 11 '18 at 22:19
  • CCPTMRS0 and CCPTMRS1 both defalut to all zeros, which associates timer 2 with both PWMs. Refer to page 201 of the manual for the bit order, but without setting this register, you haven't completely assigned timer 4 to PWM2, its still using timer2 – Joe Thomas Apr 12 '18 at 13:59
  • Can you please suggest where should I add that thing in the code? Also, what you are saying is that I should add the following command: CCPTMRS0 = 110100; – Ken Adams Apr 12 '18 at 18:32
  • add CCPTMRS0 = 10001000; right after you initialize ccp2con, that should fix it – Joe Thomas Apr 13 '18 at 01:55
  • The problem still exists. The phase shift is still not 90 degrees and also the frequency changes when both PWMs are generated. – Ken Adams Apr 13 '18 at 07:23
  • UPDATE: I have fixed the issue for phase shift, but the other issue is still there. Also I need to now change the amplitude and frequency simultaneously such that v/f ratio remains same. Any ideas on how to vary the frequency e.g 5Hz, 10Hz, ....., 50Hz. – Ken Adams Apr 13 '18 at 12:54
  • Ok, I think I see what is going on. When you say the frequency of both changes, I assume they are getting slower, correct? The issue is most likely the code is taking too long and you are most likely getting repeat duty cycles (because the registers still contain the old trigger points. Said more simply, a 10Khz PWM has a period of 100us. you are attempting to lookup a value, multiply it by .99 and then adjust the counter, twice. Remove the multiplication and see if the frequencies stabilize. As for changing the frequency of the SPW, that would require multiple sin tables, one for each Hz – Joe Thomas Apr 13 '18 at 14:16
  • Removed the 0.99 and that seems to work but I need to multiply the lookup values eventually because I need a linearly increasing amplitude that starts from 0 and reaches 5V (the amplitude of sine wave) after a certain time. The problem arises when I multiply a float variable. Is there any way to overcome that problem? – Ken Adams Apr 15 '18 at 17:43
  • Well, the first thing to do is set a spare digital pin (output) high when one of the timers overflows, and then set the pin low at the end of the if statement. This will allow you to precisely time how long one timer routine takes. Do this with and without the multiply. You only have 100us to play with (10Khz), so I'm not sure you can afford the floating point multiply. The only thing to solve that comes to mind is to stagger the timers, right now, they are overflowing at the same time. Init the first, when its at 50% of count val., init the second to stagger them – Joe Thomas Apr 15 '18 at 20:41