Irev-Dev / Arduino-Atmel-sPWM

Implementation of an sPWM signal
154 stars 79 forks source link

No Deadtime #4

Open sudiptamandal opened 6 years ago

sudiptamandal commented 6 years ago

There is no dead time in this code. sometimes pulses overlaps. Can't drive any MOSFET or IGBT with this code

tvixen commented 6 years ago

Hi Kurt Could you please comment this comment. Thanks in advance.

Terbytes commented 5 years ago

@sudiptamandal Dead time for a h-bridge I'm assuming. Feel free to make a PR

johnnypeste commented 5 years ago

can you modify the code to use 2 more pairs of pins with SPWM out of phase 120 degrees and 240 degrees. in order to make a 3 phase inverter. I guess Arduino mega is needed for that...

Irev-Dev commented 5 years ago

@johnnypeste I did have a quick go at making a three-phase version, but it was much more difficult than the single-phase with how resource-constrained these micros are. I think with the cost of hardware, it's probably worth moving to something a bit more beefy than 8-bit. Also, it's not as simple as making the same signal another two time out of phase. If you've ever looked at a three-phase bridge, it gets pretty tricky. No shorting the bridge for a single-phase is trivial and can be handled with deadtime, much harder with three-phase.

johnnypeste commented 5 years ago

Thank you for the response but i i have plenty of deadtime and i will invest in 3 phase... If i have 3 one phase ac ources dephased each other by 120 degrees i dont understand why i cannot connect therm together with one common to the 3 and use the other  3 terminals as the 3 phases. Regards Joao

Sent from Yahoo Mail on Android

On Sat, 28 Sep 2019 at 7:27, Charlienotifications@github.com wrote:
@johnnypeste I did have a quick go at making a three-phase version, but it was much more difficult than the single-phase with how resource-constrained these micros are. I think with the cost of hardware, it's probably worth moving to something a bit more beefy than 8-bit. Also, it's not as simple as making the same signal another two time out of phase. If you've ever looked at a three-phase bridge, it gets pretty tricky. No shorting the bridge for a single-phase is trivial and can be handled with deadtime, much harder with three-phase.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

AttonRisk commented 5 years ago

Something like the AtTiny85 could make for a good candidate to offload the work onto. They are also cheap and pretty easy to integrate.

johnnypeste commented 5 years ago

Seems like a nice cheap microprocessor... I will give it a try... Thank you and i will let you know if i succeed. The 1 phase ac dc conversion is the more expensive part, requiring a 20 mF capacitor or a big inductance in order to have a decent dc ripple... the cheapest capacitors i found were kemet 10 mF 450 V. I will put 2 of them in parallel when my input is 1 phase and 2 of them in series when my input is 3 phase (in this case the arduino and igbt setup is only to have 3 phase with a varible frequency). Bye

Sent from Yahoo Mail on Android

On Sat, 28 Sep 2019 at 17:10, thenuke321notifications@github.com wrote:
Something like the AtTiny85 could make for a good candidate to offload the work onto. They are also cheap and pretty easy to integrate.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

AttonRisk commented 5 years ago

Do keep in mind the issues of power factor and harmonics when dealing with mains power

johnnypeste commented 5 years ago

What do you mean exactly?

Sent from Yahoo Mail on Android

On Sun, 29 Sep 2019 at 5:35, thenuke321notifications@github.com wrote:
Do keep in mind the issues of power factor and harmonics when dealing with mains power

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

yo6ial commented 3 years ago

Hi folks. Old thread, old code but beautiful code. I'm in the process of converting a square wave inverter to sine and this piece of code struck me the second I saw it. Praises aside and to whom may this concern in the future, there is no overlap between pulses and there is no need to insert dead times in the code. Any sane inverter design implements shoot-trough prevention in hardware. The gate drivers like ir2110 have the needed internal logic for this. Here is a pic of my nano (328p) output on the scope: https://photos.app.goo.gl/U5djzXFAW4uBJ9dM7

Happy trails!

Irev-Dev commented 3 years ago

Really appreciate you sharing that. Thanks @yo6ial.

11Naweed11 commented 2 years ago

hello everyone, I tried this code with an inverter but unfortunately couldn't get it to working. here is my setup: Schematic_H bridge v3_2022-02-18_001

MOSFETs Q1 to Q4 are IRFP460 U1 and U2 are IR2110 The input voltage of the H-bridge is 300 ~ 350 VDC (J1) Gate drive voltage is 12 ~ 15 VDC for driving the FETs. (J1) Logic level is 5 volts. The LC filter after the H-bridge uses 3.3 mH inductor with 4 ohms of resistance and 2.2 uF capacitor. (J3) Signal from Arduino comes in from J2.

The output of the Arduino after filter is pure sinewave but the output of the H-bridge after the filter is nowhere near sinewave. it also takes a lot of current from power supply without any load at the output. 20220218_231511

I am sure there is nothing wrong with my build because I have used it with EGS002 spwm driver module and everything works fine. The output is pure sinewave and it takes negligable current from supply. 20220218_231712

After doing some investigation 2 things stoodout to me. One that in default configuration EGS002 does unipolar modulation while Arduino with your code does bipolar, and second is the dead time, which EGS002 by default has a 300ns of dead time. Now you could argue that if EGS002 is working fine for me why would I try something else? the answer is that EGS002 is an ASIC meaning you don't have the freedom of customization. For example I want to change the inverters parameters with a graphical user interface such as output voltage or frequency. This is hard and expensive to do with EGS002.

If you wanted to know anything more, I am very much willing to provide. Thanks.

Irev-Dev commented 2 years ago

Just guessing @11Naweed11, but I suspect that the dead time is the most likely culprit, only because that would explain why the current is high even with no load, if it's shorting the h-bridge during the crossing, and if it is shorting it wouldn't surprise me if that would have a knock on effect of distorting the output shape. 🤷

11Naweed11 commented 2 years ago

Well, the problem with bipolar modulation (meaning we feed both sides with spwm) is that it requires a better filter at the end which is difficult. This type of modulation is ok when used with low voltage low frequency transformers (because they don't require a filter) but not high voltage. But the problem with low frequency transformers are that they waste a lot of energy. I tried unipolar codes using Timer1 library but could never get the dead time to be less than 4.5 us which is alot. The dead time should be more or less 500 ns.

yo6ial commented 2 years ago

hello everyone, I tried this code with an inverter but unfortunately couldn't get it to working. here is my setup: Schematic_H bridge v3_2022-02-18_001

MOSFETs Q1 to Q4 are IRFP460 U1 and U2 are IR2110 The input voltage of the H-bridge is 300 ~ 350 VDC (J1) Gate drive voltage is 12 ~ 15 VDC for driving the FETs. (J1) Logic level is 5 volts. The LC filter after the H-bridge uses 3.3 mH inductor with 4 ohms of resistance and 2.2 uF capacitor. (J3) Signal from Arduino comes in from J2.

The output of the Arduino after filter is pure sinewave but the output of the H-bridge after the filter is nowhere near sinewave. it also takes a lot of current from power supply without any load at the output. 20220218_231511

I am sure there is nothing wrong with my build because I have used it with EGS002 spwm driver module and everything works fine. The output is pure sinewave and it takes negligable current from supply. 20220218_231712

After doing some investigation 2 things stoodout to me. One that in default configuration EGS002 does unipolar modulation while Arduino with your code does bipolar, and second is the dead time, which EGS002 by default has a 300ns of dead time. Now you could argue that if EGS002 is working fine for me why would I try something else? the answer is that EGS002 is an ASIC meaning you don't have the freedom of customization. For example I want to change the inverters parameters with a graphical user interface such as output voltage or frequency. This is hard and expensive to do with EGS002.

If you wanted to know anything more, I am very much willing to provide. Thanks.

Your problem comes from the incorrect filtering. When you pwm both branches of the line you need to use an inductor on each branch for the output filter. You go with an inductor from each half-bridge output and one (or more) capacitor between the inductors at the very end.

Your output filtering part of the schematic is for half-pwm where one of the half-bridges modulates a 50/60hz square wave with 50% pwm fill rate. Add another identical inductor and please move low voltage lines (physically) away from high voltage lines and outputs.
Take extra care of EMC, EMF and ground loops.

11Naweed11 commented 2 years ago

hello everyone, I tried this code with an inverter but unfortunately couldn't get it to working. here is my setup: Schematic_H bridge v3_2022-02-18_001 MOSFETs Q1 to Q4 are IRFP460 U1 and U2 are IR2110 The input voltage of the H-bridge is 300 ~ 350 VDC (J1) Gate drive voltage is 12 ~ 15 VDC for driving the FETs. (J1) Logic level is 5 volts. The LC filter after the H-bridge uses 3.3 mH inductor with 4 ohms of resistance and 2.2 uF capacitor. (J3) Signal from Arduino comes in from J2. The output of the Arduino after filter is pure sinewave but the output of the H-bridge after the filter is nowhere near sinewave. it also takes a lot of current from power supply without any load at the output. 20220218_231511 I am sure there is nothing wrong with my build because I have used it with EGS002 spwm driver module and everything works fine. The output is pure sinewave and it takes negligable current from supply. 20220218_231712 After doing some investigation 2 things stoodout to me. One that in default configuration EGS002 does unipolar modulation while Arduino with your code does bipolar, and second is the dead time, which EGS002 by default has a 300ns of dead time. Now you could argue that if EGS002 is working fine for me why would I try something else? the answer is that EGS002 is an ASIC meaning you don't have the freedom of customization. For example I want to change the inverters parameters with a graphical user interface such as output voltage or frequency. This is hard and expensive to do with EGS002. If you wanted to know anything more, I am very much willing to provide. Thanks.

Your problem comes from the incorrect filtering. When you pwm both branches of the line you need to use an inductor on each branch for the output filter. You go with an inductor from each half-bridge output and one (or more) capacitor between the inductors at the very end.

Your output filtering part of the schematic is for half-pwm where one of the half-bridges modulates a 50/60hz square wave with 50% pwm fill rate. Add another identical inductor and please move low voltage lines (physically) away from high voltage lines and outputs. Take extra care of EMC, EMF and ground loops.

I have tried that type of filter too. It improved things a little but not completely solved the problem. The H-bridge still draws current from power supply though less than before and the output waveform is not sinewave.

yo6ial commented 2 years ago

Larger inductances, less permeable cores. Check the cores temperatures. They might saturate even without load, only with the reactive power from the capacitor.

11Naweed11 commented 2 years ago

Larger inductances, less permeable cores. Check the cores temperatures. They might saturate even without load, only with the reactive power from the capacitor.

Like I said in my previous comments, this particular circuit with it's filter setup works fine with other spwm modules and inverters. I am sure there is no problem with the circuit or the filter. The inductance is 3.3 mh and the winding has 140 turns on a toroidal core. I have also tried many other filter values the results are almost the same.

11Naweed11 commented 2 years ago

Using different types of filter or filter values slightly change the shape of the output waveform but the high current draw from power supply always exists. If I remove the filter capacitor though, current draw goes down to zero. So is it the capacitor shorting out the power supply? I have used different values of filters in commercial inverters just to see the effects, the only thing that changes is the waveform it never shorts the power supply.

yo6ial commented 2 years ago

Alright then, I think I know now what happens. You are switching at very low frequencies and the inductors have to low impendances at those frequencies. Pump up SinDivisions (xx), Use even numbers, try like 128, 256, etc. Until you run out of space and step back a bit with an even number. But a parasitic draw will be there no matter what. The reactance of the capacitor needed to smooth out the pwm signal to a sine wave ”reflects” energy back towards the inductors and the inverter and getting lost to heat.

My 2kW inverter wastes about 20W at the filter end of it. I can't remember the division value used but it's switching around 30kHz.

GaryNotAI commented 1 year ago

This is not my code but it is open source and compiles in the Ardiuno IDE, the complete project can be found at the backshed.com under Nanoverter. It has soft start so it is compatible with a Toroid Transformer with 1:9 turns ratio for 48VDC to 240VAC. I have found my way here in my efforts to better understand the code.

This code runs very nicely and is used by a number of people to power their houses including me. I am trying different modulation though, this code is Unipolar. It works extremely well but does not work like my original inverter that I built that uses an EG8010 IC. With the EG8010 I use several Grid Tie Inverters connected to the AC output of my H-Bridge LF Off-Grid Inverter. With the GTIs connected the off grid inverter converts excess AC power to DC to charge the battery. If anybody is familiar with this and has better understanding of how it works and how the modulation effects I would really like to hear from you.

`#define ADC_OUT 0 // channel for AC output sample

define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))

define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

define NPWM 200 // 200 for this and 800 for PPWM for 50Hz and 20kHz PWM. Both must be integers.

//#define PPWM 665 // 60.062 Hz - choose one or the other.

define PPWM 800 // 50.002 Hz 799 49.939 Hz for 800

uint8_t uf,oen,v1low, lv_stopped,int_f; uint16_t pcount; uint32_t vpwr; int sst; uint16_t l[NPWM+1]; float pwr; uint8_t dbounce; double Input, Output, Setpoint; double errSum, lastErr,error,dErr; double kp, ki, kd; float xv[5],yv[5]; float ac_output, ac_setpoint;

void init_vars(void);

uint8_t init_done; uint8_t tt=0;

void setup() { int i; float t,u;

for(t=0.0,i=0; i <= NPWM; i++,t += 3.14159/ (float) (NPWM+1)) {
u = 65535.0 * sin(t); // 1/2 wave sine lookup table, scaled to (16 bits - 1) l[i] = (int)u; //lookup table, to save time from calculating the sine function. The table is an array

}

pinMode(9, OUTPUT); // V1 drive pinMode(10, OUTPUT); // V2 drive pinMode(12, OUTPUT); // inverter ON/OFF LED, pin 15 on nano, Arduino D12 pinMode(8,INPUT); // continuous on/off pin, driven by nano2 pinMode(6,INPUT); // SCR shut down, pulled high to shut down inverter pinMode(5,OUTPUT); // used for IR2110 shutdown drive, LOW = shutdown pinMode(7,OUTPUT); // DSO sync pulse, each 50Hz pinMode(2,INPUT); noInterrupts();

TCCR1A = _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1) | _BV(WGM11); TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); OCR1A = 10; ICR1 = PPWM; TIMSK1 |= (1 << TOIE1);

cbi(PORTD,5); // disable gate drive output. data direction flag set by above statement. oen = 0; // output enable. = 1 to run inverter, = 0 to stop inverter init_vars(); init_done = 1;

interrupts(); // enable all interrupts TIMSK0 = 0; // except arduino clock

sbi(ADCSRA,ADPS2) ; // ADC clock prescale = 16 now. this saves 100us in main loop with little cost to loop stability cbi(ADCSRA,ADPS1) ; cbi(ADCSRA,ADPS0) ;

//Serial.begin(115200); // remove in production code }

// // 20Khz SPWM, code has only 50uS to run, takes about 10uS // ISR(TIMER1_OVF_vect)
{
long c; if (pcount == 0) if (v1low == 1) // if first 1/2 wave.. { TCCR1A = _BV(COM1B1) | _BV(WGM11); // config output compare to suit cbi(PORTD,7); }
else { TCCR1A = _BV(COM1A1) | _BV(WGM11); // config O.C. to suit sbi(PORTD,7); } c = (l[pcount] * vpwr) >> 16; // scale sine wave by vpwr, 32 bit integer calcs. 16 bit shift fastest of all if (v1low == 1) // alternate between 2 output compare pins. Get a full 50Hz waveform { // v1low is the flag to determine if we are driving one or the other of the 1/2 wave parts. OCR1B = c; // was c 1/2 out this pinOCR1B is the duty cycle register for pin 10 } else { OCR1A = c; // and then 1/2 out this pin. OCR1A is the duty cycle register for pin 9 } pcount ++; if(pcount >= NPWM) // pcount will = NPWM, at each 1/2 wave, at the start { pcount = 0; // reset counter uf=1; // enable one PID control loop execution, in loop() if (v1low == 1) // if first 1/2 wave.. { v1low = 0; // toggle to 2nd half wave }
else { v1low = 1; // toggle to 1st half wave } } }

void init_vars() // called prior to setting oen = 1, as well as from setup() { ICR1 = PPWM; lv_stopped = 0;
sst = 0; // slow start counter 0 - 251 v1low = 1; // half wave output flag, 0 or 1 pcount = 0; // counter for sine wave lookup table uf = 0; // set to 1 to enable AC output voltage feedback code to execute pwr = 0.0; // PWM duty cycle analog, 0.0 to 1.0 vpwr= 0; // integer equivalent of pwr, 0 to PPWM dbounce = 0; // debounce counter for input switch kp = 0.1; // set up PID for AC output voltage control ki = 0.0; kd = 0.01; errSum = 0.0; // initialise PID lastErr = 0.0; cbi(PORTD,4);
}

void do_pid() {
double timeChange = 0.01; // always called at 100Hz, so dT will be 10msec.. error = Setpoint - Input; errSum += (error timeChange); dErr = (error - lastErr) / timeChange; Output = kp error + ki errSum + kd dErr; lastErr = error; }

void loop() { float ch0;

// sample channel.. // In the past, I low pass filtered this. not now, no need thanks to active LP filter on Vfb ac_output = (float)analogRead(ADC_OUT) / 1024.0; // scale 0 - 5V to 0.0 to 1.0

if(uf == 1 ) // this will execute at 100Hz { // it runs at near zero volt crossing of AC output
uf=0; ac_setpoint = 0.55; // for same Vfb as EG8010. change AC output voltage via Vfb voltage divider trimpot if (oen == 1) sst++; // slow start. If output is enabled, keep starting up. sst = output pwm% or approx. voltage. if (sst > 251)sst = 251; // stop increasing when sst has got to the end of slow start. when = 251, this enables PID. See below.. if (oen == 0) sst--; // if stopping, slow stop if (sst <= 0) // once fully stopped, no more changes to sst needed { sst = 0; cbi(PORTD,5); // pull IR2184 shutdown LOW to disable gate drive output } else sbi(PORTD,5); // pull it HIGH, to enable output

  if(sst > 0 && sst < 250)     // slow start timer counts to 250 with gentle ramp up, then switches over to PID control. (gulp!)
    {                          // sst can increase or decrease, giving the slow start and slow stop.
    if (oen == 1)              // slow stop? I think of it as de-gauss
      { 
      if(ac_output < ac_setpoint)
        pwr += 1.0/250.0;     // bang-bang control, should AC output reach setpoint prior to PID.
      else                    // During slow start need to ensure output is tracking setpoint
        pwr -= 1.0/250.0;     // should output get close enough to matter.
      }
    else
      pwr -= 1.0 /250.0;      // this will execute in slow stop
    }

  if (sst == 251)       // once sst = 251, run PID. the above bang-bang control will NOT have executed, because sst = 251
    {                   
    Setpoint = ac_setpoint;     
    Input = ac_output;  
    do_pid();
    pwr = pwr + Output;
    }

  if (pwr > 0.99) pwr = 0.99;     // clamp. Do math in floating point to prevent any integer overflow
  if (pwr < 0.01) pwr = 0.01;     // it's slower. We could do clamp after conversion to int but it's your mosfets...
  vpwr = (int)((float)PPWM * pwr);// finally apply required PWM duty power factor to vpwr     
  check_switch_cont(); 
  }

}

void check_switch_cont() {
if ((PINB & 0x01) == 0x01)
{ if (init_done == 0 && sst == 0) { init_vars(); init_done = 1; }
oen = 1; // slow start sbi(PORTB,4); // and light LED on D12, pin 15 of nano }

// scr shutdown - without a dummy connection of D6 to ground, inverter wont run. if (((PINB & 0x01) == 0) || ((PIND & 0x40) == 0x40)) // for testing, do not check scr shutdown pin, just nano2 on/off //if (((PINB & 0x01) == 0) )
{ init_done = 0; oen = 0; // slow stop cbi(PORTB,4); // and blank LED on D12, pin 15 of nano }
} `