diff --git a/library/axi_dac_interpolate/axi_dac_interpolate.v b/library/axi_dac_interpolate/axi_dac_interpolate.v index 131893f20..238d0e01f 100644 --- a/library/axi_dac_interpolate/axi_dac_interpolate.v +++ b/library/axi_dac_interpolate/axi_dac_interpolate.v @@ -124,6 +124,7 @@ module axi_dac_interpolate #( wire [ 2:0] filter_mask_b; wire dma_transfer_suspend; + wire flush_dma_s; wire start_sync_channels; wire dac_correction_enable_a; @@ -152,6 +153,9 @@ module axi_dac_interpolate #( wire underflow_b; wire stop_sync_channels; + wire [ 1:0] raw_transfer_en; + wire [15:0] dac_raw_ch_a_data; + wire [15:0] dac_raw_ch_b_data; // signal name changes @@ -215,7 +219,6 @@ module axi_dac_interpolate #( .dac_data (dac_data_a), .dac_valid (dac_valid_a), .dac_valid_out (dac_valid_out_a), - .sync_stop_channels (stop_sync_channels), .dac_enable (dac_enable_a), .dac_int_data (dac_int_data_a), @@ -226,6 +229,10 @@ module axi_dac_interpolate #( .interpolation_ratio (interpolation_ratio_a), .dma_transfer_suspend (dma_transfer_suspend), .start_sync_channels (start_sync_channels), + .sync_stop_channels (stop_sync_channels), + .flush_dma_in (flush_dma_s), + .raw_transfer_en (raw_transfer_en[0]), + .dac_raw_ch_data (dac_raw_ch_a_data), .trigger (trigger), .trigger_active (trigger_active), .en_start_trigger (en_start_trigger), @@ -244,7 +251,6 @@ module axi_dac_interpolate #( .dac_data (dac_data_b), .dac_valid (dac_valid_b), .dac_valid_out (dac_valid_out_b), - .sync_stop_channels (stop_sync_channels), .underflow (underflow_b), .dac_enable (dac_enable_b), @@ -255,6 +261,10 @@ module axi_dac_interpolate #( .interpolation_ratio (interpolation_ratio_b), .dma_transfer_suspend (dma_transfer_suspend), .start_sync_channels (start_sync_channels), + .sync_stop_channels (stop_sync_channels), + .flush_dma_in (flush_dma_s), + .raw_transfer_en (raw_transfer_en[1]), + .dac_raw_ch_data (dac_raw_ch_b_data), .trigger (trigger), .trigger_active (trigger_active), .en_start_trigger (en_start_trigger), @@ -274,6 +284,10 @@ module axi_dac_interpolate #( .dac_filter_mask_b (filter_mask_b), .dma_transfer_suspend (dma_transfer_suspend), + .flush_dma_out (flush_dma_s), + .raw_transfer_en (raw_transfer_en), + .dac_raw_ch_a_data (dac_raw_ch_a_data), + .dac_raw_ch_b_data (dac_raw_ch_b_data), .start_sync_channels (start_sync_channels), .dac_correction_enable_a(dac_correction_enable_a), .dac_correction_enable_b(dac_correction_enable_b), diff --git a/library/axi_dac_interpolate/axi_dac_interpolate_filter.v b/library/axi_dac_interpolate/axi_dac_interpolate_filter.v index 0f746959b..de4148bdf 100644 --- a/library/axi_dac_interpolate/axi_dac_interpolate_filter.v +++ b/library/axi_dac_interpolate/axi_dac_interpolate_filter.v @@ -49,7 +49,6 @@ module axi_dac_interpolate_filter #( output reg [15:0] dac_int_data, output dma_ready, output dac_valid_out, - input sync_stop_channels, output underflow, input [ 2:0] filter_mask, @@ -58,6 +57,10 @@ module axi_dac_interpolate_filter #( input dac_correction_enable, input dma_transfer_suspend, input start_sync_channels, + input sync_stop_channels, + input flush_dma_in, + input raw_transfer_en, + input [15:0] dac_raw_ch_data, input trigger, input trigger_active, input en_start_trigger, @@ -66,7 +69,14 @@ module axi_dac_interpolate_filter #( input dma_valid_adjacent ); - // internal signals + // local parameters + + localparam [1:0] IDLE = 0; + localparam [1:0] WAIT = 1; + localparam [1:0] TRANSFER = 2; + localparam [1:0] FLUSHING = 3; + + // internal registers reg dac_int_ready; reg dac_filt_int_valid; @@ -75,15 +85,20 @@ module axi_dac_interpolate_filter #( reg cic_change_rate; reg [31:0] interpolation_counter; - reg transmit_ready = 1'b0; reg dma_data_valid = 1'b0; reg dma_data_valid_adjacent = 1'b0; reg filter_enable = 1'b0; - reg transfer = 1'b0; reg [15:0] dma_valid_m = 16'd0; reg stop_transfer = 1'd0; + reg transfer = 1'd0; + reg [ 1:0] transfer_sm = 2'd0; + reg [ 1:0] transfer_sm_next = 2'd0; + reg raw_dma_n = 1'd0; + + // internal signals + wire dac_valid_corrected; wire [15:0] dac_data_corrected; wire dac_fir_valid; @@ -94,6 +109,28 @@ module axi_dac_interpolate_filter #( wire dma_valid_ch_sync; wire dma_valid_ch; + wire flush_dma; + + wire [15:0] iqcor_data_in; + wire iqcor_valid_in; + + wire transfer_start; + wire transfer_ready; + + // Once enabled the raw value will be selected until the DMA has valid data. + // This is a workaround for when DAC channels are start/stopped independent + // of each other and working in cyclic mode at a lower samplerate. It is + // used to solve a system limitation(delay) between the application and + // Linux kernel, which resulted in a pulse at the beginning of a new buffer + // consisting in the last sample on the DMA bus. + always @(posedge dac_clk) begin + 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; ad_iqcor #( .Q_OR_I_N (0), @@ -101,8 +138,8 @@ module axi_dac_interpolate_filter #( .SCALE_ONLY(1) ) i_ad_iqcor ( .clk (dac_clk), - .valid (dac_valid), - .data_in (dac_data), + .valid (iqcor_valid_in), + .data_in (iqcor_data_in), .data_iq (16'h0), .valid_out (dac_valid_corrected), .data_out (dac_data_corrected), @@ -113,7 +150,7 @@ module axi_dac_interpolate_filter #( fir_interp fir_interpolation ( .clk (dac_clk), .clk_enable (dac_cic_valid), - .reset (dac_rst | dma_transfer_suspend), + .reset (dac_rst | reset_filt), .filter_in (dac_data_corrected), .filter_out (dac_fir_data), .ce_out (dac_fir_valid)); @@ -121,28 +158,13 @@ module axi_dac_interpolate_filter #( cic_interp cic_interpolation ( .clk (dac_clk), .clk_enable (dac_valid_corrected), - .reset (dac_rst | cic_change_rate | dma_transfer_suspend), + .reset (dac_rst | cic_change_rate | reset_filt), .rate (interp_rate_cic), .load_rate (1'b0), .filter_in (dac_fir_data[30:0]), .filter_out (dac_cic_data), .ce_out (dac_cic_valid)); - assign dma_valid_ch_sync = sync_stop_channels ? - dma_valid & dma_valid_adjacent & !dma_transfer_suspend : - dma_valid & !dma_transfer_suspend; - - assign dma_valid_ch = dma_valid_ch_sync & !stop_transfer; - always @(posedge dac_clk) begin - if (dac_rst == 1'b1) begin - dma_valid_m <= 'd0; - end else begin - dma_valid_m <= {dma_valid_m[14:0], dma_valid_ch}; - end - end - - assign dac_valid_out = dma_valid_m[4'h5]; - always @(posedge dac_clk) begin filter_mask_d1 <= filter_mask; if (filter_mask_d1 != filter_mask) begin @@ -157,9 +179,7 @@ module axi_dac_interpolate_filter #( // paths randomly ready, only when using data buffers always @(posedge dac_clk) begin - if (dac_filt_int_valid & - (!start_sync_channels & dma_valid | - (dma_valid & dma_valid_adjacent))) begin + if (dac_filt_int_valid & transfer_ready) begin if (interpolation_counter == interpolation_ratio) begin interpolation_counter <= 0; dac_int_ready <= 1'b1; @@ -173,26 +193,71 @@ module axi_dac_interpolate_filter #( end end + assign transfer_ready = start_sync_channels ? + dma_valid & dma_valid_adjacent : + dma_valid; + assign transfer_start = !(en_start_trigger ^ trigger) & transfer_ready; + always @(posedge dac_clk) begin - if (dma_transfer_suspend == 1'b0) begin - transfer <= trigger ? 1'b1 : transfer | !(trigger_active & en_start_trigger); + stop_transfer <= transfer_sm == IDLE ? 1'b0 : + stop_transfer | + dma_transfer_suspend | + (en_stop_trigger & trigger) | + (sync_stop_channels & dma_valid & dma_valid_adjacent); + end + + // transfer state machine + always @(posedge dac_clk) begin + case (transfer_sm) + IDLE: begin + transfer <= 1'b0; + if (dac_int_ready) begin + transfer_sm_next <= WAIT; + end + end + WAIT: begin + transfer <= 1'b0; + if (transfer_start) begin + transfer_sm_next <= TRANSFER; + end + end + TRANSFER: begin + transfer <= 1'b1; + if (stop_transfer) begin + if (flush_dma_in) begin + transfer_sm_next <= FLUSHING; + end else begin + transfer_sm_next <= WAIT; + end + end else if (dma_valid == 1'b0) begin + transfer_sm_next <= IDLE; + end + end + FLUSHING: begin + transfer <= 1'b1; + if (dma_valid == 1'b0) begin + transfer_sm_next <= IDLE; + end + end + endcase + transfer_sm <= transfer_sm_next; + end + + assign flush_dma = transfer_sm_next == FLUSHING ? 1'b1 : raw_transfer_en & flush_dma_in; + assign dma_ready = transfer_sm_next == TRANSFER ? dac_int_ready : flush_dma; + assign underflow = dac_enable & dma_ready & ~dma_valid & !flush_dma; + + assign dma_valid_ch = transfer | raw_transfer_en; + + always @(posedge dac_clk) begin + if (dac_rst == 1'b1) begin + dma_valid_m <= 'd0; end else begin - transfer <= 1'b0; - end - if (start_sync_channels == 1'b0) begin - transmit_ready <= dma_valid & transfer; - end else begin - transmit_ready <= dma_valid & dma_valid_adjacent & transfer; + dma_valid_m <= {dma_valid_m[14:0], dma_valid_ch}; end end - always @(posedge dac_clk) begin - stop_transfer <= !en_stop_trigger | dma_transfer_suspend ? 1'b0 : - stop_transfer | (trigger_active & trigger & transfer); - end - - assign dma_ready = transmit_ready ? dac_int_ready : 1'b0; - assign underflow = dac_enable & dma_ready & ~dma_valid; + assign dac_valid_out = dma_valid_m[2]; always @(posedge dac_clk) begin case (filter_mask) diff --git a/library/axi_dac_interpolate/axi_dac_interpolate_reg.v b/library/axi_dac_interpolate/axi_dac_interpolate_reg.v index f741c729a..512f9b009 100644 --- a/library/axi_dac_interpolate/axi_dac_interpolate_reg.v +++ b/library/axi_dac_interpolate/axi_dac_interpolate_reg.v @@ -44,6 +44,10 @@ module axi_dac_interpolate_reg( output [31:0] dac_interpolation_ratio_b, output [ 2:0] dac_filter_mask_b, output dma_transfer_suspend, + output flush_dma_out, + output [ 1:0] raw_transfer_en, + output [15:0] dac_raw_ch_a_data, + output [15:0] dac_raw_ch_b_data, output start_sync_channels, output stop_sync_channels, output dac_correction_enable_a, @@ -68,7 +72,7 @@ module axi_dac_interpolate_reg( // internal registers reg [31:0] up_version = {16'h0002, /* MAJOR */ - 8'h02, /* MINOR */ + 8'h03, /* MINOR */ 8'h00}; /* PATCH */ reg [31:0] up_scratch = 32'h0; @@ -76,17 +80,21 @@ module axi_dac_interpolate_reg( reg [ 2:0] up_filter_mask_a = 3'h0; reg [31:0] up_interpolation_ratio_b = 32'h0; reg [ 2:0] up_filter_mask_b = 3'h0; - reg [2:0] up_flags = 3'h2; - reg [1:0] up_config = 2'h0; + reg [ 5:0] up_flags = 6'ha; + reg [ 1:0] up_config = 2'h0; reg [15:0] up_correction_coefficient_a = 16'h0; reg [15:0] up_correction_coefficient_b = 16'h0; reg [19:0] up_trigger_config = 20'h0; + reg [15:0] up_dac_raw_ch_a_data; + reg [15:0] up_dac_raw_ch_b_data; - wire [ 2:0] flags; + wire [ 5:0] flags; assign dma_transfer_suspend = flags[0]; assign start_sync_channels = flags[1]; assign stop_sync_channels = flags[2]; + assign flush_dma_out = flags[3]; + assign raw_transfer_en = flags[5:4]; //5-b; 4-a always @(negedge up_rstn or posedge up_clk) begin if (up_rstn == 0) begin @@ -96,11 +104,13 @@ module axi_dac_interpolate_reg( up_filter_mask_a <= 'd0; up_interpolation_ratio_b <= 'd0; up_filter_mask_b <= 'd0; - up_flags <= 'd2; + up_flags <= 'ha; up_config <= 'd0; up_correction_coefficient_a <= 'd0; up_correction_coefficient_b <= 'd0; up_trigger_config <= 'd0; + up_dac_raw_ch_a_data <= 16'd0; + up_dac_raw_ch_b_data <= 16'd0; end else begin up_wack <= up_wreq; if ((up_wreq == 1'b1) && (up_waddr[4:0] == 5'h1)) begin @@ -119,7 +129,7 @@ module axi_dac_interpolate_reg( up_filter_mask_b <= up_wdata[2:0]; end if ((up_wreq == 1'b1) && (up_waddr[4:0] == 5'h14)) begin - up_flags <= {29'h0,up_wdata[2:0]}; + up_flags <= up_wdata[5:0]; end if ((up_wreq == 1'b1) && (up_waddr[4:0] == 5'h15)) begin up_config <= up_wdata[1:0]; @@ -133,6 +143,10 @@ module axi_dac_interpolate_reg( if ((up_wreq == 1'b1) && (up_waddr[4:0] == 5'h18)) begin up_trigger_config <= up_wdata[19:0]; end + if ((up_wreq == 1'b1) && (up_waddr[4:0] == 5'h19)) begin + up_dac_raw_ch_a_data <= up_wdata[15:0]; + up_dac_raw_ch_b_data <= up_wdata[31:16]; + end end end @@ -152,11 +166,12 @@ module axi_dac_interpolate_reg( 5'h11: up_rdata <= {29'h0,up_filter_mask_a}; 5'h12: up_rdata <= up_interpolation_ratio_b; 5'h13: up_rdata <= {29'h0,up_filter_mask_b}; - 5'h14: up_rdata <= {29'h0,up_flags}; + 5'h14: up_rdata <= {26'h0,up_flags}; 5'h15: up_rdata <= {30'h0,up_config}; 5'h16: up_rdata <= {16'h0,up_correction_coefficient_a}; 5'h17: up_rdata <= {16'h0,up_correction_coefficient_b}; 5'h18: up_rdata <= {12'h0,up_trigger_config}; + 5'h19: up_rdata <= {up_dac_raw_ch_b_data, up_dac_raw_ch_a_data}; default: up_rdata <= 0; endcase end else begin @@ -166,7 +181,7 @@ module axi_dac_interpolate_reg( end up_xfer_cntrl #( - .DATA_WIDTH(127) + .DATA_WIDTH(162) ) i_xfer_cntrl ( .up_rstn (up_rstn), .up_clk (up_clk), @@ -175,7 +190,9 @@ module axi_dac_interpolate_reg( up_correction_coefficient_b,// 16 up_correction_coefficient_a,// 16 up_trigger_config, // 20 - up_flags, // 3 + up_flags, // 6 + up_dac_raw_ch_a_data, // 16 + up_dac_raw_ch_b_data, // 16 up_interpolation_ratio_b, // 32 up_interpolation_ratio_a, // 32 up_filter_mask_b, // 3 @@ -189,7 +206,9 @@ module axi_dac_interpolate_reg( dac_correction_coefficient_b, // 16 dac_correction_coefficient_a, // 16 trigger_config, // 20 - flags, // 3 + flags, // 6 + dac_raw_ch_a_data, // 16 + dac_raw_ch_b_data, // 16 dac_interpolation_ratio_b, // 32 dac_interpolation_ratio_a, // 32 dac_filter_mask_b, // 3