本编文章将对VGA的RTL代码,封装成AXI Stream,并且在vivado 里用TPG进行测试
本篇文章的VGA RTL代码在【ZYNQ-7000开发之一】基础上修改,封装好的VGA Stream可以方便我们实现视频图像处理
TGP 等的规范说明可以到官网下载最新版本
本文所使用的开发板是Miz702(兼容zedboard)
PC 开发环境版本:Vivado 2015.2 Xilinx SDK 2015.2
其它:VGA显示器
AXI Stream原理
首先这里列出axi stream的信号,红框里的是要用到的
核心的信号是,TVALID,TREADY,TLAST,TUSER
TVALID和TREADY握手信号
在TVALID和TREADY同时有效的时候,数据才有效。对于TPG来说,大部分时间TVALID是有效的,TREADY由我们自己控制。
TUSER(SOF,Start Of Frame),代表每一帧的开始。TLAST(EOL,End Of Line),代表每一行的结束。
这里给出TPG的时序图,比较简洁,要理解之后才好把RTL封装成AXI Stream
封装AXI Stream
打开vivado,建立一个工程(选择zed)
选择Tools->Create and Package IP
点击NEXT,选择Create AXI4,如图所示
输入好name和路径后,点击NEXT
按照如下配置
点击NEXT,选择Edit IP,然后点击Finish
这时会弹出一个新的IP 编辑界面,这个可以看到VIVADO已经自动生成了一些必要的AXI Stream相关的代码,我们在这个基础上修改很方便
把VGA_AXI_Stream_v1_0.v文件里的代码,修改如下
`timescale 1 ns / 1 ps
module myip_v1_0 #
(
// Users to add parameters here
// User parameters ends
// Do not modify the parameters beyond this line
// Parameters of Axi Slave Bus Interface S00_AXIS_VGA
parameter integer C_S00_AXIS_VGA_TDATA_WIDTH = 32
)
(
// Users to add ports here
input wire clk_25mhz,
output wire hsync,
output wire vsync,
output wire [11:0] rgb,
output reg led,
// User ports ends
// Do not modify the ports beyond this line
// Ports of Axi Slave Bus Interface S00_AXIS_VGA
input wire s00_axis_vga_aclk,
input wire s00_axis_vga_aresetn,
output wire s00_axis_vga_tready,
input wire [C_S00_AXIS_VGA_TDATA_WIDTH-1 : 0] s00_axis_vga_tdata,
input wire [(C_S00_AXIS_VGA_TDATA_WIDTH/8)-1 : 0] s00_axis_vga_tstrb,
input wire s00_axis_vga_tlast,
input wire s00_axis_vga_tvalid,
input wire s00_axis_vga_tuser
);
// Instantiation of Axi Bus Interface S00_AXIS_VGA
myip_v1_0_S00_AXIS_VGA # (
.C_S_AXIS_TDATA_WIDTH(C_S00_AXIS_VGA_TDATA_WIDTH)
) myip_v1_0_S00_AXIS_VGA_inst (
.S_AXIS_ACLK(s00_axis_vga_aclk),
.S_AXIS_ARESETN(s00_axis_vga_aresetn),
.S_AXIS_TREADY(s00_axis_vga_tready),
.S_AXIS_TDATA(s00_axis_vga_tdata),
.S_AXIS_TSTRB(s00_axis_vga_tstrb),
.S_AXIS_TLAST(s00_axis_vga_tlast),
.S_AXIS_TVALID(s00_axis_vga_tvalid),
.S_AXIS_TUSER(s00_axis_vga_tuser),
.clk (clk_25mhz),
.rst_n (s00_axis_vga_aresetn),
.video_en (video_en),
.hsync (hsync),
.vsync (vsync),
.pixel_x (pixel_x),
.pixel_y (pixel_y)
);
// Add user logic here
wire [9:0] pixel_x;
wire [9:0] pixel_y;
wire clk_25mhz;
reg [11:0] rgb_reg;
//显示静态图像640*480
reg [23:0] cnt;
always @(posedge clk_25mhz or negedge s00_axis_vga_aresetn)
if(!s00_axis_vga_aresetn)
begin
cnt <= 0;
led <= 0;
end
else
begin
cnt <= cnt + 1'b1;
if(cnt == 24'd12500000)
begin
cnt <= 24'b0;
led <= ~led;
end
end
always @ (posedge clk_25mhz or negedge s00_axis_vga_aresetn)
if(!s00_axis_vga_aresetn)
begin
rgb_reg <= 12'b0;
end
else if(s00_axis_vga_tvalid == 1'b1 && s00_axis_vga_tready == 1'b1)
begin //显示图像
rgb_reg[3:0] <= s00_axis_vga_tdata[7:4];
rgb_reg[7:4] <= s00_axis_vga_tdata[15:12];
rgb_reg[11:8] <= s00_axis_vga_tdata[23:20];
end
/*
always @ (posedge clk_25mhz or negedge s00_axis_vga_aresetn)
if(!s00_axis_vga_aresetn)
begin
address_sig <= 19'b0;
end
else
begin
if(pixel_x>=0 && pixel_x<= 639 && pixel_y>=0 && pixel_y<=479)
address_sig = (pixel_x + 640*pixel_y);
end
*/
//
assign rgb = (video_en == 1'b1) ? rgb_reg:12'b0;
// User logic ends
endmodule
把VGA_AXI_Stream_v1_0_S00_AXI_VgA.v文件里的代码,修改如下
// Users to add ports here
input wire clk,
input wire rst_n,
output wire video_en,
output reg hsync,
output reg vsync,
output wire [9:0] pixel_x,
output wire [9:0] pixel_y,
// User ports ends
// Do not modify the ports beyond this line
// AXI4Stream sink: Clock
input wire S_AXIS_ACLK,
// AXI4Stream sink: Reset
input wire S_AXIS_ARESETN,
// Ready to accept data in
output wire S_AXIS_TREADY,
// Data in
input wire [C_S_AXIS_TDATA_WIDTH-1 : 0] S_AXIS_TDATA,
// Byte qualifier
input wire [(C_S_AXIS_TDATA_WIDTH/8)-1 : 0] S_AXIS_TSTRB,
// Indicates boundary of last packet
input wire S_AXIS_TLAST,
// Data is in valid
input wire S_AXIS_TVALID,
input wire S_AXIS_TUSER
);
// function called clogb2 that returns an integer which has the
// value of the ceiling of the log base 2.
function integer clogb2 (input integer bit_depth);
begin
for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
bit_depth = bit_depth >> 1;
end
endfunction
// Total number of input data.
localparam NUMBER_OF_INPUT_WORDS = 8;
// bit_num gives the minimum number of bits needed to address 'NUMBER_OF_INPUT_WORDS' size of FIFO.
localparam bit_num = clogb2(NUMBER_OF_INPUT_WORDS-1);
// Define the states of state machine
// The control state machine oversees the writing of input streaming data to the FIFO,
// and outputs the streaming data from the FIFO
parameter [1:0] IDLE = 1'b0, // This is the initial/idle state
WRITE_FIFO = 1'b1; // In this state FIFO is written with the
// input stream data S_AXIS_TDATA
wire axis_tready;
// State variable
reg mst_exec_state;
// FIFO implementation signals
genvar byte_index;
// FIFO write enable
wire fifo_wren;
// FIFO full flag
reg fifo_full_flag;
// FIFO write pointer
reg [bit_num-1:0] write_pointer;
// sink has accepted all the streaming data and stored in FIFO
reg writes_done;
// I/O Connections assignments
assign S_AXIS_TREADY = axis_tready;
// Control state machine implementation
always @(posedge S_AXIS_ACLK)
begin
if (!S_AXIS_ARESETN)
// Synchronous reset (active low)
begin
mst_exec_state <= IDLE;
end
else
case (mst_exec_state)
IDLE:
// The sink starts accepting tdata when
// there tvalid is asserted to mark the
// presence of valid streaming data
if (S_AXIS_TVALID)
begin
mst_exec_state <= WRITE_FIFO;
end
else
begin
mst_exec_state <= IDLE;
end
WRITE_FIFO:
// When the sink has accepted all the streaming input data,
// the interface swiches functionality to a streaming master
if (writes_done)
begin
mst_exec_state <= IDLE;
end
else
begin
// The sink accepts and stores tdata
// into FIFO
mst_exec_state <= WRITE_FIFO;
end
endcase
end
// AXI Streaming Sink
//
// The example design sink is always ready to accept the S_AXIS_TDATA until
// the FIFO is not filled with NUMBER_OF_INPUT_WORDS number of input words.
//assign axis_tready = ((mst_exec_state == WRITE_FIFO) && (write_pointer <= NUMBER_OF_INPUT_WORDS-1)
assign axis_tready =( (pixel_x>=0 && pixel_x<= 639 && pixel_y>=0 && pixel_y<=479) );
always@(posedge S_AXIS_ACLK)
begin
if(!S_AXIS_ARESETN)
begin
write_pointer <= 0;
writes_done <= 1'b0;
end
else
if (write_pointer <= NUMBER_OF_INPUT_WORDS-1)
begin
if (fifo_wren)
begin
// write pointer is incremented after every write to the FIFO
// when FIFO write signal is enabled.
write_pointer <= write_pointer + 1;
writes_done <= 1'b0;
end
if ((write_pointer == NUMBER_OF_INPUT_WORDS-1)|| S_AXIS_TLAST)
begin
// reads_done is asserted when NUMBER_OF_INPUT_WORDS numbers of streaming data
// has been written to the FIFO which is also marked by S_AXIS_TLAST(kept for optional usage).
writes_done <= 1'b1;
end
end
end
// FIFO write enable generation
assign fifo_wren = S_AXIS_TVALID && axis_tready;
// FIFO Implementation
generate
for(byte_index=0; byte_index<= (C_S_AXIS_TDATA_WIDTH/8-1); byte_index=byte_index+1)
begin:FIFO_GEN
reg [(C_S_AXIS_TDATA_WIDTH/4)-1:0] stream_data_fifo [0 : NUMBER_OF_INPUT_WORDS-1];
// Streaming input data is stored in FIFO
always @( posedge S_AXIS_ACLK )
begin
if (fifo_wren)// && S_AXIS_TSTRB[byte_index])
begin
stream_data_fifo[write_pointer] <= S_AXIS_TDATA[(byte_index*8+7) -: 8];
end
end
end
endgenerate
// Add user logic here
reg [9:0] pixel_cnt;
reg [9:0] line_cnt;
reg v_video_en;
reg h_video_en;
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
pixel_cnt <= 10'b0;
end
else
begin
pixel_cnt <= pixel_cnt + 1'b1;
if(pixel_cnt == 10'd799 || S_AXIS_TUSER == 1'b1)
begin
pixel_cnt <= 10'b0;
end
end
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
h_video_en <= 1'b1;
hsync <= 1'b1;
end
else
begin
case (pixel_cnt)
10'd0:
begin
h_video_en <= 1'b1;
end
10'd639:
begin
h_video_en <= 1'b0;
end
10'd655:
begin
hsync <= 1'b0;
end
10'd751:
begin
hsync <= 1'b1;
end
endcase
end
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
line_cnt <= 10'b0;
end
else
begin
if(pixel_cnt <= S_AXIS_TLAST) //pixel_cnt == 10'd799
begin
line_cnt <= line_cnt + 1'b1;
end
if(line_cnt == 10'd524)
begin
line_cnt <= 10'b0;
end
if(S_AXIS_TUSER == 1'b1)
begin
line_cnt <= 10'b0;
end
end
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
v_video_en <= 1'b1;
vsync <= 1'b1;
end
else
begin
case(line_cnt)
10'd0:
begin
v_video_en <= 1'b1;
end
10'd479:
begin
v_video_en <= 1'b0;
end
10'd489:
begin
vsync <= 1'b0;
end
10'd491:
begin
vsync <= 1'b1;
end
endcase
end
assign pixel_x = pixel_cnt;
assign pixel_y = line_cnt;
assign video_en = ((h_video_en == 1'b1) && (v_video_en == 1'b1));
// User logic ends
endmodule
保存后,按照如图所示操作
其它的类似,最后在Review and Package,里选择repackage
建立硬件工程
首先要把IP的路径添加进来
在vivado里新建一个Block Design,按照如图所示建立硬件工程,FCLK_CLK0设置成25MHz
TPG这样配置
约束文件如下
set_property PACKAGE_PIN T22 [get_ports led]
set_property IOSTANDARD LVCMOS33 [get_ports led]
set_property PACKAGE_PIN AA19 [get_ports hsync]
set_property IOSTANDARD LVCMOS33 [get_ports hsync]
set_property PACKAGE_PIN Y19 [get_ports vsync]
set_property IOSTANDARD LVCMOS33 [get_ports vsync]
set_property PACKAGE_PIN Y21 [get_ports {rgb[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[0]}]
set_property PACKAGE_PIN Y20 [get_ports {rgb[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[1]}]
set_property PACKAGE_PIN AB20 [get_ports {rgb[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[2]}]
set_property PACKAGE_PIN AB19 [get_ports {rgb[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[3]}]
set_property PACKAGE_PIN AB22 [get_ports {rgb[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[4]}]
set_property PACKAGE_PIN AA22 [get_ports {rgb[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[5]}]
set_property PACKAGE_PIN AB21 [get_ports {rgb[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[6]}]
set_property PACKAGE_PIN AA21 [get_ports {rgb[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[7]}]
set_property PACKAGE_PIN V20 [get_ports {rgb[8]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[8]}]
set_property PACKAGE_PIN U20 [get_ports {rgb[9]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[9]}]
set_property PACKAGE_PIN V19 [get_ports {rgb[10]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[10]}]
set_property PACKAGE_PIN V18 [get_ports {rgb[11]}]
set_property IOSTANDARD LVCMOS33 [get_ports {rgb[11]}]