Reader Mo Hsen wrote in with an interesting query about generating PWM output from the dsPIC30F4011 on two channels with equal duty cycle but 180 degrees out of phase (see the waveforms below for an example). I’ve created a short sample program (for the C30 compiler) which is included in full below. Mo needs the PWM frequency to be 25kHz, so I’m running at the highest clock speed possible with the internal RC oscillator and I’ve set the PWM prescaler to a ratio of 1:1 in order to achieve fine-grained control of the pulse timing.
The basic approach is as follows:
- Enable up-down counting for centre-aligned PWM (“_PTMOD = 0b10;”).
- Enable PWM channels 1 and 2 in complementary mode (“PWMCON1 = 0b00110011;”).
- Set your PWM period as normal (e.g. “_PTCKPS = 0; PTPER = 600″).
- Then, whenever you set the pulse width on channel 1, you set the pulse width on channel 2 to be the opposite, i.e. “PDC2 = (2*PTPER )- PDC1;”. In my example below, I’ve phrased this slightly differently, but basically the idea is the same: if you want a duty cycle of 20%, set PDC1 for 20% and PDC2 for 80%.
- Finally, your 180 degree phase separated outputs are on PWM1H and PWM2L (pins 37 and 36 respectively).
My example program sets up this type of output, then switches back and forth indefinitely between duty cycles of 25% and 75%. Here’s are screenshots of the output waveforms on both channels for each duty cycle:
In the next screenshot, the cursors are enabled so that the period and frequency are displayed above the waveforms (40us and 25 kHz respectively). Note also that due to the high PWM frequency, I have set the sample rate to 1 MHz so that the recorded signal will not be aliased.
I’m using the following software versions:
- MPLAB IDE v8.50
- Microchip C30 Toolsuite v3.23 (free version)
- PICkit 2 Application v2.61.00
- Windows XP (service pack 3, I think)
Here’s the complete code for the program. I’m using the C30 compiler. Also, in MPLAB I have specified Configuration Bits set in code (in MPLAB’s “Configure” menu, click “Configuration Bits…” and then tick the box).
//
// This is a dsPIC30F4011 program to generate PWM on two channels
// simultaneously with equal duty cycle but 180 degrees out of phase.
//
// Written by Ted Burke
// http://batchloaf.wordpress.com
// Last updated 6-4-2012
//
#include <libpic30.h>
#include <p30f4011.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
// Function prototypes
void configure_pins();
void set_pwm_duty_cycle(double duty_cycle);
unsigned int read_analog_channel(int n);
int main()
{
// Set up digital i/o, analog input, PWM, UART and interrupt
configure_pins();
// Switch back and forth between 25% and 75% duty cycle
while(1)
{
_LATD1 = 1; // LED on
set_pwm_duty_cycle(0.75); // 75% duty cycle
__delay32(15000000);
_LATD1 = 0; // LED off
set_pwm_duty_cycle(0.25); // 25% duty cycle
__delay32(15000000);
}
return 0;
}
// Sets the duty cycle on PWM channels 1 & 2
void set_pwm_duty_cycle(double duty_cycle)
{
PDC1 = duty_cycle * (2 * PTPER);
PDC2 = (1 - duty_cycle) * (2 * PTPER);
}
// This function sets up digital i/o, analog input, PWM,
// UART and timer interrupt.
void configure_pins()
{
// Configure all four port D pins (RD0, RD1, RD2, RD3)
// as digital outputs
LATD = 0;
TRISD = 0b1111111111110000;
// Configure all three port C pins (RC13, RC14, RC15)
// as digital inputs
TRISC = 0b1111111111111111;
// Configure AN0-AN8 as analog inputs
TRISB = 0x01FF; // All 9 port B pins are inputs
ADPCFG = 0xFE00; // Lowest 9 PORTB pins are analog inputs
ADCON1 = 0; // Manually clear SAMP to end sampling, start conversion
ADCON2 = 0; // Voltage reference from AVDD and AVSS
ADCON3 = 0x0005; // Manual Sample, ADCS=5 -> Tad = 3*Tcy
ADCON1bits.ADON = 1; // Turn ADC ON
// Configure PWM for free running mode
//
// PWM period = 2 * Tcy * prescale * PTPER = 0.66ns * 1 * PTPER
// PWM pulse width = Tcy * prescale * PDC
//
PWMCON1 = 0b00110011; // Enable channels 1 & 2 in complementary mode
PTCON = 0;
_PTCKPS = 0; // prescale=1:1 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
_PTMOD = 0b10; // Select up-down counting for centre-aligned PWM
PTPER = 600; // 25kHz in up/down counting mode
PDC1 = PTPER; // 50% duty cycle on PWM channel 1
PDC2 = PTPER; // 50% duty cycle on PWM channel 2
PTMR = 0; // Clear 15-bit PWM timer counter
_PTEN = 1; // Enable PWM time base
}
// This function reads a single sample from the specified
// analog input. It should take less than 2.5us if the chip
// is running at about 30 MIPS.
// Because the dsPIC30F4011 has a 10-bit ADC, the value
// returned will be between 0 and 1023.
unsigned int read_analog_channel(int channel)
{
ADCHS = channel; // Select the requested channel
ADCON1bits.SAMP = 1; // Start sampling
__delay32(30); // 1us delay @ 30 MIPS
ADCON1bits.SAMP = 0; // Start Converting
while (!ADCON1bits.DONE); // Should take 12 * Tad = 1.2us
return ADCBUF0;
}
Finally, here are two images of the breadboard circuit I used to test the code. I took these using my phone, so unfortunately the image quality is not very good. However, the main details should hopefully be visible. Note that AVdd and AVss (pins 39 and 40) should be connected to the positive and negative supply voltages too, but I ran out of bits of wire!





Greetings mr.Ted Burke from Greece.
Your example is the only one we have tried that worked with our dsPIC30F4011 concerning the pwm and we are really happy about this.We are students at technological educational institute and would like to make an inverter using SPWM.Specifically we want to produce a pulse to drive 4 mosfets in order to get a pure sine wave.Our 1st try was to compile a source code with flowcode to make a sinus change of the duty cycle but no chance at all.We are newbies at C code and we try by our owns to find a solution to make the code works and really we have no chance.
Is there a possibility to make some additions to your source code to achieve our goal??
Thanks in advance.
Greetings mr.Ted.
Did you checked my latest reply about using your c source code and the additions i would like to make?
Hi George. I only just saw your comments this minute. I’m delighted to hear that you found my code useful, and I’ll do my best to help you solve your problem. Yes, it should be possible to make some changes to the code to produce pulses that vary their width over time in a sinusoidal fashion. I’ll have a go, but I’ll need some more details from you, such as:
1. What frequency of sinusoid do you want to produce?
2. Does the frequency of the PWM signal matter for the MOSFETs? (bearing in mind that it will certainly need to be much higher than the frequency of the sinusoid).
3. What are the maximum and minimum duty cycles that you want? In other words, what should the pulse width be at the high and low point of the sinusoid?
If you can provide this information, I’ll put together some sample code and post it on my blog.
Ted
Hello again George. I’ve just posted some sample code which I hope is similar to what you’re looking for. Here’s the link:
http://batchloaf.wordpress.com/2012/05/02/sinusoidal-variation-of-pwm-duty-cycle-with-dspic30f4011/
I set the PWM frequency to 10kHz and the sinusoidal variation to 50Hz, which I hope is appropriate, but if not I can modify it to suit your requirements. It just varies the duty cycle on PWM channel 1 (pins 37 and 38). The PWM channel is in complementary mode, so whenever one pin is high the other is low. If I’m picturing your circuit correctly, I think you may need to use the output from both pins. It’s also possible that you need to introduce some “dead time” in between one pin going low and the other going high. It’s possible to do this automatically with the dsPIC, but I’ll have to look up the datasheet to find out exactly how.
Anyway, have a look and try out the code. Let me know if it does the trick for you.
Ted
Dear Mr Burke,
Hello there. I am working on a project of making bi-directional dc dc converter,wherein i need to generate 180 degree phase shifted PWM for triggering the IGBTS. Can this same concept be used if i were to use edge triggered waveforms?
i need to trigger two legs of IGBTs ,both 180 degree phase shifted, and the upper and lower IGBT of the same leg have complementry switching. The period and the duty cycle of the IGBT remain same.
I am using dsPIC30f4011, and MPLABIDE 8.46, HI-TECH C compiler. The switching frequency is 20kHz, duty cycle remains 73 % during Boost mode and 27 % degree during Buck mode of operation.
Kindly let me know if this program can work with little addons?
Thanks in advance
Hi Jil,
I’m pretty sure it’s possible to do what you want, but I’m not 100% clear yet on the waveforms you need to produce. A few questions:
From what you’ve described so far, I suspect that it might be easier to do this using the dsPIC’s output compare pins rather than the PWM outputs. That’s not too hard though. Here are a couple of output compare example that I posted before:
Dear Mr Burke,
Thank you for your earliest reply.The answer to the questions you asked are below:
I am using four IGBTs in total,two in each leg, and the upper and lower IGBTs will work in complementary ,mode. Thus i will need four outputs, for eg if using PWM pins,i will need PWM1H,PWM1L,PWM2H,PWM2L.
By edge triggered waveform i meant sawtooth waveform, as in the above example you have used center aligned waveform. The concept is that i need to compare the sawtooth waveform with the constant 0.73 to generate the PWM pulses.
I do hae a circuit diagram and a sketch of waveforms, but i am not able to post it here. Could you please let me know how to do it so that the idea would be clear to you.
I was told that it would be difficult using output compare so i thought of using PWM motor module.
Thanking you,
jil sutaria
This link will give you the circuit diagram.
https://plus.google.com/photos/108135073972355193003/albums/5826140484845437457?authkey=CN-AuIi1pJPSKQ
Thanks Jil. I’m just writing up some example code, which I’ll post here on the blog. If you have a picture of the four waveforms you want, it would be great to see that too just in case I’m picturing the IGBT activation sequence correctly.
Regards,
Ted
Hi Jil,
I’ve just posted a first draft of some code to generate the IGBT control waveforms. It’s not complete yet, but hopefully it will give you some idea of the direction I’m going with it. if you could try compiling it and let me know how you get on, that would be great. I don’t actually have the compiler installed on this PC, so I haven’t been able to compile it myself yet. I’m using the XC16 compiler by the way, but hopefully this will compile for you without too much modification.
Here’s the link:
http://batchloaf.wordpress.com/2012/12/26/igbt-control-in-a-buck-boost-dc-dc-converter/
Ted
Hello Mr Burke,
thank you for the code.i have compiled the code and checked the output on a scope. I am not getting the phase shift.
Also i have given the link to the waveforms below the code for Buck-Boost converter.
Thanking you,
jil
HI Mr Burke,
I had look at some of your dsPic30f4011 examaples, you’ve done a great job.
I am working on a SRM drive system for my Phd project and I am interested to do “2DLinear Interpolation” by using a microprocessor which I prefer dsPic30f4011 cause I am slightly familiar with it. Could you please advice me how can I compute the time that the PIC needed to do a 2Dlinear Interpolation. The link for interpolation are below and in this stage I just need to know can I do a 2dinterpolation in less than 1mSec ( somwhere between 10usec-100usec). Or in the other hand I need to know the time that the PIC needed to Interpolate one value. Please advice me.
http://en.wikipedia.org/wiki/Bilinear_interpolation
http://en.wikipedia.org/wiki/Linear_interpolation
Regards
Mote
Please refer to linke below which explained Piecewise linear interpolation for PIC12/14/16 is maximum 137 instruction per cycle and I need this for dspic30f4011 to workout the time required for linear interpolation, cause I need to do cubic spilne interpolation which definitely needs more time than linear interpolation for latter taslk.
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1824&appnote=en020511
I highly appreciatye your help in advance Mr Bruke
Hi Mote,
Ok, let’s consider the bilinear interpolation first.
If you can supply some more information, perhaps including more details of the application (e.g. where the input to the interpolation process is coming from and where the output value is being used) hopefully we can get a clear answer to how fast it can be done.
Under certain circumstances, it should certainly be possible to do a bilinear interpolation within 1ms (and probably within 10-100us), but the time taken could vary considerably depending on the details of the application (data types, number of fixed points, etc).
Ted
Deat Ted
Fisr I have to appologies for late reply, my grandma passed away and I went to my country for her funeral thats why I could not reply on time.
Lets clarify the points you mentioned above:
1- I have to have a two dimentional grid of points, in the case of linear interpolation the grid size will be 20 columns and 61 rows (61×20=1220) and for cubic spline interpolation the grid size will reduce to 10 columns and 21 rows (21×10=210).I need to interpolate between nearest 4 points in each calculation for bilinear interpolation.
2-For bilinear interpolation the grid size is 61Rows*20Columns=1220
3-Data type that I would like to work with is minimum 5 digit number with 4decimal points (e.c 0.0000).
4-Data type are the same for all the intyerpolation process.
5-Input to the interpolation comes from a table which is a measured value of torque of a SRM machine.
6-The outpute value will store in a table to plote the torque of the machine.
Mote
Hi Mote,
I’m very sorry to hear about your grandmother.
Thanks for the additional details on the interpolation problem. I’ll need to have a think about this and try it out for myself to measure the time taken. At first glance, I can see that the lookup table will need to be stored in program memory, since each stored value will need to be a 16-bit number, and there isn’t enough RAM in the 30F4011 to store the grid values in data memory. That shouldn’t be a problem, but I suppose it will affect the execution time in some way.
Anyway, give me a day or two to think about this and I’ll get back to you.
Ted
Hi Ted
hope you are doing well. Just wanted to remind you about the computation of the time requires for interpolation in dsPic, I really appreciate if you have any idea please let me know.
Regards
Mote
Hi ted
Hope you are safe and sound, just want to know if you have thought about the interpolation’s time and if you couldn’t please advice me how can I estimate time requires for interpolations in dsPIC30f4011
Regards
Mohsen
Hi Mote,
Sorry I haven’t responded in full yet to your query, but I just haven’t had the time to get to the bottom of it because I’ve been very busy in work and there’s a backlog of queries on my blogs that I’ve been trying to get through. I have done some research on your question and I’m hoping to perform a complete experiment over the weekend to measure some actual computation times. I’ll let you know how I get on. Once I have my code written, I’ll probably put it up as a new blog post here.
Regards,
Ted
Hi Ted
I appreciate How busy you are as you have a very usefull site. Thanks again for your great help buddy.
Regards
Mote
Hi Mote,
I’m working on the interpolation problem now. I have a question though. I was re-reading your answers to my questions above and I’m still a bit confused about the input and output of the interpolation process. You said:
…but I think maybe you might have misunderstood my question. Am I right in thinking that you’re using the interpolation process to estimate torque in the SRM? If so, I assume that the grid of values has been populated with measured values that were obtained by varying two “input” parameters (current, speed, or something else?). Presumably, in your final application, you will measure the actual values of these two parameters using some kind of sensors and then use interpolation to estimate the torque?
The reason I ask is because the “input” values for the interpolation (the two measured parameters) will need to be scaled before being used as indices to the table. This is not a problem, but it’s an extra step that needs to be factored into the computation time.
I’ll keep working on it for the time being without assuming anything specific about the two parameter value ranges.
Ted