axi_hdmi_tx: Update to use ADI DMA

The frame synchronization between axi_hdmi_tx and axi_dmac is based
on the DMA(2D streaming) last signal. The last signal will be used as
an end of frame signal marking the beginning of the future frame to be
transferred by the DMA.
  Only after both HDMI and DMA are ready for a "new frame" data will be
requested from the DMA.
  The datarate and CDC between the axi_dmac and axi_hdmi_tx cores
will be handled by axi_hdmi_tx's DMA interface based on a backpressure
mechanism.
main
AndreiGrozav 2018-05-11 18:00:15 +03:00 committed by AndreiGrozav
parent 6fb250ad89
commit e607471898
4 changed files with 77 additions and 40 deletions

View File

@ -71,8 +71,7 @@ module axi_hdmi_tx #(
// vdma interface // vdma interface
input vdma_clk, input vdma_clk,
output vdma_fs, input vdma_end_of_frame,
input vdma_fs_ret,
input vdma_valid, input vdma_valid,
input [63:0] vdma_data, input [63:0] vdma_data,
output vdma_ready, output vdma_ready,
@ -237,11 +236,10 @@ module axi_hdmi_tx #(
.hdmi_raddr_g (hdmi_raddr_g_s), .hdmi_raddr_g (hdmi_raddr_g_s),
.vdma_clk (vdma_clk), .vdma_clk (vdma_clk),
.vdma_rst (vdma_rst), .vdma_rst (vdma_rst),
.vdma_fs (vdma_fs),
.vdma_fs_ret (vdma_fs_ret),
.vdma_valid (vdma_valid), .vdma_valid (vdma_valid),
.vdma_data (vdma_data), .vdma_data (vdma_data),
.vdma_ready (vdma_ready), .vdma_ready (vdma_ready),
.vdma_end_of_frame (vdma_end_of_frame),
.vdma_wr (vdma_wr_s), .vdma_wr (vdma_wr_s),
.vdma_waddr (vdma_waddr_s), .vdma_waddr (vdma_waddr_s),
.vdma_wdata (vdma_wdata_s), .vdma_wdata (vdma_wdata_s),

View File

@ -244,6 +244,10 @@ module axi_hdmi_tx_core #(
// hdmi start of frame // hdmi start of frame
always @(posedge hdmi_clk) begin always @(posedge hdmi_clk) begin
if (hdmi_rst == 1'b1) begin
hdmi_fs_toggle <= 1'b0;
hdmi_fs <= 1'b0;
end else begin
if (EMBEDDED_SYNC == 1) begin if (EMBEDDED_SYNC == 1) begin
if ((hdmi_hs_count == 1) && (hdmi_vs_count == hdmi_ve_width_s)) begin if ((hdmi_hs_count == 1) && (hdmi_vs_count == hdmi_ve_width_s)) begin
hdmi_fs <= hdmi_enable; hdmi_fs <= hdmi_enable;
@ -261,6 +265,7 @@ module axi_hdmi_tx_core #(
hdmi_fs_toggle <= ~hdmi_fs_toggle; hdmi_fs_toggle <= ~hdmi_fs_toggle;
end end
end end
end
// hdmi sof write address // hdmi sof write address
@ -280,10 +285,8 @@ module axi_hdmi_tx_core #(
always @(posedge hdmi_clk) begin always @(posedge hdmi_clk) begin
hdmi_fs_ret <= hdmi_fs_ret_s; hdmi_fs_ret <= hdmi_fs_ret_s;
if (hdmi_fs_ret_s == 1'b1) begin
hdmi_fs_waddr <= vdma_fs_waddr; hdmi_fs_waddr <= vdma_fs_waddr;
end end
end
// hdmi sync signals // hdmi sync signals
@ -332,7 +335,7 @@ module axi_hdmi_tx_core #(
always @(posedge hdmi_clk) begin always @(posedge hdmi_clk) begin
if (hdmi_rst == 1'b1) begin if (hdmi_rst == 1'b1) begin
hdmi_raddr <= 10'd0; hdmi_raddr <= 10'd0;
end else if (hdmi_fs_ret == 1'b1) begin end else if (hdmi_fs == 1'b1) begin
hdmi_raddr <= {hdmi_fs_waddr, 1'b0}; hdmi_raddr <= {hdmi_fs_waddr, 1'b0};
end else if (hdmi_de_s == 1'b1) begin end else if (hdmi_de_s == 1'b1) begin
hdmi_raddr <= hdmi_raddr + 1'b1; hdmi_raddr <= hdmi_raddr + 1'b1;

View File

@ -35,7 +35,7 @@ set_property driver_value 0 [ipx::get_ports *vsync* -of_objects [ipx::current_co
set_property driver_value 0 [ipx::get_ports *data* -of_objects [ipx::current_core]] set_property driver_value 0 [ipx::get_ports *data* -of_objects [ipx::current_core]]
set_property driver_value 0 [ipx::get_ports *es_data* -of_objects [ipx::current_core]] set_property driver_value 0 [ipx::get_ports *es_data* -of_objects [ipx::current_core]]
set_property driver_value 0 [ipx::get_ports *vdma_fs* -of_objects [ipx::current_core]] set_property driver_value 0 [ipx::get_ports *vdma_end_of_frame* -of_objects [ipx::current_core]]
set_property driver_value 0 [ipx::get_ports *vdma_valid* -of_objects [ipx::current_core]] set_property driver_value 0 [ipx::get_ports *vdma_valid* -of_objects [ipx::current_core]]
set_property driver_value 0 [ipx::get_ports *vdma_data* -of_objects [ipx::current_core]] set_property driver_value 0 [ipx::get_ports *vdma_data* -of_objects [ipx::current_core]]
set_property driver_value 0 [ipx::get_ports *vdma_ready* -of_objects [ipx::current_core]] set_property driver_value 0 [ipx::get_ports *vdma_ready* -of_objects [ipx::current_core]]

View File

@ -45,8 +45,7 @@ module axi_hdmi_tx_vdma (
input vdma_clk, input vdma_clk,
input vdma_rst, input vdma_rst,
output reg vdma_fs, input vdma_end_of_frame,
input vdma_fs_ret,
input vdma_valid, input vdma_valid,
input [63:0] vdma_data, input [63:0] vdma_data,
output reg vdma_ready, output reg vdma_ready,
@ -66,16 +65,20 @@ module axi_hdmi_tx_vdma (
// internal registers // internal registers
reg vdma_fs_toggle_m1 = 'd0; reg vdma_fs_toggle_m1 = 1'd0;
reg vdma_fs_toggle_m2 = 'd0; reg vdma_fs_toggle_m2 = 1'd0;
reg vdma_fs_toggle_m3 = 'd0; reg vdma_fs_toggle_m3 = 1'd0;
reg [22:0] vdma_tpm_data = 'd0; reg [22:0] vdma_tpm_data = 23'd0;
reg [ 8:0] vdma_raddr_g_m1 = 'd0; reg [ 8:0] vdma_raddr_g_m1 = 9'd0;
reg [ 8:0] vdma_raddr_g_m2 = 'd0; reg [ 8:0] vdma_raddr_g_m2 = 9'd0;
reg [ 8:0] vdma_raddr = 'd0; reg [ 8:0] vdma_raddr = 9'd0;
reg [ 8:0] vdma_addr_diff = 'd0; reg [ 8:0] vdma_addr_diff = 9'd0;
reg vdma_almost_full = 'd0; reg vdma_almost_full = 1'd0;
reg vdma_almost_empty = 'd0; reg vdma_almost_empty = 1'd0;
reg hdmi_fs = 1'd0;
reg vdma_fs = 1'd0;
reg vdma_end_of_frame_d = 1'd0;
reg vdma_active_frame = 1'd0;
// internal wires // internal wires
@ -104,7 +107,7 @@ module axi_hdmi_tx_vdma (
end end
endfunction endfunction
// get fs from hdmi side, return fs and sof write address back // hdmi frame sync
always @(posedge vdma_clk or posedge vdma_rst) begin always @(posedge vdma_clk or posedge vdma_rst) begin
if (vdma_rst == 1'b1) begin if (vdma_rst == 1'b1) begin
@ -116,13 +119,46 @@ module axi_hdmi_tx_vdma (
vdma_fs_toggle_m2 <= vdma_fs_toggle_m1; vdma_fs_toggle_m2 <= vdma_fs_toggle_m1;
vdma_fs_toggle_m3 <= vdma_fs_toggle_m2; vdma_fs_toggle_m3 <= vdma_fs_toggle_m2;
end end
hdmi_fs <= vdma_fs_toggle_m2 ^ vdma_fs_toggle_m3;
end end
// dma frame sync
always @(posedge vdma_clk or posedge vdma_rst) begin
if (vdma_rst == 1'b1) begin
vdma_end_of_frame_d <= 1'b0;
vdma_fs <= 1'b0;
end else begin
vdma_end_of_frame_d <= vdma_end_of_frame;
vdma_fs <= vdma_end_of_frame_d;
end
end
// sync dma and hdmi frames
always @(posedge vdma_clk) begin always @(posedge vdma_clk) begin
vdma_fs <= vdma_fs_toggle_m2 ^ vdma_fs_toggle_m3; if (vdma_rst == 1'b1) begin
if (vdma_fs_ret == 1'b1) begin vdma_fs_ret_toggle = 1'b0;
vdma_fs_waddr <= vdma_waddr; vdma_fs_waddr <= 9'b0;
end else begin
if (vdma_fs) begin
vdma_fs_ret_toggle <= ~vdma_fs_ret_toggle; vdma_fs_ret_toggle <= ~vdma_fs_ret_toggle;
vdma_fs_waddr <= vdma_waddr ;
end
end
end
// accept new frame from dma
always @(posedge vdma_clk) begin
if (vdma_rst == 1'b1) begin
vdma_active_frame <= 1'b0;
end else begin
if ((vdma_active_frame == 1'b1) && (vdma_end_of_frame == 1'b1)) begin
vdma_active_frame <= 1'b0;
end else if ((vdma_active_frame == 1'b0) && (hdmi_fs == 1'b1)) begin
vdma_active_frame <= 1'b1;
end
end end
end end
@ -144,7 +180,7 @@ module axi_hdmi_tx_vdma (
assign vdma_tpm_oos_s = (vdma_wdata == vdma_tpm_data_s) ? 1'b0 : vdma_wr; assign vdma_tpm_oos_s = (vdma_wdata == vdma_tpm_data_s) ? 1'b0 : vdma_wr;
always @(posedge vdma_clk) begin always @(posedge vdma_clk) begin
if ((vdma_rst == 1'b1) || (vdma_fs_ret == 1'b1)) begin if ((vdma_rst == 1'b1) || (vdma_fs == 1'b1)) begin
vdma_tpm_data <= 23'd0; vdma_tpm_data <= 23'd0;
vdma_tpm_oos <= 1'd0; vdma_tpm_oos <= 1'd0;
end else if (vdma_wr == 1'b1) begin end else if (vdma_wr == 1'b1) begin
@ -175,7 +211,7 @@ module axi_hdmi_tx_vdma (
if (vdma_addr_diff >= RDY_THRESHOLD_HI) begin if (vdma_addr_diff >= RDY_THRESHOLD_HI) begin
vdma_ready <= 1'b0; vdma_ready <= 1'b0;
end else if (vdma_addr_diff <= RDY_THRESHOLD_LO) begin end else if (vdma_addr_diff <= RDY_THRESHOLD_LO) begin
vdma_ready <= 1'b1; vdma_ready <= vdma_active_frame;
end end
if (vdma_addr_diff > BUF_THRESHOLD_HI) begin if (vdma_addr_diff > BUF_THRESHOLD_HI) begin
vdma_almost_full <= 1'b1; vdma_almost_full <= 1'b1;