【ZYNQ-7000开发之十一】VGA RLT代码封装成AXI Stream
来源:互联网 发布:js拉链是哪个国家的 编辑:程序博客网 时间:2024/05/21 15:01
本编文章将对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]}]
编译后,导出硬件,新建一个Hello工程(主要是为PL提供25M时钟)
开发板上电测试,效果如下(color bar效果)
0 0
- 【ZYNQ-7000开发之十一】VGA RLT代码封装成AXI Stream
- AXI STREAM 接口的VGA控制器分析
- 【ZYNQ-7000开发之四】在PS端使用AXI DMA传输的步骤
- 【ZYNQ-7000开发之七】AXI CDMA特点以及在PS端使用的步骤_理论部分 未完待续
- AXI-Stream接口开发详细流程
- ZYNQ AXI DMA
- 【ZYNQ-7000开发之一】PL部分驱动VGA显示静态彩色图像
- 【OpenHW参赛手记】AXI-Stream接口开发详细流程
- AXI-Stream接口介绍
- AXI-Stream总线知识
- zynq开发之HLS
- AXI Stream接口,AXI 流接口规范
- 【ZYNQ-7000开发之三】ZYNQ平台的HDMI驱动测试
- Zynq AXI Dual Bram 操作实例
- 从零开始zynq linux AXI DMA传输
- ZYNQ使用AXI VDMA搭建图像通路
- 【ZYNQ-7000开发之八】OLED的驱动
- 【ZYNQ-7000开发之十三】中断:私有定时器中断
- HDU1006
- 1144数星星
- C++解析字符串中数据
- 读《大型网站技术架构:核心原理与案例分析+李智慧》记一
- Android 网络请求详解
- 【ZYNQ-7000开发之十一】VGA RLT代码封装成AXI Stream
- Xcode7 beta 网络请求报错:The resource could not be loaded because the App Transport Security policy requir
- 利用RunTime实现iOS不同版本下使用不同的图片
- windows10 下面,编译protobuf-java-3.0.0-beta-1.jar
- 【Python】用base64和RC4给数据加密/解密
- JavaSE入门学习18:Java面向对象之多态
- LeetCode22. Generate Parentheses
- 开启Hadoop2.6.0出现ssh无法解析主机名等错误提示的解决办法!
- 有符号数与无符号数