alinx 黑金 zynq7000 开収平台...
TRANSCRIPT
ALINX 黑金 Zynq7000 开収平台
配套教程第二部
AX7010/AX7020
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 2
ALINX 黑金 Zynq7000 开发平台配套教程第二部
我们承诺本教程并非一劳永逸,固守丌变的文档。我们会根据论坛上大家的反馈意见,以
及实际的开収实践经验积累丌断的修正和优化教程
文档修订记录:
版本 时间 描述
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 3
ALINX 黑金 Zynq7000 开发平台配套教程第二部
序
首先感谢大家购买黑金动力社区出品的 ZYNQ7000 的开収板 AX7010 和 AX7020! 您对
我们和我们产品的支持和信任,给我们增添了永往直前的信心和勇气。
前面的教程我们领略了 Zynq7000 SOC 风采,熟悉了整个开収流程,但没有太多结合实
际应用的例子,这部课程给大家带来一些更深入的体验。 主要讲解 vivado 的调试技巧,sdk
的调试技巧,还有一些模块,像液晶屏、摄像头的使用。
“播下一粒种子,收获一片森林”,更是黑金 ALINX 硬件开収的美好愿望,同时我们会在
黑金动力社区 http://www.heijin.org 和大家一起讨论,一起学习,一起迚步,一起成长。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 4
ALINX 黑金 Zynq7000 开发平台配套教程第二部
目录
序 ............................................................................................................................................................. 3
目录 ......................................................................................................................................................... 4
第 1 章 AX7010/AX7020 PL 读写叏 PS 端的 DDR 数据 ................................................................. 6
1.1 ZYNQ 的 HP 端口的使用....................................................................................................... 6
1.2 PL 端 AXI Master ................................................................................................................... 9
1.3 ddr 读写数据的校验 ............................................................................................................. 18
1.4 vivado 软件的调试技巧 ....................................................................................................... 21
1.5 上电验证 ................................................................................................................................ 25
1.6 本章小结 ................................................................................................................................ 29
第 2 章 ZYNQ 下使用 uC/OS-III ....................................................................................................... 30
2.1 uC/OS-III 的硬件系统配置 .................................................................................................. 30
2.2 uC/OS-III BSP 配置 ............................................................................................................. 30
2.3 上板运行................................................................................................................................ 34
2.3 本章小结................................................................................................................................ 41
第 3 章 OV5640 模块的使用.............................................................................................................. 42
3.1 OV5640 简介 ........................................................................................................................ 42
3.2 VDMA 的使用 ....................................................................................................................... 42
3.3 硬件工程建立 ........................................................................................................................ 47
3.4 板上验证................................................................................................................................ 52
3.5 本章小结................................................................................................................................ 54
第 4 章 双目摄像头模块的使用 ......................................................................................................... 55
4.1 双目和单目摄像头开収的区别 ............................................................................................ 55
4.2 硬件环境搭建 ........................................................................................................................ 56
4.3 软件 SDK 的编写 .................................................................................................................. 63
4.4 板上验证................................................................................................................................ 65
第 5 章 7 寸液晶屏模块的使用 .......................................................................................................... 69
5.1 7 寸 LCD 屏模块说明介绍 ................................................................................................... 69
5.2 LCD 屏的驱动时序 ................................................................................................................ 70
5.3 zynq 的硬件系统设计 .......................................................................................................... 72
5.4 板上验证................................................................................................................................ 75
第 6 章 7 寸触摸屏的使用.................................................................................................................. 77
6.1 7 寸 LCD 触摸屏说明介绍 ................................................................................................... 77
6.2 触摸屏接口时序 .................................................................................................................... 78
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 5
ALINX 黑金 Zynq7000 开发平台配套教程第二部
6.3 uGUI 的使用 .......................................................................................................................... 79
第 7 章 裸机文件系统 FatFS 的使用 ................................................................................................. 80
7.1 ................................................................................................................................................. 80
7.2 ................................................................................................................................................. 80
7.3 ................................................................................................................................................. 80
7.4 ................................................................................................................................................. 80
第 8 章 开源 TCP/IP 协议栈 Lwip 的使用 ........................................................................................ 81
8.1 ................................................................................................................................................. 81
8.2 ................................................................................................................................................. 81
8.3 ................................................................................................................................................. 81
第 9 章 Linux 下无驱动直接使用 PL 端设备自定义 IP RTC........................................................... 82
9.1 Vivado 工程创建 .................................................................................................................. 82
9.2 ZYNQ 系统的配置 ................................................................................................................ 82
9.3 硬件导入 SDK ....................................................................................................................... 82
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 6
ALINX 黑金 Zynq7000 开发平台配套教程第二部
第 1 章 AX7010/AX7020 PL 读写叏 PS 端的 DDR 数据
PL 和 PS 的高效交互是 zynq 7000 soc 开収的重中之重,我们常常需要将 PL 端的大量数
据实时送到 PS 端处理,戒者将 PS 端处理结果实时送到 PL 端处理,常规我们会想到使用 DMA
的方式来迚行,但是各种协议非常麻烦,灵活性也比较差,本节课程讲解如何直接通过 AXI 总
线来读写 PS 端 ddr 的数据,这里面涉及到 AXI4 协议,vivado 的 FPGA 调试等。
1.1 ZYNQ 的 HP 端口的使用
zynq 7000 SOC 的 HP 口是 High-Performance Ports 的缩写,如下图所示,一共有 4
个 HP 口,HP 口是 AXI Slave 设备,我们可以通过这 4 个 HP 口完成高带宽的数据交互。
在 vivado 的界面中 HP 的配置如下图,这里面有使能控制,数据位宽选择,可选择 32 戒
64bit 的位宽。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 7
ALINX 黑金 Zynq7000 开发平台配套教程第二部
我们的实验启用 HP0 和 HP1 分别配置为 64bit 位宽,使用的时钟是 150Mhz,每个 HP
的带宽是 150Mhz * 64bit,对于视频处理,ADC 数据采集等应用都有足够的带宽。如下图所
示,配置完 HP 端口以后,zynq 会多出两个 AXI Slave 端口,名称分别为 S_AXI_HP0 和
S_AXI_HP1,丌过这些端口都是 AXI3 标准的,我们常用的是 AXI4 协议,这里添加 2 个 AXI
Interconnect IP,用于协议转换。这 2 个 HP 端口都是可读写的,但是为了方便和读写效率,
这里将 HP0 设置为只写,HP1 只读,同时我们将这 2 个 AXI4 接口引出,用于 PL 端操作。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 8
ALINX 黑金 Zynq7000 开发平台配套教程第二部
写接口的配置
写接口的配置
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 9
ALINX 黑金 Zynq7000 开发平台配套教程第二部
读接口配置
1.2 PL 端 AXI Master
AXI4 相对复杂,但 SOC 开収者必须掌握,对于 zynq 的开収者,笔者建议能够在一些已
有的模板代码基础上修改。AXI 协议的具体内容可参考 Xilinx UG761 AXI Reference Guide。
在这里我们简单了解一下。
AXI4 所采用的是一种 READY,VALID 握手通信机制,即主从模块迚行数据通信前,新根
据操作对各所用到的数据、地址通道迚行握手。主要操作包括传输収送者 A 等到传输接叐者 B
的 READY 信号后,A 将数据不 VALID 信号同时収送给 B,这是一种典型的握手机制。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 10
ALINX 黑金 Zynq7000 开发平台配套教程第二部
AXI 总线分为五个通道:
读地址通道,包含 ARVALID, ARADDR, ARREADY 信号;
写地址通道,包含 AWVALID,AWADDR, AWREADY 信号;
读数据通道,包含 RVALID, RDATA, RREADY, RRESP 信号;
写数据通道,包含 WVALID, WDATA,WSTRB, WREADY 信号;
写应答通道,包含 BVALID, BRESP, BREADY 信号;
系统通道,包含:ACLK,ARESETN 信号;
其中 ACLK 为 axi 总线时钟,ARESETN 是 axi 总线复位信号,低电平有效;读写数据不读
写地址类信号宽度都为 32bit;READY 不 VALID 是对应的通道握手信号;WSTRB 信号为 1 的
bit 对应 WDATA 有效数据字节,WSTRB 宽度是 32bit/8=4bit;BRESP 不 RRESP 分别为写回
应信号,读回应信号,宽度都为 2bit,‘h0代表成功,其他为错误。
读操作顺序为主不从迚行读地址通道握手幵传输地址内容,然后在读数据通道握手幵传输
所读内容以及读叏操作的回应,时钟上升沿有效。如图所示:
写操作顺序为主不从迚行写地址通道握手幵传输地址内容,然后在写数据通道握手幵传输
所读内容,最后再写回应通道握手,幵传输写回应数据,时钟上升沿有效。如图所示:
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 11
ALINX 黑金 Zynq7000 开发平台配套教程第二部
在我们丌擅长写 FPGA 的一些代码时我们往往要借鉴别人的代码戒者使用 IP core。在这里
笔者从 github 上找到一个 AXI master 的代码,地址是
https://github.com/aquaxis/IPCORE/tree/master/aq_axi_vdma。这个工程是一个自己写的
VDMA,里面包含了大量可参考的代码。笔者这里主要使用了 aq_axi_master.v 这个代码用于
AXI master 读写操作。借鉴别人代码有时会节省很多时间,但如果丌能理解的去借鉴,出现问
题了很难解决。aq_axi_master.v 代码如下,有部分修改。
/*
* Copyright (C)2014-2015 AQUAXIS TECHNOLOGY.
* Don't remove this header.
* When you use this source, there is a need to inherit this header.
*
* License
* For no commercial -
* License: The Open Software License 3.0
* License URI: http://www.opensource.org/licenses/OSL-3.0
*
* For commmercial -
* License: AQUAXIS License 1.0
* License URI: http://www.aquaxis.com/licenses
*
* For further information please contact.
* URI: http://www.aquaxis.com/
* E-Mail: info(at)aquaxis.com
*/
////////////////////////////////////////////////////////////////////////
//////////
// Company: ALINX黑金
// Engineer: 老梅
//
// Create Date: 2016/11/17 10:27:06
// Design Name:
// Module Name: mem_test
// Project Name:
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 12
ALINX 黑金 Zynq7000 开发平台配套教程第二部
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////
//////////
module aq_axi_master(
// Reset, Clock
input ARESETN,
input ACLK,
// Master Write Address
output [0:0] M_AXI_AWID,
output [31:0] M_AXI_AWADDR,
output [7:0] M_AXI_AWLEN, // Burst Length: 0-255
output [2:0] M_AXI_AWSIZE, // Burst Size: Fixed 2'b011
output [1:0] M_AXI_AWBURST, // Burst Type: Fixed 2'b01(Incremental
Burst)
output M_AXI_AWLOCK, // Lock: Fixed 2'b00
output [3:0] M_AXI_AWCACHE, // Cache: Fiex 2'b0011
output [2:0] M_AXI_AWPROT, // Protect: Fixed 2'b000
output [3:0] M_AXI_AWQOS, // QoS: Fixed 2'b0000
output [0:0] M_AXI_AWUSER, // User: Fixed 32'd0
output M_AXI_AWVALID,
input M_AXI_AWREADY,
// Master Write Data
output [63:0] M_AXI_WDATA,
output [7:0] M_AXI_WSTRB,
output M_AXI_WLAST,
output [0:0] M_AXI_WUSER,
output M_AXI_WVALID,
input M_AXI_WREADY,
// Master Write Response
input [0:0] M_AXI_BID,
input [1:0] M_AXI_BRESP,
input [0:0] M_AXI_BUSER,
input M_AXI_BVALID,
output M_AXI_BREADY,
// Master Read Address
output [0:0] M_AXI_ARID,
output [31:0] M_AXI_ARADDR,
output [7:0] M_AXI_ARLEN,
output [2:0] M_AXI_ARSIZE,
output [1:0] M_AXI_ARBURST,
output [1:0] M_AXI_ARLOCK,
output [3:0] M_AXI_ARCACHE,
output [2:0] M_AXI_ARPROT,
output [3:0] M_AXI_ARQOS,
output [0:0] M_AXI_ARUSER,
output M_AXI_ARVALID,
input M_AXI_ARREADY,
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 13
ALINX 黑金 Zynq7000 开发平台配套教程第二部
// Master Read Data
input [0:0] M_AXI_RID,
input [63:0] M_AXI_RDATA,
input [1:0] M_AXI_RRESP,
input M_AXI_RLAST,
input [0:0] M_AXI_RUSER,
input M_AXI_RVALID,
output M_AXI_RREADY,
// Local Bus
input MASTER_RST,
input WR_START,
input [31:0] WR_ADRS,
input [31:0] WR_LEN,
output WR_READY,
output WR_FIFO_RE,
input WR_FIFO_EMPTY,
input WR_FIFO_AEMPTY,
input [63:0] WR_FIFO_DATA,
output WR_DONE,
input RD_START,
input [31:0] RD_ADRS,
input [31:0] RD_LEN,
output RD_READY,
output RD_FIFO_WE,
input RD_FIFO_FULL,
input RD_FIFO_AFULL,
output [63:0] RD_FIFO_DATA,
output RD_DONE,
output [31:0] DEBUG
);
localparam S_WR_IDLE = 3'd0;
localparam S_WA_WAIT = 3'd1;
localparam S_WA_START = 3'd2;
localparam S_WD_WAIT = 3'd3;
localparam S_WD_PROC = 3'd4;
localparam S_WR_WAIT = 3'd5;
localparam S_WR_DONE = 3'd6;
reg [2:0] wr_state;
reg [31:0] reg_wr_adrs;
reg [31:0] reg_wr_len;
reg reg_awvalid, reg_wvalid, reg_w_last;
reg [7:0] reg_w_len;
reg [7:0] reg_w_stb;
reg [1:0] reg_wr_status;
reg [3:0] reg_w_count, reg_r_count;
reg [7:0] rd_chkdata, wr_chkdata;
reg [1:0] resp;
reg rd_first_data;
reg rd_fifo_enable;
reg[31:0] rd_fifo_cnt;
assign WR_DONE = (wr_state == S_WR_DONE);
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 14
ALINX 黑金 Zynq7000 开发平台配套教程第二部
assign WR_FIFO_RE = rd_first_data | (reg_wvalid & ~WR_FIFO_EMPTY &
M_AXI_WREADY & rd_fifo_enable);
//assign WR_FIFO_RE = reg_wvalid & ~WR_FIFO_EMPTY & M_AXI_WREADY;
always @(posedge ACLK or negedge ARESETN)
begin
if(!ARESETN)
rd_fifo_cnt <= 32'd0;
else if(WR_FIFO_RE)
rd_fifo_cnt <= rd_fifo_cnt + 32'd1;
else if(wr_state == S_WR_IDLE)
rd_fifo_cnt <= 32'd0;
end
always @(posedge ACLK or negedge ARESETN)
begin
if(!ARESETN)
rd_fifo_enable <= 1'b0;
else if(wr_state == S_WR_IDLE && WR_START)
rd_fifo_enable <= 1'b1;
else if(WR_FIFO_RE && (rd_fifo_cnt == RD_LEN[31:3] - 32'd1) )
rd_fifo_enable <= 1'b0;
end
// Write State
always @(posedge ACLK or negedge ARESETN) begin
if(!ARESETN) begin
wr_state <= S_WR_IDLE;
reg_wr_adrs[31:0] <= 32'd0;
reg_wr_len[31:0] <= 32'd0;
reg_awvalid <= 1'b0;
reg_wvalid <= 1'b0;
reg_w_last <= 1'b0;
reg_w_len[7:0] <= 8'd0;
reg_w_stb[7:0] <= 8'd0;
reg_wr_status[1:0] <= 2'd0;
reg_w_count[3:0] <= 4'd0;
reg_r_count[3:0] <= 4'd0;
wr_chkdata <= 8'd0;
rd_chkdata <= 8'd0;
resp <= 2'd0;
rd_first_data <= 1'b0;
end else begin
if(MASTER_RST) begin
wr_state <= S_WR_IDLE;
end else begin
case(wr_state)
S_WR_IDLE: begin
if(WR_START) begin
wr_state <= S_WA_WAIT;
reg_wr_adrs[31:0] <= WR_ADRS[31:0];
reg_wr_len[31:0] <= WR_LEN[31:0] -32'd1;
rd_first_data <= 1'b1;
end
reg_awvalid <= 1'b0;
reg_wvalid <= 1'b0;
reg_w_last <= 1'b0;
reg_w_len[7:0] <= 8'd0;
reg_w_stb[7:0] <= 8'd0;
reg_wr_status[1:0] <= 2'd0;
end
S_WA_WAIT: begin
if(!WR_FIFO_AEMPTY | (reg_wr_len[31:11] == 21'd0)) begin
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 15
ALINX 黑金 Zynq7000 开发平台配套教程第二部
wr_state <= S_WA_START;
end
rd_first_data <= 1'b0;
end
S_WA_START: begin
wr_state <= S_WD_WAIT;
reg_awvalid <= 1'b1;
reg_wr_len[31:11] <= reg_wr_len[31:11] - 21'd1;
if(reg_wr_len[31:11] != 21'd0) begin
reg_w_len[7:0] <= 8'hFF;
reg_w_last <= 1'b0;
reg_w_stb[7:0] <= 8'hFF;
end else begin
reg_w_len[7:0] <= reg_wr_len[10:3];
reg_w_last <= 1'b1;
reg_w_stb[7:0] <= 8'hFF;
/*
case(reg_wr_len[2:0]) begin
case 3'd0: reg_w_stb[7:0] <= 8'b0000_0000;
case 3'd1: reg_w_stb[7:0] <= 8'b0000_0001;
case 3'd2: reg_w_stb[7:0] <= 8'b0000_0011;
case 3'd3: reg_w_stb[7:0] <= 8'b0000_0111;
case 3'd4: reg_w_stb[7:0] <= 8'b0000_1111;
case 3'd5: reg_w_stb[7:0] <= 8'b0001_1111;
case 3'd6: reg_w_stb[7:0] <= 8'b0011_1111;
case 3'd7: reg_w_stb[7:0] <= 8'b0111_1111;
default: reg_w_stb[7:0] <= 8'b1111_1111;
endcase
*/
end
end
S_WD_WAIT: begin
if(M_AXI_AWREADY) begin
wr_state <= S_WD_PROC;
reg_awvalid <= 1'b0;
reg_wvalid <= 1'b1;
end
end
S_WD_PROC: begin
if(M_AXI_WREADY & ~WR_FIFO_EMPTY) begin
if(reg_w_len[7:0] == 8'd0) begin
wr_state <= S_WR_WAIT;
reg_wvalid <= 1'b0;
reg_w_stb[7:0] <= 8'h00;
end else begin
reg_w_len[7:0] <= reg_w_len[7:0] -8'd1;
end
end
end
S_WR_WAIT: begin
if(M_AXI_BVALID) begin
reg_wr_status[1:0] <= reg_wr_status[1:0] | M_AXI_BRESP[1:0];
if(reg_w_last) begin
wr_state <= S_WR_DONE;
end else begin
wr_state <= S_WA_WAIT;
reg_wr_adrs[31:0] <= reg_wr_adrs[31:0] + 32'd2048;
end
end
end
S_WR_DONE: begin
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 16
ALINX 黑金 Zynq7000 开发平台配套教程第二部
wr_state <= S_WR_IDLE;
end
default: begin
wr_state <= S_WR_IDLE;
end
endcase
/*
if(WR_FIFO_RE) begin
reg_w_count[3:0] <= reg_w_count[3:0] + 4'd1;
end
if(RD_FIFO_WE)begin
reg_r_count[3:0] <= reg_r_count[3:0] + 4'd1;
end
if(M_AXI_AWREADY & M_AXI_AWVALID) begin
wr_chkdata <= 8'hEE;
end else if(M_AXI_WSTRB[7] & M_AXI_WVALID) begin
wr_chkdata <= WR_FIFO_DATA[63:56];
end
if(M_AXI_AWREADY & M_AXI_AWVALID) begin
rd_chkdata <= 8'hDD;
end else if(M_AXI_WSTRB[7] & M_AXI_WREADY) begin
rd_chkdata <= WR_FIFO_DATA[63:56];
end
if(M_AXI_BVALID & M_AXI_BREADY) begin
resp <= M_AXI_BRESP;
end
*/
end
end
end
assign M_AXI_AWID = 1'b0;
assign M_AXI_AWADDR[31:0] = reg_wr_adrs[31:0];
assign M_AXI_AWLEN[7:0] = reg_w_len[7:0];
assign M_AXI_AWSIZE[2:0] = 2'b011;
assign M_AXI_AWBURST[1:0] = 2'b01;
assign M_AXI_AWLOCK = 1'b0;
assign M_AXI_AWCACHE[3:0] = 4'b0011;
assign M_AXI_AWPROT[2:0] = 3'b000;
assign M_AXI_AWQOS[3:0] = 4'b0000;
assign M_AXI_AWUSER[0] = 1'b1;
assign M_AXI_AWVALID = reg_awvalid;
assign M_AXI_WDATA[63:0] = WR_FIFO_DATA[63:0];
// assign M_AXI_WSTRB[7:0] = (reg_w_len[7:0] ==
8'd0)?reg_w_stb[7:0]:8'hFF;
// assign M_AXI_WSTRB[7:0] = (wr_state == S_WD_PROC)?8'hFF:8'h00;
assign M_AXI_WSTRB[7:0] = (reg_wvalid & ~WR_FIFO_EMPTY)?8'hFF:8'h00;
assign M_AXI_WLAST = (reg_w_len[7:0] == 8'd0)?1'b1:1'b0;
assign M_AXI_WUSER = 1;
assign M_AXI_WVALID = reg_wvalid & ~WR_FIFO_EMPTY;
// assign M_AXI_WVALID = (wr_state == S_WD_PROC)?1'b1:1'b0;
assign M_AXI_BREADY = M_AXI_BVALID;
assign WR_READY = (wr_state == S_WR_IDLE)?1'b1:1'b0;
// assign WR_FIFO_RE = (wr_state == S_WD_PROC)?M_AXI_WREADY:1'b0;
localparam S_RD_IDLE = 3'd0;
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 17
ALINX 黑金 Zynq7000 开发平台配套教程第二部
localparam S_RA_WAIT = 3'd1;
localparam S_RA_START = 3'd2;
localparam S_RD_WAIT = 3'd3;
localparam S_RD_PROC = 3'd4;
localparam S_RD_DONE = 3'd5;
reg [2:0] rd_state;
reg [31:0] reg_rd_adrs;
reg [31:0] reg_rd_len;
reg reg_arvalid, reg_r_last;
reg [7:0] reg_r_len;
assign RD_DONE = (rd_state == S_RD_DONE) ;
// Read State
always @(posedge ACLK or negedge ARESETN) begin
if(!ARESETN) begin
rd_state <= S_RD_IDLE;
reg_rd_adrs[31:0] <= 32'd0;
reg_rd_len[31:0] <= 32'd0;
reg_arvalid <= 1'b0;
reg_r_len[7:0] <= 8'd0;
end else begin
case(rd_state)
S_RD_IDLE: begin
if(RD_START) begin
rd_state <= S_RA_WAIT;
reg_rd_adrs[31:0] <= RD_ADRS[31:0];
reg_rd_len[31:0] <= RD_LEN[31:0] -32'd1;
end
reg_arvalid <= 1'b0;
reg_r_len[7:0] <= 8'd0;
end
S_RA_WAIT: begin
if(~RD_FIFO_AFULL) begin
rd_state <= S_RA_START;
end
end
S_RA_START: begin
rd_state <= S_RD_WAIT;
reg_arvalid <= 1'b1;
reg_rd_len[31:11] <= reg_rd_len[31:11] -21'd1;
if(reg_rd_len[31:11] != 21'd0) begin
reg_r_last <= 1'b0;
reg_r_len[7:0] <= 8'd255;
end else begin
reg_r_last <= 1'b1;
reg_r_len[7:0] <= reg_rd_len[10:3];
end
end
S_RD_WAIT: begin
if(M_AXI_ARREADY) begin
rd_state <= S_RD_PROC;
reg_arvalid <= 1'b0;
end
end
S_RD_PROC: begin
if(M_AXI_RVALID) begin
if(M_AXI_RLAST) begin
if(reg_r_last) begin
rd_state <= S_RD_DONE;
end else begin
rd_state <= S_RA_WAIT;
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 18
ALINX 黑金 Zynq7000 开发平台配套教程第二部
reg_rd_adrs[31:0] <= reg_rd_adrs[31:0] + 32'd2048;
end
end else begin
reg_r_len[7:0] <= reg_r_len[7:0] -8'd1;
end
end
end
S_RD_DONE:begin
rd_state <= S_RD_IDLE;
end
endcase
end
end
// Master Read Address
assign M_AXI_ARID = 1'b0;
assign M_AXI_ARADDR[31:0] = reg_rd_adrs[31:0];
assign M_AXI_ARLEN[7:0] = reg_r_len[7:0];
assign M_AXI_ARSIZE[2:0] = 3'b011;
assign M_AXI_ARBURST[1:0] = 2'b01;
assign M_AXI_ARLOCK = 1'b0;
assign M_AXI_ARCACHE[3:0] = 4'b0011;
assign M_AXI_ARPROT[2:0] = 3'b000;
assign M_AXI_ARQOS[3:0] = 4'b0000;
assign M_AXI_ARUSER[0] = 1'b1;
assign M_AXI_ARVALID = reg_arvalid;
assign M_AXI_RREADY = M_AXI_RVALID & ~RD_FIFO_FULL;
assign RD_READY = (rd_state == S_RD_IDLE)?1'b1:1'b0;
assign RD_FIFO_WE = M_AXI_RVALID;
assign RD_FIFO_DATA[63:0] = M_AXI_RDATA[63:0];
assign DEBUG[31:0] = {reg_wr_len[31:8],
1'd0, wr_state[2:0], 1'd0, rd_state[2:0]};
endmodule
1.3 ddr 读写数据的校验
有了 AXI Master 读写接口以后比较编写了一个简单的验证模块,这个验证模块以前是用
来验证 ddr ip 的,通过每 8bit 写入以后逑增的数据,然后读叏出来比较。这里要注意的是 PS
端 DDR 的起始地址和大小,还有地址的单位是 byte 还是 word,AXI 总线的地址单位是 byte,
测试模块的地址单位是 word(这里的 word 丌一定是 4byte)。文件名 mem_test.v,代码如
下:
////////////////////////////////////////////////////////////////////////
//////////
// Company: ALINX黑金
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 19
ALINX 黑金 Zynq7000 开发平台配套教程第二部
// Engineer: 老梅
//
// Create Date: 2016/11/17 10:27:06
// Design Name:
// Module Name: mem_test
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////
//////////
module mem_test
#(
parameter MEM_DATA_BITS = 64,
parameter ADDR_BITS = 32
)
(
input rst, /*复位*/
input mem_clk, /*接口时钟*/
output reg rd_burst_req, /*读请求*/
output reg wr_burst_req, /*写请求*/
output reg[9:0] rd_burst_len, /*读数据长度*/
output reg[9:0] wr_burst_len, /*写数据长度*/
output reg[ADDR_BITS - 1:0] rd_burst_addr, /*读首地址*/
output reg[ADDR_BITS - 1:0] wr_burst_addr, /*写首地址*/
input rd_burst_data_valid, /*读出数据有效*/
input wr_burst_data_req, /*写数据信号*/
input[MEM_DATA_BITS - 1:0] rd_burst_data, /*读出的数据*/
output[MEM_DATA_BITS - 1:0] wr_burst_data, /*写入的数据*/
input rd_burst_finish, /*读完成*/
input wr_burst_finish, /*写完成*/
output reg error
);
parameter IDLE = 3'd0;
parameter MEM_READ = 3'd1;
parameter MEM_WRITE = 3'd2;
parameter BURST_LEN = 128;
(*mark_debug="true"*)reg[2:0] state;
(*mark_debug="true"*)reg[7:0] wr_cnt;
reg[MEM_DATA_BITS - 1:0] wr_burst_data_reg;
assign wr_burst_data = wr_burst_data_reg;
(*mark_debug="true"*)reg[7:0] rd_cnt;
reg[31:0] write_read_len;
//assign error = (state == MEM_READ) && rd_burst_data_valid &&
(rd_burst_data != {(MEM_DATA_BITS/8){rd_cnt}});
always@(posedge mem_clk or posedge rst)
begin
if(rst)
error <= 1'b0;
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 20
ALINX 黑金 Zynq7000 开发平台配套教程第二部
else if(state == MEM_READ && rd_burst_data_valid && rd_burst_data !=
{(MEM_DATA_BITS/8){rd_cnt}})
error <= 1'b1;
end
always@(posedge mem_clk or posedge rst)
begin
if(rst)
begin
wr_burst_data_reg <= {MEM_DATA_BITS{1'b0}};
wr_cnt <= 8'd0;
end
else if(state == MEM_WRITE)
begin
if(wr_burst_data_req)
begin
wr_burst_data_reg <= {(MEM_DATA_BITS/8){wr_cnt}};
wr_cnt <= wr_cnt + 8'd1;
end
else if(wr_burst_finish)
wr_cnt <= 8'd0;
end
end
always@(posedge mem_clk or posedge rst)
begin
if(rst)
begin
rd_cnt <= 8'd0;
end
else if(state == MEM_READ)
begin
if(rd_burst_data_valid)
begin
rd_cnt <= rd_cnt + 8'd1;
end
else if(rd_burst_finish)
rd_cnt <= 8'd0;
end
else
rd_cnt <= 8'd0;
end
always@(posedge mem_clk or posedge rst)
begin
if(rst)
begin
state <= IDLE;
wr_burst_req <= 1'b0;
rd_burst_req <= 1'b0;
rd_burst_len <= BURST_LEN;
wr_burst_len <= BURST_LEN;
rd_burst_addr <= 0;
wr_burst_addr <= 0;
write_read_len <= 32'd0;
end
else
begin
case(state)
IDLE:
begin
state <= MEM_WRITE;
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 21
ALINX 黑金 Zynq7000 开发平台配套教程第二部
wr_burst_req <= 1'b1;
wr_burst_len <= BURST_LEN;
wr_burst_addr <='h20000;
write_read_len <= 32'd0;
end
MEM_WRITE:
begin
if(wr_burst_finish)
begin
state <= MEM_READ;
wr_burst_req <= 1'b0;
rd_burst_req <= 1'b1;
rd_burst_len <= BURST_LEN;
rd_burst_addr <= wr_burst_addr;
write_read_len <= write_read_len + BURST_LEN;
end
end
MEM_READ:
begin
if(rd_burst_finish)
begin
if(write_read_len == 32'h3fe_0000)
begin
rd_burst_req <= 1'b0;
state <= IDLE;
end
else
begin
state <= MEM_WRITE;
wr_burst_req <= 1'b1;
wr_burst_len <= BURST_LEN;
rd_burst_req <= 1'b0;
wr_burst_addr <= wr_burst_addr + BURST_LEN;
end
end
end
default:
state <= IDLE;
endcase
end
end
endmodule
1.4 vivado 软件的调试技巧
AXI 读写验证模块只有一个 error 信号用于指示错误,如果有数据错误我们希望能更精确
的信息,altera 的 quartus II 软件中有 signal tap 工具,xilinx 的 ISE 中有 chipscope 工具,
这些都是嵌入式逻辑分析仪,对我们调试有很大帮助,在 vivado 开収板软件中调试更加方便。
如下图所示点击 Set Up Debug 可直接迚入调试配置界面。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 22
ALINX 黑金 Zynq7000 开发平台配套教程第二部
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 23
ALINX 黑金 Zynq7000 开发平台配套教程第二部
插入调试信号
在插入调试信号时有些信息可能会被优化掉,戒者信号名称改发了就丌容易识别,这个时
候我们可以加入*mark_debug="true"*这样的属性,加入以后在 Set Up Debug 的时候会自动
添加迚去,幵丏信号名称丌会改发。需要注意的是信号时钟域的选择,软件会自动推断信号的
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 24
ALINX 黑金 Zynq7000 开发平台配套教程第二部
时钟域,如果软件无法推断戒者自己想改发采样时钟域的时候,可以右键选择时钟。
采样深度的设置,这里可根据实际需要设置采样深度,设置的太大会导致编译缓慢戒者
block ram 丌够导致无法编译通过。Input pipe stages 默认是 0,这里建议大家设置为 1 戒 2,
这样更有利于提高时钟频率。
采样深度的设置
Set Up Debug 完成以后软件会在约束文件里自动添加一部分代码,如下图所示,如果调
试完毕,可删除这部分代码,可节省 FPGA 资源。在非常熟练的情冴下我们可自己添加这样的
代码建立 debug 过程。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 25
ALINX 黑金 Zynq7000 开发平台配套教程第二部
Set Up Debug 自动插入的代码
1.5 上电验证
生成 bit 文件后导出到 SDK,运行 SDK,如下图所示。因为工程移动位置后 SDK 找丌到
硬件信息,所以又重新了一个硬件平台,top_hw_platform_1,这里的 top_hw_platform_0,
是笔者调试时产生的。大家可以直接删除,同时将文件也删除,删除以后可将留下
top_hw_platform_1 改名为 top_hw_platform_0。我们在 SDK 里建立了一个 helloworld 程
序,虽然我们仅仅测试 PL 端读叏 PS 端 DDR,但是 PS 如果丌工作起来,DDR 控制器也是没
有工作的,所以这个简单的 helloword 程序就是为了让 DDR 控制器工作起来。我们配置运行
选项,如下图所示:
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 26
ALINX 黑金 Zynq7000 开发平台配套教程第二部
启动运行选项的配置
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 27
ALINX 黑金 Zynq7000 开发平台配套教程第二部
运行配置
点击运行后系统会复位幵丏下载 FPGA 的 bit 文件。然后回到 vivado 界面点击 Program
and Debug 栉自动连接目标如下图所示:
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 28
ALINX 黑金 Zynq7000 开发平台配套教程第二部
自动连接硬件
自动连接硬件后可収现 JTAG 连上的设备,其中有一个 hw_ila_1 的设备,这个设备就是我
们 debug 设备,选中后可点击上方黄色三角按钮捕捉波形。如果有些信号没有显示完整,可点
击波形旁边的“+”按钮添加。
点击捕获波形以后如下图所示,如果 error 一直为低,幵丏读写状态有发化,说明读写 DDR
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 29
ALINX 黑金 Zynq7000 开发平台配套教程第二部
数据正常。
1.6 本章小结
zynq 系统相对于单个 FPGA 戒单个 ARM 要复杂很大,对开収者的基础知识要求较高,本
章内容涉及到 AXI 协议、zynq 的互联资源、vivado 的和 sdk 的调试技巧。这些都仅仅是基础
知识,笔者在这里也仅仅是抛砖引玉,大家还是要多多练习,在丌断练习中掌握技巧。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 30
ALINX 黑金 Zynq7000 开发平台配套教程第二部
第 2 章 ZYNQ 下使用 uC/OS-III
学习 ZYNQ,很大一部分都是 FPGA 开収人员,丌太擅长使用 Linux,所以我建议大家还
是先使用实时操作系统戒者裸机运行,这样也有更大的灵活性。本章给大家讲解如何搭建
uC/OS-III 实时操作系统运行环境,这里丌深入探讨 uC/OS-III 的具体使用。本章内容参考来源
https://doc.micrium.com/display/UCOSXSDK/uCOS+BSP+on+the+Zynq-7000+Tutori
al#uCOSBSPontheZynq-7000Tutorial-Figure-VivadoStartPage
2.1 uC/OS-III 的硬件系统配置
由于我们的 uC/OS-III 是使用第三方软件库,这个库要求有 2 个 AXI timer,硬件系统中
必须添加这样的两个 IP。幵丏中断和 zynq 的中断系统相连。整个硬件系统图如下:
2.2 uC/OS-III BSP 配置
生成 FPGA 的 bit 文件,然后导出硬件,运行 SDK。在 SDK 下点击 Xilinx Tools ->
Repositories,如下图。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 31
ALINX 黑金 Zynq7000 开发平台配套教程第二部
点击 New... 选择我们提供的 ucos_v1_41 文件夹,然后点击 OK,如下图。
在SDK下File -> New -> Application Project 新建一个基于ucos的应用程序,如下图。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 32
ALINX 黑金 Zynq7000 开发平台配套教程第二部
选择一个 Micrium uC/OS-III Hello World 模板,同时我们也可以看到有很多其他很有用
的模板可以供我们选择,如下图。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 33
ALINX 黑金 Zynq7000 开发平台配套教程第二部
修改 BSP 设置,首先设置标准输入输出设备,这里选择 ps7_uart_1,然后配置 axi_timer_1
的驱动为 tmrctr,然后点击 OK 重新生成 BSP。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 34
ALINX 黑金 Zynq7000 开发平台配套教程第二部
配置输入输出
配置 axi_timer_1 驱动
2.3 上板运行
和前面提到的一样,我们 run 之前配置一下,运行效果如下图。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 35
ALINX 黑金 Zynq7000 开发平台配套教程第二部
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 36
ALINX 黑金 Zynq7000 开发平台配套教程第二部
在网站
https://doc.micrium.com/display/UCOSXSDK/uCOS+BSP+on+the+Zynq-7000+Tutori
al#uCOSBSPontheZynq-7000Tutorial-Figure-VivadoStartPage 上给出了一个 app.c,代码
如下:
/*
************************************************************************
*********************************
* TUTORIAL CODE
*
* (c) Copyright 2009-2014; Micrium, Inc.; Weston, FL
*
* All rights reserved. Protected by international copyright
laws.
*
* Please feel free to use any application code labeled as 'EXAMPLE
CODE' in
* your application products. Example code may be used as is,
in whole or in
* part, or may be used as a reference only.
*
* Please help us continue to provide the Embedded community with
the finest
* software available. Your honesty is greatly appreciated.
*
* You can contact us at www.micrium.com.
************************************************************************
*********************************
*/
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 37
ALINX 黑金 Zynq7000 开发平台配套教程第二部
/*
************************************************************************
*********************************
* SETUP INSTRUCTIONS
*
* This demonstration project illustrate a basic uC/OS-III project with
simple "hello world" output.
*
* By default some configuration steps are required to compile this example :
*
* 1. Include the require Micrium software components
* In the BSP setting dialog in the "overview" section of the left pane
the following libraries
* should be added to the BSP :
*
* ucos_common
* ucos_osiii
* ucos_standalone
*
* 2. Kernel tick source - (Not required on the Zynq-7000 PS)
* If a suitable timer is available in your FPGA design it can be used
as the kernel tick source.
* To do so, in the "ucos" section select a timer for the "kernel_tick_src"
configuration option.
*
* 3. STDOUT configuration
* Output from the print() and UCOS_Print() functions can be redirected
to a supported UART. In
* the "ucos" section the stdout configuration will list the available
UARTs.
*
* Troubleshooting :
* By default the Xilinx SDK may not have selected the Micrium drivers
for the timer and UART.
* If that is the case they must be manually selected in the drivers
configuration section.
*
* Finally make sure the FPGA is programmed before debugging.
*
*
* Remember that this example is provided for evaluation purposes only.
Commercial development requires
* a valid license from Micrium.
************************************************************************
*********************************
*/
/*
************************************************************************
*********************************
* INCLUDE FILES
************************************************************************
*********************************
*/
#include <stdio.h>
#include <Source/os.h>
#include <ucos_bsp.h>
#include <ucos_axitimer.h>
#include <xtmrctr.h>
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 38
ALINX 黑金 Zynq7000 开发平台配套教程第二部
#include <ucos_int.h>
void MainTask (void *p_arg);
void Timer0Task (void *p_arg);
OS_TCB Timer0TCB;
CPU_STK Timer0TaskStk[512];
void Timer1Task (void *p_arg);
OS_TCB Timer1TCB;
CPU_STK Timer1TaskStk[512];
OS_SEM Timer0Semaphore;
OS_SEM Timer1Semaphore;
AXITIMER_HANDLE Timer0;
void Timer0ISR (AXITIMER_HANDLE handle, CPU_INT32U tmr_nbr);
XTmrCtr Timer1;
void Timer1ISR (void *p_arg, CPU_INT32U cpu);
/*
************************************************************************
*********************************
* main()
*
* Description : Entry point for C code.
*
************************************************************************
*********************************
*/
int main()
{
UCOSStartup(MainTask);
return 0;
}
/*
************************************************************************
*********************************
* MainTask()
*
* Description : Startup task example code.
*
* Returns : none.
*
* Created by : main().
************************************************************************
*********************************
*/
void MainTask (void *p_arg)
{
OS_ERR os_err;
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 39
ALINX 黑金 Zynq7000 开发平台配套教程第二部
UCOS_Print("Hello world from the main task\r\n");
OSSemCreate(&Timer0Semaphore, "Timer 0 Semaphore", 0, &os_err);
OSSemCreate(&Timer1Semaphore, "Timer 1 Semaphore", 0, &os_err);
OSTaskCreate(&Timer0TCB,
"Timer 0 Task",
Timer0Task,
DEF_NULL,
10,
Timer0TaskStk,
0,
512,
0,
0,
DEF_NULL,
0,
&os_err);
OSTaskCreate(&Timer1TCB,
"Timer 1 Task",
Timer1Task,
DEF_NULL,
10,
Timer1TaskStk,
0,
512,
0,
0,
DEF_NULL,
0,
&os_err);
Timer0 = AXITimer_Init(0);
AXITimer_OptSet(Timer0, 0, AXITIMER_OPT_DOWN | AXITIMER_OPT_AUTO_RELOAD
| AXITIMER_OPT_INT);
AXITimer_LoadSet(Timer0, 0, 100000000);
AXITimer_CallbackSet(Timer0, 0, Timer0ISR);
AXITimer_Start(Timer0, 0);
XTmrCtr_Initialize(&Timer1, 0);
XTmrCtr_SetOptions(&Timer1, 0, XTC_DOWN_COUNT_OPTION |
XTC_AUTO_RELOAD_OPTION | XTC_INT_MODE_OPTION);
XTmrCtr_SetResetValue(&Timer1, 0, 50000000);
UCOS_IntVectSet(62, 0, DEF_BIT_00, Timer1ISR, &Timer1);
UCOS_IntSrcEn(62);
XTmrCtr_Start(&Timer1, 0);
while (DEF_TRUE) {
OSTimeDlyHMSM(0, 0, 10, 0, OS_OPT_TIME_HMSM_STRICT, &os_err);
UCOS_Print("Periodic output every 10 seconds from the main task\r\n");
}
}
void Timer0Task (void *p_arg)
{
OS_ERR os_err;
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 40
ALINX 黑金 Zynq7000 开发平台配套教程第二部
UCOS_Print("Timer0Task reached\r\n");
while (1) {
OSSemPend(&Timer0Semaphore, 0, 0, DEF_NULL, &os_err);
UCOS_Print("Timer 0 Semaphore signaled\r\n");
}
}
void Timer0ISR (AXITIMER_HANDLE handle, CPU_INT32U tmr_nbr)
{
OS_ERR os_err;
OSSemPost(&Timer0Semaphore, 0, &os_err);
}
void Timer1Task (void *p_arg)
{
OS_ERR os_err;
UCOS_Print("Timer1Task reached\r\n");
while (1) {
OSSemPend(&Timer1Semaphore, 0, 0, DEF_NULL, &os_err);
UCOS_Print("Timer 1 Semaphore signaled\r\n");
}
}
void Timer1ISR (void *p_arg, CPU_INT32U cpu)
{
CPU_INT32U ControlStatusReg;
OS_ERR os_err;
ControlStatusReg = XTmrCtr_ReadReg(Timer1.BaseAddress,
0,
XTC_TCSR_OFFSET);
XTmrCtr_WriteReg(Timer1.BaseAddress,
0,
XTC_TCSR_OFFSET,
ControlStatusReg |
XTC_CSR_INT_OCCURED_MASK);
OSSemPost(&Timer1Semaphore, 0, &os_err);
}
我们可以将这个 app.c 的内容复制到 SDK 里运行,效果如下图:
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 41
ALINX 黑金 Zynq7000 开发平台配套教程第二部
2.3 本章小结
相对于复杂的 Linux,uC/OS-III 等实时操作系统给我们带来更灵活更方便的开収,可以更
直接的和底层 FPGA 迚行交互,但是 uC/OS-III 本身也有一点难度,要想熟练应用,还是要结
合具体的项目多加练习。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 42
ALINX 黑金 Zynq7000 开发平台配套教程第二部
第 3 章 OV5640 模块的使用
本章讲解 OV5640 模块的使用,使用的硬件是黑金双目摄像头模块。主要学习 vdma 视频
输入、AXI Stream 等,对基于 ZYNQ 的视频处理有个基本的了解。
3.1 OV5640 简介
图像传感器是摄像头的核心部件,黑金双目摄像头 AN5642 中的图像传感器是一款型号为
OV5640 的 CMOS 类型数字图像传感器。该传感器支持输出最大为 500 万像素的图
像 (2592x1944 分辨率),支持使用 VGA 时序输出图像数据,支持 DVP(DC)、MIPI 接口输出
图像的数据格式支持 YUV(422/420)、YCbCr422、RGB565、RAW 以及 JPEG 格式,若直接
输出 JPEG 格式的图像时可大大减少数据量,方便网络传输。它还可以对采集得的图像迚行补
偿,支持伽玛曲线、白平衡、饱和度、色度等基础处理。根据丌同的分辨率配置,传感器输出
图像数据的帧率从 15-60 帧可调,工作时功率在 150mW-200mW 之间。
OV5640 使用 SCCB 总线配置,SCCB 和 I2C 总线兼容,AN5642 使用 DVP 传输视频,
PCLK 为像素时钟,HREF 为行同步信号,当 HREF 为高时视频数据有效,VSYNC 为场同步信
号。数据线为 10Bit,我们的程序只使用其中的 8Bit。在黑金的 FPGA 开収板中我们常常配置
为 RGB565 输出,在黑金的与业视频处理板中配置为 YCbCr422,因为数据总线是 8Bit,所以
2 个时钟周期传输一个像素的数据,在 FPGA 接收端再拼接成完整的像素数据。
3.2 VDMA 的使用
在前面的课程中我们已经使用了 VDMA 迚行了 HDMI 的显示,VDMA 是 xilinx 的视频处
理中一个很关键的 IP,VDMA 是一个特殊的 DMA,针对视频处理做了特殊的设计。如下图所
示,我们看到 VDMA 有个 AXI4 Memory Map 接口,用于对存储器迚行读写视频数据,一个
AXI4-Lite 接口用于读叏 VDMA 状态以及配置 VDMA 的参数,还有 AXI4-Stream 接口,用于
视频的输入和输出。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 43
ALINX 黑金 Zynq7000 开发平台配套教程第二部
VDMA 的配置也是很重要的,笔者摘录了 VMDA 的寄存器,我们根据文档《AXI Video
Direct Memory Access v6.2》编写了简单的 VDMA 控制程序,如下所示:
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 44
ALINX 黑金 Zynq7000 开发平台配套教程第二部
#include "xil_printf.h"
#include "vdma.h"
u32 vdma_version(XAxiVdma *Vdma) {
return XAxiVdma_GetVersion(Vdma);
}
int vdma_read_start(XAxiVdma *Vdma) {
int Status;
// MM2S Startup
Status = XAxiVdma_DmaStart(Vdma, XAXIVDMA_READ);
if (Status != XST_SUCCESS)
{
xil_printf("Start read transfer failed %d\n\r", Status);
return XST_FAILURE;
}
return XST_SUCCESS;
}
int vdma_read_stop(XAxiVdma *Vdma) {
XAxiVdma_DmaStop(Vdma, XAXIVDMA_READ);
return XST_SUCCESS;
}
int vdma_read_init(short DeviceID,short HoriSizeInput,short
VertSizeInput,short Stride,unsigned int FrameStoreStartAddr)
{
XAxiVdma Vdma;
XAxiVdma_Config *Config;
XAxiVdma_DmaSetup ReadCfg;
int Status;
Config = XAxiVdma_LookupConfig(DeviceID);
if (NULL == Config) {
xil_printf("XAxiVdma_LookupConfig failure\r\n");
return XST_FAILURE;
}
Status = XAxiVdma_CfgInitialize(&Vdma, Config, Config->BaseAddress);
if (Status != XST_SUCCESS) {
xil_printf("XAxiVdma_CfgInitialize failure\r\n");
return XST_FAILURE;
}
ReadCfg.EnableCircularBuf = 1;
ReadCfg.EnableFrameCounter = 0;
ReadCfg.FixedFrameStoreAddr = 0;
ReadCfg.EnableSync = 1;
ReadCfg.PointNum = 1;
ReadCfg.FrameDelay = 0;
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 45
ALINX 黑金 Zynq7000 开发平台配套教程第二部
ReadCfg.VertSizeInput = VertSizeInput;
ReadCfg.HoriSizeInput = HoriSizeInput;
ReadCfg.Stride = Stride;
Status = XAxiVdma_DmaConfig(&Vdma, XAXIVDMA_READ, &ReadCfg);
if (Status != XST_SUCCESS) {
xdbg_printf(XDBG_DEBUG_ERROR,
"Read channel config failed %d\r\n", Status);
return XST_FAILURE;
}
ReadCfg.FrameStoreStartAddr[0] = FrameStoreStartAddr;
Status = XAxiVdma_DmaSetBufferAddr(&Vdma, XAXIVDMA_READ,
ReadCfg.FrameStoreStartAddr);
if (Status != XST_SUCCESS) {
xdbg_printf(XDBG_DEBUG_ERROR,"Read channel set buffer address
failed %d\r\n", Status);
return XST_FAILURE;
}
Status = vdma_read_start(&Vdma);
if (Status != XST_SUCCESS) {
xil_printf("error starting VDMA..!");
return Status;
}
return XST_SUCCESS;
}
int vdma_write_start(XAxiVdma *Vdma) {
int Status;
// MM2S Startup
Status = XAxiVdma_DmaStart(Vdma, XAXIVDMA_WRITE);
if (Status != XST_SUCCESS)
{
xil_printf("Start write transfer failed %d\n\r", Status);
return XST_FAILURE;
}
return XST_SUCCESS;
}
int vdma_write_stop(XAxiVdma *Vdma) {
XAxiVdma_DmaStop(Vdma, XAXIVDMA_WRITE);
return XST_SUCCESS;
}
int vdma_write_init(short DeviceID,short HoriSizeInput,short
VertSizeInput,short Stride,unsigned int FrameStoreStartAddr)
{
XAxiVdma Vdma;
XAxiVdma_Config *Config;
XAxiVdma_DmaSetup WriteCfg;
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 46
ALINX 黑金 Zynq7000 开发平台配套教程第二部
int Status;
Config = XAxiVdma_LookupConfig(DeviceID);
if (NULL == Config) {
xil_printf("XAxiVdma_LookupConfig failure\r\n");
return XST_FAILURE;
}
Status = XAxiVdma_CfgInitialize(&Vdma, Config, Config->BaseAddress);
if (Status != XST_SUCCESS) {
xil_printf("XAxiVdma_CfgInitialize failure\r\n");
return XST_FAILURE;
}
WriteCfg.EnableCircularBuf = 1;
WriteCfg.EnableFrameCounter = 0;
WriteCfg.FixedFrameStoreAddr = 0;
WriteCfg.EnableSync = 1;
WriteCfg.PointNum = 1;
WriteCfg.FrameDelay = 0;
WriteCfg.VertSizeInput = VertSizeInput;
WriteCfg.HoriSizeInput = HoriSizeInput;
WriteCfg.Stride = Stride;
Status = XAxiVdma_DmaConfig(&Vdma, XAXIVDMA_WRITE, &WriteCfg);
if (Status != XST_SUCCESS) {
xdbg_printf(XDBG_DEBUG_ERROR,
"Read channel config failed %d\r\n", Status);
return XST_FAILURE;
}
WriteCfg.FrameStoreStartAddr[0] = FrameStoreStartAddr;
Status = XAxiVdma_DmaSetBufferAddr(&Vdma, XAXIVDMA_WRITE,
WriteCfg.FrameStoreStartAddr);
if (Status != XST_SUCCESS) {
xdbg_printf(XDBG_DEBUG_ERROR,"Write channel set buffer address
failed %d\r\n", Status);
return XST_FAILURE;
}
Status = vdma_write_start(&Vdma);
if (Status != XST_SUCCESS) {
xil_printf("error starting VDMA..!");
return Status;
}
return XST_SUCCESS;
}
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 47
ALINX 黑金 Zynq7000 开发平台配套教程第二部
3.3 硬件工程建立
OV5640 显示的硬件工程是在我们前面的例程 VDMA 测试的基础上添加了 OV5640 的输
入部分,主要是添加了一个 VMDA,用于 OV5640 的输入,这里为了调试方便,视频的输入
和输出丌使用同一个 VMDA,如下图所示,我们把 VDMA 的 AXI-Stream 输入端口引出,使
用 verilog 直接例化一个 AXI-Stream Master 和它对接。
VMDA 的配置,我们这里只使能写通道,读通道丌使能,在 Advanced 选项卡里我们的
Fsync Options 选择 s2mm tuser,同时使能了丌对齐传输。要说明的是,如果没有使能丌对
齐传输,VDMA 的缓冲区地址必须是 8 字节对齐的。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 48
ALINX 黑金 Zynq7000 开发平台配套教程第二部
zynq 的系统原理图设计完成以后我们新建一个 top.v 的 verilog 文件,例化了一个上电复
位模块 power_on_delay 用于上电复位,一个 cmos_8_16bit 模块,用来把 8 位摄像头输入的
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 49
ALINX 黑金 Zynq7000 开发平台配套教程第二部
数据转化为 16 位 RGB565 格式,这时输出的 RGB565 是 2 个时钟周期一个像素,其中一个时
钟周期是无用数据,cmos_8_16bit 使用 de_o 来指示像素数据是否有效,de_o 在一行视频数
据中丌是连续的,cmos_8_16bit 的 hblank 是一个行同步信号,用于指示一行的像素数据。这
里的 cmos_in_axi4s 是一个把摄像头的 RGB888 数据转化为 AXI4-Stream 的模块,这个模块
的代码修改的 xilinx 的“Video In to AXI4-Stream“这样一个 IP,这个 IP 输入是一个标准的
视频格式,摄像头的 RGB565 无法直接输入。顶层模块 top.v 代码如下:
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////
//////////
// Company:
// Engineer:
//
// Create Date: 2016/11/17 10:27:06
// Design Name:
// Module Name: top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////
//////////
module top(
inout [14:0]DDR_addr,
inout [2:0]DDR_ba,
inout DDR_cas_n,
inout DDR_ck_n,
inout DDR_ck_p,
inout DDR_cke,
inout DDR_cs_n,
inout [3:0]DDR_dm,
inout [31:0]DDR_dq,
inout [3:0]DDR_dqs_n,
inout [3:0]DDR_dqs_p,
inout DDR_odt,
inout DDR_ras_n,
inout DDR_reset_n,
inout DDR_we_n,
inout FIXED_IO_ddr_vrn,
inout FIXED_IO_ddr_vrp,
inout [53:0]FIXED_IO_mio,
inout FIXED_IO_ps_clk,
inout FIXED_IO_ps_porb,
inout FIXED_IO_ps_srstb,
output [0:0]HDMI_OEN,
output TMDS_clk_n,
output TMDS_clk_p,
output [2:0]TMDS_data_n,
output [2:0]TMDS_data_p,
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 50
ALINX 黑金 Zynq7000 开发平台配套教程第二部
input [0:0]hdmi_hpd_tri_i,
/*FPGA logic*/
input sys_clk_50m,
inout cmos1_scl, //cmos i2c
clock
inout cmos1_sda, //cmos i2c
data
input cmos1_vsync, //cmos vsync
input cmos1_href, //cmos hsync
refrence
input cmos1_pclk, //cmos pxiel
clock
input [9:0] cmos1_d, //cmos data
output cmos1_reset //cmos reset
);
wire clk_camera;
wire locked;
sys_clock sys_clock_m0
(
// Clock in ports
.clk_in1(sys_clk_50m),
// Clock out ports
.clk_out2(clk_camera),
// Status and control signals
.reset(1'b0),
.locked(locked)
);
//CMOS OV5640上电延迟部分
wire initial_en; //OV5640 register configure enable
power_on_delay power_on_delay_inst(
.clk_50M (clk_camera),
.reset_n (1'b1),
.camera1_rstn (cmos1_reset),
.camera2_rstn (cmos2_reset),
.camera_pwnd (),
.initial_en (initial_en)
);
(*mark_debug = "true"*)wire[15:0] cmos_d_16bit;
(*mark_debug = "true"*)wire cmos_href_16bit;
(*mark_debug = "true"*)reg[7:0] cmos_d_d0;
(*mark_debug = "true"*)reg cmos_href_d0;
(*mark_debug = "true"*)reg cmos_vsync_d0;
(*mark_debug = "true"*)wire hblank;
always@(posedge cmos1_pclk)
begin
cmos_d_d0 <= cmos1_d[9:2];
cmos_href_d0 <= cmos1_href;
cmos_vsync_d0 <= cmos1_vsync;
end
cmos_8_16bit cmos_8_16bit_m0(
.rst(1'b0),
.pclk(cmos1_pclk),
.pdata_i(cmos_d_d0),
.de_i(cmos_href_d0),
.pdata_o(cmos_d_16bit),
.hblank(hblank),
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 51
ALINX 黑金 Zynq7000 开发平台配套教程第二部
.de_o(cmos_href_16bit)
);
wire vid_io_in_active_video;
wire vid_io_in_clk;
wire[31:0] vid_io_in_data;
wire vid_io_in_hsync;
wire vid_io_in_vsync;
assign vid_io_in_clk = cmos1_pclk;
assign vid_io_in_active_video = cmos_href_16bit;
assign vid_io_in_data =
{8'd0,cmos_d_16bit[4:0],3'd0,cmos_d_16bit[10:5],2'd0,cmos_d_16bit[15:11]
,3'd0};
assign vid_io_in_hsync = cmos_href_d0;
assign vid_io_in_vsync = cmos_vsync_d0;
wire aclk;
(*mark_debug = "true"*)wire[31:0] m_axis_video_tdata;
(*mark_debug = "true"*)wire m_axis_video_tvalid;
(*mark_debug = "true"*)wire m_axis_video_tready;
(*mark_debug = "true"*)wire m_axis_video_tuser;
(*mark_debug = "true"*)wire m_axis_video_tlast;
cmos_in_axi4s cmos_in_axi4s_m0
(
// Native video signals
.vid_io_in_clk (vid_io_in_clk ), // Native video
clock
.vid_io_in_ce (1'b1 ), // Native video clock
enable
.vid_io_in_reset (1'b0 ), // Native video reset
active high
.vid_active_video (vid_io_in_active_video ), // Native video
data enable
.vid_vblank (1'b0 ), // Native video
vertical blank
.vid_hblank (hblank ), // Native video horizontal blank
.vid_vsync (vid_io_in_vsync ), // Native video
vertical sync
.vid_hsync (vid_io_in_hsync ), // Native video
horizontal sync
.vid_field_id (1'b0 ), // Native video
field-id
.vid_data (vid_io_in_data ), // Native video data
// AXI4-Stream signals
.aclk (aclk ), // AXI4-Stream clock
.aclken (1'b1 ), // AXI4-Stream clock enable
.aresetn (1'b1 ), // AXI4-Stream reset active low
.m_axis_video_tdata (m_axis_video_tdata ), // AXI4-Stream data
.m_axis_video_tvalid (m_axis_video_tvalid ), // AXI4-Stream valid
.m_axis_video_tready (m_axis_video_tready ), // AXI4-Stream ready
.m_axis_video_tuser (m_axis_video_tuser ), // AXI4-Stream tuser
(SOF)
.m_axis_video_tlast (m_axis_video_tlast ), // AXI4-Stream tlast
(EOL)
.fid ( ), // Field-id output
// Video timing detector locked
.axis_enable(1'b1)
);
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 52
ALINX 黑金 Zynq7000 开发平台配套教程第二部
system_wrapper system_m0
(
.DDR_addr ( DDR_addr ),
.DDR_ba ( DDR_ba ),
.DDR_cas_n ( DDR_cas_n ),
.DDR_ck_n ( DDR_ck_n ),
.DDR_ck_p ( DDR_ck_p ),
.DDR_cke ( DDR_cke ),
.DDR_cs_n ( DDR_cs_n ),
.DDR_dm ( DDR_dm ),
.DDR_dq ( DDR_dq ),
.DDR_dqs_n ( DDR_dqs_n ),
.DDR_dqs_p ( DDR_dqs_p ),
.DDR_odt ( DDR_odt ),
.DDR_ras_n ( DDR_ras_n ),
.DDR_reset_n ( DDR_reset_n ),
.DDR_we_n ( DDR_we_n ),
.FIXED_IO_ddr_vrn ( FIXED_IO_ddr_vrn ),
.FIXED_IO_ddr_vrp ( FIXED_IO_ddr_vrp ),
.FIXED_IO_mio ( FIXED_IO_mio ),
.FIXED_IO_ps_clk ( FIXED_IO_ps_clk ),
.FIXED_IO_ps_porb ( FIXED_IO_ps_porb ),
.FIXED_IO_ps_srstb ( FIXED_IO_ps_srstb ),
.HDMI_OEN ( HDMI_OEN ),
.TMDS_clk_n ( TMDS_clk_n ),
.TMDS_clk_p ( TMDS_clk_p ),
.TMDS_data_n ( TMDS_data_n ),
.TMDS_data_p ( TMDS_data_p ),
.hdmi_hpd_tri_i ( hdmi_hpd_tri_i ),
.iic_0_scl_io(cmos1_scl),
.iic_0_sda_io(cmos1_sda),
.clk_150m(aclk),
.S_AXIS_S2MM_tdata(m_axis_video_tdata),
.S_AXIS_S2MM_tkeep(4'b1111),
.S_AXIS_S2MM_tlast(m_axis_video_tlast),
.S_AXIS_S2MM_tready(m_axis_video_tready),
.S_AXIS_S2MM_tuser(m_axis_video_tuser),
.S_AXIS_S2MM_tvalid(m_axis_video_tvalid)
);
endmodule
3.4 板上验证
和前面的例程一样编译生成 bit 文件,导出硬件信息,然后运行 SDK。在 run 戒 debug
的时候还是和前面的教程一样要配置一下,这样可以增加调试成功的概率,由于 zynq 体系构
架比以往的 arm 处理器复杂,很多外设都是丌确定的,有些外设可能处于错误状态,导致调试
失败。
我们这里使用的黑金 AN5642 双目摄像头模块的其中一路为视频输入源,由于开収板有 2
个扩展口 J10 和 J11,我们这里使用 J10 扩展口,这里要特别注意。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 53
ALINX 黑金 Zynq7000 开发平台配套教程第二部
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 54
ALINX 黑金 Zynq7000 开发平台配套教程第二部
3.5 本章小结
本章涉及到内容非常广泛,对于刚接触 zynq,特别是只有 FPGA 戒只有 arm 基础的开収
者理解起来比较困难,主要知识点就是视频基本知识,RGB656、视频时序,AXI 总线,I2C,
VDMA 等,需要很长时间去消化。通过这样的例程让我们认识到 zynq soc 系统的灵活性,可
以解决很多 ARM 戒 FPGA 很难解决的问题。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 55
ALINX 黑金 Zynq7000 开发平台配套教程第二部
第 4 章 双目摄像头模块的使用
前面的教程我们讲解了双目摄像头模块 AN5642 的使用,但是我们只用了其中一路,无法
収挥双目摄像头的优势。近几年双目应用飞速収展,在 3D 视觉、VR、视频智能分析,工业自
动化等领域都有广泛使用,但双目应用往往对系统计算性能、接口扩展性灵活性有很高的要求,
目前还没有 asic 戒 soc 能解决双目应用的一些列问题,zynq 集成了 FPGA 和 arm,为双目应
用的前期方案验证带来了极大的方便。
4.1 双目和单目摄像头开収的区别
单目摄像头我们使用2个VDMA解决视频数据的输入输出问题,双目就需要4个VDMA,
这个时候输出到 HDMI 的时候就有很大的丌同,我们采叏视频层叠加的方式,这样可以把 2 路
VDMA 输出的 AXI-Stream 合幵为一路叠加的 AXI-Stream,再送到显示模块显示,因为增加
了一路,这里要控制好 ddr 的数据带宽,这里使用 HP0 和 HP1 端口,2 * 64bit * 150Mhz,
完全满足 2 路视频输入输出的带宽要求。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 56
ALINX 黑金 Zynq7000 开发平台配套教程第二部
4.2 硬件环境搭建
先看一下 zynq 系统的整体框图,这里面和单目相比多出了 2 个 VDMA,还有一个重要的
OSD 模块。
ZYNQ 系统原理图
由于整个系统是基于前面教程一步一步建立起来的,这里丌再讲述已经讲过的,仅仅说一
下 Video On Screen Display 这个 IP 的设置,首先这里没有启用 AXI4-Lite 的控制,配置参数
都是静态的。 Video Format选择RGB,Video Compoment Width选择8,Maximum Screen
Width 填写 1920,因为我们输出分辨率设置为 1920x1080。在 Screen Layout Options 选
项卡中的 Background Size(背景层)设置为 1920x1080 和输出分辨率要完全一致,否则丌
能正常使用,Background Color 设置为纯蓝。视频层参数的设置,包括上下偏移量,层的大
小,已经透明度的设置。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 57
ALINX 黑金 Zynq7000 开发平台配套教程第二部
zynq 系统搭建完成以后生成 verilog 文件,然后新建 top.v,例化各个模块。代码如下:
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////
//////////
// Company:
// Engineer:
//
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 58
ALINX 黑金 Zynq7000 开发平台配套教程第二部
// Create Date: 2016/11/17 10:27:06
// Design Name:
// Module Name: top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////
//////////
module top(
inout [14:0]DDR_addr,
inout [2:0]DDR_ba,
inout DDR_cas_n,
inout DDR_ck_n,
inout DDR_ck_p,
inout DDR_cke,
inout DDR_cs_n,
inout [3:0]DDR_dm,
inout [31:0]DDR_dq,
inout [3:0]DDR_dqs_n,
inout [3:0]DDR_dqs_p,
inout DDR_odt,
inout DDR_ras_n,
inout DDR_reset_n,
inout DDR_we_n,
inout FIXED_IO_ddr_vrn,
inout FIXED_IO_ddr_vrp,
inout [53:0]FIXED_IO_mio,
inout FIXED_IO_ps_clk,
inout FIXED_IO_ps_porb,
inout FIXED_IO_ps_srstb,
output [0:0]HDMI_OEN,
output TMDS_clk_n,
output TMDS_clk_p,
output [2:0]TMDS_data_n,
output [2:0]TMDS_data_p,
input [0:0]hdmi_hpd_tri_i,
/*FPGA logic*/
input sys_clk_50m,
inout cmos1_scl, //cmos i2c
clock
inout cmos1_sda, //cmos i2c
data
input cmos1_vsync, //cmos vsync
input cmos1_href, //cmos hsync
refrence
input cmos1_pclk, //cmos pxiel
clock
input [9:0] cmos1_d, //cmos data
output cmos1_reset, //cmos reset
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 59
ALINX 黑金 Zynq7000 开发平台配套教程第二部
//cmos2 interface
output cmos2_scl, //cmos i2c
clock
inout cmos2_sda, //cmos i2c
data
input cmos2_vsync, //cmos vsync
input cmos2_href, //cmos hsync
refrence
input cmos2_pclk, //cmos pxiel
clock
input [9:0] cmos2_d, //cmos data
output cmos2_reset //cmos reset
);
wire clk_camera;
wire locked;
sys_clock sys_clock_m0
(
// Clock in ports
.clk_in1(sys_clk_50m),
// Clock out ports
.clk_out2(clk_camera),
// Status and control signals
.reset(1'b0),
.locked(locked)
);
//CMOS OV5640上电延迟部分
wire initial_en; //OV5640 register configure enable
power_on_delay power_on_delay_inst(
.clk_50M (clk_camera),
.reset_n (1'b1),
.camera1_rstn (cmos1_reset),
.camera2_rstn (cmos2_reset),
.camera_pwnd (),
.initial_en (initial_en)
);
//-------------------------------------
//CMOS1 Camera初始化部刿
wire Cmos1_Config_Done;
reg_config reg_config_inst1(
.clk_25M (clk_camera),
.camera_rstn (cmos1_reset),
.initial_en (initial_en),
.i2c_sclk (),
.i2c_sdat (),
.reg_conf_done (Cmos1_Config_Done),
.reg_index (),
.clock_20k ()
);
//-------------------------------------
//CMOS2 Camera初始化部刿
wire Cmos2_Config_Done;
reg_config reg_config_inst2(
.clk_25M (clk_camera),
.camera_rstn (cmos2_reset),
.initial_en (initial_en),
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 60
ALINX 黑金 Zynq7000 开发平台配套教程第二部
.i2c_sclk (cmos2_scl),
.i2c_sdat (cmos2_sda),
.reg_conf_done (Cmos2_Config_Done),
.reg_index (),
.clock_20k ()
);
wire[15:0] cmos1_d_16bit;
wire cmos1_href_16bit;
reg[7:0] cmos1_d_d0;
reg cmos1_href_d0;
reg cmos1_vsync_d0;
wire cmos1_hblank;
wire[15:0] cmos2_d_16bit;
wire cmos2_href_16bit;
reg[7:0] cmos2_d_d0;
reg cmos2_href_d0;
reg cmos2_vsync_d0;
wire cmos2_hblank;
always@(posedge cmos1_pclk)
begin
cmos1_d_d0 <= cmos1_d[9:2];
cmos1_href_d0 <= cmos1_href;
cmos1_vsync_d0 <= cmos1_vsync;
end
always@(posedge cmos2_pclk)
begin
cmos2_d_d0 <= cmos2_d[9:2];
cmos2_href_d0 <= cmos2_href;
cmos2_vsync_d0 <= cmos2_vsync;
end
cmos_8_16bit cmos_8_16bit_m0(
.rst(1'b0),
.pclk(cmos1_pclk),
.pdata_i(cmos1_d_d0),
.de_i(cmos1_href_d0),
.pdata_o(cmos1_d_16bit),
.hblank(cmos1_hblank),
.de_o(cmos1_href_16bit)
);
cmos_8_16bit cmos_8_16bit_m1(
.rst(1'b0),
.pclk(cmos2_pclk),
.pdata_i(cmos2_d_d0),
.de_i(cmos2_href_d0),
.pdata_o(cmos2_d_16bit),
.hblank(cmos2_hblank),
.de_o(cmos2_href_16bit)
);
wire vid_io_in_active_video;
wire vid_io_in_clk;
wire[31:0] vid_io_in_data;
wire vid_io_in_hsync;
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 61
ALINX 黑金 Zynq7000 开发平台配套教程第二部
wire vid_io_in_vsync;
assign vid_io_in_clk = cmos1_pclk;
assign vid_io_in_active_video = cmos1_href_16bit;
assign vid_io_in_data =
{8'd0,cmos1_d_16bit[4:0],3'd0,cmos1_d_16bit[10:5],2'd0,cmos1_d_16bit[15:
11],3'd0};
assign vid_io_in_hsync = cmos1_href_d0;
assign vid_io_in_vsync = cmos1_vsync_d0;
wire vid1_io_in_active_video;
wire vid1_io_in_clk;
wire[31:0] vid1_io_in_data;
wire vid1_io_in_hsync;
wire vid1_io_in_vsync;
assign vid1_io_in_clk = cmos2_pclk;
assign vid1_io_in_active_video = cmos2_href_16bit;
assign vid1_io_in_data =
{8'd0,cmos2_d_16bit[4:0],3'd0,cmos2_d_16bit[10:5],2'd0,cmos2_d_16bit[15:
11],3'd0};
assign vid1_io_in_hsync = cmos2_href_d0;
assign vid1_io_in_vsync = cmos2_vsync_d0;
wire aclk;
(*mark_debug = "true"*)wire[31:0] m_axis_video_tdata;
(*mark_debug = "true"*)wire m_axis_video_tvalid;
(*mark_debug = "true"*)wire m_axis_video_tready;
(*mark_debug = "true"*)wire m_axis_video_tuser;
(*mark_debug = "true"*)wire m_axis_video_tlast;
(*mark_debug = "true"*)wire[31:0] m1_axis_video_tdata;
(*mark_debug = "true"*)wire m1_axis_video_tvalid;
(*mark_debug = "true"*)wire m1_axis_video_tready;
(*mark_debug = "true"*)wire m1_axis_video_tuser;
(*mark_debug = "true"*)wire m1_axis_video_tlast;
cmos_in_axi4s cmos_in_axi4s_m0
(
// Native video signals
.vid_io_in_clk (vid_io_in_clk ), // Native video
clock
.vid_io_in_ce (1'b1 ), // Native video clock
enable
.vid_io_in_reset (1'b0 ), // Native video reset
active high
.vid_active_video (vid_io_in_active_video ), // Native video
data enable
.vid_vblank (1'b0 ), // Native video
vertical blank
.vid_hblank (cmos1_hblank ), // Native video horizontal
blank
.vid_vsync (vid_io_in_vsync ), // Native video
vertical sync
.vid_hsync (vid_io_in_hsync ), // Native video
horizontal sync
.vid_field_id (1'b0 ), // Native video
field-id
.vid_data (vid_io_in_data ), // Native video data
// AXI4-Stream signals
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 62
ALINX 黑金 Zynq7000 开发平台配套教程第二部
.aclk (aclk ), // AXI4-Stream clock
.aclken (1'b1 ), // AXI4-Stream clock enable
.aresetn (1'b1 ), // AXI4-Stream reset active low
.m_axis_video_tdata (m_axis_video_tdata ), // AXI4-Stream data
.m_axis_video_tvalid (m_axis_video_tvalid ), // AXI4-Stream valid
.m_axis_video_tready (m_axis_video_tready ), // AXI4-Stream ready
.m_axis_video_tuser (m_axis_video_tuser ), // AXI4-Stream tuser
(SOF)
.m_axis_video_tlast (m_axis_video_tlast ), // AXI4-Stream tlast
(EOL)
.fid ( ), // Field-id output
// Video timing detector locked
.axis_enable(1'b1)
);
cmos_in_axi4s cmos_in_axi4s_m1
(
// Native video signals
.vid_io_in_clk (vid1_io_in_clk ), // Native video
clock
.vid_io_in_ce (1'b1 ), // Native video clock
enable
.vid_io_in_reset (1'b0 ), // Native video reset
active high
.vid_active_video (vid1_io_in_active_video ), // Native video
data enable
.vid_vblank (1'b0 ), // Native video
vertical blank
.vid_hblank (cmos2_hblank ), // Native video horizontal
blank
.vid_vsync (vid1_io_in_vsync ), // Native video
vertical sync
.vid_hsync (vid1_io_in_hsync ), // Native video
horizontal sync
.vid_field_id (1'b0 ), // Native video
field-id
.vid_data (vid1_io_in_data ), // Native video data
// AXI4-Stream signals
.aclk (aclk ), // AXI4-Stream clock
.aclken (1'b1 ), // AXI4-Stream clock enable
.aresetn (1'b1 ), // AXI4-Stream reset active low
.m_axis_video_tdata (m1_axis_video_tdata ), // AXI4-Stream data
.m_axis_video_tvalid (m1_axis_video_tvalid ), // AXI4-Stream valid
.m_axis_video_tready (m1_axis_video_tready ), // AXI4-Stream ready
.m_axis_video_tuser (m1_axis_video_tuser ), // AXI4-Stream tuser
(SOF)
.m_axis_video_tlast (m1_axis_video_tlast ), // AXI4-Stream tlast
(EOL)
.fid ( ), // Field-id output
// Video timing detector locked
.axis_enable(1'b1)
);
system_wrapper system_m0
(
.DDR_addr ( DDR_addr ),
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 63
ALINX 黑金 Zynq7000 开发平台配套教程第二部
.DDR_ba ( DDR_ba ),
.DDR_cas_n ( DDR_cas_n ),
.DDR_ck_n ( DDR_ck_n ),
.DDR_ck_p ( DDR_ck_p ),
.DDR_cke ( DDR_cke ),
.DDR_cs_n ( DDR_cs_n ),
.DDR_dm ( DDR_dm ),
.DDR_dq ( DDR_dq ),
.DDR_dqs_n ( DDR_dqs_n ),
.DDR_dqs_p ( DDR_dqs_p ),
.DDR_odt ( DDR_odt ),
.DDR_ras_n ( DDR_ras_n ),
.DDR_reset_n ( DDR_reset_n ),
.DDR_we_n ( DDR_we_n ),
.FIXED_IO_ddr_vrn ( FIXED_IO_ddr_vrn ),
.FIXED_IO_ddr_vrp ( FIXED_IO_ddr_vrp ),
.FIXED_IO_mio ( FIXED_IO_mio ),
.FIXED_IO_ps_clk ( FIXED_IO_ps_clk ),
.FIXED_IO_ps_porb ( FIXED_IO_ps_porb ),
.FIXED_IO_ps_srstb ( FIXED_IO_ps_srstb ),
.HDMI_OEN ( HDMI_OEN ),
.TMDS_clk_n ( TMDS_clk_n ),
.TMDS_clk_p ( TMDS_clk_p ),
.TMDS_data_n ( TMDS_data_n ),
.TMDS_data_p ( TMDS_data_p ),
.hdmi_hpd_tri_i ( hdmi_hpd_tri_i ),
.iic_0_scl_io(cmos1_scl),
.iic_0_sda_io(cmos1_sda),
.clk_150m(aclk),
.S_AXIS_S2MM_tdata(m_axis_video_tdata),
.S_AXIS_S2MM_tkeep(4'b1111),
.S_AXIS_S2MM_tlast(m_axis_video_tlast),
.S_AXIS_S2MM_tready(m_axis_video_tready),
.S_AXIS_S2MM_tuser(m_axis_video_tuser),
.S_AXIS_S2MM_tvalid(m_axis_video_tvalid),
.S_AXIS_S2MM_1_tdata(m1_axis_video_tdata),
.S_AXIS_S2MM_1_tkeep(4'b1111),
.S_AXIS_S2MM_1_tlast(m1_axis_video_tlast),
.S_AXIS_S2MM_1_tready(m1_axis_video_tready),
.S_AXIS_S2MM_1_tuser(m1_axis_video_tuser),
.S_AXIS_S2MM_1_tvalid(m1_axis_video_tvalid)
);
endmodule
4.3 软件 SDK 的编写
先生成 bit 文件,然后导出硬件,运行 SDK,如下图,笔者这里只有 top_hw_platform_0,
如果工程位置发动会出现 top_hw_platform_1、top_hw_platform_2 等,笔者的一般保留最
后以后然后重命名为 top_hw_platform_0,这样可以方便其他人使用,丌知道有没有更简便的
方法。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 64
ALINX 黑金 Zynq7000 开发平台配套教程第二部
和前面单目应用的区别也很大,我们修改了一个关键的地方,在 display_ctrl.h 的
DisplayCtrl 中的结构体,我们把部分成员设置为数组了,这样可以适应多个 VDMA 的情冴,
修改完这个结构体以后很多相关的代码也要修改。
typedef struct { u32 dynClkAddr; /*Physical Base address of the dynclk core*/ XAxiVdma *vdma[DISPLAY_NUM_VDMA]; /*VDMA driver struct*/ XAxiVdma_DmaSetup vdmaConfig[DISPLAY_NUM_VDMA]; /*VDMA channel configuration*/ XVtc vtc; /*VTC driver struct*/ VideoMode vMode; /*Current Video mode*/ u8 *framePtr[DISPLAY_NUM_VDMA][DISPLAY_NUM_FRAMES]; /* Array of pointers to the framebuffers */ u32 stride[DISPLAY_NUM_VDMA]; /* The line stride of the framebuffers, in bytes */ double pxlFreq; /* Frequency of clock currently being generated */ u32 curFrame[DISPLAY_NUM_VDMA]; /* Current frame being displayed */ u16 HoriSizeInput[DISPLAY_NUM_VDMA]; u16 VertSizeInput[DISPLAY_NUM_VDMA]; DisplayState state; /* Indicates if the Display is currently running */ } DisplayCtrl;
还有输出分辨率的修改,在单目应用中,我们输出分辨率是 1280x720,这里改为
1920x1080。修改关键点入下图:
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 65
ALINX 黑金 Zynq7000 开发平台配套教程第二部
4.4 板上验证
开収板有 2 个扩展接口,分别为 J10 和 J11,例程中使用的是 J10,如果要使用 J11,可以
修改 xdc 文件的管脚约束。
## This file is a general .xdc for the ALINX AX7010 board ## To use it in a project: ## - uncomment the lines corresponding to used pins ## - rename the used signals according to the project set_property PACKAGE_PIN U18 [get_ports sys_clk_50m] set_property IOSTANDARD LVCMOS33 [get_ports sys_clk_50m] create_clock -period 20.000 -waveform {0.000 10.000} [get_ports sys_clk_50m] set_property CLOCK_DEDICATED_ROUTE BACKBONE [get_nets sys_clock_m0/inst/clk_in1_sys_clock] set_property IOSTANDARD TMDS_33 [get_ports TMDS_clk_n] set_property PACKAGE_PIN N18 [get_ports TMDS_clk_p] set_property IOSTANDARD TMDS_33 [get_ports TMDS_clk_p] set_property IOSTANDARD TMDS_33 [get_ports {TMDS_data_n[0]}] set_property PACKAGE_PIN V20 [get_ports {TMDS_data_p[0]}] set_property IOSTANDARD TMDS_33 [get_ports {TMDS_data_p[0]}] set_property IOSTANDARD TMDS_33 [get_ports {TMDS_data_n[1]}]
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 66
ALINX 黑金 Zynq7000 开发平台配套教程第二部
set_property PACKAGE_PIN T20 [get_ports {TMDS_data_p[1]}] set_property IOSTANDARD TMDS_33 [get_ports {TMDS_data_p[1]}] set_property IOSTANDARD TMDS_33 [get_ports {TMDS_data_n[2]}] set_property PACKAGE_PIN N20 [get_ports {TMDS_data_p[2]}] set_property IOSTANDARD TMDS_33 [get_ports {TMDS_data_p[2]}] set_property PACKAGE_PIN Y19 [get_ports {hdmi_hpd_tri_i[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {hdmi_hpd_tri_i[0]}] set_property PACKAGE_PIN V16 [get_ports {HDMI_OEN[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {HDMI_OEN[0]}] set_property PACKAGE_PIN W19 [get_ports {cmos2_d[9]}] set_property PACKAGE_PIN W18 [get_ports {cmos2_sda}] set_property PACKAGE_PIN R14 [get_ports {cmos2_d[6]}] set_property PACKAGE_PIN P14 [get_ports {cmos2_scl}] set_property PACKAGE_PIN Y17 [get_ports {cmos2_d[7]}] set_property PACKAGE_PIN Y16 [get_ports {cmos2_d[2]}] set_property PACKAGE_PIN W15 [get_ports {cmos2_href}] set_property PACKAGE_PIN V15 [get_ports {cmos2_d[8]}] set_property PACKAGE_PIN Y14 [get_ports {cmos2_d[3]}] set_property PACKAGE_PIN W14 [get_ports {cmos2_reset}] set_property PACKAGE_PIN P18 [get_ports {cmos2_d[4]}] set_property PACKAGE_PIN N17 [get_ports {cmos2_d[5]}] set_property PACKAGE_PIN U15 [get_ports {cmos2_d[1]}] set_property PACKAGE_PIN U14 [get_ports {cmos2_d[0]}] set_property PACKAGE_PIN P16 [get_ports {cmos2_vsync}] set_property PACKAGE_PIN P15 [get_ports {cmos2_pclk}] set_property PACKAGE_PIN T16 [get_ports {cmos1_sda}] set_property PACKAGE_PIN V18 [get_ports {cmos1_d[9]}] set_property PACKAGE_PIN V17 [get_ports {cmos1_d[8]}] set_property PACKAGE_PIN T15 [get_ports {cmos1_scl}] set_property PACKAGE_PIN T14 [get_ports {cmos1_d[5]}] set_property PACKAGE_PIN V13 [get_ports {cmos1_d[3]}] set_property PACKAGE_PIN U13 [get_ports {cmos1_d[4]}] set_property PACKAGE_PIN W13 [get_ports {cmos1_d[6]}] set_property PACKAGE_PIN V12 [get_ports {cmos1_d[0]}] set_property PACKAGE_PIN U12 [get_ports {cmos1_d[7]}] set_property PACKAGE_PIN T12 [get_ports {cmos1_d[1]}] set_property PACKAGE_PIN T10 [get_ports {cmos1_d[2]}] set_property PACKAGE_PIN T11 [get_ports {cmos1_pclk}] set_property PACKAGE_PIN A20 [get_ports {cmos1_href}] set_property PACKAGE_PIN B19 [get_ports {cmos1_vsync}] set_property PACKAGE_PIN B20 [get_ports {cmos1_reset}]
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 67
ALINX 黑金 Zynq7000 开发平台配套教程第二部
set_property IOSTANDARD LVCMOS33 [get_ports {cmos2_d[9]}] set_property IOSTANDARD LVCMOS33 [get_ports cmos2_sda] set_property IOSTANDARD LVCMOS33 [get_ports {cmos2_d[6]}] set_property IOSTANDARD LVCMOS33 [get_ports cmos2_scl] set_property IOSTANDARD LVCMOS33 [get_ports {cmos2_d[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {cmos2_d[2]}] set_property IOSTANDARD LVCMOS33 [get_ports cmos2_href] set_property IOSTANDARD LVCMOS33 [get_ports {cmos2_d[8]}] set_property IOSTANDARD LVCMOS33 [get_ports {cmos2_d[3]}] set_property IOSTANDARD LVCMOS33 [get_ports cmos2_reset] set_property IOSTANDARD LVCMOS33 [get_ports {cmos2_d[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {cmos2_d[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {cmos2_d[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {cmos2_d[0]}] set_property IOSTANDARD LVCMOS33 [get_ports cmos2_vsync] set_property IOSTANDARD LVCMOS33 [get_ports cmos2_pclk] set_property IOSTANDARD LVCMOS33 [get_ports cmos1_sda] set_property IOSTANDARD LVCMOS33 [get_ports {cmos1_d[9]}] set_property IOSTANDARD LVCMOS33 [get_ports {cmos1_d[8]}] set_property IOSTANDARD LVCMOS33 [get_ports cmos1_scl] set_property IOSTANDARD LVCMOS33 [get_ports {cmos1_d[5]}] set_property IOSTANDARD LVCMOS33 [get_ports {cmos1_d[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {cmos1_d[4]}] set_property IOSTANDARD LVCMOS33 [get_ports {cmos1_d[6]}] set_property IOSTANDARD LVCMOS33 [get_ports {cmos1_d[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {cmos1_d[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {cmos1_d[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {cmos1_d[2]}] set_property IOSTANDARD LVCMOS33 [get_ports cmos1_pclk] set_property IOSTANDARD LVCMOS33 [get_ports cmos1_href] set_property IOSTANDARD LVCMOS33 [get_ports cmos1_vsync] set_property IOSTANDARD LVCMOS33 [get_ports cmos1_reset] set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets cmos1_pclk_IBUF] set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets cmos2_pclk_IBUF]
同样配置 run 的选项如下面的图中所示:
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 68
ALINX 黑金 Zynq7000 开发平台配套教程第二部
双目运行实物图
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 69
ALINX 黑金 Zynq7000 开发平台配套教程第二部
第 5 章 7 寸液晶屏模块的使用
在以往单纯的 FPGA 设计人机交互非常麻烦,往往需要再配置一个处理器用于人机交互,
zynq 的出现大大方便了 FPGA 设计需要人机交互的设计。液晶屏在人机交互中是一个非常常见
的部件,在前面教程中我们介绍了 VDMA 结合 HDMI 的显示例程,本章讲解黑金 7 寸液晶屏
的使用。
5.1 7 寸 LCD 屏模块说明介绍
黑金 7寸 LCD屏模块(AN070)采用台湾友达光电的 7寸 TFT LCD液晶屏, 液晶屏的型号为
A070VW05V2。AN070 LCD 屏模块由 TFT 液晶屏和驱动板组成,AN070 实物照片如下:
AN070 LCD 屏正面图
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 70
ALINX 黑金 Zynq7000 开发平台配套教程第二部
AN070 LCD 屏背面图
以下为 AN070 液晶屏详绅参数:
液晶模块尺寸:见下图1;
液晶屏幕尺寸:7.0 寸(对角线);
显示像素:800 (水平) x 480 (垂直);
颜色深度:16.7M 种颜色 (RGB 24 位色);
供电和功耗:单电源供电 5V, 功耗为 1.8 瓦;
5.2 LCD 屏的驱动时序
LCD 屏显示方式从屏幕左上角一点开始,从左像右逐点显示,每显示完一行,再回到屏幕的
左边下一行的起始位置,在这期间,需要对行迚行消隐,每行结束时,用行同步信号迚行同步;
LCD 的驱动有两种方式,一种为 HV 模式,另一种为 DE 模式,这两种模式都能驱动 LCD 屏,
数据在 DCLK 的上升沿采样。以下为行显示的时序图:
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 71
ALINX 黑金 Zynq7000 开发平台配套教程第二部
LCD 行的显示时序参数如下表所示:
当显示完所有的行,形成一帧,用场同步信号迚行场同步,幵使 LCD 显示回到屏幕左上方,
同时迚行场消隐,开始下一帧。以下为列显示的时序图:
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 72
ALINX 黑金 Zynq7000 开发平台配套教程第二部
LCD 列的显示时序参数如下表所示:
5.3 zynq 的硬件系统设计
7 寸液晶屏的硬件系统和 VDMA 测试有很多相似的的地方,主要差别就是 VDMA 通过
HDMI 显示,需要添加 HDMI 编码输出模块,而丏 HDMI 的分辨率是可发的,但是对于固定型
号的液晶屏的分辨率是固定的。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 73
ALINX 黑金 Zynq7000 开发平台配套教程第二部
在完成 zynq 的原理图设计以后,我们没有直接使用自动生成的 verilog 做为顶层模块,又
建立的一个 top.v 做为顶层,top.v 里对视频输出接口做了一级寄存器输出的,这里没有太多原
因,只是笔者的经验戒者习惯问题,像素时钟 PCLK 做了一个反向输出,液晶屏的背光控制没
有采用 PWM,而是用最亮,建议大家使用的时候降低亮度,节省功耗。
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////
//////////
// Company:
// Engineer:
//
// Create Date: 2016/12/16 11:45:01
// Design Name:
// Module Name: top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////
//////////
module top(
inout [14:0]DDR_addr,
inout [2:0]DDR_ba,
inout DDR_cas_n,
inout DDR_ck_n,
inout DDR_ck_p,
inout DDR_cke,
inout DDR_cs_n,
inout [3:0]DDR_dm,
inout [31:0]DDR_dq,
inout [3:0]DDR_dqs_n,
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 74
ALINX 黑金 Zynq7000 开发平台配套教程第二部
inout [3:0]DDR_dqs_p,
inout DDR_odt,
inout DDR_ras_n,
inout DDR_reset_n,
inout DDR_we_n,
inout FIXED_IO_ddr_vrn,
inout FIXED_IO_ddr_vrp,
inout [53:0]FIXED_IO_mio,
inout FIXED_IO_ps_clk,
inout FIXED_IO_ps_porb,
inout FIXED_IO_ps_srstb,
output lcd_dclk,
output lcd_bl_pwm,
output lcd_hsync,
output lcd_vsync,
output lcd_de,
output[7:0] lcd_r,
output[7:0] lcd_g,
output[7:0] lcd_b
);
wire vid_io_out_clk;
wire[23:0] vid_io_out_data;
wire vid_io_out_active_video;
wire vid_io_out_hsync;
wire vid_io_out_vsync;
reg[23:0] vid_io_out_data_d0;
reg vid_io_out_active_video_d0;
reg vid_io_out_hsync_d0;
reg vid_io_out_vsync_d0;
assign lcd_dclk = ~vid_io_out_clk;
assign lcd_bl_pwm = 1'b1;
assign lcd_hsync = vid_io_out_hsync_d0;
assign lcd_vsync = vid_io_out_vsync_d0;
assign lcd_de = vid_io_out_active_video_d0;
assign lcd_r = vid_io_out_data_d0[23:16];
assign lcd_g = vid_io_out_data_d0[15: 8];
assign lcd_b = vid_io_out_data_d0[ 7: 0];
always@(posedge vid_io_out_clk)
begin
vid_io_out_data_d0 <= vid_io_out_data;
vid_io_out_active_video_d0 <= vid_io_out_active_video;
vid_io_out_hsync_d0 <= vid_io_out_hsync;
vid_io_out_vsync_d0 <= vid_io_out_vsync;
end
system_wrapper system_m0
(
.DDR_addr ( DDR_addr ),
.DDR_ba ( DDR_ba ),
.DDR_cas_n ( DDR_cas_n ),
.DDR_ck_n ( DDR_ck_n ),
.DDR_ck_p ( DDR_ck_p ),
.DDR_cke ( DDR_cke ),
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 75
ALINX 黑金 Zynq7000 开发平台配套教程第二部
.DDR_cs_n ( DDR_cs_n ),
.DDR_dm ( DDR_dm ),
.DDR_dq ( DDR_dq ),
.DDR_dqs_n ( DDR_dqs_n ),
.DDR_dqs_p ( DDR_dqs_p ),
.DDR_odt ( DDR_odt ),
.DDR_ras_n ( DDR_ras_n ),
.DDR_reset_n ( DDR_reset_n ),
.DDR_we_n ( DDR_we_n ),
.FIXED_IO_ddr_vrn ( FIXED_IO_ddr_vrn ),
.FIXED_IO_ddr_vrp ( FIXED_IO_ddr_vrp ),
.FIXED_IO_mio ( FIXED_IO_mio ),
.FIXED_IO_ps_clk ( FIXED_IO_ps_clk ),
.FIXED_IO_ps_porb ( FIXED_IO_ps_porb ),
.FIXED_IO_ps_srstb ( FIXED_IO_ps_srstb ),
.vid_io_out_active_video (vid_io_out_active_video ),
.vid_io_out_clk (vid_io_out_clk ),
.vid_io_out_data (vid_io_out_data ),
.vid_io_out_field ( ),
.vid_io_out_hblank ( ),
.vid_io_out_hsync (vid_io_out_hsync ),
.vid_io_out_vblank ( ),
.vid_io_out_vsync (vid_io_out_vsync )
);
endmodule
5.4 板上验证
和前面的例程一样,编译生成 bit 文件,然后导出硬件,运行 SDK。7 寸液晶屏连接到开
収板的 J10 扩展口,按下图所示的运行配置,点击 run,可看到和 VDMA 测试例程一样,液晶
屏上会显示小猫的图片。
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 76
ALINX 黑金 Zynq7000 开发平台配套教程第二部
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 77
ALINX 黑金 Zynq7000 开发平台配套教程第二部
第 6 章 7 寸触摸屏的使用
黑金除了普通 7 寸液晶屏模块外,还有一个带电容触摸的 7 寸液晶屏,是在 7 寸液晶屏的
基础上加入了电容触摸外屏和触摸控制器,所以显示部分完全和普通 7 寸液晶屏一样。本章的
重点在于掌握触摸控制器的使用以及带触摸功能的 GUI 使用。
6.1 7 寸 LCD 触摸屏说明介绍
黑金 7 寸 LCD 触摸屏模块(AN071)是由 7 寸 TFT LCD 屏和电容触摸屏组合而成,LCD 屏
采用台湾友达光电的 7 寸 TFT LCD 液晶屏, 液晶屏的型号为 A070VW05V2。电容触摸屏采用
创天泓电子公司 7 寸电容触摸屏,电容触摸屏的型号为 CTH-07002。
AN071 LCD 触摸屏模块由 TFT 液晶屏,电容触摸屏和驱动板组成,AN071 实物照片如
下:
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 78
ALINX 黑金 Zynq7000 开发平台配套教程第二部
6.2 触摸屏接口时序
FPGA 开収板和电容触摸屏之间采用 CTPM 的接口,接口的电平为 2.8V~3.3V。串行接口
支持 SPI 和 I2C 接口中的一个,本 LCD 触摸屏为 I2C 接口。除了串行接口,还有两个信号分别
为“/INT”和“/Wake", “/INT”为触摸屏収送给 FPGA 的中断信号,如果有触摸动作,会触
収此信号,低电平有效。"/Wake"信号为 CTP 模块唤醒信号,也相当于复位信号,低电平 CTP
模块处于复位状态,高电平正常工作。
触摸屏 CTP 模块的串口通信的时序为 IIC 的读写标准,CTP 模块处于 IIC 从设备,FPGA
处于主设备。FPGA 通过 IIC 总线读写触摸屏 CTP 模块里的寄存器。具体的 IIC 读写时序如下:
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 79
ALINX 黑金 Zynq7000 开发平台配套教程第二部
触摸控制器检测到有触摸行为以后会使能中断信号,这个时候 FPGA 戒 PS 可以通过 IIC 通
道读叏触摸的状态信息。具体的通信格式可参考 7 寸触摸屏相关文档“communication
protocal.pdf”。
6.3 uGUI 的使用
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 80
ALINX 黑金 Zynq7000 开发平台配套教程第二部
第 7 章 裸机文件系统 FatFS 的使用
7.1
7.2
7.3
7.4
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 81
ALINX 黑金 Zynq7000 开发平台配套教程第二部
第 8 章 开源 TCP/IP 协议栈 Lwip 的使用
8.1
8.2
8.3
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 82
ALINX 黑金 Zynq7000 开发平台配套教程第二部
第 9 章 Linux 下无驱动直接使用 PL 端设备自定义 IP RTC
9.1 Vivado 工程创建
9.2 ZYNQ 系统的配置
9.3 硬件导入 SDK
ALINX 黑金 Zynq7000 系列开发宝典 http://www.heijin.org 83
ALINX 黑金 Zynq7000 开发平台配套教程第二部