From 130fe9aba2f08b765c18821450c8b584a5983c13 Mon Sep 17 00:00:00 2001 From: AndreiGrozav Date: Wed, 14 Aug 2024 19:37:44 +0300 Subject: [PATCH] m2k:axi_ad9963, axi_dac_interpolate fixes This commit fixes the last sample hold and spike before buffers at low samplerates by compensating for the interpolation filter delays. Signed-off-by: AndreiGrozav --- library/axi_ad9963/axi_ad9963_tx_channel.v | 11 ++-- .../axi_dac_interpolate_filter.v | 52 ++++++++++++------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/library/axi_ad9963/axi_ad9963_tx_channel.v b/library/axi_ad9963/axi_ad9963_tx_channel.v index 7a28898bd9..3eff56294e 100644 --- a/library/axi_ad9963/axi_ad9963_tx_channel.v +++ b/library/axi_ad9963/axi_ad9963_tx_channel.v @@ -1,6 +1,6 @@ // *************************************************************************** // *************************************************************************** -// Copyright (C) 2017-2023 Analog Devices, Inc. All rights reserved. +// Copyright (C) 2017-2024 Analog Devices, Inc. All rights reserved. // // In this HDL repository, there are many different and unique modules, consisting // of various HDL (Verilog or VHDL) components. The individual modules are @@ -88,7 +88,6 @@ module axi_ad9963_tx_channel #( // internal registers reg dac_valid_sel = 'd0; - reg data_source_valid = 'd0; reg [23:0] dac_test_data = 'd0; reg [15:0] dac_test_counter = 'd0; reg [15:0] dac_pat_data = 'd0; @@ -111,27 +110,29 @@ module axi_ad9963_tx_channel #( wire dac_iqcor_enb_s; wire [15:0] dac_iqcor_coeff_1_s; wire [15:0] dac_iqcor_coeff_2_s; + wire data_source_valid_s; // dac iq correction always @(posedge dac_clk) begin - data_source_valid <= dac_data_sel_s == 4'h2 ? dma_valid_m : dac_valid; dac_enable <= (dac_data_sel_s == 4'h2) ? 1'b1 : 1'b0; if (dac_iqcor_valid_s == 1'b1) begin dac_data <= dac_iqcor_data_s[15:4]; end end + assign data_source_valid_s = dac_data_sel_s == 4'h2 ? dma_valid_m : dac_valid; + generate if (DATAPATH_DISABLE == 1) begin - assign dac_iqcor_valid_s = data_source_valid; + assign dac_iqcor_valid_s = data_source_valid_s; assign dac_iqcor_data_s = {dac_data_out, 4'd0}; end else begin ad_iqcor #( .Q_OR_I_N (Q_OR_I_N) ) i_ad_iqcor ( .clk (dac_clk), - .valid (data_source_valid), + .valid (data_source_valid_s), .data_in ({dac_data_out, 4'd0}), .data_iq ({dac_data_in, 4'd0}), .valid_out (dac_iqcor_valid_s), diff --git a/library/axi_dac_interpolate/axi_dac_interpolate_filter.v b/library/axi_dac_interpolate/axi_dac_interpolate_filter.v index 4d23ed2232..1e9a0f2754 100644 --- a/library/axi_dac_interpolate/axi_dac_interpolate_filter.v +++ b/library/axi_dac_interpolate/axi_dac_interpolate_filter.v @@ -88,8 +88,8 @@ module axi_dac_interpolate_filter #( reg cic_change_rate; reg [31:0] interpolation_counter; - reg filter_enable = 1'b0; reg [15:0] dma_valid_m = 16'd0; + reg [15:0] reset_filt_m = 16'd0; reg stop_transfer = 1'd0; reg clear_stop_flag = 1'd0; @@ -97,6 +97,8 @@ module axi_dac_interpolate_filter #( reg [ 1:0] transfer_sm = 2'd0; reg [ 1:0] transfer_sm_next = 2'd0; reg raw_dma_n = 1'd0; + reg last_m = 1'd0; + reg dac_int_ready_residual; // internal signals @@ -128,8 +130,6 @@ module axi_dac_interpolate_filter #( raw_dma_n <= raw_transfer_en | flush_dma ? 1'b1 : raw_dma_n & !dma_valid; end - assign reset_filt = !raw_dma_n & dma_transfer_suspend; - assign iqcor_data_in = raw_dma_n ? dac_raw_ch_data : dac_data; assign iqcor_valid_in = raw_dma_n ? 1'b1 : dac_valid; @@ -175,10 +175,6 @@ module axi_dac_interpolate_filter #( end end - // - for start synchronized, wait until the DMA has valid data on both channels - // - for non synchronized channels the start of transmission gets the 2 data - // paths randomly ready, only when using data buffers - always @(posedge dac_clk) begin if (dac_filt_int_valid & transfer_ready) begin if (interpolation_counter == interpolation_ratio) begin @@ -194,13 +190,22 @@ module axi_dac_interpolate_filter #( end end + always @(posedge dac_clk) begin + last_m <= last; + end + + // - for start synchronized, wait until the DMA has valid data on both channels + // - for non synchronized channels the start of transmission gets the 2 data + // paths randomly ready, only when using data buffers + assign transfer_ready = start_sync_channels ? dma_valid & dma_valid_adjacent : dma_valid; assign transfer_start = !(en_start_trigger ^ trigger) & transfer_ready & !dma_transfer_suspend; - assign rearm_channel = last & rearm_on_last; + assign rearm_channel = ~last_m & last & rearm_on_last; // re-arm on last rise + always @(posedge dac_clk) begin stop_transfer <= transfer_sm == IDLE ? 1'b0 : (stop_transfer & !clear_stop_flag) | @@ -258,29 +263,38 @@ module axi_dac_interpolate_filter #( always @(posedge dac_clk) begin if (dac_rst == 1'b1) begin - dma_valid_m <= 'd0; + dma_valid_m <= 16'h0; end else begin - dma_valid_m <= {dma_valid_m[14:0], dma_valid_ch}; + if (dac_filt_int_valid == 1'b1) begin + dma_valid_m <= {dma_valid_m[14:0], dma_valid_ch}; + end end end - assign dac_valid_out = dma_valid_m[2]; - always @(posedge dac_clk) begin - case (filter_mask) - 3'b000: filter_enable <= 1'b0; - default: filter_enable <= 1'b1; - endcase + if (dac_rst == 1'b1) begin + reset_filt_m <= 16'hffff; + end else begin + if (dac_filt_int_valid == 1'b1) begin + reset_filt_m <= {reset_filt_m[14:0], dma_transfer_suspend}; + end else if (dma_transfer_suspend == 1'b0) begin + reset_filt_m <= 16'h0; + end + end end + // compensate fir cic filter + assign dac_valid_out = |filter_mask ? dma_valid_m[13] : dma_valid_m[2]; + assign reset_filt = !raw_dma_n & reset_filt_m[13]; + always @(*) begin - case (filter_enable) - 1'b0: dac_int_data = dac_data_corrected; + case (filter_mask) + 3'b000: dac_int_data = dac_data_corrected; default: dac_int_data = dac_cic_data[31:16]; endcase case (filter_mask) - 1'b0: dac_filt_int_valid = dac_valid_corrected & !dma_transfer_suspend; + 1'b0: dac_filt_int_valid = dac_valid_corrected; default: dac_filt_int_valid = dac_fir_valid; endcase