Buck 3 Closed loop voltage mode - owntech-foundation/Tutorials GitHub Wiki

Objectives

The goal of this tutorial is to use the O2 as a buck converter in closed-loop. We will implement a PID controller that tracks the reference voltage. We will start from the Buck 2 tutorial.

To better represent what will be done, the image below shows the control of one single leg. It is possible to see that the output low-side voltage measurement is used by the power converter to drive its PWM value.

image

Simplified representation of a power converter showing its power switches, filter and control loop. This control will be implemented in this tutorial.

There is an important different between the previous image and the actual implementation. In the O2 converter, the legs are interleaved, meaning they are controlled in parallel. This is best represented by the image below, where both legs are driven by the control function.

image

The O2 converter with its both legs being driven by the control function

Required hardware

  • O2 v_1_1_2
  • STLinkV3
  • PC 64-bits (windows or linux)
  • DC power supply (48 V, 2 A)
  • Oscilloscope or multimeter

Required software

  • Git
  • Visual Studio Code with PlatformIO (see Blinky tutorial)
  • SerialPlot (see SerialPlot tutorial)

Create the project

  1. We will save our progress by committing in git. In the side menu, click on the Source Control button, Which will open a new menu source_control_button. You can see that the only changes on your code are located at the main.cpp file. We are going to commit these changes as to keep track of our progress.

  2. Click on the + button on the right side of the main.cpp file to "stage" the changes. You can add a comment to explain what these changes are useful for. It is good practice to describe your changes when you commit them in git. Click on the + Commit button.

staged_changes_buck_2_tutorial

Staged changes for the buck-2 tutorial

Step-by-step implementation

  1. Configure the libraries and Define the variables

In src/main.cpp, in the section OWNTECH DRIVERS, include the following library. It will activate the code for PID control which will be used for the voltage mode.

//-------------OWNTECH DRIVERS-------------------
#include "opalib_control_pid.h"

Go to the owntech.ini file under the main.cpp file and decomment line 18. As shown in the image below. It will automatically download the pid library that will be used in this tutorial.

The owntech.ini file

In src/main.cpp, in the section USER VARIABLE DECLARATIONS, add the voltage reference, a counter for the step applying a step on the reference and the PID parameteres. Keep all the previous variables.

//--------------USER VARIABLES DECLARATIONS----------------------

static float32_t voltage_reference = 10; //voltage reference (app task)
static int cpt_step = 0; //counter for voltage reference (app task)

static float32_t kp = 0.000215;
static float32_t ki = 2.86;
static float32_t kd = 0.0;


  1. Configure the hardware peripherals

In src/main.cpp, in the setup_hardware() function, do not modify anything.

  1. Configure the software scheduling

In src/main.cpp, in the function setup_software(), initialize the pid controller, the data acquisition and all the scheduling functions. The pid control will now be available through a series of function calls.

void setup_software()
{
    opalib_control_init_interleaved_pid(kp, ki, kd, control_task_period);

    application_task_number =  scheduling.defineAsynchronousTask(loop_application_task);
    communication_task_number = scheduling.defineAsynchronousTask(loop_communication_task);
    scheduling.defineUninterruptibleSynchronousTask(&loop_control_task, control_task_period);

    scheduling.startAsynchronousTask(application_task_number);
    scheduling.startAsynchronousTask(communication_task_number);
    scheduling.startUninterruptibleSynchronousTask();
}
  1. Loop communication task

In the communication task you will change the commands to enable the closed-loop buck mode. To do so you will create a new mode called POWERMODE.

Find the enum serial_interface_menu_mode. Add the following code to declare a new mode called BUCKMODE.

enum serial_interface_menu_mode //LIST OF POSSIBLE MODES FOR THE OWNTECH CONVERTER
{
    IDLEMODE =0,
    SERIALMODE,
    POWERMODE,
    BUCKMODE,
};

In src/main.cpp, in the function loop_communication_task(), add the following code. This code listens to the Serial port. Depending on the character it has received, it switches between IDLEMODE, POWERMODE and BUCKMODE.

void loop_communication_task()
{
    received_serial_char = console_getchar();
    switch (received_serial_char) {
        case 'h':
            //----------SERIAL INTERFACE MENU-----------------------
	        printk(" ________________________________________\n");
            printk("|     ------- MENU ---------             |\n");
            printk("|     press i : idle mode                |\n");
            printk("|     press s : serial mode              |\n");
            printk("|     press p : power mode               |\n");
            printk("|     press u : duty cycle UP            |\n");
            printk("|     press d : duty cycle DOWN          |\n");
            printk("|     press b : closed-loop buck mode    |\n");
            printk("|________________________________________|\n\n");
            //------------------------------------------------------

            break;
        case 'i':
            printk("idle mode\n");
            mode = IDLEMODE;
            break;
        case 's':
            printk("serial mode\n");
            mode = SERIALMODE;
            break;
        case 'p':
            printk("power mode\n");
            mode = POWERMODE;
            pwm_enable = true;
            break;
        case 'u':
            duty_cycle = duty_cycle + duty_cycle_step;
            if(duty_cycle>1.0) duty_cycle = 1.0;
            break;
        case 'd':
            duty_cycle = duty_cycle - duty_cycle_step;
            if(duty_cycle<0.0) duty_cycle = 0.0;
            break;
        case 'b':
            printk("closed-loop buck mode\n");
            mode = BUCKMODE;
            break;        
        default:
            break;
    }
}
  1. Define the application task

In src/main.cpp, in the function loop_application_task(), add the following code. The IDLEMODE stops the power flow, the transmission of data and turns the LED1 off. The SERIALMODE only turns on the LED1. The POWERMODE turns the LED1 is ON and prints the values of duty_cycle on the Serial Monitor. In BUCKMODE, the value of the voltage_reference will change periodically creating a square wave. Now the data is constantly printed to the serial port.

void loop_application_task()
{
    if(mode==IDLEMODE) {
        hwConfig.setLedOff();
    }else if(mode==SERIALMODE) {
        hwConfig.setLedOn();
    }else if(mode==POWERMODE) {
        hwConfig.setLedOn();
    }else if(mode==BUCKMODE) {
        hwConfig.setLedOn();
        if(cpt_step==10) voltage_reference = 15;
        if(cpt_step==20) {
            voltage_reference = 10;
            cpt_step=0;
        }
        cpt_step ++;
    }

    printk("%f:", duty_cycle);
    printk("%f:", Vhigh_value);
    printk("%f:", V1_low_value);
    printk("%f:", V2_low_value);
    printk("%f:", ihigh_value);
    printk("%f:", i1_low_value);
    printk("%f:", i2_low_value);
    printk("%f\n", voltage_reference);
    
    scheduling.suspendCurrentTaskMs(100); 
}
  1. Loop control task

In src/main.cpp, in the function loop_control_task(), add the following code. In BUCKMODE, the PID tracks the voltage_reference by modifying the duty_cycle.

void loop_control_task()
{
    meas_data = dataAcquisition.getLatest(V_HIGH);
    if(meas_data!=NO_VALUE) Vhigh_value = meas_data;

    meas_data = dataAcquisition.getLatest(V1_LOW);
    if(meas_data!=NO_VALUE) V1_low_value = meas_data;

    meas_data = dataAcquisition.getLatest(V2_LOW);
    if(meas_data!=NO_VALUE) V2_low_value= meas_data;

    meas_data = dataAcquisition.getLatest(I_HIGH);
    if(meas_data!=NO_VALUE) ihigh_value = meas_data;

    meas_data = dataAcquisition.getLatest(I1_LOW);
    if(meas_data!=NO_VALUE) i1_low_value = meas_data;

    meas_data = dataAcquisition.getLatest(I2_LOW);
    if(meas_data!=NO_VALUE) i2_low_value = meas_data;

    if(mode==IDLEMODE || mode==SERIALMODE) {
         pwm_enable = false;
         hwConfig.setInterleavedOff();

    }else if(mode==POWERMODE || mode==BUCKMODE) {


        if(!pwm_enable) {
            pwm_enable = true;
            hwConfig.setInterleavedOn();
        }

        if(mode==BUCKMODE) duty_cycle = opalib_control_interleaved_pid_calculation(voltage_reference, V1_low_value);


        //Sends the PWM to the switches
	hwConfig.setInterleavedDutyCycle(duty_cycle);
    }
}
  1. Connect hardware

Now we will connect OwnTech’s O2 to the power supply and to the PC.

  • :warning: Make sure that the jumper JP4 is open.
  • Connect the USB power supply cable. The LED2 of the O2 should be ON.
  • Connect the pins Vhigh and GND of the O2 to the 40 V power supply (set the current limitation at 1 A).
  • Connect the micro-JTAG connector of the O2 to the PC thanks to the STLinkV3. The leds PWR and COM of the STLinkV3 should be ON.
  • Switch ON the power supply.

step6

  1. Build and Upload (build_icon+ flash_icon).

Expected outputs

  • Press i to switch to IDLEMODE: stop printing measuremnent and turns the LED1 OFF.
  • Press p to switch to COMMMODE: print measurements and turns the LED1 ON.
  • Press b to switch to BUCKMODE: tracks the reference voltage.
  • Press u to increase the duty_cycle.
  • Press d to decrease the duty_cycle.

OwnPlot Visualization

  1. First kill the Serial Monitor by clicking on the trash button on the right hand side of the window as shown in the image below.

Kill serial monitor

  1. Launch OwnPlot. In Port tab, choose the STLinkV3. Click on the Closed button to open the port.

:warning: The Port might have a different name depending on your operating system.

open_port_running

  1. In OwnPlot, Settings tab, set the # of channels to 8.

ownplot_settings_buck-3

  1. In OwnPlot, in the Chart tab, change the same of the datasets as shown below:

ownplot_chart_buck-3

  1. In OwnPlot, in the Send tab, add the commands below by typing the command name and its associated character.

ownplot_send_buck-3

  1. When you click on the Boost buttion the output should track the voltage reference that switches between 10 V and 15 V.

ownplot_counter_up_down

  1. In OwnPlot, click on the Idle button corresponding to the i command to switch to IDLEMODE and turn the LED1 OFF.

That’s it!

Contributors

  • 2021.11.04: Romain Delpoux, Loic Queval, Adrien Prévost
  • 2021.11.07: Luiz Villa, Antoine Boche
  • 2022.01.24: Luiz Villa, Loic Queval
  • 2022.02.01: Luiz Villa
  • 2022.02.22: Luiz Villa
  • 2022.03.13: Luiz Villa
  • 2023.01.17: Luiz Villa
  • 2023.07.12: Luiz Villa