Xilinx FPGA MIPI CSI-2 Transmitter Subsystem 仿真笔记

MIPI——Mobile Industry Processor Interface

DSI用于显示屏,CSI用于摄像头。在某些场合想用FPGA模拟摄像头,可以用Xilinx FPGA MIPI CSI-2 Transmitter Subsystem0。

MIPI协议,网上资料很多,此处不做赘述,此处仅对Xilinx FPGA MIPI CSI-2 Transmitter Subsystem做主要说明。


配置

MIPI CSI-2 Transmitter Subsystem这个IP核,内部包括MIPI D-PHY和MIPI CSI-2 TX Controller。

 此处配置接口为AXI4S,CSI lane选择1,输入像素数目为1,Line buffer深度为2048。

如果整个工程仅用一个接口,那么此处选择inlcude shared logic in core。

管脚根据你的硬件设计进行指定,此处数据管脚和时钟管脚,仅HP BANK可以用,绘制原理图之前需要提前看一下某些管脚是否可以用。


仿真验证

由于IP不自动example工程,所以自己搭建测试。

里面有个DATA_TYPE特别恶心,Xilinx的文档没提各个对应关系,让查MIPI官方文档,MIPI官方又要注册账号。

我这里产生图像是128*32的RGB888图像数据,用于仿真。

它的s_axis_tuser对应的Line number和Frame number可以设置为0,内核会自动匹配检测,但是后级MIPI接收端可能不知道图像的行场大小。

module tb_mipi_core  ; 
//------------------------------------------------------------ 
parameter C_M_AXI_ADDR_WIDTH = 8;


  reg    dphy_clk_200M   ; 
//s_axi
  wire    s_axi_awready   ; 
  wire    s_axi_awvalid   ; 
  wire  [C_M_AXI_ADDR_WIDTH-1:0]  s_axi_awaddr   ;  
  wire    s_axi_arready   ; 
  wire    s_axi_arvalid   ; 
  wire  [C_M_AXI_ADDR_WIDTH-1:0]  s_axi_araddr   ; 
  wire    s_axi_wready   ; 
  wire    s_axi_wvalid   ; 
  wire  [31:0]  s_axi_wdata   ; 
  wire  [3:0]  s_axi_wstrb   ; 
  wire    s_axi_rready   ; 
  wire    s_axi_rvalid   ; 
  wire  [31:0]  s_axi_rdata   ; 
  wire  [1:0]  s_axi_rresp   ; 
  wire    s_axi_bready   ; 
  wire    s_axi_bvalid   ; 
  wire  [1:0]  s_axi_bresp   ; 
  
  
//s_axis  
  reg    s_axis_aclk   ; 
  reg    s_axis_aresetn   ; 
  // reg    s_axis_tvalid   ; 
  wire    s_axis_tvalid   ; 
  wire    s_axis_tready   ; 
  reg  [47:0]  s_axis_tdata   ; 
  // reg    s_axis_tlast   ; 
  wire    s_axis_tlast   ; 
  // reg  [95:0]  s_axis_tuser   ; 
  wire  [95:0]  s_axis_tuser   ; 
  reg  [5:0]  s_axis_tkeep   ; 
  reg  [1:0]  s_axis_tdest   ; 
  
  wire    txclkesc_out   ; 
  wire    mmcm_lock_out   ; 
  wire    clkoutphy_out   ; 
  wire  [0:0]  mipi_phy_if_data_p   ; 
  wire  [0:0]  mipi_phy_if_data_n   ; 
  wire    mipi_phy_if_clk_p   ; 
  wire    mipi_phy_if_clk_n   ; 
  wire    txbyteclkhs   ; 
  wire    interrupt   ; 
  wire    system_rst_out   ;
  wire    pll_lock_out   ; 
  
  wire  s_axi_init_rdy;
  
//------------------------------------------------------------ 
initial  begin
dphy_clk_200M = 0;

s_axis_aresetn = 0;
s_axis_tdest = 0;

// s_axi_awvalid = 0;
// s_axi_wdata = 0;
// s_axi_arvalid = 0;
// s_axi_araddr = 0;
// s_axi_rready = 0  ; 
// s_axi_bready = 0  ; 
// s_axi_wstrb  = 0  ; 
// s_axi_awaddr = 0;
// s_axi_wvalid = 0  ; 

s_axis_aclk = 0;
s_axis_tdata = 0;
// s_axis_tlast = 0;
// s_axis_tuser = 0;
// s_axis_tvalid = 0;
s_axis_tkeep = 5'h1f;

#200;
s_axis_aresetn = 1;


end 

always #2.5   dphy_clk_200M = ~dphy_clk_200M;
always #5  s_axis_aclk = ~s_axis_aclk;

reg [10:0]  cnt_h = 0;
reg [10:0]  cnt_v = 0;

// 128*32
always @(posedge s_axis_aclk)
	if(s_axis_aresetn && s_axi_init_rdy==1)
	begin
		if(s_axis_tready)
			if(cnt_h==200)
				cnt_h <= 40;
			else
				cnt_h <= cnt_h + 1;
			
		if(cnt_h==200)
			if(cnt_v >= 31)
				cnt_v <= 0;
			else
				cnt_v <= cnt_v + 1;
	end
//----------------------------------------------------------------------------------

// assign s_axis_tvalid = 0;
assign s_axis_tvalid = (cnt_h >= 73) ? 1:0;
assign s_axis_tuser[0] = (cnt_v==0 && cnt_h==73)? 1 : 0 ;
assign s_axis_tlast = (cnt_h==200)? 1 : 0 ;
//-------------------------------------------------------
assign s_axis_tuser[95:64] = 0;  //reserved
assign s_axis_tuser[15:7] = 0;  //reserved

assign s_axis_tuser[63:48] = 128;  //Word count  ---- 128*32
assign s_axis_tuser[47:32] = 0;  //Line number
assign s_axis_tuser[31:16] = 0;  //Frame number
assign s_axis_tuser[6:1] = 6'h24;  //Data type  ---  RGB888
// s_axis_tuser[0] = 0;  //Frame start

always @(posedge s_axis_aclk)
	if(s_axis_tvalid && s_axis_tready) begin
		s_axis_tdata[41:34] <= s_axis_tdata[41:34] + 1;
		s_axis_tdata[27:20] <= s_axis_tdata[27:20] + 1;
		s_axis_tdata[13:6]  <= s_axis_tdata[13:6]  + 1;
	end
		
//------------------------------------------------------------
  mipi_csi2_tx_subsystem_0  
   DUT  ( 
       .s_axi_awready (s_axi_awready ) ,
      .s_axis_aresetn (s_axis_aresetn ) ,
      .txclkesc_out (txclkesc_out ) ,
      .mmcm_lock_out (mmcm_lock_out ) ,
      .s_axis_tdest (s_axis_tdest ) ,
      .clkoutphy_out (clkoutphy_out ) ,
      .mipi_phy_if_data_n (mipi_phy_if_data_n ) ,
      .mipi_phy_if_clk_n (mipi_phy_if_clk_n ) ,
      .s_axi_arready (s_axi_arready ) ,
//      .s_axi_arprot (0 ) ,
      .s_axi_awvalid (s_axi_awvalid ) ,
      .s_axis_tdata (s_axis_tdata ) ,
      .s_axi_wdata (s_axi_wdata ) ,
      .dphy_clk_200M (dphy_clk_200M ) ,
      .mipi_phy_if_data_p (mipi_phy_if_data_p ) ,
      .mipi_phy_if_clk_p (mipi_phy_if_clk_p ) ,
      .txbyteclkhs (txbyteclkhs ) ,
      .interrupt (interrupt ) ,
      .s_axis_tlast (s_axis_tlast ) ,
      .s_axi_arvalid (s_axi_arvalid ) ,
      .s_axis_tready (s_axis_tready ) ,
      .s_axi_rresp (s_axi_rresp ) ,
      .s_axi_bresp (s_axi_bresp ) ,
      .s_axi_wready (s_axi_wready ) ,
//      .s_axi_awprot (0 ) ,
      .s_axis_tuser (s_axis_tuser ) ,
      .s_axi_araddr (s_axi_araddr ) ,
      .s_axis_aclk (s_axis_aclk ) ,
      .s_axis_tvalid (s_axis_tvalid ) ,
      .s_axi_rready (s_axi_rready ) ,
      .s_axi_bready (s_axi_bready ) ,
      .s_axi_wvalid (s_axi_wvalid ) ,
      .system_rst_out (system_rst_out ) ,
      .s_axi_rvalid (s_axi_rvalid ) ,
      .s_axi_bvalid (s_axi_bvalid ) ,
      .s_axi_wstrb (s_axi_wstrb ) ,
      .s_axi_awaddr (s_axi_awaddr ) ,
      .s_axis_tkeep (s_axis_tkeep ) ,
      .s_axi_rdata (s_axi_rdata ) ,
      .pll_lock_out (pll_lock_out ) ); 
//-------------------------------------------------------------	  
//-------------------------------------------------------------	  
//-------------------------------------------------------------	   
axi_lite_sm  
	#(
	.C_M_AXI_ADDR_WIDTH (C_M_AXI_ADDR_WIDTH)
	)
lite_sm_u
   (
    // -- System Signals
    .s_axi_aclk (s_axis_aclk),
    .aresetn (s_axis_aresetn),

    // -- Master Interface Write Address
    .s_axi_awaddr (s_axi_awaddr),
    .s_axi_awvalid (s_axi_awvalid),
    .s_axi_awready (s_axi_awready),

    // -- Master Interface Write Data
    .s_axi_wdata (s_axi_wdata),
    .s_axi_wstrb (s_axi_wstrb),
    .s_axi_wvalid (s_axi_wvalid),
    .s_axi_wready (s_axi_wready),

    // -- Master Interface Write Response
    .s_axi_bresp (s_axi_bresp),
    .s_axi_bvalid (s_axi_bvalid),
    .s_axi_bready (s_axi_bready),

    // -- Master Interface Read Address
    .s_axi_araddr (s_axi_araddr),
    .s_axi_arvalid (s_axi_arvalid),
    .s_axi_arready (s_axi_arready),

    // -- Master Interface Read Data 
    .s_axi_rdata (s_axi_rdata),
    .s_axi_rresp (s_axi_rresp),
    .s_axi_rvalid (s_axi_rvalid),
    .s_axi_rready (s_axi_rready),
	
	.s_axi_init_rdy(s_axi_init_rdy)
    );

endmodule

原来以为不对其做任何配置,直接输入AXIS的数据,这个IP应该就能够正常运行,但是仿真发现其根本没有反应。所以后面通过AXI-LITE总线对其做寄存器配置。

根据手册说明,仅对配置寄存器(Core Configuration options)做配置就可以了。

register_write(0,32'h12);  //reset Controller
register_write(0,32'h11);  // Enables the core to receive and process packets

// wait Controller ready
		while(s_axi_rdata_r[2]==0)
		begin
			register_read(32'h0);
			repeat(10) @(posedge s_axi_aclk);
		end

//----
send AXIS stream data to core

根据手册说明,物理层默认初始化时间是1ms,等内核就绪后,发送AXIS数据流,它就应该能正常工作,但是观察输出的时钟和数据,始终不变化。并且内核AXIS接口在接收几包数据后,内核的ready信号一直为0,不能再继续接收数据。

并且输出的差分时钟和数据信号一直不变。

后面折腾半天,最终找到问题原因。

register_write(0,32'h12);  //reset Controller

// wait Controller ready
		while(s_axi_rdata_r[2]==0)
		begin
			register_read(32'h0);
			repeat(10) @(posedge s_axi_aclk);
		end

register_write(0,32'h11);  // Enables the core to receive and process packets

//----
send AXIS stream data to core

将之前代码顺序进行调整,仿真竟然通过。也就是在使能内核之前,必须先等内核就绪。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页