Hi,
here is the code.
It should be a differential PWM, e.g. two signals with 50% duty cycle phase shifted.
The resolution of the amount of phase shift should be very high.
So I use the phase shift options of the PLL-IP for the two LSB of duty value.
And one pulse should get addidional delay.
module DifferentialPWM_V3( input clk, input clk_P45, input clk_P90, input clk_P135, input enable,
input [13:0] signal, input [10:0] zvs_delay,
input [7:0] masterVolume,
output sigClk, output trg,
output Prim_SW1, output Prim_SW2, output Sec_SW1, output Sec_SW2,
output [12:0] duty,
output [ 1:0] phase_sel,
output pwmP0, output pwmP45, output pwmP90, output pwmP135);
// signal parts
reg sign_reg = 1'd0;
reg [ 1:0] phase_reg = 2'd0;
reg [10:0] duty_reg = 11'd0;
// ZVS delay
reg [10:0] delay_reg = 11'd20;
// values
wire signBit;
wire [12:0] amplitude;
wire [12:0] absAmplitude;
wire [20:0] mulRes;
wire [12:0] effAmplitude;
wire [12:0] limit;
wire [12:0] limitedAmplitude;
// counters
// Simulate random values as they will be found in the FPGA after power on.
reg [10:0] cnt_base = 11'd0;
reg [10:0] cnt_P45 = 11'd0;
reg [10:0] cnt_P90 = 11'd0;
reg [10:0] cnt_P135 = 11'd0;
reg en_cntP45 = 1'b0;
reg en_cntP90 = 1'b0;
reg en_cntP135= 1'b0;
reg blanking = 1'd0;
// PWM ffs
reg pwm_base = 1'd0;
reg [ 1:0] pwm_P0 = 2'd0;
reg [ 1:0] pwm_P45 = 2'd0;
reg [ 1:0] pwm_P90 = 2'd0;
reg [ 1:0] pwm_P135 = 2'd0;
// Just to generate test signals
reg [ 9:0] cnt_test = 10'd0;
reg p1, p2, s1, s2;
reg [13:0] sigTest;
// Advance the four counters at the positive edge
// of their individual clocks
always @(posedge clk)
begin
//cnt_base <= (enable == 1'b1) ? cnt_base + 11'd1 : 11'd0;
//cnt_base <= cnt_base + 11'd1;
if (enable == 1'b0)
begin
cnt_base <= 11'd00;
en_cntP45 <= 1'b0;
end
else
begin
cnt_base <= cnt_base + 11'd1;
en_cntP45 <= 1'b1;
end
end
always @(posedge clk_P45)
begin
//cnt_P45 <= (enable == 1'b1) ? cnt_P45 + 11'd1 : 11'd0;
//cnt_P45 <= cnt_P45 + 11'd1;
if (en_cntP45 == 1'b0)
begin
cnt_P45 <= 11'd0;
en_cntP90 <= 1'b0;
end
else
begin
cnt_P45 <= cnt_P45 + 11'd1;
en_cntP90 <= 1'b1;
end
end
always @(posedge clk_P90)
begin
//cnt_P90 <= (enable == 1'b1) ? cnt_P90 + 11'd1 : 11'd0;
//clk_P90 <= cnt_P90 + 11'd1;
if ( en_cntP90 == 1'b0)
begin
cnt_P90 <= 11'd0;
en_cntP135 <= 1'b0;
end
else
begin
cnt_P90 <= cnt_P90 + 11'd1;
en_cntP135 <= 1'b1;
end
end
always @(posedge clk_P135)
begin
cnt_P135 <= (en_cntP135 == 1'b1) ? cnt_P135 + 11'd1 : 11'd0;
//cnt_P135 <= cnt_P135 + 11'd1;
end
// Generate Prim_SW1 signal, this is the base for all
// Generate Prim_SW2 signal, which is shifted by the value in duty_reg
// Generate Sec_SW1 which is delayed version of Prim_SW2 (ZVS-delay) and
// flipped for negative signal values
// Generate some sub clocks
always @(negedge clk)
begin
if ( enable == 1'b1)
begin
if (cnt_base == 11'd0) pwm_base <= ~pwm_base;
if (cnt_base == duty_reg ) pwm_P0[0] <= ~pwm_P0[0];
if (cnt_base == delay_reg) pwm_P0[1] <= sign_reg == 0 ? pwm_P0[0] : ~pwm_P0[0];
if (cnt_base == 11'd2040) blanking <= ~pwm_base;
if (cnt_base == 11'd2047) blanking <= 0;
if (cnt_base == duty_reg) s1 <= ~s1;
end
else
begin
pwm_P0 <= 2'b0;
end
end
// Generate Prim_SW2 and Sec_SW1 as above but use the counter
// which phase is 45° behind clk
always @(negedge clk_P45)
begin
if (enable == 1'b1)
begin
pwm_P45[0] <= (cnt_P45 == duty_reg ) ? ~pwm_P45[0] : pwm_P45[0];
pwm_P45[1] <= (cnt_P45 == delay_reg) ? (sign_reg == 0) ? pwm_P45[0] : ~pwm_P45[0] : pwm_P45[1];
s2 <= (cnt_P45 == duty_reg) ? ~s2 : s2;
end
else
begin
pwm_P45 <= 2'b0;
end
end
// Generate Prim_SW2 and Sec_SW1 as above but use the counter
// which phase is 90° behind clk
always @(negedge clk_P90)
begin
if ( enable == 1'b1)
begin
if (cnt_P90 == duty_reg ) pwm_P90[0] <= ~pwm_P90[0];
if (cnt_P90 == delay_reg) pwm_P90[1] <= (sign_reg == 0) ? pwm_P90[0] : ~pwm_P90[0];
end
else
begin
pwm_P90 <= 2'b0;
end
end
// Generate Prim_SW2 and Sec_SW1 as above but use the counter
// which phase is 135° behind clk
always @(negedge clk_P135)
begin
if ( enable == 1'b1)
begin
if (cnt_P135 == duty_reg ) pwm_P135[0] <= ~pwm_P135[0];
if (cnt_P135 == delay_reg) pwm_P135[1] <= (sign_reg == 0) ? pwm_P135[0] : ~pwm_P135[0];
end
else
begin
pwm_P135 <= 2'b0;
end
end
always @(negedge blanking)
begin
cnt_test <= cnt_test + 9'd1;
//sigTest <= signal;
end
// Update duty cycle data
// Extract the sign bit from signal, calc the absolute value of the rest,
// Calculate the effective value according the masterVolume setting and
// limit the result, we can't over drive the output stage
// The update of the duty_reg must be done before the cnt_base counter
// reaches his end value
always @(posedge blanking)
begin
sign_reg <= signBit;
{duty_reg, phase_reg} <= limitedAmplitude;
delay_reg <= limitedAmplitude[12:2] + zvs_delay;
$display("duty-reg = %d, delay_reg = %d", duty_reg, delay_reg);
end
assign {signBit, amplitude} = signal;
assign absAmplitude = (signBit == 1'b0) ? amplitude : -amplitude;
assign mulRes = absAmplitude * masterVolume;
assign effAmplitude = mulRes >> 8;
assign limit = 13'd8148 - (zvs_delay << 2);
assign limitedAmplitude = (effAmplitude < limit) ? effAmplitude : limit;
assign trg = blanking;
assign Prim_SW1 = pwm_base;
// assign Prim_SW2 = phase_reg == 2'd0 ? pwm_P0 [0] : phase_reg == 2'd1 ? pwm_P45 [0] :
// phase_reg == 2'd2 ? pwm_P90[0] : pwm_P135[0];
assign Sec_SW1 = phase_reg == 2'd0 ? pwm_P0 [1] : phase_reg == 2'd1 ? pwm_P45 [1] :
phase_reg == 2'd2 ? pwm_P90[1] : pwm_P135[1];
//assign Prim_SW2 = pwm_P90 [0];
//assign Sec_SW1 = pwm_P90 [1];
assign Sec_SW2 = ~Sec_SW1;
assign duty = {duty_reg, phase_reg};
assign phase_sel = phase_reg;
assign pwmP0 = pwm_P0[0];
assign pwmP45 = pwm_P45[0];
assign pwmP90 = pwm_P90[0];
assign pwmP135 = pwm_P135[0];
endmodule
// if ( cnt_180 >= 2025 & pwm_180[0] == 0)
// begin
// end
// else
// begin
// if (phase_reg[1] == 1'd1)
// begin
// pwm_180[0] <= (cnt_180 == duty_reg ) ? ~pwm_180[0] : pwm_180[0];
// pwm_180[1] <= (cnt_180 == delay_reg) ? (sign_reg == 0) ? pwm_180[0] : ~pwm_180[0] : pwm_180[1];
// end
// end
// if (cnt_base == 0) pwm_base <= ~pwm_base;
//pwm_base <= (cnt_base == 0) ? ~pwm_base : pwm_base;
// if (cnt_base >= 2028 & pwm_base == 0)
// begin
// sign_reg <= sign;
// phase_reg <= duty[ 1:0];
// duty_reg <= duty[12:2];
// delay_reg <= duty[12:2] + zvs_delay;
// end
// else
// begin
// if (phase_reg[1] == 1'd0)
// begin
// if (cnt_base == duty_reg ) pwm_0[0] = ~pwm_0[0];
// if (cnt_base == delay_reg) pwm_0[1] <= sign_reg == 0 ? pwm_0[0] : ~pwm_0[0];
// end
// end
// always @(pwm_0[0] or pwm_180[0])
// begin
// //p2 <= phase_reg[1] == 1'd0 ? pwm_0[0] : pwm_180[0];//pwm[1];
// Prim_SW2 <= phase_reg[1] == 1'd0 ? pwm_0[0] : pwm_180[0];//pwm[1];
// end
//
// always @(pwm_0[1] or pwm_180[1])
// begin
// //s1 <= phase_reg[1] == 1'd0 ? pwm_0[1] : pwm_180[1];//pwm[2];
// Sec_SW1 <= phase_reg[1] == 1'd0 ? pwm_0[1] : pwm_180[1];//pwm[2];
// //s2 <= ~Sec_SW1;//~pwm[2];
// end
//assign Prim_SW2 = phase_reg[1] == 1'd0 ? pwm_P0[0] : pwm_P90[0];//pwm[1];
//assign Sec_SW1 = s1; //phase_reg[1] == 1'd0 ? pwm_0[1] : pwm_180[1];//pwm[2];
//~Sec_SW1;//~pwm[2];
With bets regards
Gerhard