Skip to content

Commit 39b2a2b

Browse files
committed
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
1 parent 6998cc9 commit 39b2a2b

File tree

3 files changed

+150
-52
lines changed

3 files changed

+150
-52
lines changed

library/axi_dac_interpolate/axi_dac_interpolate.v

+16-2
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ module axi_dac_interpolate #(
124124
wire [ 2:0] filter_mask_b;
125125

126126
wire dma_transfer_suspend;
127+
wire flush_dma_s;
127128
wire start_sync_channels;
128129

129130
wire dac_correction_enable_a;
@@ -152,6 +153,9 @@ module axi_dac_interpolate #(
152153
wire underflow_b;
153154

154155
wire stop_sync_channels;
156+
wire [ 1:0] raw_transfer_en;
157+
wire [15:0] dac_raw_ch_a_data;
158+
wire [15:0] dac_raw_ch_b_data;
155159

156160
// signal name changes
157161

@@ -215,7 +219,6 @@ module axi_dac_interpolate #(
215219
.dac_data (dac_data_a),
216220
.dac_valid (dac_valid_a),
217221
.dac_valid_out (dac_valid_out_a),
218-
.sync_stop_channels (stop_sync_channels),
219222

220223
.dac_enable (dac_enable_a),
221224
.dac_int_data (dac_int_data_a),
@@ -226,6 +229,10 @@ module axi_dac_interpolate #(
226229
.interpolation_ratio (interpolation_ratio_a),
227230
.dma_transfer_suspend (dma_transfer_suspend),
228231
.start_sync_channels (start_sync_channels),
232+
.sync_stop_channels (stop_sync_channels),
233+
.flush_dma_in (flush_dma_s),
234+
.raw_transfer_en (raw_transfer_en[0]),
235+
.dac_raw_ch_data (dac_raw_ch_a_data),
229236
.trigger (trigger),
230237
.trigger_active (trigger_active),
231238
.en_start_trigger (en_start_trigger),
@@ -244,7 +251,6 @@ module axi_dac_interpolate #(
244251
.dac_data (dac_data_b),
245252
.dac_valid (dac_valid_b),
246253
.dac_valid_out (dac_valid_out_b),
247-
.sync_stop_channels (stop_sync_channels),
248254
.underflow (underflow_b),
249255

250256
.dac_enable (dac_enable_b),
@@ -255,6 +261,10 @@ module axi_dac_interpolate #(
255261
.interpolation_ratio (interpolation_ratio_b),
256262
.dma_transfer_suspend (dma_transfer_suspend),
257263
.start_sync_channels (start_sync_channels),
264+
.sync_stop_channels (stop_sync_channels),
265+
.flush_dma_in (flush_dma_s),
266+
.raw_transfer_en (raw_transfer_en[1]),
267+
.dac_raw_ch_data (dac_raw_ch_b_data),
258268
.trigger (trigger),
259269
.trigger_active (trigger_active),
260270
.en_start_trigger (en_start_trigger),
@@ -274,6 +284,10 @@ module axi_dac_interpolate #(
274284
.dac_filter_mask_b (filter_mask_b),
275285

276286
.dma_transfer_suspend (dma_transfer_suspend),
287+
.flush_dma_out (flush_dma_s),
288+
.raw_transfer_en (raw_transfer_en),
289+
.dac_raw_ch_a_data (dac_raw_ch_a_data),
290+
.dac_raw_ch_b_data (dac_raw_ch_b_data),
277291
.start_sync_channels (start_sync_channels),
278292
.dac_correction_enable_a(dac_correction_enable_a),
279293
.dac_correction_enable_b(dac_correction_enable_b),

library/axi_dac_interpolate/axi_dac_interpolate_filter.v

+105-40
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ module axi_dac_interpolate_filter #(
4949
output reg [15:0] dac_int_data,
5050
output dma_ready,
5151
output dac_valid_out,
52-
input sync_stop_channels,
5352
output underflow,
5453

5554
input [ 2:0] filter_mask,
@@ -58,6 +57,10 @@ module axi_dac_interpolate_filter #(
5857
input dac_correction_enable,
5958
input dma_transfer_suspend,
6059
input start_sync_channels,
60+
input sync_stop_channels,
61+
input flush_dma_in,
62+
input raw_transfer_en,
63+
input [15:0] dac_raw_ch_data,
6164
input trigger,
6265
input trigger_active,
6366
input en_start_trigger,
@@ -66,7 +69,14 @@ module axi_dac_interpolate_filter #(
6669
input dma_valid_adjacent
6770
);
6871

69-
// internal signals
72+
// local parameters
73+
74+
localparam [1:0] IDLE = 0;
75+
localparam [1:0] WAIT = 1;
76+
localparam [1:0] TRANSFER = 2;
77+
localparam [1:0] FLUSHING = 3;
78+
79+
// internal registers
7080

7181
reg dac_int_ready;
7282
reg dac_filt_int_valid;
@@ -75,15 +85,20 @@ module axi_dac_interpolate_filter #(
7585
reg cic_change_rate;
7686
reg [31:0] interpolation_counter;
7787

78-
reg transmit_ready = 1'b0;
7988
reg dma_data_valid = 1'b0;
8089
reg dma_data_valid_adjacent = 1'b0;
8190

8291
reg filter_enable = 1'b0;
83-
reg transfer = 1'b0;
8492
reg [15:0] dma_valid_m = 16'd0;
8593
reg stop_transfer = 1'd0;
8694

95+
reg transfer = 1'd0;
96+
reg [ 1:0] transfer_sm = 2'd0;
97+
reg [ 1:0] transfer_sm_next = 2'd0;
98+
reg raw_dma_n = 1'd0;
99+
100+
// internal signals
101+
87102
wire dac_valid_corrected;
88103
wire [15:0] dac_data_corrected;
89104
wire dac_fir_valid;
@@ -94,15 +109,37 @@ module axi_dac_interpolate_filter #(
94109

95110
wire dma_valid_ch_sync;
96111
wire dma_valid_ch;
112+
wire flush_dma;
113+
114+
wire [15:0] iqcor_data_in;
115+
wire iqcor_valid_in;
116+
117+
wire transfer_start;
118+
wire transfer_ready;
119+
120+
// Once enabled the raw value will be selected until the DMA has valid data.
121+
// This is a workaround for when DAC channels are start/stopped independent
122+
// of each other and working in cyclic mode at a lower samplerate. It is
123+
// used to solve a system limitation(delay) between the application and
124+
// Linux kernel, which resulted in a pulse at the beginning of a new buffer
125+
// consisting in the last sample on the DMA bus.
126+
always @(posedge dac_clk) begin
127+
raw_dma_n <= raw_transfer_en | flush_dma ? 1'b1 : raw_dma_n & !dma_valid;
128+
end
129+
130+
assign reset_filt = !raw_dma_n & dma_transfer_suspend;
131+
132+
assign iqcor_data_in = raw_dma_n ? dac_raw_ch_data : dac_data;
133+
assign iqcor_valid_in = raw_dma_n ? 1'b1 : dac_valid;
97134

98135
ad_iqcor #(
99136
.Q_OR_I_N (0),
100137
.DISABLE(CORRECTION_DISABLE),
101138
.SCALE_ONLY(1)
102139
) i_ad_iqcor (
103140
.clk (dac_clk),
104-
.valid (dac_valid),
105-
.data_in (dac_data),
141+
.valid (iqcor_valid_in),
142+
.data_in (iqcor_data_in),
106143
.data_iq (16'h0),
107144
.valid_out (dac_valid_corrected),
108145
.data_out (dac_data_corrected),
@@ -113,36 +150,21 @@ module axi_dac_interpolate_filter #(
113150
fir_interp fir_interpolation (
114151
.clk (dac_clk),
115152
.clk_enable (dac_cic_valid),
116-
.reset (dac_rst | dma_transfer_suspend),
153+
.reset (dac_rst | reset_filt),
117154
.filter_in (dac_data_corrected),
118155
.filter_out (dac_fir_data),
119156
.ce_out (dac_fir_valid));
120157

121158
cic_interp cic_interpolation (
122159
.clk (dac_clk),
123160
.clk_enable (dac_valid_corrected),
124-
.reset (dac_rst | cic_change_rate | dma_transfer_suspend),
161+
.reset (dac_rst | cic_change_rate | reset_filt),
125162
.rate (interp_rate_cic),
126163
.load_rate (1'b0),
127164
.filter_in (dac_fir_data[30:0]),
128165
.filter_out (dac_cic_data),
129166
.ce_out (dac_cic_valid));
130167

131-
assign dma_valid_ch_sync = sync_stop_channels ?
132-
dma_valid & dma_valid_adjacent & !dma_transfer_suspend :
133-
dma_valid & !dma_transfer_suspend;
134-
135-
assign dma_valid_ch = dma_valid_ch_sync & !stop_transfer;
136-
always @(posedge dac_clk) begin
137-
if (dac_rst == 1'b1) begin
138-
dma_valid_m <= 'd0;
139-
end else begin
140-
dma_valid_m <= {dma_valid_m[14:0], dma_valid_ch};
141-
end
142-
end
143-
144-
assign dac_valid_out = dma_valid_m[4'h5];
145-
146168
always @(posedge dac_clk) begin
147169
filter_mask_d1 <= filter_mask;
148170
if (filter_mask_d1 != filter_mask) begin
@@ -157,9 +179,7 @@ module axi_dac_interpolate_filter #(
157179
// paths randomly ready, only when using data buffers
158180

159181
always @(posedge dac_clk) begin
160-
if (dac_filt_int_valid &
161-
(!start_sync_channels & dma_valid |
162-
(dma_valid & dma_valid_adjacent))) begin
182+
if (dac_filt_int_valid & transfer_ready) begin
163183
if (interpolation_counter == interpolation_ratio) begin
164184
interpolation_counter <= 0;
165185
dac_int_ready <= 1'b1;
@@ -173,26 +193,71 @@ module axi_dac_interpolate_filter #(
173193
end
174194
end
175195

196+
assign transfer_ready = start_sync_channels ?
197+
dma_valid & dma_valid_adjacent :
198+
dma_valid;
199+
assign transfer_start = !(en_start_trigger ^ trigger) & transfer_ready;
200+
176201
always @(posedge dac_clk) begin
177-
if (dma_transfer_suspend == 1'b0) begin
178-
transfer <= trigger ? 1'b1 : transfer | !(trigger_active & en_start_trigger);
179-
end else begin
180-
transfer <= 1'b0;
181-
end
182-
if (start_sync_channels == 1'b0) begin
183-
transmit_ready <= dma_valid & transfer;
184-
end else begin
185-
transmit_ready <= dma_valid & dma_valid_adjacent & transfer;
186-
end
202+
stop_transfer <= transfer_sm == IDLE ? 1'b0 :
203+
stop_transfer |
204+
dma_transfer_suspend |
205+
(en_stop_trigger & trigger) |
206+
(sync_stop_channels & dma_valid & dma_valid_adjacent);
207+
end
208+
209+
// transfer state machine
210+
always @(posedge dac_clk) begin
211+
case (transfer_sm)
212+
IDLE: begin
213+
transfer <= 1'b0;
214+
if (dac_int_ready) begin
215+
transfer_sm_next <= WAIT;
216+
end
217+
end
218+
WAIT: begin
219+
transfer <= 1'b0;
220+
if (transfer_start) begin
221+
transfer_sm_next <= TRANSFER;
222+
end
223+
end
224+
TRANSFER: begin
225+
transfer <= 1'b1;
226+
if (stop_transfer) begin
227+
if (flush_dma_in) begin
228+
transfer_sm_next <= FLUSHING;
229+
end else begin
230+
transfer_sm_next <= WAIT;
231+
end
232+
end else if (dma_valid == 1'b0) begin
233+
transfer_sm_next <= IDLE;
234+
end
235+
end
236+
FLUSHING: begin
237+
transfer <= 1'b1;
238+
if (dma_valid == 1'b0) begin
239+
transfer_sm_next <= IDLE;
240+
end
241+
end
242+
endcase
243+
transfer_sm <= transfer_sm_next;
187244
end
188245

246+
assign flush_dma = transfer_sm_next == FLUSHING ? 1'b1 : raw_transfer_en & flush_dma_in;
247+
assign dma_ready = transfer_sm_next == TRANSFER ? dac_int_ready : flush_dma;
248+
assign underflow = dac_enable & dma_ready & ~dma_valid & !flush_dma;
249+
250+
assign dma_valid_ch = transfer | raw_transfer_en;
251+
189252
always @(posedge dac_clk) begin
190-
stop_transfer <= !en_stop_trigger | dma_transfer_suspend ? 1'b0 :
191-
stop_transfer | (trigger_active & trigger & transfer);
253+
if (dac_rst == 1'b1) begin
254+
dma_valid_m <= 'd0;
255+
end else begin
256+
dma_valid_m <= {dma_valid_m[14:0], dma_valid_ch};
257+
end
192258
end
193259

194-
assign dma_ready = transmit_ready ? dac_int_ready : 1'b0;
195-
assign underflow = dac_enable & dma_ready & ~dma_valid;
260+
assign dac_valid_out = dma_valid_m[2];
196261

197262
always @(posedge dac_clk) begin
198263
case (filter_mask)

0 commit comments

Comments
 (0)