USB3.0 HDMI输入方案之FT601Q

原创
2019/09/14 20:54
阅读数 2.1K

USB3.0 HDMI输入方案之FT601Q

 

         本文内容和” USB3.0摄像头方案之FT601Q”方案实质上是一个方案,独立出来只是加以区分。毕竟HDMI输入不是摄像头。

1、构架设计

如下图所示,对于FDMA是我们米联客(MSXBO英文注册商标)自定的AXI4总线IP非常适合于图像数据的缓存应用,我们设计的FDMA控制器构架可以很方便的应用于视频的数据缓存。如果你用过米联客的开发板并且之前已经掌握了FMDA IP的使用,那么这部分内容就很简单了。因为对于FT601Q的FPGA代码非常简单。我们对FT601Q的FPGA代码做了一个简单的视频信号转换后接到了FDMA控制器,之前已经开发好的的代码几乎不用修改就可以使用了。这也是我一直强调的构架设计,设计一个优秀的构架,一个可重复利用的构架,可以提高我们的编程效率,以及降低代码的bug.

 

 

2、FPGA BD 设计

下图的BD设计没啥好好说的,对于第一次使用FMDA的人来说,主要是了解FDMA这个IP的使用,那就去阅读我们专门讲解FMDA的章节吧,因为这个BD工程和专门讲解FMDA IP章节的一样,这就是优秀代码构架的好处,不管你用于什么工程,基本上只要做很小的代码修改。

3、USB接口代码

USB接口代码依然非常简单

module ft60x(

// system control

input                  Rstn_i,//fpga reset

output                 USBSS_EN,//power enable   

// FIFO interface    

input                  CLK_i,

inout [31:0]           DATA_io,

inout [3:0]            BE_io,

input                  RXF_N_i,   // ACK_N

input                  TXE_N_i,

output                 OE_N_o,

output                 WR_N_o,    // REQ_N

output                 SIWU_N_o,

output                 RD_N_o,

output                 WAKEUP_o,

output [1:0]           GPIO_o,

output                 usb_rd_en,

output                 usb_frame,

input  [31:0]          usb_data     

);

   

assign USBSS_EN = 1'b1;   

assign WAKEUP_o = 1'b1;

assign GPIO_o   = 2'b00;   

assign SIWU_N_o = 1'b0;

 

wire rstn;

 

(*mark_debug = "true"*) wire            usb_rd_en;

(*mark_debug = "true"*) wire            usb_frame;

 

(*mark_debug = "true"*) wire            RXF_N_i;   // ACK_N

(*mark_debug = "true"*) wire            TXE_N_i;

(*mark_debug = "true"*) reg             OE_N_o;

(*mark_debug = "true"*) reg             WR_N_o;    // REQ_N

(*mark_debug = "true"*) reg             RD_N_o;

 

(*mark_debug = "true"*) (* KEEP = "TRUE" *)wire [31:0] rd_data;

(*mark_debug = "true"*) (* KEEP = "TRUE" *)wire [31:0] wr_data;

(*mark_debug = "true"*) wire [3 :0] BE_RD;

(*mark_debug = "true"*) wire [3 :0] BE_WR;

(*mark_debug = "true"*) reg [1:0] USB_S;

 

wire data_rd_valid,data_wr_valid;

assign data_rd_valid = (RD_N_o==1'b0)&&(RXF_N_i==1'b0);

assign data_wr_valid = (WR_N_o==1'b0)&&(TXE_N_i==1'b0);

//read or write flag

assign rd_data  =  (USB_S==2'd1) ? DATA_io : 32'd0;//read data dir

assign BE_RD    =  (USB_S==2'd1) ? BE_io   : 4'd0;

assign DATA_io  =  (USB_S==2'd2) ? wr_data : 32'bz;// write data dir

assign BE_io    =  (USB_S==2'd2) ? BE_WR   : 4'bz;// write data dir

assign BE_WR    =  4'b1111;

 

assign wr_data = usb_data;

 

(*mark_debug = "true"*) (* KEEP = "TRUE" *) reg [15:0]rd_cnt;

 

(*mark_debug = "true"*) (* KEEP = "TRUE" *) reg [31:0] fram_cmd;

 

always @(posedge CLK_i)begin

    if(!rstn)begin

        fram_cmd <= 32'd0;

    end

    else if(data_rd_valid) begin

        fram_cmd <= rd_data;

    end

    else begin

        if(fram_cmd> 32'd0)begin

            fram_cmd <= fram_cmd - 1'b1;

        end

    end

end

 

assign usb_frame = (fram_cmd> 32'd2000);

assign usb_rd_en = data_wr_valid;

 

 

always @(posedge CLK_i)begin

    if(!rstn)begin

        USB_S <= 2'd0;

        OE_N_o <= 1'b1;

        RD_N_o <= 1'b1;

        WR_N_o <= 1'b1;

    end

    else begin

        case(USB_S)

        0:begin

            OE_N_o <= 1'b1;

            RD_N_o <= 1'b1;

            WR_N_o <= 1'b1;

            if((!RXF_N_i)) begin

                USB_S  <= 2'd1;

                OE_N_o <= 1'b0;  

            end

            else if((!TXE_N_i))begin

                USB_S  <= 2'd2;

            end

        end

        1:begin

            RD_N_o <= 1'b0;  

            if(RXF_N_i) begin

                USB_S  <= 2'd0;

                RD_N_o <= 1'b1;

                OE_N_o <= 1'b1;     

            end

        end

        2:begin

            WR_N_o <= 1'b0;

            if(TXE_N_i) begin

                USB_S  <= 2'd0;

                WR_N_o <= 1'b1;

             end

        end

        3:begin

            USB_S <= 2'd0;

        end

        endcase                

    end

end

 

 

Delay_rst_0 Delay_rst_inst

(

    .clk_i(CLK_i),

    .rstn_i(Rstn_i),

    .rst_o(rstn)

 );

 

  

endmodule

 

请注意这三个信号

usb_rd_en  此信号接到FDMA读接口的R0_rden_i代表读数据使能

usb_frame  此信号接到FDMA读接口的R0_FS_i代表读数据帧信号

usb_data   此信号接到FDMA读接口的R0_data_o代表读到的有效数据

 

always @(posedge CLK_i)begin

    if(!rstn)begin

        fram_cmd <= 32'd0;

    end

    else if(data_rd_valid) begin

        fram_cmd <= rd_data;

    end

    else begin

        if(fram_cmd> 32'd0)begin

            fram_cmd <= fram_cmd - 1'b1;

        end

    end

end

assign usb_frame = (fram_cmd> 32'd2000);

assign usb_rd_en = data_wr_valid;

 

再看其中的关键设计,fram_cmd计数器用保存上位机发过来的帧信号,这里就是用计数器值去产生读通道的帧同步信号。这个设计非常巧妙,不耗费代码,但是却实现了功能。

 

再看我们用data_wr_valid信号去实现了读使能,由于USB的数据对于FT601Q来说最大4KB,每次4KB一包完成后,必然有个停顿,进行下次一传输,正好我们就可以用这个信号作为每次的同步读取信号,类似行同步信号。

 

4、在线逻辑分析仪观察信号

 

比如下图是我们抓紧到的在线逻辑分析仪观察关键信号的截图

下图是帧同步

下图可以理解未场同步,每次最大4KB数据

5、测试结果

展开阅读全文
打赏
0
0 收藏
分享
加载中
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部