基于AXI-Stream接口的Modelsim图像处理仿真平台的搭建

该文详细介绍了在FPGA设计中使用AXI_Stream接口处理图像数据的过程,包括VALID和TLAST信号的正确使用,以及如何在一行结束后拉低VALID信号。文中还涉及到BMP图片的生成,通过灰度转换算法处理像素数据并存储到BMP文件中。

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

AXI_Stream接口注意事项
这里需要注意到:
1**、在EOL(AXIS_TLAST)被(拉高)后,VALID是需要在下一个时刻置低的。
2、无论是EOL还是SOF,拉高时数据通道依然是有效的,如果需要对行计数时,需要对LAST信号进行延时,等待延时信号后对行清零。**在这里插入图片描述## AXI_Stream接口编写
#s_axis_tvaild控制

reg [5:0] rst_cnt;	
	
//赋初值再加一个初始延时
always @(posedge clk or negedge rst_n) begin
	if (~rst_n)
		rst_cnt <= 6'd0;
	else if (rst_cnt == 6'd30)
		rst_cnt <= rst_cnt;
	else
		rst_cnt <= rst_cnt + 1'b1;
end
		
//s_axis_tvalid信号在一行的结束拉低
always @(posedge clk or negedge rst_n) begin
	if(~rst_n)
		s_axis_tvalid <= 1'b0;
	else if(s_axis_tlast) 
		s_axis_tvalid <= 1'b0;
	else if(rst_cnt == 6'd30)
		s_axis_tvalid <= 1'b1;
	else
		s_axis_tvalid <= s_axis_tvalid;  
end	

s_axis_tlast在一行的最后一个数据拉高

reg [10:0] w_cnt;
always @(posedge clk or negedge rst_n) begin
	if(~rst_n)begin
		w_cnt <= 11'b0;
	end
	else if(s_axis_tvalid && s_axis_tready && w_cnt < iBmpWidth - 1 ) begin
		w_cnt <= w_cnt  + 1'b1;
	end
	else if(w_cnt ==  iBmpWidth-1) begin
		w_cnt <= 11'b0;
	end
	else begin
		w_cnt <= w_cnt;
	end
end

assign s_axis_tlast = (w_cnt ==  iBmpWidth - 1) ? 1'b1: 1'b0 ;

s_axis_tuser在第一行的第一列数据拉高

reg [10:0] h_cnt;

always @(posedge clk or negedge rst_n) begin
	if(~rst_n)begin
		h_cnt <= 1'b0;
	end
	else if(s_axis_tlast) begin
		h_cnt <= h_cnt  + 1'b1;
	end
	else if(h_cnt == iBmpHight - 1'd1) begin
		h_cnt <= 1'b0;
	end
	else begin
		h_cnt <= h_cnt;
	end
end
assign s_axis_tuser = (h_cnt == 0 && w_cnt == 0) ? 1'b1: 1'b0 ;

从数组中以视频格式输出像素数据

reg	[23:0]	cmos_data;	
reg [31:0]  cmos_index;

always@(posedge clk or negedge rst_n)begin
   if(!rst_n) begin
       cmos_index   <=  0;
       cmos_data    <=  24'd0;
   end
   else begin
       //cmos_index   <=  y_pos * 960  + x_pos*3 + 54;        //  3*(y*320 + x) + 54
       cmos_index   <=  h_cnt * 1920  + w_cnt * 3 + 54;         //  3*(y*640 + x) + 54
       cmos_data    <=  {rBmpData[cmos_index], rBmpData[cmos_index+1] , rBmpData[cmos_index+2]};
   end
end

wire [7:0]	img_red		=	cmos_data[ 7: 0];	   	
wire [7:0]	img_green	=	cmos_data[15: 8];   	            
wire [7:0]	img_blue	=	cmos_data[23:16]; 

assign s_axis_tdata = (s_axis_tvalid && s_axis_tready) ? {img_red, img_green, img_blue} : 24'd0;

以灰度转换为例

//--------------------
//VIP算法——彩色转灰度
wire 		per_frame_tvalid	;
wire 		per_frame_tready	;	
wire 		per_frame_tuser		;	
wire 		per_frame_tlast		;	
wire [23:0]	per_frame_tdata		;	

wire 		pose0_frame_tvalid	;
wire 		pose0_frame_tready	;	
wire 		pose0_frame_tuser	;	
wire 		pose0_frame_tlast	;
wire [23:0] pose0_frame_tdata	;		
	
wire [7:0]	post0_img_Y      	;   
wire [7:0]	post0_img_Cb     	;   
wire [7:0]	post0_img_Cr     	;  


assign per_frame_tvalid		= s_axis_tvalid	;	
assign per_frame_tuser		= s_axis_tuser	;
assign per_frame_tlast		= s_axis_tlast	;
assign per_frame_tdata 		= s_axis_tdata	;

//s_axis_tready信号由主机输出
assign s_axis_tready 		= per_frame_tready;
	

assign pose0_frame_tvalid	= m_axis_tvalid	;
assign pose0_frame_tuser	= m_axis_tuser	;
assign pose0_frame_tlast	= m_axis_tlast	;	
assign post0_img_Y 			= pose0_frame_tdata[23:16];
assign post0_img_Cb		 	= pose0_frame_tdata[15:8];
assign post0_img_Cr 		= pose0_frame_tdata[7:0];


rgb_ycbcr u_rgb_ycbcr(

	 //AXI4_Stream Slave接口0,来自摄像头,获取当前帧数据
	.clk    			(clk				),
	.rst_n 				(rst_n				),
	.s0_axis_tdata    	(per_frame_tdata 	),
	.s0_axis_tready   	(per_frame_tready	),		//输出
	.s0_axis_tvalid   	(per_frame_tvalid	),
	.s0_axis_tuser    	(per_frame_tuser 	),   	//tuser == start of frame(SOF) 
	.s0_axis_tlast    	(per_frame_tlast 	),   	//tlast == end of line(EOL)
    
    
    //AXIS4_Stream Master接口,输出到VDMA
//    input               m_axis_aclk    	,
//    input               m_axis_aresetn 	,
    .m_axis_tdata    	(pose0_frame_tdata	),
    .m_axis_tvalid   	(pose0_frame_tvalid	),
    .m_axis_tready   	(pose0_frame_tready	),
    .m_axis_tuser    	(pose0_frame_tuser	),
    .m_axis_tlast    	(pose0_frame_tlast	)
);
##   生成BMP图片

```c
//寄存图像处理之后的像素数据

//-------------------------------------
//第一张图

reg [31:0]  PIC1_vip_cnt;
reg         PIC1_vip_out_en;     	//寄存VIP处理图像的使能信号,仅维持一帧的时间
reg 		m_axis_tuser_r0;		//采集上升沿
reg 		m_axis_tuser_r1;
wire 		m_axis_tuser_p;

reg         PIC1_vip_vsync_r;    	//寄存VIP输出的场同步


always@(posedge clk or negedge rst_n)begin
   
	if(!rst_n) begin
		m_axis_tuser_r0 <= 1'd0;
        m_axis_tuser_r1 <= 1'd0;
	end
	else begin
		m_axis_tuser_r0 <= PIC1_vip_out_tuser	;
        m_axis_tuser_r1 <= m_axis_tuser_r0		;
	end
end

assign m_axis_tuser_p = (~m_axis_tuser_r1) && m_axis_tuser_r0;



always@(posedge clk or negedge rst_n)begin
   if(!rst_n) 
        PIC1_vip_vsync_r   <=  1'b0;
   else if (m_axis_tuser_p)
        PIC1_vip_vsync_r   <=  ~PIC1_vip_vsync_r;
end


always@(posedge clk or negedge rst_n)begin
   if(!rst_n) 
        PIC1_vip_out_en    <=  1'b1;
   else if(PIC1_vip_vsync_r & m_axis_tuser_p)  //第一帧结束之后,使能拉低
        PIC1_vip_out_en    <=  1'b0;
end


always@(posedge clk or negedge rst_n)begin
	if(!rst_n) begin
		PIC1_vip_cnt <=  32'd0;
	end
	else if (PIC1_vip_out_en) begin
		if(PIC1_vip_out_tvalid & PIC1_vip_out_tready) begin
			PIC1_vip_cnt <=  PIC1_vip_cnt + 3;
			vip_pixel_data_1[PIC1_vip_cnt+0] <= PIC1_vip_out_img_R;
			vip_pixel_data_1[PIC1_vip_cnt+1] <= PIC1_vip_out_img_G;
			vip_pixel_data_1[PIC1_vip_cnt+2] <= PIC1_vip_out_img_B;
		end
	end
end

	//输出第一张
	for (iIndex = 0; iIndex < iBmpSize; iIndex = iIndex + 1) begin
		if(iIndex < 54)
            Vip_BmpData_1[iIndex] = rBmpData[iIndex];
        else
            Vip_BmpData_1[iIndex] = vip_pixel_data_1[iIndex-54];
	end
    //将数组中的数据写到输出BMP图片中    
	for (iIndex = 0; iIndex < iBmpSize; iIndex = iIndex + 4) begin
		rBmpWord = {Vip_BmpData_1[iIndex+3],Vip_BmpData_1[iIndex+2],Vip_BmpData_1[iIndex+1],Vip_BmpData_1[iIndex]};
		$fwrite(oBmpFileId_1,"%u",rBmpWord);
	end

效果展示

在这里插入图片描述

参考文献

https://hwbyyds.blog.youkuaiyun.com/article/details/124319453?spm=1001.2014.3001.5502
b站大磊FPGA图像处理,基于Modelsim的图像仿真处理平台搭建

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值