PWM and SS Control V4#
The IP core implements a modulation and switching state control unit that generates control signals for power electronic applications for three phase legs of two-level inverter topologies. Interlock and dead-time functionalities are not part of this IP core and are handled in a subsequent IP core. If less than three phase legs are used, unused phase legs can be set to a tristate mode, where neither the top nor the bottom switch of the phase leg are active. For higher phase numbers, multiple instances of this module can be used in the FPGA, each containing its own up-down counter. For synchronizing multiple instances, the counter can be fed to subsequent instances. Furthermore, an interleaved operation is possible. Every half-bridge can be shifted individually. The IP-Core has a setting, at which point of the triangle signal the phase-shift and output of new inverter switching signals does happen. These features are the only difference between versions V3 and V4. In the standard block design of the ultrazohm_sw framework, 4 synchronized instances of this ip core are present with respective software driver instances for controlling up to 12 half-bridge phase legs.
The IP core provides two general modes of operation.
Pulse width modulator mode (PWM)
Direct control of the switching states (SS)
In PWM mode one can choose from two different sources of reference values (duty cycles).
Reference values can be sent from the processing system via AXI to the IP core.
Reference values can be provided directly from within the FPGA.
The PWM mode uses a 20bit up-down counter and has been tested for switching frequencies of 100 Hz to 100 kHz. For operation especially with lower PWM frequencies one has to adapt the bitsize of the counter.
The IP core uses asymmetrical regular sampling for generation of the pulses:
![../../_images/asymmregsampling.png](../../_images/asymmregsampling.png)
Fig. 305 Asymmetric regular sampling according to Grahame Holmes: Pulse Width Modulation For Power Converters#
The triangle signal respectively DutyCycle of each half-bridge can be individually shifted depending on the input. The following variables in the config
-struct are used for this.
triangle_shift_HB1
triangle_shift_HB2
triangle_shift_HB3
The timing of the triangle shift operation as well as the output of new switching signals can be configured in the config
-struct via an enum.
trigger_at_MIN
of the triangle signaltrigger_at_MAX
of the triangle signaltrigger_at_EITHER
of the triangle signal
The input is fixed to 0
till 1
. Whilst 0
represents no shift at all, 1
represents a shift by an entire period.
E.g. with a PWM-frequency of \(f=10kHz\) and \(T=100µs\) the input triangle_shift_HB2 = 0.1f
would shift the second half-bridge by \(10µs\).
This is done internally by shifting the carrier wave itself.
![../../_images/Shift_example.png](../../_images/Shift_example.png)
Fig. 306 Shift of HB2 by triangle_shift_HB2 = 0.1f
@10kHz.#
IP-Core Hardware#
![../../_images/ip_core_overview.png](../../_images/ip_core_overview.png)
Fig. 307 Test bench of PWM and SS Control IP-Core#
![../../_images/phase_leg.png](../../_images/phase_leg.png)
Fig. 308 PWM implementation of one phase leg#
Example usage#
Vivado#
One instance:
![../../_images/vivado_example.png](../../_images/vivado_example.png)
Fig. 309 Example implementation in the block design#
For further instances, add the IP core to your design as many times as needed and connect them accordingly. For synchronization of instances, feed the triangle_out port of the first instance into the triangle_in port of one or several subsequent instances:
![../../_images/vivado_2instances.png](../../_images/vivado_2instances.png)
Fig. 310 Example implementation in the block design with two synchronized instances#
A flag for 1 cycle is active at the counter maximum and minimum value for triggering subsequent blocks or interrupts.
Vitis#
The software driver is called “uz_PWM_SS_2L”
Each instance has to be configured by a config struct
Note
If at least two synchronized ip cores are present, both have to be configured with
use_external_counter = enable
and connected the way shown above for correct synchronization.
struct uz_PWM_SS_2L_config_t config_1 = {
.base_address= XPAR_GATES_PWM_AND_SS_CONTROL_V_0_BASEADDR,
.ip_clk_frequency_Hz=100000000,
.Tristate_HB1 = false,
.Tristate_HB2 = false,
.Tristate_HB3 = false,
.min_pulse_width = 0.01f,
.PWM_freq_Hz = UZ_PWM_FREQUENCY,
.PWM_mode = normalized_input_via_AXI,
.PWM_en = true,
.use_external_counter = true,
.init_dutyCyc_HB1 = 0.0f,
.init_dutyCyc_HB2 = 0.0f,
.init_dutyCyc_HB3 = 0.0f,
.triangle_shift_HB1 = 0.0f,
.triangle_shift_HB2 = 0.0f,
.triangle_shift_HB3 = 0.0f,
.trigger_source = trigger_at_MIN
};
An instance has to be initialized first and then configured:
PWM_SS_2L_instance_1 = uz_PWM_SS_2L_init(config_1);
After that it can be used in the application. For easy setting of the duty cycles, use the uz_PWM_SS2L_set_duty_cycle
function.
Driver reference#
-
typedef struct uz_PWM_SS_2L_t uz_PWM_SS_2L_t#
Data type for object UZ_PWM_SS_2L.
-
enum uz_PWM_SS_2L_PWM_mode#
enum for readable configuring of the PWM mode in uz_PWM_SS_2L_hw_SetMode function
Values:
-
enumerator normalized_input_via_AXI#
-
enumerator normalized_input_via_FPGA#
-
enumerator direct_control_via_FPGA#
-
enumerator normalized_input_via_AXI#
-
enum uz_PWM_SS_2L_PWM_trigger_source#
enum for readable configuring of the PWM trigger source for the output of new DutyCycles and triangle shift in uz_PWM_SS_2L_hw_SetTriggerSource function
Values:
-
enumerator trigger_at_MIN#
-
enumerator trigger_at_MAX#
-
enumerator trigger_at_EITHER#
-
enumerator trigger_at_MIN#
-
struct uz_PWM_SS_2L_config_t#
Configuration struct for UZ_PWM_SS_2L.
Public Members
-
uint32_t base_address#
Base address of the IP-Core
-
uint32_t ip_clk_frequency_Hz#
Clock frequency of the IP-Core
-
bool Tristate_HB1#
Tristate flag for half-bridge 1, true=on, false=off
-
bool Tristate_HB2#
Tristate flag for half-bridge 2, true=on, false=off
-
bool Tristate_HB3#
Tristate flag for half-bridge 3, true=on, false=off
-
float min_pulse_width#
Minimum pulse width in percent, e.g. 0.01
-
float PWM_freq_Hz#
Switching frequency of PWM mode in Hz
-
enum uz_PWM_SS_2L_PWM_mode PWM_mode#
PWM mode selector
0 = normalized input of reference signal via AXI
e.g. a reference voltage value between 0 and 1
1 = normalized input of reference signal via FPGA
e.g. a reference voltage value between 0 and 1
2 = direct control of switching states via FPGA
-
bool PWM_en#
IP core enable flag
0=disable module, 1=enable module
-
bool use_external_counter#
Flag for choosing the PWM triangle source
0 = internal counter source of the instance
1 = triangle signal at port triangle_in
-
float init_dutyCyc_HB1#
Initial PWM duty cycle of half-bridge 1, 0…1
-
float init_dutyCyc_HB2#
Initial PWM duty cycle of half-bridge 2, 0…1
-
float init_dutyCyc_HB3#
Initial PWM duty cycle of half-bridge 3, 0…1
-
float triangle_shift_HB1#
Shift the triangle signal of HB1 to enable interleaved PWM operation. Input is fixed to 0-1.
0=no shift
0.5=shift by a half period
1=shift by an entire period
-
float triangle_shift_HB2#
Shift the triangle signal of HB2 to enable interleaved PWM operation. Input is fixed to 0-1.
-
float triangle_shift_HB3#
Shift the triangle signal of HB3 to enable interleaved PWM operation. Input is fixed to 0-1.
-
enum uz_PWM_SS_2L_PWM_trigger_source trigger_source#
Trigger source for new DutyCycles and triangle shifts
0 = trigger at MIN of triangle
1 = trigger at MAX of triangle
2 = trigger at EITHER MAX or MIN of triangle
-
uint32_t base_address#
-
uz_PWM_SS_2L_t *uz_PWM_SS_2L_init(struct uz_PWM_SS_2L_config_t config)#
Initializes an instance of the uz_PWM_SS_2L driver.
- Parameters:
config – Config struct of type uz_PWM_SS_2L_config_t for the IP-Core
- Returns:
uz_PWM_SS_2L_t* Pointer to initialized instance
-
void uz_PWM_SS_2L_set_duty_cycle(struct uz_PWM_SS_2L_t *self, float dutyCyc_HB1, float dutyCyc_HB2, float dutyCyc_HB3)#
Uses a configuration struct of type uz_PWM_SS_2L_config_t from a uz_PWM_SS_2L_t instance and writes the configuration to the IP-core.
- Parameters:
self – Instance of uz_PWM_SS_2L
dutyCyc_HB1 – DutyCycle for half-bridge 1
dutyCyc_HB2 – DutyCycle for half-bridge 2
dutyCyc_HB3 – DutyCycle for half-bridge 3
-
void uz_PWM_SS_2L_set_tristate(struct uz_PWM_SS_2L_t *self, bool Tristate_HB1, bool Tristate_HB2, bool Tristate_HB3)#
Sets selected half-bridges in a non conducting high-Z tri state mode.
- Parameters:
self – Instance of uz_PWM_SS_2L
Tristate_HB1 – Tristate flag for half-bridge 1, true=on, false=off
Tristate_HB2 – Tristate flag for half-bridge 2, true=on, false=off
Tristate_HB3 – Tristate flag for half-bridge 3, true=on, false=off
-
void uz_PWM_SS_2L_set_PWM_mode(struct uz_PWM_SS_2L_t *self, enum uz_PWM_SS_2L_PWM_mode PWM_mode)#
Sets the input source of gate signals.
- Parameters:
self – Instance of uz_PWM_SS_2L
PWM_mode –
There are three modes to chose
0 = normalized input of reference signal via AXI
e.g. a reference voltage value between 0 and 1
1 = normalized input of reference signal via FPGA
e.g. a reference voltage value between 0 and 1
2 = direct control of switching states via FPGA
-
void uz_PWM_SS_2L_set_triangle_shift(struct uz_PWM_SS_2L_t *self, float triangle_shift_HB1, float triangle_shift_HB2, float triangle_shift_HB3)#
sets the shift of the carrier triangle signal for each half-bridge to enable interleaved operation.
- Parameters:
self – Instance of uz_PWM_SS_2L
triangle_shift_HB1 – Shift of HB1 fixed to 0-1, e.g. 0.25f. 0 represents no shift and 1 represents a shift by an entire period.
triangle_shift_HB2 – Shift of HB2 fixed to 0-1, e.g. 0.25f. 0 represents no shift and 1 represents a shift by an entire period.
triangle_shift_HB3 – Shift of HB3 fixed to 0-1, e.g. 0.25f. 0 represents no shift and 1 represents a shift by an entire period.