Two square waves with arbitrary phase shift on dsPIC

Reader Imad wrote in with an interesting query about generating two square waves with equal frequency but an arbitrary phase shift between them using a dsPIC microcontroller. I’m still working out the fine details, but here’s the general gist of it:

// This dsPIC30F4011 example program generates two
// square waves with a variable phase shift between
// them. Both waveforms 10kHz, 50% duty cycle.
// Written by Ted Burke - last updated 20-8-2012

#include <xc.h>
#include <libpic30.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

int main()
	// Configure all four port D pins (RD0, RD1, RD2, RD3)
	// as digital outputs
	TRISD = 0b1111111111110000;

	// Set OC channel 1 pulse start and stop times
	OC1R = 0;
	OC1RS = 1500;

	// Set OC channel 2 pulse start and stop times
	OC2R = 750;
	OC2RS = 2250;

	// Set output compare mode for continuous pulses
	OC1CONbits.OCM = 0b101;
	OC2CONbits.OCM = 0b101;

	// Configure timer 2 (default timer for output compare)
	PR2 = 3000; // 0.1ms period
	T2CONbits.TON = 1; // Enable timer 2

	// Flash an LED on RD0 indefinitely at 1Hz
		_LATD2 = 0;          // LED off
		__delay32(30000000); // 500ms delay
		_LATD2 = 1;          // LED on
		__delay32(30000000); // 500ms delay

	return 0;

I compiled it using Microchip’s new XC16 C compiler. Here’s a screenshot of the generated waveform, which I checked using the incredibly useful PICkit2 helper application.

I’m using two output compare channels (OC1 on pin 23 and OC2 on pin 18) to generate the waveforms. In this example, both output compare channels are driven by Timer 2 (which is the default setting). I set the period register PR2 to 3000 to set the frequency to 10kHz (the chip is running at 30 MIPS, so 3000 instruction cycles is 0.1ms). This means that Timer 2 counts from 0 up to 3000 over and over again. The start and stop times for the pulses on each output compare channel are then controlled using the four registers OC1R, OC1RS, OC2R and OC2RS. To modify the phase shift between the two waveforms, just specify different values for OC2R and OC2RS which control the start and stop times respectively of each pulse on output compare channel 2.

Finally, I set an LED flashing on RD3 (pin 22) just so that I could see that the circuit was running correctly. Of course, this is not needed for the square wave generation to work correctly, but it’s always useful to be absolutely sure the program is actually running when you’re debugging these things! In due course, I’ll add in an analog read into the while loop to allow the phase shift between the waveforms to be varied using a potentiometer connected to an analog input channel.

This entry was posted in Uncategorized and tagged , , , , , , , , , , , , . Bookmark the permalink.

32 Responses to Two square waves with arbitrary phase shift on dsPIC

  1. Imad says:

    Thank you Ted a lot. I Really appreciate it. Thank you for your timing. I will try it tomorrow in the lab.

  2. Imad says:

    Hello Ted,
    I have tried the code above, its working perfectly, however when i vary OC2R and OC2RS (varying the phase) and keeping other values constant the waveforms still the same as the above one. Can you please check if you vary OC2R and OC2RS the shift will change ? also do i need to change any other variables along with OC2R and OC2RS to have the correct phase shift?


  3. Imad says:

    okay Ted, i figured it out.

    • batchloaf says:

      Ok, that’s great! Best of luck with whatever you’re working on.

      When I get a chance, I’ll probably update this post to facilitate real-time variation of the phase shift with a potentiometer, so if that’s relevant to your design keep an eye out for the updated version.

  4. manu says:

    Hello Ted,
    Is it possible to generate 2 sinewaves (push-pull) with output compare alone ?

  5. batchloaf says:

    Hi Manu,
    Unfortunately, the short answer is no. The output compare pins are digital rather than analog – i.e. they can only be logic high (e.g. 5V) or logic low (0V). As a result, they can only be used to generate “rectangular” waveforms. None of the microcontrollers I’ve ever used has had an analog output, so generating sinusoidal waveforms requires one of a number of possible workarounds. Here are three options that spring to mind:

    1. Generate a squarewave at the desired frequency (e.g. using output compare or the PWM outputs), then use a filter to “round the corners off” the waveform by attenuating the higher harmonics. Unless you use a filter with a very sharp cutoff between the fundamental frequency and the second harmonic, this probably won’t produce a very good sine wave.
    2. Use an additional digital-to-analog converter (DAC) IC to generate the analog waveform. The PIC sends a series of numerical sample values to the DAC, which in turn outputs the corresponding analog waveform. This should work really well once you have it working, but you would need to work out how to use the DAC which a lot of people find difficult.
    3. If the desired sine frequency is not too high, you can generate a good waveform by varying the duty cycle of a PWM output in a sinusoidal fashion. The frequency of the PWM signal needs to be much higher than the desired frequency of the sine wave though. To produce the actual sine waveform, the PWM signal needs to be low pass filtered, for example using an RC low-pass filter. This approach is straightforward to do and produces a good result, provided that the desired frequency is low. For example, generating a 50Hz sinusoid should work great. If the frequency is low enough, this is the method I would recommend.

    What kind of signals are you trying to produce? In particular, what frequency (or range of frequencies)? What phase shift between the waveforms? When you say “push-pull”, do you mean the signals should be 180 degrees out of phase?

    If you can supply some more details, and if it looks like method 3 above might work, I should be able to sketch out some example code.


    • manu says:

      Hi Ted,

      I was implying a Sinusoidal PWM signal, rather than an analog signal.
      Something of the order, where PWM frequency is 100kHz and the sine
      frequency is 25Hz. The 2 signals that need to be generated have a phase shift of 180 degrees each, ie; OC1= 0-180 degrees while OC2=180-360 degrees. These 2 signals do drive a pair of MOSFET’s, so there needs to be a small deadtime between the 2 phases additionally. It should be small enough, so that it doesn’t distort the final constructed sinusoidal waveform Yes, it is like the method 3 that you mentioned.


      • batchloaf says:

        Hi Manu,

        In that case, yes, you can certainly do this with output compare and it won’t be too difficult. If I get a few minutes later on, I’ll try to sketch out some example code and publish it as a new post.


      • manu says:

        Hi Ted,

        That sounds great. I am awaiting your new post.


    • Darko Gojanovic says:


      Can you clarify what is in xc.h and where is located.

      • batchloaf says:

        Hi Darko,

        Microchip recently consolidated all of their PIC C compilers into a rebranded family comprising XC8 (for 8-bit PIC microcontrollers), XC16 (for 16-bit microcontrollers – e.g. dsPIC) and XC32 (for 32-bit PIC32 microcontrollers). I think each of these compilers is actually just a modified version of the gcc compiler, adapted to compile code for a specific family of PIC microcontrollers.

        Because I’m using a dsPIC30F4011 here, the compiler I’m using is XC16. The code for this compiler is basically identical to what I would have previously compiled with Microchip’s C30 compiler. However, instead of including a chip specific header file (e.g. “#include <p30f4011.h>” for the dsPIC30f4011) I can now just include “xc.h” and XC16 will pull in all the correct definitions for whatever chip I’m using. Of course, it’s actually still pulling in a chip-specific header file, but it should pick the correct one automatically.

        If you’re using MPLAB X (or using the XC16 compiler directly as I am), it should find “xc.h” without any problems (it will be located in a subdirectory of the XC16 installation directory, but you shouldn’t need to specify the exact location – it should already know where it is). However, if you’re using an older version of MPLAB, or if you’re using C30 rather than XC16, then you’ll probably need to include “p30f4011.h” rather than “xc.h”.

        Does that answer your question?


  6. Vandana says:

    I want to the same with PICFJ128GA010.. I want the PWM frequency to be varied bw 50k to 100k .. I used PWM channels .. but am nt able to get delay .. So am reading the error signal and comparing it with the sawtooth to get the PWM ..To generate sawtooth am writing code and error signal receiving it externally..But am unable to get required frequency . can someone help

    MY code:

    // General configuration of the PIC24FJ128GA010

    void initTimer()
    TMR2 = 0;
    PR2 = 600;
    IPC1bits.T2IP = 5; //set interrupt priority
    IFS0bits.T2IF = 0; //reset interrupt flag
    IEC0bits.T2IE = 1; //turn on the timer2 interrupt
    T2CON = 0b1000000000000000; //turn on the timer

    int NewADCValue = 0;
    int main(void)
    int ADCValue = 0;
    int step = 0,j;
    AD1PCFG = 0; // select analogue input pins
    TRISD = 0;
    LATD = 0;
    TRISA = 0;
    LATA = 0;
    AD1CON1 =0b0000000011100000;
    AD1CHS = 0x0005;
    AD1CSSL = 0;
    AD1CON3 = 0b0000111100000000;
    AD1CON2 = 0;
    IFS0bits.AD1IF = 0;
    IEC0bits.AD1IE = 1;
    AD1CON1bits.ADON = 1;

    //sawtooth generation

    ADCValue = NewADCValue >> 2;
    AD1CON1bits.SAMP = 1;

    step = 0;

    step = step + 1;

    if ((stepADCValue) && (PORTDbits.RD2 == 0))
    PORTDbits.RD2 = 1;


    void __attribute__((__interrupt__, auto_psv)) _T2Interrupt(void)
    PORTDbits.RD3 = PORTDbits.RD2;
    IFS0bits.T2IF = 0;

    void __attribute__ ((__interrupt__)) _ADC1Interrupt(void)
    NewADCValue = ADC1BUF0;
    IFS0bits.AD1IF = 0;

  7. Swati says:

    Hi Ted,
    can u tell me why you have used following statement
    ” OC1R = 0;
    OC1RS = 1500;
    //Set OC channel 1 pulse start and stop times”

    and how to modify this for micro controller dsPIC33FJ128GP706 ?

    Thanks in advance,

  8. batchloaf says:

    Hi Swati,

    In this example, the waveforms are driven by Timer 2 which is a counter running constantly in the background. I set PR2=3000, which means that Timer 2 period is 3000 instruction cycles. In other words, every time TMR2 (the counter register for Timer 2) reaches the value 3000 it resets to 0. Because the chip is running at 30MIPS (30 million instructions per second) in this example, TMR2 takes 0.1ms to count from 0 to 3000. The values OC1R and OC1RS set the start and stop times for the pulse generated on output compare channel 1. In other words, whenever TMR2 reaches the value of OC1R, a pulse starts, and whenever TMR2 reaches the value of OC1RS, a pulse ends.

    Hopefully that explains it?

    I don’t have a dsPIC33FJ128GP706 microcontroller, so it’s awkward for me to convert the code. Are you getting specific errors or problems?


  9. sanju says:

    PWM period = Tcy * prescale * PTPER = 0.33ns * 64 * 9470 = 20ms (example frm fourm)
    how can i get PTPER and PTMR values? i want to produce 16 khz puls train for H bridge sine. at complimented o/p in each 10 millyseconds with DSPIC 30F2010..(xt=6.144 mhz*16pll=98.308 mhz). iam using CCS compiler (not familiar with mplab)..i want to load the registors properly..
    help me..pls..
    //PTMR : PWM Timebase Register Count Value???????????????????
    //PTPER: PWM Time Base Period Register????????????
    CLR PTCON; //PWM Time Base Control register
    CLR PTMR; // PWM Time Base register
    CLR PTPER; // PWM Time Base Period register
    CLR SEVTCMP; // PWM Special Event Compare register
    CLR PWMCON1; // PWM Control register #1
    CLR PWMCON2; // PWM Control register #2
    CLR DTCON1; //Dead Time Control register #1
    CLR FLTACON; // Fault A Control register
    CLR PDC1; // PWM Duty Cycle register #1
    CLR PDC2; //PWM Duty Cycle register #2
    CLR PDC3; // PWM Duty Cycle register #3

    BSET PTCON, 1; //PWM time base operates in a continuous up/down counting mode
    BSET PTCON, 13; //PWM time base halts in CPU Idle mode
    BSET PTCON, 15; //PWM time base is ON


  10. ara says:

    Well lemme start my sayin am a newbie and dude that was one awesome way to explain …. am doing my final year project on LED lamps and am on the process of designing a dimmer circuit.Can u please tell me how to generate a unit step saw tooth wave in a pic microcontroller,Compare it with a given input wave and obtain the duty cycle of the thus generated PWM wave? am looking forward for your reply…

  11. batchloaf says:

    Hi ara,

    Can you explain a bit more about your setup? The PIC can generate a PWM waveform internally without any actual sawtooth waveform being generated, so I just want to be clear exactly what you’re trying to do.

    Actually, I’m not quite sure what you mean by a unit step sawtooth wave. A unit step function is just 0 before time t=0, and 1 after that time. i.e. it’s just a constant signal that “switches on” at time 0, a bit like the following:

    5V                 |                 

    A sawtooth waveform is a periodic waveform that climbs steadily from some minimum value (e.g. 0) up to some maximum value (e.g. 5V?) and then resets to the minimum and starts climbing again. It looks a bit like this:

      /|     /|     /|     /|     /|   
     / |    / |    / |    / |    / |   
    /  |   /  |   /  |   /  |   /  |   
       |  /   |  /   |  /   |  /   |  /
       | /    | /    | /    | /    | / 
       |/     |/     |/     |/     |/  

    A few questions:

    1. Are you trying to generate a sawtooth waveform, or a PWM waveform, or both?
    2. What is the input signal to your PIC and where is it coming from?
    3. What is the output signal from your PIC and where is it going to?
    4. Please include specific voltages in your circuit, as well as time and frequency information for each waveform you mention.

    If you can provide this information, I’ll do my best to point you in the right direction.


  12. sanju says:

    hai ted,

    i made the sinewave using the formula from your post, i have a question in this:
    void __attribute__((__interrupt__, __auto_psv__)) _T1Interrupt(void)
    double dc, sine_term;

    // Clear Timer 1 interrupt flag
    _T1IF = 0;

    // Vary PWM duty cycle sinusoidally (in 100 steps)
    n = n + 1;
    if (n == 100) n = 0;

    // Calculate duty cycle
    sine_term = (1 + sin(2 * PI * n / 100.0)); // varies between 0 and 2
    dc = sine_term * dc_min + (2 – sine_term) * dc_max; // varies between 2*dc_min and 2*dc_max

    // Update the duty cycle register
    PDC1 = dc * PTPER;
    PDC2 = (2*PTPER)-PDC1;


    i want to start the sine wave slow and leaner pattern. ups want slow start on start-up 3-5 second. my PTPER VALUE is for 8.3 khz and timer1 is 200 us.(50hz). without changing the 50hz, i want to start up this wave slowly. pdc1 and pdc2 = 50% means output=0; in the wave foam.

    help me for this.

  13. sanju says:

    hai ted,
    i solved the soft start issue, the isr code here

    double upsout=.60;///////////62 volt out// .99= 254 volt.

    double v_min=0.50, v_max=0.50;

    double duty, sine_term;
    void __attribute__((__interrupt__, __auto_psv__)) _T1Interrupt(void)
    _T1IF = 0;

    count = count + 1;
    if (count == 100) count = 0;
    sine_term = (1 + sin(PI2 * count / 100.0));
    duty = sine_term * v_min + (2 – sine_term) * v_max;
    PDC1 = duty * PTPER;
    PDC2= (2*PTPER)-PDC1;

    how can i read the adc values from mains and ups sinewave? i have an ofset voltage of 2.5 v,
    and how can i synchronise the ups to mains ..before the changeover time? only by this 2 adc's?

  14. Mustapha says:

    Hello Ted
    I have a project to produce 3 PWM variable duty cycle but from three triangular phase signals between them 120 degrees. All this using a dsPIC.
    Help if possible

    • batchloaf says:

      Hi Mustapha,

      That’s probably possible, but I don’t understand exactly where the triangular waveforms fit in. Are they inputs to the dsPIC? Or are they outputs? If you can explain the application clearly I’ll try to advise.


  15. sanjay says:

    hai ted,
    i have a problem on the sine math function,ie, it takes around 180us to compleate it, so i modified it using pikkit3 debuger and made a table of 100 steps using watch window, now again iam not able to produce soft start output, i created the table with a value of
    double v_min=0.03, v_max=0.97; iam getting full open of 240v at the o/p. how can i achive cold start using the table?
    my table is here,
    const int st[100]={1378,1295,1213,1131,1049,970,891,815,741,669,601,535,473,414,359,308,261,219,181,148,120,96,78,65,57,55, 57,65,78,96,119,147,180,218,260,307,357,412,471,533,599,668,739,813,889,968,1047,1128,1211,1293,1376,1459,1542,1624,1706,1785,1864,1940,2014,2086,2155,2220,2283,2342,2397,2448,2495,2537,2575,2608,2637,2660,2678,2692,2700,2702, 2700,2692,2680,2662,2639,2611,2578,2540,2498,2452,2401,2346,2287,2225,2160,2091,2020,1946,1870,1791,1712,1631,1549,1466};

    pls route me, i want instantaneous volt correction at out put, so i cant sit in isr for a long time,every 3.6 degree, i want to modify pdc1 and pdc2 with the adc result.

    • batchloaf says:

      Hi Sanjay,

      Sorry I couldn’t reply to you sooner. I was thinking about your application, but I’m still confused about exactly what it is you’re trying to do. As I understand it:

      • You want to generate 8.3 khz PWM.
      • The duty cycle will vary sinusoidally at 50Hz.
      • The duty cycle will be updated once every 10ms, using your lookup table which contains 100 values.
      • The max and min duty cycle at steady state will be 97% and 3% respectively.
      • However, at startup time the max and min duty cycle will both begin at 50%.
      • At startup time, the signal will be 50Hz, but it will take 3-5 seconds for the system to reach steady state amplitude (3% min and 97% max duty cycle).
      • The output signal must startup in phase with the mains supply, which is read through an analog input with an offset voltage of 2.5V.

      Are all of the above details correct?


  16. Saptarshi De says:

    Hi Sir, Thank you for the code. Is it possible to generate 4 pwm signals with same duty cycle and each with a 90 degrees phase shift from the previous one using dspic30f4011 ?

    • batchloaf says:

      Hi Saptarshi,

      Yes, it’s possible, but you might need to be a little bit ingenious. Depending on the required frequency and range of duty cycle, it could be easier or more difficult. Can you give me some more details such as the frequency and the required duty cycle range and I’ll try to advise on how it can be done.


      • Saptarshi De says:

        Frequency is 50khz and i want to vary the duty cycle . Actually i am using pi controller to control the duty cycle. Thanks to you i was able to use pi controller with your code for “PWM output on 2 channels of the dsPIC30F4011 with equal duty cycle and 180 degrees out of phase”.which i am using for 2 phase interleaved boost converter and it is working fine. Now i want to use for four phase interleaved boost. The wave form is in the link below.

      • batchloaf says:

        Hi Saptarshi,

        That was an interesting challenge! I have a reasonable solution, but it requires that you invert two of the output signals using an external inverter (such as an inexpensive CMOS logic inverter IC). You can read my complete description here:

        I didn’t have a logic inverter chip when I tested it this evening, so I just used a couple of NPN transistors to flip the two signals that need to be inverted, but that did severely limit the speed I could run it at. With faster inverters, there should be no problem at all running at 50 kHz.

        For my test, I just set the duty cycle to a constant value of 20%, but it should be easy enough to vary it by recalculating and setting the values of OCxR and OCxRS for each channel, just the same way it’s done in my current example.

        Have a look and see if it does the trick for your boost converter.


  17. Saptarshi De says:

    Hi sir, the pwm pulses are perfect and yes it does the trick. You are awesome sir.

  18. jyoti says:

    can anybody help me….. I have to generate six pulses using timer in 360 degree i.e in 40 msec and between each pulse delay is 60 degree i.e in 40 msec. I am using dspic33ep microcontroller. I want help in writing code logic for pulses

  19. jyoti says:

    can anybody help me….. I have to generate six pulses using timer in 360 degree i.e in 40 msec and between each pulse delay is 60 degree i.e in 20 msec. I am using dspic33ep microcontroller. I want help in writing code logic for pulses

  20. jyoti says:

    can anybody help me….. I have to generate six pulses using timer in 360 degree i.e in 40 msec and between each pulse delay is 60 degree i.e in 6.66 msec. I am using dspic33ep microcontroller. I want help in writing code logic for pulses

  21. arif says:

    hi ted.. can you please tell me how to know what is mips value and how to select ptper value.. i want to generate sinusoidally varying frequency..

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s