Search code examples
picmicrochippwmdspic

dsPIC33 updating PWM duty and frequency


I am trying to control a H-bridge converter using one PWM generator for each diagonal (PWM1 and PWM4 in my case).

I want to be able to control both frequency and duty cycle. To do so, I generate a trigger interrupt at the beginning of PWM4 period, and then update registers for period, phase and duty cycle for both PWM channels.

The problem is, when this update happens, there is some unexpected behaviour for one period or so. See picture.

PWM4 is cyan, PWM1 is magenta, and yellow toggles when trigger interrupt for PWM4 happens.

It seems like PWM1 (magenta) updates to a slower frequency (as it should), but PWM4 keeps running on the old one for another period. Also PWM1 produces one more short impulse. I measured the time it takes to update values for period, duty and phase registers, and it is around 1us so that shouldn't be a problem. Here are PWM configurations:

void PWM4Config()  {

ANSELEbits.ANSE6 = 0;
ANSELEbits.ANSE7 = 0;
TRISEbits.TRISE6 = 0;
TRISEbits.TRISE7 = 0;

PTPER = 7002;                   //period je 50us
PTCON2bits.PCLKDIV = 0b000;     //1:1  

//fazni stavovi
PHASE4 = 0;
SPHASE4 = 0;

//duty
PDC4 = 3501;
SDC4 = 3501;
//dead time
DTR4 = 0;
//set PWM mode to independent, active high
IOCON4bits.PENH = 1;
IOCON4bits.PENL = 1;
IOCON4bits.POLH = 0;
IOCON4bits.POLL = 0;
IOCON4bits.PMOD = 0b11;
IOCON4bits.OVRENH = 0;
IOCON4bits.OVRENL = 0;
IOCON4bits.OVRDAT = 0b00;
IOCON4bits.FLTDAT = 0b00;
IOCON4bits.CLDAT = 0b00;
IOCON4bits.SWAP = 0;
IOCON4bits.OSYNC = 0;

//set primary time base, edge aligned, independent duty cycles
PWMCON4 = 0x0000;
//PWMCON4bits.IUE = 1;  //privremeno
//config faults
FCLCON4 = 0x0003;

//config trigger & interrupt
IFS6bits.PWM4IF = 0;
IEC6bits.PWM4IE = 1;  
TRGCON4 = 0x0000;       //triger at every period of pwm
TRIG4 = 0x0000;         //triger at start of pwm period
PWMCON4bits.TRGIEN = 0;


}

void PWM1Config()  {

ANSELEbits.ANSE0 = 0;
ANSELEbits.ANSE1 = 0;
TRISEbits.TRISE0 = 0;
TRISEbits.TRISE1 = 0;

PTPER = 7002;                   //period je 50us
PTCON2bits.PCLKDIV = 0b000;     //1:1  

//fazni stavovi
PHASE1 = 3051;
SPHASE1 = 3501;

//duty
PDC1 = 3501;
SDC1 = 3501;
//dead time
DTR1 = 0;
//set PWM mode to independent, active high
IOCON1bits.PENH = 1;
IOCON1bits.PENL = 1;
IOCON1bits.POLH = 0;
IOCON1bits.POLL = 0;
IOCON1bits.PMOD = 0b11;
IOCON1bits.OVRENH = 0;
IOCON1bits.OVRENL = 0;
IOCON1bits.OVRDAT = 0b00;
IOCON1bits.FLTDAT = 0b00;
IOCON1bits.CLDAT = 0b00;
IOCON1bits.SWAP = 0;
IOCON1bits.OSYNC = 0;

//set primary time base, edge aligned, independent duty cycles
PWMCON1 = 0x0000;
//PWMCON1bits.IUE = 1;  //privremeno
//config faults
FCLCON1 = 0x0003;

//config trigger & interrupt
//IFS5bits.PWM1IF = 0;
//IEC5bits.PWM1IE = 1;  
//TRGCON1 = 0x0000;       //triger na svakom periodu pwm-a
//TRIG1 = 0x0000;         //triger je na pocetku pwm-a
//PWMCON1bits.TRGIEN = 0;


}

They are set to independent mode, using master time base.


Solution

  • I solved this problem by disabling PWM (by clearing PTEN bit) before I update duty cycle and frequency for both PWM channels, then enabling it immediately afterwards. The result is that there might be one PWM pulse that is somewhat shorter than it should be at the moment of update, but overlapping of pulses for complementary channels doesn't happen. This is more like a workaround than real solution, but it serves the purpose for me.