Duty cycle not updating

In this project I’m using an Uno to control a buck-boost converter, I am able to test the design but it doesn’t seem the duty cycle is updating depending on the input/output voltages. I am relatively green when it comes to timerPWM. Need a higher frequency, I’m using pins 5 and 6’s Fast PWM function to get 62.5 khz.

#define RELAY_ENABLE 0
#define BOOST_PWM 5
#define BUCK_PWM 6
#define VIN A4
#define IIN A1
#define VOUT A3
#define IOUT A2

#define BUCK_ENABLE_VOLTAGE 26.0 
#define BUCK_DISABLE_VOLTAGE 24.0
#define BOOST_ENABLE_VOLTAGE 5.0 
#define BOOST_DISABLE_VOLTAGE 23.9
#define BUCK_THRESHOLD 25.0
#define BOOST_THRESHOLD 15.0
#define OUTPUT_TARGET_VOLTAGE_LOW 17.8
#define OUTPUT_TARGET_VOLTAGE_HIGH 17.9


#define INPUT_CURRENT_LIMIT 4.0
#define OUTPUT_CURRENT_LIMIT 6.0
#define INPUT_CURRENT_MINIMUM 0.1

//Duty cycle limits
#define DUTY_CYCLE_MINIMUM 10
#define DUTY_CYCLE_MAXIMUM 240

//Duty cycle mode
uint8_t duty_cycle = 115;
String mode="";
bool startup=true;

//This compenstates for the timer running at a clock that is 64 faster than usual
#define DELAY_FACTOR 64

#define VIN_MULTIPLIER 0.0576
#define VOUT_MULTIPLIER 0.02738

//Set up the LCD library
#include <LiquidCrystal.h>
#define LCD_RS 12
#define LCD_RW 11
#define LCD_EN 10
#define LCD_D7 8
#define LCD_D6 2
#define LCD_D5 3
#define LCD_D4 4
LiquidCrystal lcd(LCD_RS, LCD_RW, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);

//Some global variables
uint8_t bb_dutycycle;
float input_voltage;
float input_current;
float output_voltage;
float output_current;

//Set up the step-down DC-DC converter
void bb_setup()
{
  pinMode(RELAY_ENABLE, OUTPUT);
  digitalWrite(RELAY_ENABLE, LOW);
  //Half-bridge driver PWM signal
  pinMode(BOOST_PWM, OUTPUT);
  pinMode(BUCK_PWM, OUTPUT);
  //Fast PWM (mode 3) on OC0A (Arduino pin 5 & 6)
  TCCR0A = 0b00000011; 
  TCCR0B = 0b00000001; //Prescaler=1
  //Set dutycycle
  bb_dutycycle = 0;
  OCR0A = bb_dutycycle;    
}

//Turn on the DC-DC converter 
void relay_enable()
{
  // Clock source enabled with prescaler=1
  TCCR0A &= 0b10111111;
  TCCR0A |= 0b10000000;
  //Enable signal high
  digitalWrite(RELAY_ENABLE, HIGH);
}

//Turn off the DC-DC converter
void relay_disable()
{
  //Enable signal low
  digitalWrite(RELAY_ENABLE, LOW);
  // Clock source disabled
  TCCR0A &= 0b00111111;
  bb_dutycycle = 0;
}

//Set the duty-cycle for the DC-DC converter
void bb_duty(uint8_t duty)
{
  //The buck needs some off-time to keep the bootstrap capacitor of the upper FET charged
  //To ensure this we set a duty cycle clearly below 100%
  if(duty>DUTY_CYCLE_MAXIMUM)
  {
     duty = DUTY_CYCLE_MAXIMUM;
  }
  //A synchronous buck like ours can pump energy from the output to the input if the duty cycle drops below 50%
  //Eliminate this possibility by enforcing a duty cycle clearly above 50%
  if(duty<DUTY_CYCLE_MINIMUM)
  {
      duty = DUTY_CYCLE_MINIMUM;
  }
  bb_dutycycle = duty;
  OCR0A = duty;
}

//Shows measured voltages and currents on the LCD
void write_display()
{
  lcd.setCursor(0, 0);
  lcd.print("     V  ");
  lcd.setCursor(0, 0);
  lcd.print(input_voltage);
  
  lcd.setCursor(8, 0);
  lcd.print("     V  ");
  lcd.setCursor(8, 0);
  lcd.print(output_voltage);
  
  lcd.setCursor(0, 1);
  lcd.print("     A  ");
  lcd.setCursor(0, 1);
  lcd.print(input_current);
  
  lcd.setCursor(8, 1);
  lcd.print("     A  ");
  lcd.setCursor(8, 1);
  lcd.print(output_current);

//  delay(30000);
//  lcd.clear();
//  
//  lcd.setCursor(0,0);
//  lcd.print("Duty Cycle = ");
//  lcd.setCursor(14,0);
//  lcd.print(duty_cycle);
//
//  lcd.setCursor(0,1);
//  lcd.print("Mode = ");
//  lcd.setCursor(8,1);
//  lcd.print(mode);
//
//  delay(300000);
}

//Measure input and output voltage and current
//Each value is measured 16 times and then averaged
void read_values()
{
  float vin_dac = 0;
  float iin_dac = 0;
  float vout_dac = 0;
  float iout_dac = 0;
  for(int i = 0; i < 16; i++)
  {
    vin_dac += analogRead(VIN);
    vout_dac += analogRead(VOUT);
    iin_dac += (.0742 * analogRead(IIN) - 37.1);
    iout_dac += (.0742 * analogRead(IOUT) - 37.1);
    //.742 * analogRead(A0) -37.8
  }
  input_voltage = vin_dac * VIN_MULTIPLIER / 16;
  output_voltage = vout_dac * VOUT_MULTIPLIER / 16;
  input_current = iin_dac / 16;
  output_current = iout_dac / 16;
}

//Check if the duty cycle needs to be increased or decreased
//Also check if the DC-DC converter needs to be turned on or off
void buck_update()
{
  if(bb_dutycycle) //DC-DC converter is currently running
  {
  mode="";
  mode="Buck";
  analogWrite(BOOST_PWM,LOW); //Disable Boost FET
    //Disable
    if((input_voltage<BUCK_DISABLE_VOLTAGE) || (input_current<INPUT_CURRENT_MINIMUM))
    {
      relay_disable();
    }
    //Update
    else
    {
      //Reduce duty cycle
      if((input_voltage<BUCK_THRESHOLD) || (output_voltage>OUTPUT_TARGET_VOLTAGE_HIGH) || (input_current>INPUT_CURRENT_LIMIT) || (output_current>OUTPUT_CURRENT_LIMIT))
      {
        bb_duty(bb_dutycycle-1);
      }
      //Increase duty cycle
      if((input_voltage>BUCK_THRESHOLD) && (output_voltage<OUTPUT_TARGET_VOLTAGE_LOW)) 
      {
        bb_duty(bb_dutycycle+1);
      } 
    }
  }
  else //DC-DC converter is turned off
  {
    //Enable
    if(input_voltage>BUCK_ENABLE_VOLTAGE)
    {
       bb_duty((uint8_t) (255*output_voltage/input_voltage));
       relay_enable();
    }
  }
}
void boost_update()
{
  mode="";
  mode="Boost";
  analogWrite(BUCK_PWM,HIGH); //Keep Buck FET on.
  if(bb_dutycycle) //DC-DC converter is currently running
  {
    //Disable
    if((input_voltage<BOOST_ENABLE_VOLTAGE) || (input_current<INPUT_CURRENT_MINIMUM))
    {
      relay_disable(); 
    }
    //Update
    else
    {
      //Increase duty cycle
      if((input_voltage<BOOST_THRESHOLD) || (output_voltage<OUTPUT_TARGET_VOLTAGE_LOW) || (input_current>INPUT_CURRENT_LIMIT) || (output_current>OUTPUT_CURRENT_LIMIT))
      {
        bb_duty(bb_dutycycle+1);
      } 
      //Decrease duty cycle
      if((input_voltage<BOOST_THRESHOLD) && (output_voltage<OUTPUT_TARGET_VOLTAGE_HIGH)) 
      {
        bb_duty(bb_dutycycle-1);
      } 
    }
  }
  else //DC-DC converter is turned off
  {
    //Enable
    if(input_voltage>BOOST_ENABLE_VOLTAGE)
    {
       bb_duty((uint8_t) (255*output_voltage/input_voltage));
       relay_enable();
    }
  }
}


void setup()
{

  //Show startup screen
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("  ");
  lcd.setCursor(0, 1);
  lcd.print(" ");
  
  //Set up DC-DC convert  er
  bb_setup();
  
  //Wait a bit to show the startup screen
  delay(500*DELAY_FACTOR);
}


//This function is called forever once setup() has completed
//Again, this is Arduino-specific behaviour
void loop()
{
  for(uint8_t i=0; i<32; ++i)
  {
    read_values();
    buck_update();
    boost_update();
    delay(10*DELAY_FACTOR);
  }
  write_display();
}

I included my whole code, my issue could be in my logic for buck/boost behavior and maybe I’m not seeing it. I’m using Soldernerd’s Buck converter code as a reference: https://soldernerd.com/2016/01/21/arduino-mppt-solar-charger-shield

Thanks,
Hohokam

bump

I'm using pins 5 and 6's Fast PWM function to get 62.5 khz.

This code only puts PWM output on Timer0 output A pin 6. BUCK_PWM.

I am able to test the design but it doesn't seem the duty cycle is updating depending on the input/output voltages

Can you get any serial output to help you debug?
What are the values of our input/output voltages and currents?
Is the bb_duty() function getting called and is the value of OCR0A being updated?

This code only puts PWM output on Timer0 output A pin 6. BUCK_PWM.

Is there a way to call on both? or do I need to define each separately and use which ever one is being used?

Can you get any serial output to help you debug?
What are the values of our input/output voltages and currents?
Is the bb_duty() function getting called and is the value of OCR0A being updated?

I'm not sure how to accomplish this, I set it to display the duty cycle and it never changed from the initial value it was set to "Duty Cycle = 115".

my input voltage range from 15 - 30 volts and I kept the current only .7 A. I was getting the same the output voltage boosted maybe 2 volts above the input and the current dropped a little.

Yes that is the idea for bb_duty()

I set it to display the duty cycle and it never changed from the initial value it was set to "Duty Cycle = 115".

I see no place in your code where the displayed variable "duty_cycle" (which is initialized to 115) is ever changed.

You probably should be displaying bb_dutycycle.

You really need to get displayed output for everything which goes into changing the variable which drives the value of OCR0A.

Is there a way to call on both? or do I need to define each separately and use which ever one is being used?

It appears that to operate in buck mode, the boost mode fet is not driven with pwm but is set LOW. I'd try and get the buck mode operating first, before figuring out how to enable pwm on the B pin. If you can't figure out how to update OCR0A it won't help you to be trying to update OCR0B.

I see no place in your code where the displayed variable "duty_cycle" (which is initialized to 115) is ever changed

I'm dumb, I didn't know why I put that in there.

If I'm understanding Arduino Playground - TimerPWMCheatsheet when I set TCCR0A it sets both pins 5 and 6 to the frequency of 62.5k?

It appears that to operate in buck mode, the boost mode fet is not driven with pwm but is set LOW. I'd try and get the buck mode operating first, before figuring out how to enable pwm on the B pin. If you can't figure out how to update OCR0A it won't help you to be trying to update OCR0B.

That's the way buck boost works. When the device is in buck mode the the boost FET is open and the buck is oscillating like so . When the in boost mode the buck FET stays on and boost oscillates.

when I set TCCR0A it sets both pins 5 and 6 to the frequency of 62.5k?

Not exactly. The frequency is set by the prescaler which is actually a bit in TCCR0B. Both pins 5 and 6 will output at this frequency, but they must both be in OUTPUT mode, and enabled with settings in COM0A1, COM0A0, COM0B1 and COM0B0. The duty cycle will be set by OCR0A and OCR0B.

That's the way buck boost works. When the device is in buck mode the the boost FET is open and the buck is oscillating like so . When the in boost mode the buck FET stays on and boost oscillates.

I understand that. Do you have BUCK mode operating as you want it? Is OCR0A and the duty cycle changing as you desire?

Do you need assistance setting up the B pin?

I understand that. Do you have BUCK mode operating as you want it? Is OCR0A and the duty cycle changing as you desire?

Do you need assistance setting up the B pin?

Using a oscilloscope, I can see the frequency is coming out to 62.5 and the duty cycle is adjusting but seems to be boosting no matter what.

Using a oscilloscope, I can see the frequency is coming out to 62.5 and the duty cycle is adjusting but seems to be boosting no matter what.

I'm not a hardware guy, and whether or not your circuit and code work as a buck converter is a separate issue from varying the duty cycle of an input which you appear to be doing successfully.

I recommend that you start a new thread in the general electronics section of this forum. Be prepared to post the code you have and a schematic of your circuit. The original soldernerd reference may be useful, but you must post a schematic. Hand drawn will be OK.

I'm not a hardware guy, and whether or not your circuit and code work as a buck converter is a separate issue from varying the duty cycle of an input which you appear to be doing successfully.

I recommend that you start a new thread in the general electronics section of this forum. Be prepared to post the code you have and a schematic of your circuit. The original soldernerd reference may be useful, but you must post a schematic. Hand drawn will be OK.

Actually I figured out my issue, the Vgs on the MOSFETs is 10v and the Arduino only supplies 5v meaning I need to change the FETs. Do you mind helping me understand how to set up the PWM on the Boost pin (5)?

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks... Tom.. :slight_smile:

Do you mind helping me understand how to set up the PWM on the Boost pin (5)?

Here are the places in the code where you manage the timer modified for A and B output. If the comments are not enough, ask specific questions. It also helps to have an ATmega 328 data sheet at hand for reference.

void bb_setup()
{
  pinMode(RELAY_ENABLE, OUTPUT);
  digitalWrite(RELAY_ENABLE, LOW);
  //Half-bridge driver PWM signal
  pinMode(BOOST_PWM, OUTPUT);//#define BOOST_PWM 5
  pinMode(BUCK_PWM, OUTPUT); //#define BUCK_PWM 6
  //Fast PWM (mode 3) on Timer0
  TCCR0A = 0b00000011; //fast pwm to 255
  TCCR0B = 0b00000001; //Prescaler=1
  //Set dutycycle
  bb_dutycycle = 0;
  OCR0A = bb_dutycycle; //pin 6 outputA compare match
  OCR0B = bb_dutycycle;//pin 5 outputB compare match     
}

void relay_enable()
{
  TCCR0A |= 0b10100000;//pwm outputs A and B enabled Clear on Compare Match, set at BOTTOM (non-inverting mode)
  //Enable signal high
  digitalWrite(RELAY_ENABLE, HIGH);
}

//Turn off the DC-DC converter
void relay_disable()
{
  //Enable signal low
  digitalWrite(RELAY_ENABLE, LOW);
  TCCR0A &= 0b00000011;//pwm outputs A and B disabled
  bb_dutycycle = 0;
}

void bb_duty(uint8_t duty)
{
  //The buck needs some off-time to keep the bootstrap capacitor of the upper FET charged
  //To ensure this we set a duty cycle clearly below 100%
  if(duty>DUTY_CYCLE_MAXIMUM)
  {
     duty = DUTY_CYCLE_MAXIMUM;
  }
  //A synchronous buck like ours can pump energy from the output to the input if the duty cycle drops below 50%
  //Eliminate this possibility by enforcing a duty cycle clearly above 50%
  if(duty<DUTY_CYCLE_MINIMUM)
  {
      duty = DUTY_CYCLE_MINIMUM;
  }
  bb_dutycycle = duty;
  OCR0A = duty;
  OCR0B = duty;
}

EDIT: I’m unsure about some of the timing issues, and whether or not the calling of the buck/boost update functions and the relay enable/disable functions possibly allow for both outputs to be active at the same time.

I also think that these lines should be changed, because HIGH ==1

// analogWrite(BUCK_PWM,HIGH); //Keep Buck FET on.
analogWrite(BUCK_PWM, 255);// will default to digitalWrite(BUCK_PWM,HIGH)
 //analogWrite(BOOST_PWM,LOW); //Disable Boost FET
analogWrite(BOOST_PWM,0);//  will default to digitalWrite(BOOST_PWM, LOW)

TomGeorge:
Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks… Tom… :slight_smile:

I’m using different current sensors ACS712, EAGLE didn’t have them, but everything else should be the similar.

cattledog:
Here are the places in the code where you manage the timer modified for A and B output. If the comments are not enough, ask specific questions. It also helps to have an ATmega 328 data sheet at hand for reference.

EDIT: I'm unsure about some of the timing issues, and whether or not the calling of the buck/boost update functions and the relay enable/disable functions possibly allow for both outputs to be active at the same time.

Thank you!

I check if this with the addition of the right FETs works and let you know.

Thank you!

I check if this with the addition of the right FETs works and let you know.

Put in the new FETs, they shorted and burnt up for some reason.. I believe it's accruing in the Boost mode FET (N-Channel), when I pull it out, it stops the shorting. Maybe I ordered the wrong ones some how? Anyways, I ordering new ones from Sparkfun that are proven to work with Arduino.

Hohokam:
...my input voltage range from 15 - 30 volts...

How are you planning to get the 30volt needed to switch the p-channel fet (Q3) off with a 5volt Arduino.

Currently the fet is always on, independent of the Arduino pin is HIGH or LOW.

The fet will go to silicon-heaven if input voltage is >20volt (absolute max Vgs is ± 20V).
Leo..

Hi,

What are you using as a power supply, does it have current limiting, if not FIT A FUSE!!!

Where does power go in and go out?

Please connect your wires, not make us play search a word, when you connect your wires you can see your signal flow.
Wind_BB.JPG
What does K1 do and the red circled areas, something missing?
Wind_BBedit.jpg

Tom… :slight_smile:

I'm using a bench power supply 60V/5A, I am using a constant current flow act as the battery.

I didn't mean to make you play word search, the K1 is a relay switch. I building this for a wind turbine so if the battery capacity is full it will dump the excess energy. When there is enough voltage it will switch the relay to position "87" completing the circuit. Otherwise, it's in position "87a".

The whole circuit needs to be scrapped.

Currently any voltage on the input (C1) will appear on the output (C2), even if you don’t PWM the fets.
Leo…

Wawa:
Currently any voltage on the input (C1) will appear on the output (C2) of you don't PWM the fets.
And will short the input or blow the fets if you do.
Leo..

Can you explain why this occurs? I have a buck converter built in the same fashion and it works fine..