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

本文围绕Xilinx FPGA MIPI CSI-2 Transmitter Subsystem展开。介绍了该IP核的配置,包括接口、CSI lane、输入像素等设置,以及管脚指定。在仿真验证中,因IP无示例工程需自行搭建测试,遇到DATA_TYPE对应关系不明等问题,经调试发现要等内核就绪才能使能。最后补充了仿真中的axi lite寄存器读写代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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,不能再继续接收数据。

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

后面折腾半天,最终找到问题原因,原来IP核启动后需要等好久才能就绪,未就绪情况下不能使用,所以加入等待代码。

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

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

仿真代码补充

好多人问仿真中的axi lite寄存器读写函数怎么写,我把代码贴上供大家使用。

/// axi lite register write 
task register_write;
	input [31:0]  reg_addr;
	input [31:0]  reg_value;
	begin
		@(posedge s_axi_aclk) ;
		// while(s_axi_awready == 0) @(posedge s_axi_aclk) ;
		
		@(posedge s_axi_aclk)
			begin
				s_axi_awaddr <= reg_addr[C_M_AXI_ADDR_WIDTH-1:0];
			end
		@(posedge s_axi_aclk) s_axi_awvalid<= 1;
		wait(s_axi_awready) @(posedge s_axi_aclk) s_axi_awvalid<= 0;
		@(posedge s_axi_aclk) s_axi_awvalid<= 0;
			
		@(posedge s_axi_aclk)
			begin
				s_axi_wdata  <= reg_value;
				s_axi_wvalid <= 1;
			end
		while(s_axi_wready == 0)  @(posedge s_axi_aclk) ;
		s_axi_wvalid = 0;
		@(posedge s_axi_aclk) s_axi_wvalid<= 0;
	end
endtask   

/// axi lite register read
task register_read;
	input [31:0]  reg_addr;
	begin
		@(posedge s_axi_aclk) ;

		@(posedge s_axi_aclk)
			begin
				s_axi_araddr <= reg_addr[C_M_AXI_ADDR_WIDTH-1:0];
				s_axi_arvalid<= 1;
			end
		wait(s_axi_arready) @(posedge s_axi_aclk) s_axi_arvalid<= 0;
		wait(s_axi_rvalid) @(posedge s_axi_aclk) s_axi_rdata_r <= s_axi_rdata;
		@(posedge s_axi_aclk) ;
		
	end
endtask    

Xilinx MIPI CSI2 TX子系统是一种用于将图像数据从MIPI RX传输到MIPI TX的解决方案。根据引用\[1\]中提到的信息,为了使图像能够正常传输,需要进行一些映射操作。具体来说,需要将MIPI RX的tuser和tdest信息映射到MIPI TX的对应位置。 根据引用\[2\]和引用\[3\]中的代码片段,可以看出在初始化和配置过程中,需要进行一些寄存器的写入操作。例如,通过register_write(0,32'h12)来重置控制器,通过register_write(0,32'h11)来启用核心接收和处理数据包。此外,在等待控制器准备好的过程中,还需要进行一些寄存器的读取和时钟延迟的操作。 综上所述,Xilinx MIPI CSI2 TX子系统是一种用于图像数据传输的解决方案,需要进行映射和配置操作,并且在初始化和配置过程中需要进行一些寄存器的读写和时钟延迟的操作。 #### 引用[.reference_title] - *1* [Xilinx FPGAmipi tx\mipi rx配置](https://blog.youkuaiyun.com/weixin_37620587/article/details/126686835)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Xilinx FPGA MIPI CSI-2 Transmitter Subsystem 仿真笔记](https://blog.youkuaiyun.com/web_star/article/details/98477927)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值