Switching PWM outputs on a PIC24F16KM204.

Switching PWM outputs on a PIC24F16KM204.

Postby KTrenholm » Thu Feb 28, 2019 11:02 pm

Hey everyone,

I also posted this on the official forum, but since embedding pictures there is busted, I'm going to try my luck here as well.

I'm seeing something really strange with some PWM outputs on my PIC24F16KM204. I'm using XC16 v1.31 and MPLAB X 5.10.

What I want to is, upon user input, switch my PWM output between CCP3 and CCP2. The goal being to switch a set of backlights to another set. What I'm seeing is the PWM shuts off fine, but the newly turned on PWM output for some reason spends up to an entire period high before settling to the written Duty Cycle value.

My configuration for the two CCP modules is below:

Code: Select all
    float pwm_period;
    uint16_t pr_val;
    pwm_period = (1.0f/(float)freq);
    pr_val = pwm_period/TCY;
    /*CCP3B*/
    CCP3CON2Lbits.PWMRSEN = 1;
    CCP3CON1Lbits.CCSEL = 0; //Output Compare
    CCP3CON1Lbits.MOD = 0b0101; //Dual Edge Compare (PWM)
    CCP3CON1Lbits.TMRSYNC = 0;
    CCP3CON1Lbits.TMR32 = 0;
    CCP3CON1Lbits.CLKSEL = 0b000; //Source Clock: FCY
    CCP3CON1Lbits.TMRPS = 0b00; //Prescale 1 -> about 60Hz to 40kHz range for 100 DC Steps

    CCP3CON1Hbits.TRIGEN = 0;
    CCP3CON1Hbits.SYNC = 0b0000;
    CCP3CON2Hbits.OCAEN = 0;
    CCP3CON2Hbits.OCBEN = 1;
   
    CCP3CON3Hbits.OUTM = 0b000;
    if (Cfg_PWM_LoActive){
        CCP3CON3Hbits.POLBDF = 1;
    }else {
        CCP3CON3Hbits.POLBDF = 0;
    }

    CCP3TMRL = 0x0000;
    CCP3PRL = pr_val; //Timer Period
    CCP3RAL = 0;
    CCP3RBL = 0;
    CCP3CON1Lbits.CCPON = 1;
       
    /*CCP2A*/
    CCP2CON2Lbits.PWMRSEN = 1;
    CCP2CON1Lbits.CCSEL = 0; //Output Compare
    CCP2CON1Lbits.MOD = 0b0101; //Dual Edge Compare (PWM)
    CCP2CON1Lbits.TMRSYNC = 0;
    CCP2CON1Lbits.TMR32 = 0;
    CCP2CON1Lbits.CLKSEL = 0b000; //Source Clock: FCY
    CCP2CON1Lbits.TMRPS = 0b00; //Prescale 1 -> about 60Hz to 40kHz range for 100 DC Steps

    CCP2CON1Hbits.TRIGEN = 0;
    CCP2CON1Hbits.SYNC = 0b0000;

    CCP2CON2Hbits.OCAEN = 1;

    CCP2CON3Hbits.OUTM = 0b000;
    if (Cfg_PWM_LoActive){
        CCP2CON3Hbits.POLACE = 1;
    }else {
        CCP2CON3Hbits.POLACE = 0;
    }

    CCP2TMRL = 0x0000;
    CCP2PRL = pr_val; //Timer Period
    CCP2RAL = 0;
    CCP2RBL = 0;
    CCP2CON1Lbits.CCPON = 1;


The switch is simple, just turning off the other output and writing a passed in value brt to the pwm module:

Code: Select all
#define PWM_A_SET(x)      (CCP2RBL = x)
#define PWM_B_SET(x)      (CCP3RBL = x)
#define PWM_A_OFF     CCP2RBL = CCP2RAL
#define PWM_B_OFF    CCP3RBL = CCP3RAL


if (Switch_A){
    PWM_B_OFF;
    PWM_A_SET(brt);
} else if (Switch_B){
    PWM_A_OFF;
    PWM_B_SET(brt);
}



What I would see here is the switch would happen and I would get a high time (up to a full period) for some reason before dropping to the desired duty cycle This results in a nasty "flash" of the backlights jumping:
scope_0.jpg
scope_0.jpg (82.13 KiB) Viewed 442 times


I don't really understand WHY this would happen, I assumed it had something to do with the CCP module buffering the new period value before putting it out, since a new compare value won't take effect until the next falling edge. What confuses me is that the previous compare value was to set the PWM entirely LOW, so why would it suddenly give me a high period before using my new compare value? This only ever happens when I turn one CCP module off, and the other on. I can zero the PWM and bring it back no problem provided there is no switching of the module.

I attempted a fix, figuring I could maybe turn the OCxEN low while I wait for the new PWM value to settle, since the module should continue to run regardless of OCxEN state. Both pins are configured as output LOW when configured as port pins when OCxEN is 0:

Code: Select all

#define PWM_A_OCEN    CCP2CON2Hbits.OCAEN
#define PWM_B_OCEN   CCP3CON2Hbits.OCBEN

if (Switch_A){
    PWM_A_OCEN = 0;
    PWM_B_OFF;
    PWM_A_SET(brt);
    __delay_ms(20);
    PWM_A_OCEN = 1;
} else if (Switch_B){
    PWM_B_OCEN = 0;
    PWM_A_OFF;
    PWM_B_SET(brt);
    __delay_ms(20);
    PWM_B_OCEN = 1;
}



20mS was chosen just to make sure enough time has passed for the DC to settle. In reality a period of this PWM should never exceed 10mS. What I got was not what I was expecting:

scope_1.jpg
scope_1.jpg (81.13 KiB) Viewed 442 times


I'm STILL getting a high period, which makes no sense to me, as during the delay, the corresponding OCEN bit should be low. The CCP module should be running, just not outputting.
So I'm at a loss now. Both as to why the module does this at all, and why my workaround didn't have any effect.

Anyone have any ideas?

Thanks in advance for the thoughts on what could be going on here.
User avatar
KTrenholm
 
Posts: 17
Joined: Mon Sep 10, 2018 3:57 pm
PIC experience: Professional 5+ years with MCHP products

Return to CCP, ECCP and PWM

Who is online

Users browsing this forum: No registered users and 1 guest