Updated version of IGBT control program for buck-boost dc-dc converter

This is an updated version of my IGBT control example for the dsPIC30F4011, which appeared in an earlier post. In this version, an analog control signal on pin AN6 is used to vary the duty cycle of the waveforms produced. Also, deadtime has now been included between the “on” phases of the two IGBTs in each pair (to prevent shoot-through).

// igbt_dcdc_converter.c
// dsPIC30F4011 program for IGBT DC-DC converter
// Written by Ted Burke
// Last updated 12-1-2013

#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

// Used to read analog input voltage
unsigned int read_analog_channel(int n);

int main()
	// Times (units are instruction cycles, Tcy=33.3ns @ 30 MIPS)
	int T = 1500;	// f = 20kHz -> T = 50us = 1500 x Tcy
	int Tdead = 30;	// 1us = 30 x Tcy
	int Ton, Toff;	// On and off times per cycle
	double dc;	// duty cycle
	// v is the input voltage in digital units
	// Values from 0->1023 represent the voltage range 0->Vdd.
	int v;
	// Configure AN0-AN8 as analog inputs
	ADCON3bits.ADCS = 15;  // Tad = 266ns, conversion time is 12*Tad
	ADCON1bits.ADON = 1;   // Turn ADC ON
	// Make all port D pins outputs
	TRISD = 0;
	// Configure timers 2 and 3 for 20kHz,
	// but 180 degrees out of phase
	PR2 = T; TMR2 = 0;
	PR3 = T; TMR3 = T/2;
	// Configure output compare channels 1 & 2
	// to control one pair of IGBTs (using Timer 2)
	OC1CONbits.OCM = 0b101; OC1CONbits.OCTSEL = 0;
	OC2CONbits.OCM = 0b101; OC2CONbits.OCTSEL = 0;
	// Configure output compare channels 3 & 4
	// to control the other pair of IGBTs (using Timer 3)
	OC3CONbits.OCM = 0b101; OC3CONbits.OCTSEL = 1;
	OC4CONbits.OCM = 0b101; OC4CONbits.OCTSEL = 1;
	// Now just keep updating the duty cycle while
	// the output compare pins do their work.
		// Update duty cycle based on analog input
		// First read analog input voltage from pin AN6
		// Input voltage range to circuit is 108V->130V
		// Assume scaling down by factor of 50
		// Input voltage range to dsPIC is 2.12V->2.6V
		// Voltages from 0->5V are represented by integers from 0->1023
		// Input voltage range in digital units is therefore 434->532
		v = read_analog_channel(6);
		// Output voltage is assumed to be 450V
		// Output voltage scaled down by factor of 50 is 7V
		// Scaled output voltage (7V) in digital units is 1432.2
		// Formula for duty cycle is: dc = 1 - (Vin / Vout)
		dc = 1 - (v / 1432.2);
		// Update pulse times for OC1 and OC2
		OC1R = Tdead;
		OC1RS = dc*T;
		OC2R = dc*T + Tdead;
		OC2RS = T;
		// Update pulse times for OC3 and OC4
		OC3R = Tdead;
		OC3RS = dc*T;
		OC4R = dc*T + Tdead;
		OC4RS = T;
		// Enable both timers (they may already be enabled)
		T2CONbits.TON = 1;
		T3CONbits.TON = 1;
		// Optionally include delay here if duty cycle
		// update frequency should be limited
		__delay32(3000000); // 0.1s delay
	return 0;

// This function reads a single sample from the specified
// analog input. It should take less than 5us when the
// microcontroller is running at 30 MIPS.
// The dsPIC30F4011 has a 10-bit ADC, so the value
// returned is between 0 and 1023 inclusive.
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 = 3.2us
	return ADCBUF0;

I’ve just tested this code and it seems to be working. Here are some graphs I captured using my makeshift dsPIC 4-channel logic analyser. I set the analog input voltage to three different values to observe the change in the waveforms.

These are the waveforms when the input voltage is 1.26V:

IGBT waveforms for input voltage 1.26V.

These are the waveforms when the input voltage is 3.34V:

IGBT waveforms for input voltage 3.34V

These are the waveforms when the input voltage is 4.41V:

IGBT waveforms for input voltage 4.41V

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

23 Responses to Updated version of IGBT control program for buck-boost dc-dc converter

  1. Jil Sutaria says:

    Hello Mr Burke,
    Sorry for the delay in reply. i tried running this program, but i am getting error in the output compare pulses. The OC2R should start after the dead band as i am delaying the rising edge of the pulses. so i set
    OC1R = Tdead;
    OC1RS = dc*T;
    OC2R = dc*T +Tdead;
    OC2RS = T;
    however when i tried to run the program i did not get output pulses on OC2 pin.
    Also i chose the ADC channel 6, by writing to ADCHS register but the dutycycle is still not changing with the change in the analog input.
    please let me know where i am making mistake.
    Thanking you,

    • batchloaf says:

      Hi Jil,

      There’s no need to set the ADCHS register directly – that happens already in the read_analog_channel function. I’ve changed line 67 so that it reads the analog input voltage from pin AN6 now (“v = read_analog_channel(6);”).

      Also, I’ve modified the pulse start and stop times to delay the rising edge of the complementary pulse using the dead time (see lines 76-86) as you described.

      I can’t try out the modified code here because I’m at home, but I’ll try it when I’m back in the office later.


    • batchloaf says:

      Hi Jil,

      I made a few small further updates and then checked the code on my setup here. As you can see from the waveforms I’ve added above, the program seems to be working correctly. Four waveforms are produced, the duty cycle varies with the analog input voltage (on AN6), and the dead time seems to be present. Let me know if you’re still having difficulty getting it working.


  2. Jil Sutaria says:

    Hi Mr Burke,
    Thank you so much. It is working fine.i made some mistake with analog channel.and yes the dead band is added i checked it on the controller.
    Thank you so much again.
    I had this doubt if i can dense the direction of current, suppose lets say that if i take that my converter is working in Boost mode so i take that direction of the flow of current as positive and the other direction to be negative in Buck mode. Then can the controller check and decide in which mode the converter is working?
    Thanking you,

    • batchloaf says:

      Hi Jil,

      Ok, I’m glad to hear the waveforms are appearing correctly now. Unfortunately, I don’t really understand the buck-boost circuit clearly enough to answer your question. When you talk about the controller checking in which mode the converter is working (buck or boost), doesn’t that just depend on the ratio of the input and output voltages? Doesn’t buck mode just mean that the output is a lower voltage than the input, and doesn’t boost mode just mean that the output is a higher voltage that the input? If so, and if the polarity of the input and output voltages is the same (i.e. both positive voltages), then it wouldn’t be difficult at all to just scale both voltages down (using a simple potential divider for each voltage) and feed them into two more analog inputs on the dsPIC. To work out which mode was active, all the program would need to do is read the voltage from both analog inputs and compare them to see which is higher.

      Is that the kind of thing you mean?


  3. Jil Sutaria says:

    Dear Mr Burke,
    You are right about the definition of the Buck-Boost converter. But this would be true in case of a unidirectional Buck-Boost converter. However i am making a Bi-directional Buck-Boost converter, meaning there are voltage sources on both the sides, in input and output , so the converter basically needs to decide which side is input and which side is output, and accordingly take the feedback voltage from the output side, in case of a closed loop system. The two voltage sources in my project is DC link from rectifier on one side and battery on the other. The DC link available is 320 V and the battery if fully charged is 40 V. This can be used in case of a Uninterrupted power supply. Thus when DC link is not available the Battery acts as source, thus working in Boost mode and when it is available the DC link would act as source supplying power to the Battery. I have done a closed loop simulation in MATLAB and to decide which direction the converter is working i used the direction of flow of inductor current.
    I hope this will help you understand what i mean. Basically i am making a Two quadrant chopper.
    Thanking you,

    • batchloaf says:

      Hi Jil,
      Ok, I had to think about it for a while, but I think I see how your circuit works now. Am I right in thinking that you effectively have two converters in parallel here (presumably to reduce output ripple). When I say “two converters”, I mean:

      1. First converter: L1, S1, S3.
      2. Second converter: L2, S2, S4.

      I’m assuming they’re both included to reduce output ripple since they are 180 degrees out of phase. However, it looks like the system would basically operate with just one of these – e.g. if L2, S2 and S4 were removed – albeit with more ripple.

      Am I correct about this? If so, then presumably the following is true:

      • The voltage on Chigh is always higher than the voltage on Clow (irrespective of whether the system is in buck or boost mode).
      • When the system is in buck mode, power always flows from left to right.
      • When the system is in buck mode, the current flows through L1 from left to right.
      • When the system is in buck mode, D1 conducts (rather than S1).
      • When the system is in boost mode, poser always flows from right to left.
      • When the system is in boost mode, the current flows through L1 from right to left.
      • When the system is in buck mode, S1 conducts (rather than D1).

      If all of the above is true, one easy way for the microcontroller to tell the difference between buck and boost modes is to place a very low-valued current-sensing resistor between S1/D1 and ground (or between S2/D2 and ground) and keep an eye on the voltage across it by connecting it to an analog input on the microcontroller. If the voltage goes positive when the control signal to S1 is on, then the system is in boost mode. If it doesn’t, then it’s in buck mode.

      You just need to be careful when selecting the current-sensing resistor value to limit the resistor voltage to a small value (based on the expected current magnitude). In buck mode, the voltage generated across the current-sensing resistor will be negative and this voltage will be connected to an analog input, so it’s important that it does not go further below zero than the microcontroller specs allow for an analog input.


  4. Jil Sutaria says:

    Hi Mr Burke,
    you have understood it correctly and exactly.Thank you. The two converters are connected in parallel so as to reduce the ripple. Actually there is no separate diode to be used. The switch does not operate even though the gate pulse is provided to it, since it is reverse biased, on the other hand the diode is forward biased so it operates in the reverse direction.
    The Body diode in the IGBT will operate when the switch is not ON. So how can i provide a sensing resistor between the two?
    That is the reason i was thinking if i can sense the direction of current through inductor.
    Thanking you,

    • batchloaf says:

      Hi Jil,
      A current-sensing resistor between the IBGT and ground effectively senses the direction of the inductor current, which as you correctly stated is what you really want to know.

      For example, consider the IGBT labelled S1/D1 in your circuit. In your original circuit, the emitter is connected directly to ground, so current can flow easily in either direction (i.e. with the IGBT acting as either a transistor or a diode depending on whether it is forward or reverse biased). When you place a very low-valued resistor (e.g. less than 1 Ohm) between the emitter and ground, this current has to flow through the low-valued resistor which generates a small voltage due to Ohm’s law. By sensing the polarity of the generated voltage, you can determine which way the current is flowing through the IGBT, and therefore which way it is flowing through the inductor. Of course, this voltage will only be present while the IGBT is conducting (i.e. when it is switched on).

      The advantage of detecting the current direction at this point in the circuit (rather than at the inductor) is simply that one end of the current-sensing resistor is connected to ground, so the generated voltage is relative to 0V and is therefore really easy to input into an analog input on your microcontroller.

      If you don’t want to use a current-sensing resistor at this point in the circuit for some reason, there are alternatives of course. For example, you could probably use some kind of current transformer to sense the inductor current directly. One benefit of sensing the current direction in the inductor (rather than at the IGBT) is that the inductor current flows continuously (unlike the IGBT current which switches on and off), so you don’t need to worry about checking at the right time.

      Hopefully that explains it?


  5. Jil Sutaria says:

    Hi Mr Burke,
    Thank you. I now see the point. I was not able to understand exactly where the resistor is to be placed. As such the switching current is same as inductor current so it can be used as a reference. i will have to take care of the timings though. will try and simulate this.
    Thank you so much.

    • batchloaf says:

      Hi Jil,
      Another thought struck me about timing the check on the current-sensing resistor voltage. Rather than trying to determine the correct time by looking at TMR1 or something like that, you can just connect the logical control signal for S1 (from OCx output pin) back into a digital input pin. Then when you’re reading the analog input to check the direction of current, you can just check the digital input to see whether S1 is “on” or not. When it’s not on, you can just ignore the analog input reading because it won’t be telling you anything about the current.

      It’s not a very elegant way of timing your measurement, but it should be simple and effective.


  6. Jil Sutaria says:

    hi Mr Burke,
    Thank you for suggesting it. I did not understand your point clearly. actually when S1 is ON and current is flowing through it, and we assume that direction of the current to be positive then it would mean that the converter is working in Boost mode, And when S1 is off and converter is still in Boost mode ,no current will be flowing through it as the upper diode D3 conducts.
    Whereas in Buck mode although the switch gets the control signal it would not turn ON , instead the diode D1 will work and hence current will flow in reverse direction through it, which can be assumed as negative direction of current flow, So the sensing resistor should show positive voltage and it should be measured when the switch is ON .In Buck mode only the diode will work during the turn on control signal, and the voltage obtained will be negative.
    So i am supposed to measure the voltage always irrespective of the mode of working only when i provide the turn on signal to the switch. Am i right in thinking that?

    • batchloaf says:

      Hi Jil,

      Yes, that’s right! you only measure the current-sensing resistor voltage when the control signal to S1 is ON, no matter what mode the system is in. If the system is operating in boost mode, S1 will be conducting when the control signal is ON and the current-sensing resistor voltage will be positive. If the system is operating in buck mode, D1 will conduct instead when the control signal is ON and the current-sensing resistor voltage will be negative. When the control signal is OFF, neither S1 or D1 will be conducting, so the current-sensing resistor voltage will be zero, irrespective of whether boost or buck mode is active.


  7. Jil Sutaria says:

    Hi Mr Burke,
    Thank you. will try to simulate that first.

  8. Jil Sutaria says:

    Hello Mr Burke,
    I have completed the open loop operation of the converter and now have started with the closed loop operation. i was trying the sensing of the output dc voltage in buck mode , that first it has to be converted to 5 V,then it has to be sensed by the ADC and converted to digital that is 0-1023 and then display the output again in voltage on a lcd. The analog input AN5 to AN10 can be used to display it. As it is DC i can display it directly.however the output has ripple in it means it is not constant at all instants.so i was confused whether i will have sample it?but i am not able to decide the sampling rate. how should i go about it.
    Thanking you,

    • batchloaf says:

      Hi Jil,

      Have you looked at the ripple on the oscilloscope to get an idea about its waveform and frequency content? If the shape of the ripple is reasonably consistent, it should be possible to measure the average (i.e. DC) level of the signal by taking the average of several samples separated by specific time delays.

      For example, let’s suppose the ripple was a 50Hz sine wave (a very simplistic example of course), you could measure the DC level easily enough by taking two samples separated in time by 10ms and then finding the mean of the two values. It wouldn’t matter where in the waveform the first sample occurs, just as long as the two samples are separated by 10ms. In reality, it might be preferable to take a series of samples at 100Hz (an even number in total) and find their mean, which would tend to reduce the effect of random noise and measurement errors.


  9. Jil Sutaria says:

    hi Mr Burke,
    ya i have taken the output voltage waveform on oscilloscope and the voltage ripple comes to be around 1.6 V in and the output voltage is 36 V. This is the switching frequency ripple and the switching frequency is 20 kHz so will it be alright if the samples are taken at a frequency of 100 Hz?i have attached the result of oscilloscope for ur reference on this link:
    hope it will give you some idea.
    And if so then the programing for this will be somewhere along the lines of the post “Simple interrupt-driven sampling example for the dsPIC30F4011”. am i right in thinking that?
    Thanking you,

  10. batchloaf says:

    Hi Jil,

    Since the ripple frequency is at a very high frequency, it might be more difficult to sample at the exact right moments to average a small number of samples as I described in my previous reply. I would probably suggest one of the following two approaches instead:

    1. Use a hardware RC low-pass filter to filter the ripple out of the signal before it is measured at an analog input. The cutoff frequency of the filter just needs to be well below 20kHz. For example, you could use an RC filter with a cutoff frequency of a couple of hundred Hz. An low pass RC filter with R = 12kOhm and C = 47nF would give you a -3dB frequency of 282.19Hz.

    2. If you don’t want to use any additional hardware components, you could just take a large number of samples in quick succession over a few periods of the ripple and get the average of them. For a high frequency ripple like this, I probably wouldn’t bother trying to time it too accurately (although it might be possible with some care) – I would rely instead on taking the average of a larger number of randomly timed samples so that the exact timing is not that important.

    Option 1 above is probably the simpler and more reliable option, so that’s what I would recommend.


  11. Jil Sutaria says:

    Hello Mr Burke,
    i have tried using the RC filter in the output of my converter, but if i limit the switching frequency ripple upto 200 Hz then it will filter out the original ripple and also delay the transient response of the system. so i was thinking to go for taking a number of samples, and averaging out. But i am not able to understand how to configure the adc, and display it on lcd.

  12. Song says:

    Dear Ted,
    How are you?

    I have tied your code, it’s work. Thank you very much for your sample code.
    But I wonder about the ADC setting in the ADC Buffer that you set to ADCBUF0. The ADC of dsPIC30F4011 have 16 buffers (ADCBUF0-ADCBUFF).
    My question,
    1. why only the ADCBUF0? What about the other ADCBUF ?
    2. If I want to select the other ADCBUF ,how to select them ?
    3. The ADCBUF0 is the default buffer ?
    Could you briefly explain about ADC Buffer ? (The other instruction I have seen in datasheet, but I dont understand for the ADC Buffer.)

    Thank you so much again.

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Google+ photo

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

Connecting to %s