High Frequency PWM for smps

First of all, hello everyone.

I'm writing using Google translate, sorry for my bad English.

I have an old product. The Atmega48-20au model was used to drive the IGBTs in the switching power supply section. Unfortunately spare parts and software are no longer available and I need to get this product working.

The circuit works with half bridge topology. The biggest problem here is that it operates at 125khz per IGBT. atmega48-88-328 has the same pin layout. I can program it with the minicore library via the Arduino ide. I'm not very good at Arduino, but even though I tried for a few days, I couldn't get an output above 31khz from Arduino pins 9 and 10. I'm trying to code with Arduino Uno and Rigol oscilloscope. SMPS will operate at 31khz level, but the power and efficiency loss will be too high.

I found GyverPWM library for high pwm output. The person who prepared the library is Russian and all the resources are in Russian, which I did not understand because I do not have much experience.

With this code I get a useful signal at 31khz. This is an original code. I do not use the A0 analogread command. There is no voltage measurement in my circuit. It works with a fixed duty cycle of 48%.
But I need to get at least 100khz. The design power of SMPS is around 700w.

I would be grateful if you could help me.
I am adding an example schema

int Output_PWM = 0;
int DT = 10; // Set Dead Time
int Voutput = 0;
int inductor = 0;
int SetPoint = 500; // 500 = 15V @ Voltage output

void setup()
{
pinMode(10, OUTPUT); // PWM Signal Lo Side
pinMode(9, OUTPUT); // PWM Signal High Side
pinMode(13, OUTPUT); // LED Signal OK System RUN
Serial.begin(9600);

TCCR1A = 0b11100001; //Set Record Phase Correct PWM
TCCR1B = 0b00000001; //set Fsw = 31.372 kHz

delay(1000);
digitalWrite(13, HIGH);
delay(500);
digitalWrite(13, LOW);
}

void loop()
{
 
        Output_PWM = analogRead(A0);
        Iinductor = analogRead(A1); // Read ADC A1 for inductor
   
        Output_PWM = 255-(Output_PWM/8);
     
       if (Output_PWM<5){Output_PWM=10;}
       if (Output_PWM>250){Output_PWM=255;}

         OCR1A = Output_PWM; //PIN D11
         OCR1B = (Output_PWM-DT); //PIN D3
         delay(50);
    }



sic-ap-1-2_f1

The maximum value of the 8-bit PWM frequency for Atmega48-88-328 chips at a core frequency of 16 MHz is about 62 KHz:

16 MHz / 256 = 62 kHz

You don't need any library for this, Just change the timer settings.
For Timer1 (pins 9 and 10) it will be like this:

TCCR1A = 0b00000001;  // 8bit
TCCR1B = 0b00001001;  // x1 fast pwm

It is impossible on AVR chip clocked on 16 MHz without decreasing of PWM resolution.

2 days ago I found out that I can get 62 khz PWM on Arduino. But what really worries me is that I see 125khz PWM when I measure with the oscilloscope from the working device.

Yes, it is possible if you decrease a PWM bit resolution.

I'm now looking at the library you mentioned - GyverPWM - it has very easy examples.

When I used gyverpwm, I couldn't figure out how to change the phase of one of the PWMs.
While the 1st pwm is high, the 2nd pwm should be low
While the 1st pwm is low, the 2nd pwm should be high
there should never be two high and two low

The library actually is very simple.
Its documentation has not been translated into English, but this documentation is not needed there.
See examples.
Here is an example of setting 150 KHZ PWM frequency on pins 9 and 10. I have translated some comments into English:

#include <GyverPWM.h>

void setup() {
 
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  
  // only pins D3, D5, D9 & D10 available on ATmega328

  // run PWM on D9 with freq 150'000 Hz,  FAST_PWM mode
  PWM_frequency(9, 150000, FAST_PWM);

  // run PWM on D10 with freq 150'000 Hz,  FAST_PWM mode
  PWM_frequency(10, 150000, FAST_PWM);

  // pins 9 & 10 can use the same PWM frequencies only!
}

void loop() {

  // PWM duty should be always set in range 0-255 regardless to actual PWM resolution
  PWM_set(9, 25);        // duty 10%
  PWM_set(10, 255 -25);  // duty 90%
}

I don't see the possibility to manage phase on GyverPWM library

A quick search of the forum turned up this topic -

I think this is what you need

I looked at all the topics related to PWM yesterday and I missed this topic. I will review the codes and try it tomorrow.

Actually, what I want is two synchronous square waves. For example, two signals will operate with 48% duty cycle and there will be 2% dead time between them.

If a PWM is 90%, the IGBT connected here will have great difficulty and will fail.

const int pin9 = 9;
const int pin10 = 10;

void setup() {
   pinMode(pin9, OUTPUT);
   pinMode(pin10, OUTPUT);
}

void loop() {
   // Square wave outputs at the frequency and duty cycle you want
   int periodMicroseconds = 8000; // At customized frequency, for example 125 kHz
   int halfPeriodMicroseconds = periodMicroseconds / 2;

   // Square wave output with the duty cycle you want on pin 9
   digitalWrite(pin9, HIGH);
   delayMicroseconds(halfPeriodMicroseconds * 0.48); //Customized duty cycle
   digitalWrite(pin9, LOW);
   delayMicroseconds(halfPeriodMicroseconds * 0.52); //Customized duty cycle

   // Square wave output with the duty cycle you want inverted on pin 10
   digitalWrite(pin10, LOW); // To reverse phase
   delayMicroseconds(halfPeriodMicroseconds * 0.48); //Customized duty cycle
   digitalWrite(pin10, HIGH); // To reverse phase
   delayMicroseconds(halfPeriodMicroseconds * 0.52); //Customized duty cycle
}

I'm thinking of trying this code as well. My only fear is that there will be distortion in the square wave form at high frequency.

8000 us = 8 ms = 125 Hz, not 125 KHz!

But even if you correct the delay value, with this code you will never get more than a couple of kilohertz frequency because the digitalWrite() function is too slow for it.

Use hardware timers as we discussed above - this is the only way for you.

With the code below, 42% duty cycle operates at 125 kHz.
I am thinking of stopping it with the following code in case of any error.

   void stopPWM() {
   TCCR1A = 0; //Reset Timer1 control registers
   TCCR1B = 0; //Reset Timer1 control registers

All I want to do now is to create a soft start for pmw.
For example, I want the duty cycle to start with 20% at the first run and reach 42% duty cycle in 500ms and remain constant.


void setup() {
  pinMode(9, OUTPUT); //output A
  pinMode(10, OUTPUT); //output B
  TCCR1A = 0; //clear timer registers
  TCCR1B = 0;
  TCNT1 = 0;



  TCCR1B |= _BV(CS10); //no prescaler
  ICR1 = 64;//PWM mode counts up and back down for 80 counts

  OCR1A = 37; //Pin 9 match
  //output A set rising/clear falling
  TCCR1A |= _BV(COM1A1) | _BV(COM1A0); //output A set rising/clear falling

  OCR1B = 27; //Pin 10 match
  TCCR1A |= _BV(COM1B1); //output B clear rising/set falling

}

void loop() {


  TCCR1B |= _BV(WGM13); //PWM mode with ICR1 Mode 10
  TCCR1A |= _BV(WGM11); //WGM13:WGM10 set 1010
  }

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.