From 39b2a2b8bb4252d314290533a3437645ce59186f Mon Sep 17 00:00:00 2001 From: AndreiGrozav Date: Fri, 22 Sep 2023 14:13:50 +0300 Subject: [PATCH] axi_dac_interpolate: Improve the ctrl logic 1. Simplify the control logic by adding a state machine. The improvements are on code readability and reliability. 2.Add a flush feature which can be used to clean the data from the DMA fifo. This is useful when the DMA is programmed in cyclic mode and data transmission is stopped by dma_transfer_suspend flag The software intervention is reduced at setting the flag(dma_flush_en). Flushing can also be done when activating the raw value with dma_flush_en active. 3. Add raw value support. Through this changes a user can set the dac output to a fixed predefined value in the following two cases: 1. direct, without using the dma. 2. with dma, as a hold value. The fixed value will be kipped after a cyclic buffer is stopped by axi_dac_interpolate, through dma_transfer_suspend register/signal. The raw value ca be set and transmitted independently on each channel. The predefined value is stored in reg 0x19(0x64). For more details se the documentation available at https://wiki.analog.com/resources/fpga/docs/axi_dac_interpolate --- .../axi_dac_interpolate/axi_dac_interpolate.v | 18 ++- .../axi_dac_interpolate_filter.v | 147 +++++++++++++----- .../axi_dac_interpolate_reg.v | 39 +++-- 3 files changed, 151 insertions(+), 53 deletions(-) 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