Author Topic: PIC PWM question  (Read 743 times)

0 Members and 1 Guest are viewing this topic.

Offline chilternviewTopic starter

  • Regular Contributor
  • *
  • Posts: 145
  • Country: gb
PIC PWM question
« on: February 03, 2023, 11:23:46 am »
I hope someone can help with what I thought was a simple task but for the life of me I can't see it.

I am using a 12LF1572 to generate gate drive signals for a simple low frequency inverter. The signals are at 100Hz with a variable duty cycle 30-50%. So I'm using 2 PWM sources, I can set up the period and duty cycle correctly but I can't see how to get PWM2 to be lag by around half the period after PWM1 to give me a pair of non-overlapping pulses.

I thought that varying PWM2PH would allow me to shift the second PWM's phase relative to PWM1 but no, that would be too easy... how is it done?

Code so far below (ignoring config bits and trivial main() that calls init)pwm(duty_cycle) and then sits in a loop)

#define _XTAL_FREQ 16000000 // Oscillator frequency.
#define PERIOD 2500               // PWM period. With divide by 64 prescaler on
                                              // HFINTOSC, PWM period is 2500 cycles of 16MHz/64
                                              // i.e. freq = (16E6 / 64 / 2500) = 100Hz

// Initialise the PWM to a specific duty cycle and period
void
init_pwm( int duty_cycle) {
   
  // Output PWM1 to pin 2 using RA5, PWM2 to pin 3 using RA4
  APFCONbits.P1SEL = 1;
  APFCONbits.P2SEL = 1;
 
  // Set PWM pin RA5 and RA4 to be output
  TRISAbits.TRISA5 = 0;
  TRISAbits.TRISA4 = 0;

  // Set PWM input to HFINTOSC clock, prescaler = div-by-64
  PWM1CLKCON = 0b01100001;
  PWM2CLKCON = 0b01100001;

  // PWM control set to standard mode
  PWM1CON = 0b11000000;
  PWM2CON = 0b11000000;

  // Phase
  PWM1PH = 0;
  PWM2PH = 0;

  // Duty cycle in %
  PWM1DC = duty_cycle * (PERIOD/100);
  PWM2DC = duty_cycle * (PERIOD/100);
 
  // Period
  PWM1PR = PERIOD;
  PWM2PR = PERIOD;
 
  // Start the PWM's
  PWM1LD = 1;
  PWM2LD = 1;
}
 

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 3461
  • Country: it
Re: PIC PWM question
« Reply #1 on: February 03, 2023, 11:38:02 am »
Reread the datasheet
https://www.microchip.com/40001723
using the phase registers require you to set one of the offset modes (current datasheet, revision E, is on section 22.3)

However, it's possible that what you're really looking for is the complementary waveform generator? (takes a PWM output and generates the two phases with settable dead band)
 

Offline chilternviewTopic starter

  • Regular Contributor
  • *
  • Posts: 145
  • Country: gb
Re: PIC PWM question
« Reply #2 on: February 03, 2023, 11:58:08 am »
Thanks, I tried the offset trigger source register but I'm obviously missing something as if I do this:

PWM2OFCON = 0b01000001;

to set the offset mode to trigger on PWM1, then PWM2 never fires. I guess I'm not understanding how to set up offset mode as the documentation is as clear as mud - an example would be nice but I've had no luck googling it.

I did try CWG but I don't want complementary signals, I want the same but just 180 degrees out of phase.
 

Offline chilternviewTopic starter

  • Regular Contributor
  • *
  • Posts: 145
  • Country: gb
Re: PIC PWM question
« Reply #3 on: February 03, 2023, 02:14:36 pm »
So after a bit more experimenting, this works:

void
init_pwm( int duty_cycle) {
   
  // Output PWM1 to pin 2 using RA5, PWM2 to pin 3 using RA4
  // Pin selection RA5
  APFCONbits.P1SEL = 1;
  APFCONbits.P2SEL = 1;
 
  // Set PWM pin RA5 and RA4 to be output
  TRISAbits.TRISA5 = 0;
  TRISAbits.TRISA4 = 0;

  // Set PWM input to HFINTOSC clock, prescaler = div-by-64
  PWM1CLKCON = 0b01100001;
  PWM2CLKCON = 0b01100001;

  // PWM control set to standard mode
  PWM1CON = 0b11000000;
  PWM2CON = 0b11000000;
 
  // Set PWM2 to continuous slave run (bits 6/5 = 11)
  // triggered by OF1 match (bits 1/0 = 01)
  PWM2OFCON = 0b01100001;
 
  // Phase
  PWM1PH = 0;
  PWM2PH = 0;
 
  // Set the offset match to half period
  PWM1OF = PERIOD/2;
 
  // Duty cycle in %
  PWM1DC = duty_cycle * (PERIOD/100);
  PWM2DC = duty_cycle * (PERIOD/100);
 
  // Period
  PWM1PR = PERIOD;
  PWM2PR = PERIOD;
 
  // Start the PWM's
  PWM1LD = 1;
  PWM2LD = 1;
}

Not sure exactly why!
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf