2020/10/04 20:44:26
GirishGanesan
I require two PWM signals of 20kHz frequency phase shifted by a constant 25us. Both PWM signals will have the SAME duty cycle. I am using an external crystal oscillator of 16MHz value.
I am using AN0 as analog input. This analog input will determine the value of Duty for both the PWM signals.
I am using both CCP modules set to PWM mode - PR2 register is the Time Period for both these waveforms.
The problem is: I need to insert a 25us delay into one of the PWM outputs.
Is there any way to do this? Timer0 and Timer1 are free. I am open to any solution. I have attached the code below.
 
Thank you in advance for your time and patience. I hope I have commented liberally to help you understand my code.
 
// CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage programming enabled)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <pic16f876a.h>

#define _XTAL_FREQ 16000000

void ADC_initialize()
{
    ADCON0=0x81; // using Fosc/64 ; AN0 is input ; AD module Powered up
    ADCON1=0x8E; // Result is right justified; AN0 is input, VDD and VSS are references.
}

unsigned int ADC_read(unsigned char input1)
{
  __delay_us(15); // waiting for acquitision \\29 sep 2020
  GO_nDONE=1; //Begin ADC
  while(GO_nDONE);
  return((ADRESH<<8)+ADRESL); //Appends the two bits in ADRESH to ADRESL. We chose ADFM=1 in ADCON1
}

void PWM_initialize()
{
    PR2=0xC7; //Time period of C8 giving 50.25us As per dutycycle calculations.
    T2CON=0x04; // Turn on Timer 2
    
    CCP1M3=1; CCP1M2=1;// CCPxM3:CCPxM2=11 - PWM Mode
    CCP2M3=1; CCP2M2=1;
    
    //Default 50% duty cycle. = C7/2 approx. => 63H = 0b00 0110 0011
    CCP1X=1; CCP1Y=1; //LSBs of Duty Cycle
    CCPR1L=0x18;
    CCP2X=1; CCP2Y=1; //LSBs of Duty Cycle
    CCPR2L=0x18;
    
}

void main(void) {
    
    unsigned int vout;
    TRISA=0xFF;
    TRISC=0x00;
    ADC_initialize();
    PWM_initialize();
    do
    {
        vout=ADC_read(0);


        if (vout>0x246)
        {} //pwm INCREASE
        else if (vout<0x246)
        {} //PWM decrease
        else
        {} //do nothing
    }while(1);
    
    
    
    
    
}

2020/10/04 21:31:50
ric
GirishGanesan
...
The problem is: I need to insert a 25us delay into one of the PWM outputs.
Is there any way to do this?

Not with the CCP peripheral in that PIC.
Can you change to something a bit less ancient?
 
2020/10/04 22:20:32
GirishGanesan
ric
GirishGanesan
...
The problem is: I need to insert a 25us delay into one of the PWM outputs.
Is there any way to do this?

Not with the CCP peripheral in that PIC.
Can you change to something a bit less ancient?
 


So its totally impossible? What do you mean, less ancient? I vaguely ready someplace else, we could use another timer, 0 or 1 to cause the delay and then turn on the other PWM channel. Is there absolutely no other way of doing so?
2020/10/04 22:32:29
ric
GirishGanesan
So its totally impossible?

Yes.
The CCP peripheral in a PIC16F876A can only use Timer-2 as the reference for PWM, so your phase is locked to that.

What do you mean, less ancient?

The PIC16F876A was released in November 2001.
It was just a small tweak to the PIC16F876, which was released in 1998.
 
In microprocessor terms, that is pre-historic.
PIC16F devices have come a lng way since then.
 

I vaguely ready someplace else, we could use another timer, 0 or 1 to cause the delay and then turn on the other PWM channel.

The phase is locked to the reference timer. If both CCPs use the same timer, they have the same phase.
Newer PIC16F devices let you select from multiple timers to use as the reference.
Even newer ones have a built in PHASE register.
 

Is there absolutely no other way of doing so?

With a PIC16F876A?
The only way is to forget about the CCP peripheal, and bit bang it yourself just using the timer, or it may be possible using the CCP in "Compare" mode, generating an interrupt for both edges of the signal.
Not easy at high frequencies.
There are plenty of newer PICs that are pin compatible with the 876A. Can you really not change the PIC?
 
2020/10/04 22:36:21
upand_at_them
20kHz is a period of 50us.  A shift of 25us is just an inversion, no?
2020/10/04 22:40:25
GirishGanesan
ric
 

With a PIC16F876A?
The only way is to forget about the CCP peripheal, and bit bang it yourself just using the timer, or it may be possible using the CCP in "Compare" mode, generating an interrupt for both edges of the signal.
Not easy at high frequencies.
There are plenty of newer PICs that are pin compatible with the 876A. Can you really not change the PIC?
 


 
Okay i'm open to changing the PIC. If this PIC is really 19 years old then it really makes no sense in proceeding with it given the disadvantages and the weight of the work around. Thank you for your comments.
 
Can you suggest any new PIC ? I will mostly be reading a few analog signals (ADC), doing phase shifted PWMs about 1-6 PWMs( at least 2) at around 20-50kHz frequencies. It doesn't even have to be pin compatible. Anything that works with the XC8 compiler on MPLABX IDE.
 
Edit to add: I am working in Power Electronic Controllers, this problem corresponds to a DC-DC Converter I am working on now.
2020/10/04 22:42:05
GirishGanesan
upand_at_them
20kHz is a period of 50us.  A shift of 25us is just an inversion, no?


Only if my duty cycle is always 50%. Say my dutycycle is 30%, the second signal will be on for 70% of the time when the first signal isnt. It isnt a direct inversion.
2020/10/04 22:51:07
ric
A PIC16F18455 would be a much more suitable chip.
It has similar CCP modules, but each one can use a seperate timer for PWM.
 
Alternatively, you could go for a PIC16F1773 (or other 177x variant).
They contain a much more complex PWM module that can do 16-bit pulse width and phase adjustment.
 
 
2020/10/04 22:54:05
GirishGanesan
ric
A PIC16F18455 would be a much more suitable chip.
It has similar CCP modules, but each one can use a seperate timer for PWM.
 
Alternatively, you could go for a PIC16F1773 (or other 177x variant).
They contain a much more complex PWM module that can do 16-bit pulse width and phase adjustment.
 
 


Thank you so much ric. I will look it up rightaway. This is of great help.
2020/10/05 06:24:13
upand_at_them
GirishGanesan
upand_at_them
20kHz is a period of 50us.  A shift of 25us is just an inversion, no?

Only if my duty cycle is always 50%. Say my dutycycle is 30%, the second signal will be on for 70% of the time when the first signal isnt. It isnt a direct inversion.



Sorry, late night cloudy thinking.
© 2021 APG vNext Commercial Version 4.5

Use My Existing Forum Account