1. 程式人生 > >FPGA影象處理系列-video訊號轉Avalon-ST模組

FPGA影象處理系列-video訊號轉Avalon-ST模組

    年前到手一塊Altera的SoCKit開發板,跑了跑友晶的VIP例程。也是為了練手,自己寫了個video input format detection模組(此模組官方有提供IP)。功能為:將輸入的包含RGB data, hsync,vsync,data_valid訊號的video視訊流轉換成Avalon-ST匯流排。

    核心就是一個非同步fifo和fifo的控制器,注意avalon-ST的時鐘一定要大於video時鐘。寫入端的寫使能為data_valid,然後讀出端構建一個狀態機,產生Avalon-ST的包。Avalon-ST匯流排和X家的AXI4-stream類似,都是適合視訊流傳輸的匯流排。可參考官方的Avalon specification。關於Avalon-ST的視訊包格式,可以參考Altera的Video and Image Processing Suite User Guide文件的第二章Interface,一個包包含兩部分,控制包和資料包,控制包含影象的大小,以24bit寬度的匯流排為例,控制包以0x00000f作為起始標誌;資料包就是影象的資料了,以0x000000作為起始標誌。fifo讀取端,通過檢測fifo的空狀態,在狀態STATE_DATA_PKT_DAT期間來產生fifo的讀使能訊號。直接上原始碼:

module convertor
(
	clk_video,
	reset_n_video,
	video_data,
	video_hsync,
	video_vsync,
	video_valid,
	
	clk_st,
	reset_n_st,
 
	// streaming source
	source_data,
	source_valid,
	source_ready,
	source_sop,
	source_eop
);
input           clk_video;
input           reset_n_video;
input [23:0]    video_data;
input           video_hsync;
input           video_vsync;
input           video_valid;

input           clk_st;
input           reset_n_st;
// streaming source
output	[23:0]  source_data;
output			source_valid;
input			source_ready;
output			source_sop;
output			source_eop;

parameter WIDTH  = 640;
parameter HEIGHT = 480;
localparam CTRL_PKT_NUM     = 3;
localparam CTRL_PKT_HEADER  = 24'd15;
localparam DATA_PKT_HEADER  = 24'd0;

wire [10 :0] rdusedw_sig;
wire [23 :0] q_sig;
wire         rdreq_sig;

wire [15:0] w_LOG_WIDTH = WIDTH;
wire [15:0] w_LOG_HEIGHT = HEIGHT;
///////////////////////
reg [2:0] dout_data_type;
reg [2:0] ctrl_data_type;
reg [11:0] dot_cnt;
reg [11:0] line_cnt;
wire rdempty_sig;
assign source_data = (dout_data_type[2:0] == 3'd0) ? q_sig:
                   (dout_data_type[2:0] == 3'd1) ? CTRL_PKT_HEADER:
                   (dout_data_type[2:0] == 3'd2) ? { 4'b0,  w_LOG_WIDTH[ 7: 4], 4'b0,  w_LOG_WIDTH[11: 8], 4'b0,  w_LOG_WIDTH[15:12] }:
                   (dout_data_type[2:0] == 3'd3) ? { 4'b0,  w_LOG_HEIGHT[11: 8], 4'b0, w_LOG_HEIGHT[15:12], 4'b0,  w_LOG_WIDTH[ 3: 0] }:
                   (dout_data_type[2:0] == 3'd4) ? { 4'b0,            4'b0, 4'b0, w_LOG_HEIGHT[ 3: 0], 4'b0, w_LOG_HEIGHT[ 7: 4] }:
                   (dout_data_type[2:0] == 3'd5) ? DATA_PKT_HEADER:
						 q_sig;
assign source_valid = source_ready & (dout_data_type[2:0] >= 3'd1 && dout_data_type[2:0] <= 3'd5 ) | source_ready & rdreq_sig;
						 
assign 	rdreq_sig =  source_ready & (dout_data_type[2:0] == 3'd0) & !rdempty_sig;			 
///////////////////////
// State Machine
//reg     out;
reg  [1:0]   pkt_state;
        
localparam STATE_CTRL_PKT_SOP = 0;
localparam STATE_CTRL_PKT_DAT = 1;
localparam STATE_DATA_PKT_SOP = 2;
localparam STATE_DATA_PKT_DAT = 3;



wire ctrl_pkt_sop = (pkt_state == STATE_CTRL_PKT_SOP ) ? 1 : 0 ;
wire ctrl_pkt_eop = ((pkt_state == STATE_CTRL_PKT_DAT) & (dot_cnt==(CTRL_PKT_NUM-1))  ) ? 1 : 0 ; 


wire data_pkt_sop = (pkt_state == STATE_DATA_PKT_SOP ) ? 1 : 0 ;
wire data_pkt_eop = ((pkt_state == STATE_DATA_PKT_DAT) & (dot_cnt==(WIDTH-1)) & (line_cnt==(HEIGHT-1))  ) ? 1 : 0 ;

always @ (posedge clk_st) begin
  if (!reset_n_st)  pkt_state <= STATE_CTRL_PKT_SOP; 
  else 
    case (pkt_state) // state transitions
        STATE_CTRL_PKT_SOP: if (source_ready)  pkt_state <= STATE_CTRL_PKT_DAT;
        STATE_CTRL_PKT_DAT: if (source_ready & ctrl_pkt_eop)  pkt_state <= STATE_DATA_PKT_SOP;
        STATE_DATA_PKT_SOP: if (source_ready)  pkt_state <= STATE_DATA_PKT_DAT;
        STATE_DATA_PKT_DAT: if (source_ready & data_pkt_eop)  pkt_state <= STATE_CTRL_PKT_SOP;
        default :  pkt_state = STATE_CTRL_PKT_DAT;
    endcase
end		

// sop and eop signals
assign source_sop = (ctrl_pkt_sop | data_pkt_sop) ;
assign source_eop = (ctrl_pkt_eop | data_pkt_eop) ;	
/////////////////////////
// dot and line counter
always @(posedge clk_st) begin
  if (!reset_n_st) begin
     dot_cnt <= 0;
  end
  else begin
    if (source_ready)
      if ((pkt_state == STATE_DATA_PKT_DAT) ) begin
	    if(rdreq_sig)
			if ( dot_cnt < (WIDTH-1) )
			   dot_cnt <= dot_cnt + 11'd1;
			else
			  dot_cnt <= 0;
      end
      else if ((pkt_state == STATE_CTRL_PKT_DAT) )begin // control packet
        if ( dot_cnt < (CTRL_PKT_NUM-1) )
           dot_cnt <= dot_cnt + 11'd1;
        else
           dot_cnt <= 0;
      end
  end
end

always @(posedge clk_st) begin
  if (!reset_n_st) begin
     line_cnt <= 0;
  end
  else begin
    if (source_ready)begin
      if (pkt_state == STATE_DATA_PKT_DAT) begin
 	    if(rdreq_sig)
			if ( dot_cnt == (WIDTH-1) )  begin
			  if ( line_cnt < (HEIGHT-1) )
				 line_cnt <= line_cnt + 11'd1;
			  else
				 line_cnt <= 0;
			end
      end
      else
           line_cnt <= 0;
    end
  end
end


///////////////////////
// Making Final Output Data
always @(pkt_state or ctrl_data_type ) begin
  case (pkt_state) 
     STATE_CTRL_PKT_SOP: dout_data_type = {3'd1};//CTRL_PKT_HEADER;
     STATE_CTRL_PKT_DAT: dout_data_type = {ctrl_data_type};//ctrl_data_type;
     STATE_DATA_PKT_SOP: dout_data_type = {3'd5};//DATA_PKT_HEADER;
     default:            dout_data_type = {3'd0};//image_data; 
  endcase
end

always @(dot_cnt[3:0]) begin
  case (dot_cnt[3:0])
    0 : ctrl_data_type = 3'd2;//{ 4'b0,  w_LOG_WIDTH[ 7: 4], 4'b0,  w_LOG_WIDTH[11: 8], 4'b0,  w_LOG_WIDTH[15:12] };
    1 : ctrl_data_type = 3'd3;//{ 4'b0, w_LOG_HEIGHT[11: 8], 4'b0, w_LOG_HEIGHT[15:12], 4'b0,  w_LOG_WIDTH[ 3: 0] };
    2 : ctrl_data_type = 3'd4;//{ 4'b0,            4'b0, 4'b0, w_LOG_HEIGHT[ 3: 0], 4'b0, w_LOG_HEIGHT[ 7: 4] };
    default : ctrl_data_type = 3'd0;//24'bx;
  endcase
end
			 
//////// output data path -- fifo //////////
////////////////////////////////////////////////////
reg[1:0] video_vsync_r;	

always @(posedge clk_video )
	if(!reset_n_video) video_vsync_r <= 2'd0;
	else video_vsync_r <= {video_vsync_r[0],video_vsync};

wire fifo_clr = ~video_vsync_r[1] & video_vsync_r[0];	//
pixel_fifo	pixel_fifo_inst (
	.aclr (fifo_clr),
	.data ( video_data ),
	.rdclk ( clk_st ),
	.rdreq ( rdreq_sig ),
	.wrclk ( clk_video ),
	.wrreq ( video_valid ),
	.q ( q_sig ),
	.rdempty ( rdempty_sig ),
	.rdfull ( rdfull_sig ),
	.rdusedw ( rdusedw_sig ),
	.wrempty ( wrempty_sig ),
	.wrfull ( wrfull_sig ),
	.wrusedw ( wrusedw_sig )
	);

	
	
endmodule