DC AC 1 Open loop PWM control - owntech-foundation/Tutorials GitHub Wiki
The goal of this tutorial is to build the base open-loop block of an DC-AC conversion. In practice, you will deactivate the NGND and control the switches such that a bi-polar modulation can take place.The O² converter will be in open-loop.
This figure shows how the inverter is set from the O² board. It shows the NGND switch is off.
This figure shows the bi-polar modulation used in this example
- O2
v_1_1_2
- STLinkV3
- PC (windows or linux)
- Power supply (40 V, 2 A)
- Oscilloscope or multimeter
- SerialPlot
- We will create the project by copying the Buck 1 Task tutorial in a new branch, that will be called inverter_1 in the bottom menu, click on the New Terminal icon . This will open a new terminal into which you can write the commands below to create a new git branch.
git status
git branch inverter_1
git checkout inverter_1
- In the bottom menu, check that you are now in the
inverter_1
branch.
- Define the variables
In src/main.cpp
, in the section USER VARIABLE DECLARATIONS
, add the variables below. We start the duty cycle at 0.5. The duty cycle steps are set to 0.01. A boolean will indicate the state the PWM (ON or OFF). A variable will also define the period of the control task.
//--------------USER VARIABLES DECLARATIONS----------------------
static float32_t duty_cycle = 0.5; //duty cycle (comm task)
static float32_t duty_cycle_step = 0.01; //duty cycle step (comm task)
static bool pwm_enable = false; //state of the PWM (ctrl task)
static uint32_t control_task_period = 50; // sets the period of the control in micro-seconds
static float32_t V1_low_value; //store value of V1_low (app task)
static float32_t V2_low_value; //store value of V2_low (app task)
static float32_t Vhigh_value; //store value of Vhigh (app task)
static float32_t i1_low_value; //store value of i1_low (app task)
static float32_t i2_low_value; //store value of i2_low (app task)
static float32_t ihigh_value; //store value of ihigh (app task)
static float32_t data_value; //stores the value of the data converted by the ADC
static int8_t direction=1; //stores the direction of the waveform
- Configure the hardware peripherals
In src/main.cpp
, in the setup_hardware()
function, paste the code below. It initializes the inverter mode by setting a full bridge buck. In this example, the legs will be complementary, to set the bipolar modulation. This is done with the function hwConfig.initFullBridgeBuckMode()
.
void setup_hardware(){
hwConfig.setBoardVersion(v_1_1_2);
bool bipolar_mode = true; // declares a variable to set the modulation
hwConfig.initFullBridgeBuckMode(bipolar_mode); //sets the inverter as bipolar mode
hwConfig.setNgndOff();
hwConfig.configureAdcDefaultAllMeasurements();
console_init();
}
- Configure the software scheduling
In src/main.cpp
, in the function setup_software()
, initialize all the scheduling functions. The data acquisition will be started here. This function also starts the control task along with the communication and application tasks.
Due to its time criticity, the control task has a precise period and with a higher priority over the others.
void setup_software()
{
dataAcquisition.start();
scheduling.startControlTask(loop_control_task,control_task_period);
scheduling.startApplicationTask(loop_application_task,APPLICATION_THREAD_PRIORITY);
scheduling.startCommunicationTask(loop_communication_task,COMMUNICATION_THREAD_PRIORITY);
}
- Loop communication task
In the communication task you will change the commands to update the duty cycle
. You will also add a new mode to it, the INVERTERMODE
.
Find the enum serial_interface_menu_mode
. Add the following code to declare a new mode called INVERTERMODE.
enum serial_interface_menu_mode //LIST OF POSSIBLE MODES FOR THE OWNTECH CONVERTER
{
IDLEMODE =0,
SERIALMODE,
POWERMODE,
INVERTERMODE
};
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 INVERTERMODE.
In INVERTERMODE, it implements a gradual step change to the duty cycle that creates a triangular waveform.
void loop_communication_task()
{
while(1) {
received_serial_char = console_getchar();
switch (received_serial_char) {
case 'h':
//----------SERIAL INTERFACE MENU-----------------------
printk(" ________________________________________\n");
printk("| Communication task Tutorial |\n");
printk("| ------- MENU --------- |\n");
printk("| press i : idle mode |\n");
printk("| press s : serial mode |\n");
printk("| press p : power mode on |\n");
printk("| press u : duty cycle up by 0.01 |\n");
printk("| press d : duty cycle down by 0.01 |\n");
printk("| press v : inverter mode on |\n");
printk("|________________________________________|\n\n");
//------------------------------------------------------
break;
case 'i':
printk("idle mode\n");
mode = IDLEMODE;
break;
case 's':
printk("serial mode on!\n");
mode = SERIALMODE;
break;
case 'p':
printk("power mode on!\n");
mode = POWERMODE;
pwm_enable = true;
break;
case 'u':
printk("Duty Cycle UP: %f\n", duty_cycle);
duty_cycle = duty_cycle + duty_cycle_step;
break;
case 'd':
printk("Duty Cycle DOWN: %f\n", duty_cycle);
duty_cycle = duty_cycle - duty_cycle_step;
break;
case 'v':
printk("inverter mode on!");
mode = INVERTERMODE;
break;
default:
break;
}
}
}
- Loop application task
This application task will print the value of the duty cycle.
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. The INVERTERMODE
turns on the inverter mode with a fixed frequency.
void loop_application_task()
{
while(1){
if(mode==IDLEMODE) {
hwConfig.setLedOff();
}else if(mode==POWERMODE) {
hwConfig.setLedOn();
}else if(mode==INVERTERMODE) {
hwConfig.setLedOn();
}
printk("%f:", V1_low_value);
printk("%f:", V2_low_value);
printk("%f:", i1_low_value);
printk("%f:", i2_low_value);
printk("%f\n", duty_cycle);
k_msleep(100);
}
}
- Loop control task
The control task will have the purpose of turning the power conversion on or off and sending the duty cycle to the power converter.
In src/main.cpp
, in the function loop_control_task()
, add the following code. It states that if either the IDLEMODE
or SERIALMODE
are on, the power conversion stops. If POWERMODE
is on, then the power conversion resumes and the duty cycle is sent to the drivers and to the power hardware. If INVERTERMODE
is on, the power converter will output a triangular wave form with a fixed frequency.
void loop_control_task()
{
data_value = dataAcquisition.getV1Low();
if(data_value != -10000) V1_low_value = data_value;
data_value = dataAcquisition.getV2Low();
if(data_value != -10000) V2_low_value = data_value;
data_value = dataAcquisition.getI1Low();
if(data_value != -10000) i1_low_value = data_value;
data_value = dataAcquisition.getI2Low();
if(data_value != -10000) i2_low_value = data_value;
if(mode==IDLEMODE) {
pwm_enable = false;
hwConfig.setFullBridgeBuckOff();
}else if(mode==POWERMODE || mode==INVERTERMODE) {
if(!pwm_enable) {
pwm_enable = true;
if(mode==POWERMODE) hwConfig.setInterleavedOn();
if(mode==INVERTERMODE) hwConfig.setFullBridgeBuckOn();
}
if(mode==INVERTERMODE){
if(direction < 0 && duty_cycle < 0.1) direction = 1;
if(direction > 0 && duty_cycle > 0.9) direction = -1;
duty_cycle = duty_cycle + direction*duty_cycle_step;
}
if(mode==POWERMODE) hwConfig.setInterleavedDutyCycle(duty_cycle);
if(mode==INVERTERMODE) hwConfig.setFullBridgeBuckDutyCycle(duty_cycle);
}
}
- Connect hardware
Now we will connect OwnTech’s O2 to the power supply and to the PC.
⚠️ 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 its 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.
This image shows the connection of the power converter. Notice that the Neutral is not used and that the red and black wires are connected to the +V1Low and +V2Low.
- Build and Upload (+ ).
- In the bottom toolbar, click on the Serial Monitor icon , select it and press the
h
key. Remember to click on theopen
button in the SerialPlot application to liberate the serial interface.
- Press the
i
key to switch to IDLEMODE: disables the power flow, stops printingduty_cycle
and turns the LED1 OFF. - Press the
s
key to switch to SERIALMODE: disables the power flow, stops printing theduty_cycle
and turns the LED1 ON. - Press the
p
key to switch to POWERMODE: enables the power flow, printduty_cycle
and turns the LED1 ON. - Press the
u
key to increase theduty_cycle
. - Press the
d
key to decrease theduty_cycle
. - Press the
v
key to switch to INVERTERMODE: enables the triangular wave form
You can measure the output voltage thanks to an oscilloscope or a multimeter.
- How would you change the frequency of the triangular waveform?
- How would you create a sinusoidal waveform?
- How can you create a square waveform?
- How can you set the offset and the gain?
- How can you close the loop and drive the single phase AC?
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.03.13: Luiz Villa
- 2022.04.19: Luiz Villa
- 2022.06.23: Luiz Villa, Olivier Chevilley