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_interpolatemain
parent
6998cc99b4
commit
39b2a2b8bb
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue