Skip to content

Commit

Permalink
axi_dac_interpolate: Improve the ctrl logic
Browse files Browse the repository at this point in the history
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
  • Loading branch information
AndreiGrozav committed Nov 9, 2023
1 parent 2903e83 commit 88c9757
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 51 deletions.
18 changes: 16 additions & 2 deletions library/axi_dac_interpolate/axi_dac_interpolate.v
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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),
Expand All @@ -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),
Expand All @@ -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),
Expand All @@ -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),
Expand All @@ -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),
Expand Down
145 changes: 105 additions & 40 deletions library/axi_dac_interpolate/axi_dac_interpolate_filter.v
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -94,15 +109,37 @@ 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),
.DISABLE(CORRECTION_DISABLE),
.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),
Expand All @@ -113,36 +150,21 @@ 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));

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
Expand All @@ -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;
Expand All @@ -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);
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;
end
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
stop_transfer <= !en_stop_trigger | dma_transfer_suspend ? 1'b0 :
stop_transfer | (trigger_active & trigger & transfer);
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 dma_ready = transmit_ready ? dac_int_ready : 1'b0;
assign underflow = dac_enable & dma_ready & ~dma_valid;
assign dac_valid_out = dma_valid_m[4'h2];

always @(posedge dac_clk) begin
case (filter_mask)
Expand Down
Loading

0 comments on commit 88c9757

Please sign in to comment.