From 81320b6469a327d962a20c194ebeffcf3cb8eabb Mon Sep 17 00:00:00 2001 From: AndreiGrozav Date: Tue, 8 Jun 2021 19:04:34 +0300 Subject: [PATCH] axi_pwm_gen: Fix offset mechanism Fix offset for pwms with different periods. The previous version was using an offset scheme based on pwm counter_0. By using a separate offset counter the user will not be constrained by pwm_0 period in regards with the offset of other pulses. In this version offset 0 is used to delay pwm 0 in regards to the offset counter. The offset counter will start after the load_config signal is asserted and all active pwm counters finish the previous cycle or by a software reset. The software reset should also be used when using external_sync. --- library/axi_pwm_gen/axi_pwm_gen.v | 129 +++++++++++++---------- library/axi_pwm_gen/axi_pwm_gen_ip.tcl | 51 +++++---- library/axi_pwm_gen/axi_pwm_gen_regmap.v | 5 +- 3 files changed, 104 insertions(+), 81 deletions(-) diff --git a/library/axi_pwm_gen/axi_pwm_gen.v b/library/axi_pwm_gen/axi_pwm_gen.v index 6f8f5ebfc..13ac05efa 100644 --- a/library/axi_pwm_gen/axi_pwm_gen.v +++ b/library/axi_pwm_gen/axi_pwm_gen.v @@ -39,7 +39,7 @@ module axi_pwm_gen #( parameter ID = 0, parameter ASYNC_CLK_EN = 1, parameter N_PWMS = 1, - parameter PWM_0_EXT_SYNC = 0, + parameter PWM_EXT_SYNC = 0, parameter EXT_ASYNC_SYNC = 0, parameter PULSE_0_WIDTH = 7, parameter PULSE_1_WIDTH = 7, @@ -49,6 +49,7 @@ module axi_pwm_gen #( parameter PULSE_1_PERIOD = 10, parameter PULSE_2_PERIOD = 10, parameter PULSE_3_PERIOD = 10, + parameter PULSE_0_OFFSET = 0, parameter PULSE_1_OFFSET = 0, parameter PULSE_2_OFFSET = 0, parameter PULSE_3_OFFSET = 0)( @@ -93,14 +94,13 @@ module axi_pwm_gen #( // internal registers - reg sync_0; - reg sync_1; - reg sync_2; - reg sync_3; - reg sync_active_0; - reg sync_active_1; - reg sync_active_2; - reg sync_active_3; + reg sync_0 = 1'b0; + reg sync_1 = 1'b0; + reg sync_2 = 1'b0; + reg sync_3 = 1'b0; + reg [31:0] offset_cnt = 32'd0; + reg offset_alignment = 1'b0; + reg pause_cnt_d = 1'b0; // internal signals @@ -118,10 +118,12 @@ module axi_pwm_gen #( wire [127:0] pwm_width_s; wire [127:0] pwm_period_s; wire [127:0] pwm_offset_s; - wire [ 31:0] pwm_counter[0:N_PWMS-1]; + wire [ 31:0] pwm_counter[0:3]; wire load_config_s; wire pwm_gen_resetn; wire ext_sync_s; + wire pause_cnt; + wire offset_alignment_ready; assign up_clk = s_axi_aclk; assign up_rstn = s_axi_aresetn; @@ -140,6 +142,7 @@ module axi_pwm_gen #( .PULSE_1_PERIOD (PULSE_1_PERIOD), .PULSE_2_PERIOD (PULSE_2_PERIOD), .PULSE_3_PERIOD (PULSE_3_PERIOD), + .PULSE_0_OFFSET (PULSE_0_OFFSET), .PULSE_1_OFFSET (PULSE_1_OFFSET), .PULSE_2_OFFSET (PULSE_2_OFFSET), .PULSE_3_OFFSET (PULSE_3_OFFSET)) @@ -162,6 +165,59 @@ module axi_pwm_gen #( .up_rdata (up_rdata_s), .up_rack (up_rack_s)); + // external sync + + generate + + reg ext_sync_m0 = 1'b1; + reg ext_sync_m1 = 1'b1; + + if (EXT_ASYNC_SYNC) begin + always @(posedge clk) begin + if (pwm_gen_resetn == 1'b0) begin + ext_sync_m0 <= 1'b1; + ext_sync_m1 <= 1'b1; + end else begin + ext_sync_m0 <= (PWM_EXT_SYNC == 1) ? ext_sync : 0; + ext_sync_m1 <= ext_sync_m0; + end + end + assign ext_sync_s = ext_sync_m1; + end else begin + assign ext_sync_s = (PWM_EXT_SYNC == 1) ? ext_sync : 0; + end + + endgenerate + + // offset counter + + always @(posedge clk) begin + if (offset_alignment) begin + offset_cnt <= 32'd0; + end else begin + offset_cnt <= offset_cnt + 1'b1; + end + + if (pwm_gen_resetn == 1'b0) begin + pause_cnt_d <= 1'b0; + offset_alignment <= 1'b0; + end else begin + pause_cnt_d <= pause_cnt_d; + + // when using external sync an offset alignment can be done only + // after all pwm counters are paused(load_config)/reseated + offset_alignment <= (load_config_s == 1'b1) ? 1'b1 : + offset_alignment & + (ext_sync_s ? 1'b1 : !offset_alignment_ready); + end + end + + assign pause_cnt = ((pwm_counter[0] == 32'd1 || + pwm_counter[1] == 32'd1 || + pwm_counter[2] == 32'd1 || + pwm_counter[3] == 32'd1) ? 1'b1 : 1'b0); + assign offset_alignment_ready = !pause_cnt_d & pause_cnt; + axi_pwm_gen_1 #( .PULSE_WIDTH (PULSE_0_WIDTH), .PULSE_PERIOD (PULSE_0_PERIOD)) @@ -177,38 +233,14 @@ module axi_pwm_gen #( always @(posedge clk) begin if (pwm_gen_resetn == 1'b0) begin - sync_active_0 <= 1'b1; sync_0 <= 1'b1; end else begin - sync_active_0 <= PWM_0_EXT_SYNC; - if (sync_active_0) begin - sync_0 <= ext_sync_s; - end else begin - sync_0 <= 1'b0; - end + sync_0 <= (offset_cnt == pwm_offset_s[31:0]) ? 1'b0 : 1'b1; end end generate - reg ext_sync_m0 = 1'b1; - reg ext_sync_m1 = 1'b1; - - if (EXT_ASYNC_SYNC) begin - always @(posedge clk) begin - if (pwm_gen_resetn == 1'b0) begin - ext_sync_m0 <= 1'b1; - ext_sync_m1 <= 1'b1; - end else begin - ext_sync_m0 <= ext_sync; - ext_sync_m1 <= ext_sync_m0; - end - end - assign ext_sync_s = ext_sync_m1; - end else begin - assign ext_sync_s = ext_sync; - end - if (N_PWMS >= 2) begin axi_pwm_gen_1 #( .PULSE_WIDTH (PULSE_1_WIDTH), @@ -225,19 +257,14 @@ module axi_pwm_gen #( always @(posedge clk) begin if (pwm_gen_resetn == 1'b0) begin - sync_active_1 <= 1'b1; sync_1 <= 1'b1; end else begin - sync_active_1 <= |pwm_offset_s[63:32]; - if (sync_active_1) begin - sync_1 <= (pwm_counter[0] == pwm_offset_s[63:32]) ? 1'b0 : 1'b1; - end else begin - sync_1 <= 1'b0; - end + sync_1 <= (offset_cnt == pwm_offset_s[63:32]) ? 1'b0 : 1'b1; end end end else begin assign pwm_1 = 1'b0; + assign pwm_counter[1] = 32'd1; end if (N_PWMS >= 3) begin @@ -256,19 +283,14 @@ module axi_pwm_gen #( always @(posedge clk) begin if (pwm_gen_resetn == 1'b0) begin - sync_active_2 <= 1'b1; sync_2 <= 1'b1; end else begin - sync_active_2 <= |pwm_offset_s[95:64]; - if (sync_active_2) begin - sync_2 <= (pwm_counter[0] == pwm_offset_s[95:64]) ? 1'b0 : 1'b1; - end else begin - sync_2 <= 1'b0; - end + sync_2 <= (offset_cnt == pwm_offset_s[95:64]) ? 1'b0 : 1'b1; end end end else begin assign pwm_2 = 1'b0; + assign pwm_counter[2] = 32'd1; end if (N_PWMS >= 4) begin @@ -287,19 +309,14 @@ module axi_pwm_gen #( always @(posedge clk) begin if (pwm_gen_resetn == 1'b0) begin - sync_active_3 <= 1'b1; sync_3 <= 1'b1; end else begin - sync_active_3 <= |pwm_offset_s[127:96]; - if (sync_active_3) begin - sync_3 <= (pwm_counter[0] == pwm_offset_s[127:96]) ? 1'b0 : 1'b1; - end else begin - sync_3 <= 1'b0; - end + sync_3 <= (offset_cnt == pwm_offset_s[127:96]) ? 1'b0 : 1'b1; end end end else begin assign pwm_3 = 1'b0; + assign pwm_counter[3] = 32'd1; end endgenerate diff --git a/library/axi_pwm_gen/axi_pwm_gen_ip.tcl b/library/axi_pwm_gen/axi_pwm_gen_ip.tcl index 9f223367d..80194907f 100644 --- a/library/axi_pwm_gen/axi_pwm_gen_ip.tcl +++ b/library/axi_pwm_gen/axi_pwm_gen_ip.tcl @@ -68,7 +68,7 @@ set_property -dict [list \ ipgui::add_param -name "EXT_ASYNC_SYNC" -component $cc -parent $page0 set_property -dict [list \ - "display_name" "External sync signal for pwm_0 is asynchronous" \ + "display_name" "External sync signal is asynchronous" \ "tooltip" "NOTE: If active the ext_sync will be delayed 2 clock cycles." \ "widget" "checkBox" \ ] [ipgui::get_guiparamspec -name "EXT_ASYNC_SYNC" -component $cc] @@ -78,8 +78,22 @@ set_property -dict [list \ "display_name" "Number of pwms" \ ] [ipgui::get_guiparamspec -name "N_PWMS" -component $cc] +ipgui::add_param -name "PWM_EXT_SYNC" -component $cc -parent $page0 +set_property -dict [list \ + "display_name" "External sync" \ + "tooltip" "NOTE: If active the whole pwm gen module will be waiting for the ext_sync to be set low. A load config or reset must be used before deaserting the ext_sync" \ + "widget" "checkBox" \ +] [ipgui::get_guiparamspec -name "PWM_EXT_SYNC" -component $cc] + +ipgui::add_param -name "EXT_ASYNC_SYNC" -component $cc -parent $page0 +set_property -dict [list \ + "display_name" "External sync signal is asynchronous" \ + "tooltip" "NOTE: If active the ext_sync will be delayed 2 clock cycles." \ + "widget" "checkBox" \ +] [ipgui::get_guiparamspec -name "EXT_ASYNC_SYNC" -component $cc] + # Maximum 4 pwms -for {set i 1} {$i < 4} {incr i} { +for {set i 0} {$i < 4} {incr i} { ipgui::add_param -name "PULSE_${i}_WIDTH" -component $cc -parent $page0 set_property -dict [list \ "display_name" "PULSE $i width" \ @@ -106,27 +120,18 @@ for {set i 1} {$i < 4} {incr i} { ] \ [ipx::get_user_parameters PULSE_${i}_PERIOD -of_objects $cc] - if { $i == 1 } { - ipgui::add_param -name "PWM_0_EXT_SYNC" -component $cc -parent $page0 - set_property -dict [list \ - "display_name" "Main pwm(1) sync" \ - "tooltip" "NOTE: If active the whole pwm gen module will be waiting for the ext_sync to be set high." \ - "widget" "checkBox" \ - ] [ipgui::get_guiparamspec -name "PWM_0_EXT_SYNC" -component $cc] - } else { - ipgui::add_param -name "PULSE_${i}_OFFSET" -component $cc -parent $page0 - set_property -dict [list \ - "display_name" "PULSE ${i} offset" \ - "tooltip" "Offset of the generated signal referenced to PULSE 1. The unit interval is the system or external clock period." \ - ] [ipgui::get_guiparamspec -name "PULSE_${i}_OFFSET" -component $cc] + ipgui::add_param -name "PULSE_${i}_OFFSET" -component $cc -parent $page0 + set_property -dict [list \ + "display_name" "PULSE ${i} offset" \ + "tooltip" "Offset of the generated signal referenced to PULSE 1. The unit interval is the system or external clock period." \ + ] [ipgui::get_guiparamspec -name "PULSE_${i}_OFFSET" -component $cc] - set_property -dict [list \ - "value_validation_type" "range_long" \ - "value_validation_range_minimum" "0" \ - "value_validation_range_maximum" "2147483647" \ - ] \ - [ipx::get_user_parameters PULSE_${i}_OFFSET -of_objects $cc] - } + set_property -dict [list \ + "value_validation_type" "range_long" \ + "value_validation_range_minimum" "0" \ + "value_validation_range_maximum" "2147483647" \ + ] \ + [ipx::get_user_parameters PULSE_${i}_OFFSET -of_objects $cc] } for {set i 1} {$i < 4} {incr i} { @@ -135,7 +140,7 @@ for {set i 1} {$i < 4} {incr i} { } adi_set_ports_dependency "ext_sync" \ - "(spirit:decode(id('MODELPARAM_VALUE.PWM_0_EXT_SYNC')) == 1)" + "(spirit:decode(id('MODELPARAM_VALUE.PWM_EXT_SYNC')) == 1)" set_property driver_value 0 [ipx::get_ports -filter "direction==in" -of_objects $cc] diff --git a/library/axi_pwm_gen/axi_pwm_gen_regmap.v b/library/axi_pwm_gen/axi_pwm_gen_regmap.v index a90285345..0fc087a50 100644 --- a/library/axi_pwm_gen/axi_pwm_gen_regmap.v +++ b/library/axi_pwm_gen/axi_pwm_gen_regmap.v @@ -50,6 +50,7 @@ module axi_pwm_gen_regmap #( parameter PULSE_2_PERIOD = 10, parameter PULSE_3_PERIOD = 10, parameter PULSE_0_EXT_SYNC = 0, + parameter PULSE_0_OFFSET = 0, parameter PULSE_1_OFFSET = 0, parameter PULSE_2_OFFSET = 0, parameter PULSE_3_OFFSET = 0)( @@ -92,7 +93,7 @@ module axi_pwm_gen_regmap #( reg [31:0] up_pwm_period_1 = PULSE_1_PERIOD; reg [31:0] up_pwm_period_2 = PULSE_2_PERIOD; reg [31:0] up_pwm_period_3 = PULSE_3_PERIOD; - reg [31:0] up_pwm_offset_0 = 32'd0; + reg [31:0] up_pwm_offset_0 = PULSE_0_OFFSET; reg [31:0] up_pwm_offset_1 = PULSE_1_OFFSET; reg [31:0] up_pwm_offset_2 = PULSE_2_OFFSET; reg [31:0] up_pwm_offset_3 = PULSE_3_OFFSET; @@ -111,7 +112,7 @@ module axi_pwm_gen_regmap #( up_pwm_period_1 <= PULSE_1_PERIOD; up_pwm_period_2 <= PULSE_2_PERIOD; up_pwm_period_3 <= PULSE_3_PERIOD; - up_pwm_offset_0 <= 32'd0; + up_pwm_offset_0 <= PULSE_0_OFFSET; up_pwm_offset_1 <= PULSE_1_OFFSET; up_pwm_offset_2 <= PULSE_2_OFFSET; up_pwm_offset_3 <= PULSE_3_OFFSET;