FPGA 摄像头到屏幕完整链路:从 OV5640 采集到 HDMI 实时显示
概述
在视频监控、工业检测、医疗成像等领域,实时图像采集和显示已成为必不可少的功能。FPGA 因其高并行处理能力和低延迟特性,成为实现高性能视频处理系统的首选方案。
本文详细介绍 OV5640 摄像头的工作原理与配置方法、DVP 接口数据采集的完整流程、SDRAM/DDR3 缓存管理与乒乓操作、HDMI 显示输出的时序与驱动,以及从采集到显示的完整系统设计。
FPGA 视频处理系统通过 OV5640 摄像头采集图像数据,经 DVP 接口传输至 FPGA。系统利用 SCCB 协议配置摄像头寄存器,通过行列计数器实现时序同步与 RGB565 格式转换。数据存入 SDRAM 进行乒乓操作缓存,解决采集与显示速率不匹配问题。最后通过 VGA 时序生成与 TMDS 编码驱动 HDMI 输出,实现低延迟实时显示。涉及跨时钟域处理、SDRAM 控制器集成及引脚时序约束等关键技术。
在视频监控、工业检测、医疗成像等领域,实时图像采集和显示已成为必不可少的功能。FPGA 因其高并行处理能力和低延迟特性,成为实现高性能视频处理系统的首选方案。
本文详细介绍 OV5640 摄像头的工作原理与配置方法、DVP 接口数据采集的完整流程、SDRAM/DDR3 缓存管理与乒乓操作、HDMI 显示输出的时序与驱动,以及从采集到显示的完整系统设计。
一个完整的 FPGA 摄像头采集处理显示系统由以下几个主要部分组成:
| 模块名称 | 功能描述 | 关键参数 |
|---|---|---|
| OV5640 驱动 | 摄像头初始化、寄存器配置、数据采集 | 分辨率、帧率、数据格式 |
| SCCB 控制器 | I2C 兼容的摄像头配置接口 | 时钟频率、地址宽度 |
| DVP 采集 | 并行数据采集、时序同步 | 像素时钟、行列同步 |
| 图像缓存 | 帧数据存储、读写管理 | 缓存大小、带宽 |
| VGA 驱动 | 显示时序生成、数据输出 | 分辨率、刷新率 |
| HDMI 驱动 | HDMI 信号编码、差分输出 | 分辨率、色深 |
摄像头 (OV5640) ↓ [DVP 接口:PCLK, HREF, VSYNC, Y[7:0]]
FPGA 采集模块 ↓ [16 位 RGB565 或 YUV422]
图像处理模块 ↓ [处理后的图像数据]
SDRAM/DDR3 缓存 ↓ [读取请求]
VGA/HDMI 驱动 ↓ [HDMI 差分信号]
显示器
关键时序特性:
OV5640 是 OmniVision 公司设计的一款高性能 CMOS 图像传感器,广泛应用于监控、医疗、工业检测等领域。
OV5640 核心特性:
OV5640 模组采用标准接口,主要引脚如下:
| 引脚名称 | 类型 | 功能描述 |
|---|---|---|
| XCLK | 输入 | 外部时钟输入(24-96MHz),驱动摄像头芯片 |
| PCLK | 输出 | 像素同步时钟,数据在其上升沿有效 |
| HREF | 输出 | 行同步信号(高电平表示有效数据) |
| VSYNC | 输出 | 帧同步信号(脉冲表示新帧开始) |
| Y[7:0] | 输出 | 8 位像素数据输出 |
| SIO_C | 输入 | SCCB 时钟线(类似 I2C 的 SCL) |
| SIO_D | I/O | SCCB 数据线(类似 I2C 的 SDA) |
| RESET | 输入 | 系统复位(低电平有效) |
| PWDN | 输入 | 掉电/省电模式(高电平有效) |
OV5640 采用 DVP(Digital Video Parallel)接口输出图像数据。
关键时序特性:
PCLK: ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘
HREF: ┌─────────────────────────┐ └─────────────────────────┘
DATA: [R4R0G5G3][G2G0B4B0][R4R0G5G3]... ↑第 1 字节 ↑第 2 字节 ↑第 3 字节
SCCB(Serial Camera Control Bus)是 OV 摄像头的配置接口,与 I2C 协议兼容。
SCCB 写操作流程:
SCCB 读操作流程:
摄像头初始化需要配置大量寄存器。以 VGA(640×480) 分辨率为例:
关键寄存器配置:
| 寄存器地址 | 功能描述 | 典型值 |
|---|---|---|
| 0x3008 | 系统复位与时钟控制 | 0x82 |
| 0x3103 | 时钟源选择 | 0x02 |
| 0x3017 | 时钟使能 | 0x00 |
| 0x3018 | 时钟使能 | 0x00 |
| 0x3034 | PLL 倍频系数 | 0x1A |
| 0x3035 | PLL 分频系数 | 0x21 |
| 0x3036 | PLL 系统分频 | 0x69 |
| 0x3037 | PLL 根分频 | 0x13 |
| 0x4300 | 输出格式选择 | 0x61(RGB565) |
| 0x5001 | ISP 控制 | 0x80 |
初始化步骤:
Verilog 初始化代码框架:
// SCCB 写操作
task write_sccb(input [15:0] addr, input [7:0] data);
begin
// 发送 START
sccb_start();
// 发送设备地址 (0x78)
sccb_write_byte(8'h78);
// 发送寄存器地址高字节
sccb_write_byte(addr[15:8]);
// 发送寄存器地址低字节
sccb_write_byte(addr[7:0]);
// 发送数据
sccb_write_byte(data);
// 发送 STOP
sccb_stop();
end
endtask
// 初始化序列
initial begin
write_sccb(16'h3008, 8'h82); // 系统复位
#100000; // 等待复位完成
write_sccb(16'h3103, 8'h02); // 时钟源选择
write_sccb(16'h3034, 8'h1A); // PLL 配置
// ... 更多寄存器配置
end
DVP 采集模块是连接摄像头和 FPGA 的关键桥梁,负责接收摄像头的并行数据流并进行时序同步。
模块功能:
行列计数器用于追踪当前像素在图像中的位置。
计数器工作原理:
Verilog 实现:
module dvp_capture(
input clk,
input rst_n,
input vsync, // 帧同步信号
input href, // 行同步信号
input [7:0] data, // 8 位像素数据
output [15:0] pix_data, // 16 位 RGB565 像素
output [11:0] haddr, // 行地址
output [11:0] vaddr, // 列地址
output data_vld // 数据有效
);
reg [11:0] h_cnt, v_cnt;
reg [7:0] data_r1, data_r2;
reg href_r, vsync_r;
// 打一拍用于边沿检测
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
href_r <= 0;
vsync_r <= 0;
data_r1 <= 0;
data_r2 <= 0;
end
else
begin
href_r <= href;
vsync_r <= vsync;
data_r1 <= data;
data_r2 <= data_r1;
end
end
// 行计数器
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) h_cnt <= 0;
else if(href_r) h_cnt <= h_cnt + 1;
else h_cnt <= 0;
end
// 列计数器
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) v_cnt <= 0;
else if({vsync_r, vsync} == 2'b10) // VSYNC 下降沿
v_cnt <= 0;
else if({href_r, href} == 2'b10) // HREF 下降沿
v_cnt <= v_cnt + 1;
end
// RGB565 数据拼接(两个 8 位数据组成一个 16 位像素)
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) pix_data <= 0;
else pix_data <= {pix_data[7:0], data_r2};
end
// 数据有效信号(每两个时钟周期产生一个有效像素)
assign data_vld = href_r && h_cnt[0];
assign haddr = h_cnt[11:1];
assign vaddr = v_cnt;
endmodule
OV5640 输出 8 位数据,需要转换为 16 位 RGB565 格式。
RGB565 格式说明:
第 1 字节:[R4 R3 R2 R1 R0 G5 G4 G3]
第 2 字节:[G2 G1 G0 B4 B3 B2 B1 B0]
合并后:[R4 R3 R2 R1 R0 G5 G4 G3 G2 G1 G0 B4 B3 B2 B1 B0]
转换逻辑:
关键设计要点:
稳定性改进代码:
// 丢弃初始帧
reg [3:0] frame_cnt;
reg output_enable;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
frame_cnt <= 0;
output_enable <= 0;
end
else if({vsync_r, vsync} == 2'b10)
begin
if(frame_cnt < 10) frame_cnt <= frame_cnt + 1;
else output_enable <= 1;
end
end
// 最终数据有效信号
assign data_vld = href_r && h_cnt[0] && output_enable;
完整的采集模块需要与 SDRAM 控制器集成,实现数据的写入。
模块接口:
集成框架:
// 采集模块输出
wire [15:0] capture_data;
wire [11:0] capture_h, capture_v;
wire capture_vld;
dvp_capture u_capture(
.clk(pclk),
.rst_n(rst_n),
.vsync(vsync),
.href(href),
.data(dvp_data),
.pix_data(capture_data),
.haddr(capture_h),
.vaddr(capture_v),
.data_vld(capture_vld)
);
// 计算 SDRAM 写地址
wire [31:0] write_addr = {capture_v, capture_h} << 1;
// 连接到 SDRAM 写端口
assign sdram_wr_data = capture_data;
assign sdram_wr_addr = write_addr;
assign sdram_wr_en = capture_vld;
摄像头采集的高速数据流无法直接驱动显示器,需要通过缓存实现采集与显示的解耦。
为什么需要缓存?
缓存容量计算:
单帧容量 = 宽度 × 高度 × 字节数
VGA(640×480): 640 × 480 × 2 = 614.4KB
1080P(1920×1080): 1920 × 1080 × 2 = 4.15MB
乒乓操作是 FPGA 视频处理中的经典设计模式,通过双缓冲实现无缝数据流处理。
乒乓操作流程:
时间轴:T0 T1 T2 T3 T4
├──────┼──────┼──────┼──────┤
写入:[缓冲 A 写入第 1 帧][缓冲 B 写入第 2 帧][缓冲 A 写入第 3 帧]
读取:[缓冲 A 读取第 1 帧][缓冲 B 读取第 2 帧]
优势:采集和显示同时进行,无停顿
乒乓操作的关键特性:
帧缓冲管理模块负责协调采集和显示的读写操作。
帧缓冲地址分配:
SDRAM 地址空间分配(以 4MB 为例)
┌─────────────────────────────┐
│ 缓冲 A (帧 0): 0x00000 - 0x9FFFF │ 640KB
├─────────────────────────────┤
│ 缓冲 B (帧 1): 0xA0000 - 0x13FFFF │ 640KB
├─────────────────────────────┤
│ 缓冲 C (帧 2): 0x140000 - 0x1DFFFF │ 640KB
├─────────────────────────────┤
│ 保留区域
└─────────────────────────────┘
帧缓冲切换逻辑:
module frame_buffer_ctrl(
input clk,
input rst_n,
input vsync, // 采集帧同步
input display_vsync, // 显示帧同步
output [31:0] write_base_addr, // 采集写地址
output [31:0] read_base_addr, // 显示读地址
output frame_switch_flag // 帧切换标志
);
reg [1:0] write_frame_idx; // 采集帧索引 (0-2)
reg [1:0] read_frame_idx; // 显示帧索引 (0-2)
reg vsync_r, display_vsync_r;
// 采集帧切换
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) write_frame_idx <= 0;
else if({vsync_r, vsync} == 2'b10) // VSYNC 下降沿
write_frame_idx <= (write_frame_idx + 1) % 3;
end
// 显示帧切换(延迟一帧)
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) read_frame_idx <= 0;
else if({display_vsync_r, display_vsync} == 2'b10)
read_frame_idx <= (read_frame_idx + 1) % 3;
end
// 地址计算
assign write_base_addr = write_frame_idx * 32'hA0000;
assign read_base_addr = read_frame_idx * 32'hA0000;
assign frame_switch_flag = (write_frame_idx != read_frame_idx);
endmodule
SDRAM 控制器通常由 FPGA 厂商提供的 IP 核生成。
SDRAM 控制器接口:
读写操作时序:
写操作:
clk: ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ └─┘ └─┘ └─┘ └─┘ └─┘
wr_en: ┌─────────┐
wr_addr: [地址 A][地址B]
wr_data: [数据 1][数据 2]
↑写入延迟 (通常 2-3 个周期)
读操作:
rd_en: ┌─────────┐
rd_addr: [地址A]
rd_data: [数据 1][数据 2]
↑读取延迟 (通常 3-4 个周期)
在缓存中的图像可进行各种处理。
常见图像处理操作:
简单的灰度转换示例:
// RGB565 转灰度
wire [7:0] gray = (r[4:0] * 77 + g[5:0] * 150 + b[4:0] * 29) >> 8;
// 灰度转 RGB565
wire [15:0] gray_rgb565 = {gray[7:3], gray[7:2], gray[7:3]};
采集、处理、显示可能工作在不同时钟域。
跨时钟域同步方法:
异步 FIFO 应用:
// 采集时钟域写入,显示时钟域读出
async_fifo #( .WIDTH(16), .DEPTH(1024) ) u_fifo(
.wr_clk(pclk),
.wr_en(capture_vld),
.wr_data(capture_data),
.rd_clk(display_clk),
.rd_en(display_rd_en),
.rd_data(display_data),
.empty(fifo_empty),
.full(fifo_full)
);
HDMI(High-Definition Multimedia Interface)是现代显示设备的标准接口。
HDMI 版本与支持分辨率:
| HDMI 版本 | 最高分辨率 | 带宽 | 发布年份 |
|---|---|---|---|
| HDMI 1.4 | 4K@30Hz | 10.2Gbps | 2008 |
| HDMI 2.0 | 4K@60Hz | 18Gbps | 2013 |
| HDMI 2.1 | 8K@60Hz | 48Gbps | 2017 |
HDMI 19 针接口定义:
HDMI 接口引脚分布
┌─────────────────────────────┐
│ 1 2 3 4 5 6 7 8 9 │ 第一排
│ 10 11 12 13 14 15 16 17 18 │ 第二排
│ 19 │ 第三排
└─────────────────────────────┘
关键引脚:
- 1-3: TMDS 数据通道 0(蓝色)
- 4-6: TMDS 数据通道 1(绿色)
- 7-9: TMDS 数据通道 2(红色)
- 10-12: TMDS 时钟通道
- 13: CEC(消费电子控制)
- 14: 接地
- 15-16: DDC(显示数据通道)
- 17-18: 接地
- 19: +5V 电源
HDMI 显示基于 VGA 时序标准。VGA 时序定义了像素、行、帧的同步关系。
VGA 时序参数(1080P@60Hz 为例):
水平时序:
总像素数:2200
有效像素:1920
前廊 (Front Porch): 88
同步脉冲 (Sync): 44
后廊 (Back Porch): 148
垂直时序:
总行数:1125
有效行:1080
前廊:4
同步脉冲:5
后廊:36
VGA 时序生成模块:
module vga_timing(
input clk, // 像素时钟
input rst_n,
output hsync, // 行同步
output vsync, // 帧同步
output de, // 数据有效
output [11:0] haddr,// 水平地址
output [11:0] vaddr // 垂直地址
);
parameter H_TOTAL = 2200;
parameter H_ACTIVE = 1920;
parameter H_SYNC_START = 2008;
parameter H_SYNC_END = 2052;
parameter V_TOTAL = 1125;
parameter V_ACTIVE = 1080;
parameter V_SYNC_START = 1084;
parameter V_SYNC_END = 1089;
reg [11:0] h_cnt, v_cnt;
// 水平计数器
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) h_cnt <= 0;
else if(h_cnt == H_TOTAL - 1) h_cnt <= 0;
else h_cnt <= h_cnt + 1;
end
// 垂直计数器
always @(posedge clk or negedge rst_n)
begin
if(!rst_n) v_cnt <= 0;
else if(h_cnt == H_TOTAL - 1)
begin
if(v_cnt == V_TOTAL - 1) v_cnt <= 0;
else v_cnt <= v_cnt + 1;
end
end
// 同步信号生成
assign hsync = (h_cnt >= H_SYNC_START) && (h_cnt < H_SYNC_END);
assign vsync = (v_cnt >= V_SYNC_START) && (v_cnt < V_SYNC_END);
assign de = (h_cnt < H_ACTIVE) && (v_cnt < V_ACTIVE);
assign haddr = h_cnt;
assign vaddr = v_cnt;
endmodule
HDMI 使用 TMDS(Transition Minimized Differential Signaling)编码传输数据。
TMDS 编码特点:
TMDS 编码流程:
8 位数据 → 8B/10B 编码 → 序列化 → 差分驱动 → HDMI 输出
FPGA 中的 TMDS 实现:
完整的 HDMI 驱动模块集成 VGA 时序和数据输出。
HDMI 驱动模块框架:
module hdmi_driver(
input clk, // 像素时钟
input clk_5x, // 5 倍像素时钟(用于 TMDS)
input rst_n,
input [15:0] rgb_data, // RGB565 数据
output hdmi_clk_p, hdmi_clk_n, // TMDS 时钟
output [2:0] hdmi_d_p, // TMDS 数据正
output [2:0] hdmi_d_n // TMDS 数据负
);
wire hsync, vsync, de;
wire [11:0] haddr, vaddr;
// VGA 时序生成
vga_timing u_vga(
.clk(clk),
.rst_n(rst_n),
.hsync(hsync),
.vsync(vsync),
.de(de),
.haddr(haddr),
.vaddr(vaddr)
);
// 数据读取与 TMDS 编码
// ... TMDS 编码逻辑 ...
// 差分驱动输出
// ... 差分驱动逻辑 ...
endmodule
实际应用中常使用专用 HDMI 驱动芯片。
常见芯片对比:
| 芯片型号 | 最高分辨率 | 接口 | 功耗 | 应用 |
|---|---|---|---|---|
| SiI9134 | 1080P@60Hz | LVDS | 低 | 工业应用 |
| ADV7511 | 4K@30Hz | I2C | 中 | 消费类 |
| TFP410 | 1080P@60Hz | DVI | 低 | 显示器 |
SiI9134 集成方案:
FPGA → 并行 RGB 数据 → SiI9134 → HDMI 输出
I2C 配置接口
常见问题与解决方案:
调试工具:
一个完整的 FPGA 摄像头采集显示工程通常包含以下文件结构:
project_root/
├── rtl/ # RTL 设计文件
│ ├── top.v # 顶层模块
│ ├── dvp_capture.v # DVP 采集模块
│ ├── frame_buffer_ctrl.v # 帧缓冲控制
│ ├── vga_timing.v # VGA 时序生成
│ ├── hdmi_driver.v # HDMI 驱动
│ ├── sccb_master.v # SCCB 控制器
│ └── pll.v # PLL 时钟生成
├── sim/ # 仿真文件
│ ├── tb_dvp_capture.v # DVP 采集仿真
│ └── tb_hdmi_driver.v # HDMI 驱动仿真
├── constraints/ # 约束文件
│ ├── pins.xdc # 引脚约束
│ └── timing.xdc # 时序约束
├── ip/ # IP 核
│ ├── sdram_ctrl.xci # SDRAM 控制器
│ └── clk_pll.xci # PLL 时钟
└── doc/ # 文档
└── design_spec.md # 设计规范
顶层模块连接所有子模块,实现完整的数据流。
顶层模块框架:
module top(
input clk_100m, // 100MHz 外部时钟
input rst_n, // 复位
// 摄像头接口
input [7:0] dvp_data,
input dvp_pclk,
input dvp_href,
input dvp_vsync,
output dvp_xclk,
output dvp_reset,
output dvp_pwdn,
// SCCB 接口
inout sccb_sda,
inout sccb_scl,
// HDMI 接口
output hdmi_clk_p, hdmi_clk_n,
output [2:0] hdmi_d_p, hdmi_d_n,
// 调试接口
output [7:0] led,
input [3:0] btn
);
// 时钟生成
wire pclk, clk_100m_pll, clk_5x;
clk_pll u_pll(
.clk_in(clk_100m),
.clk_out1(pclk), // 50MHz 像素时钟
.clk_out2(clk_100m_pll),
.clk_out3(clk_5x) // 250MHz TMDS 时钟
);
// DVP 采集
wire [15:0] capture_data;
wire [11:0] capture_h, capture_v;
wire capture_vld;
dvp_capture u_capture(
.clk(pclk),
.rst_n(rst_n),
.vsync(dvp_vsync),
.href(dvp_href),
.data(dvp_data),
.pix_data(capture_data),
.haddr(capture_h),
.vaddr(capture_v),
.data_vld(capture_vld)
);
// 帧缓冲控制
wire [31:0] write_addr, read_addr;
frame_buffer_ctrl u_fbuf(
.clk(pclk),
.rst_n(rst_n),
.vsync(dvp_vsync),
.display_vsync(display_vsync),
.write_base_addr(write_addr),
.read_base_addr(read_addr)
);
// SDRAM 控制器
wire [31:0] sdram_wr_addr, sdram_rd_addr;
wire [15:0] sdram_wr_data, sdram_rd_data;
wire sdram_wr_en, sdram_rd_en;
sdram_ctrl u_sdram(
.clk(clk_100m_pll),
.rst_n(rst_n),
.wr_addr(sdram_wr_addr),
.wr_data(sdram_wr_data),
.wr_en(sdram_wr_en),
.rd_addr(sdram_rd_addr),
.rd_data(sdram_rd_data),
.rd_en(sdram_rd_en),
// SDRAM 芯片接口
.sdram_clk(sdram_clk),
.sdram_cke(sdram_cke),
.sdram_cs_n(sdram_cs_n),
.sdram_ras_n(sdram_ras_n),
.sdram_cas_n(sdram_cas_n),
.sdram_we_n(sdram_we_n),
.sdram_ba(sdram_ba),
.sdram_a(sdram_a),
.sdram_dq(sdram_dq)
);
// HDMI 驱动
hdmi_driver u_hdmi(
.clk(pclk),
.clk_5x(clk_5x),
.rst_n(rst_n),
.rgb_data(display_data),
.hdmi_clk_p(hdmi_clk_p),
.hdmi_clk_n(hdmi_clk_n),
.hdmi_d_p(hdmi_d_p),
.hdmi_d_n(hdmi_d_n)
);
// SCCB 控制器(摄像头配置)
sccb_master u_sccb(
.clk(clk_100m),
.rst_n(rst_n),
.sda(sccb_sda),
.scl(sccb_scl)
);
endmodule
引脚约束文件定义 FPGA 引脚与外部接口的映射。
pins.xdc 示例(Xilinx):
# 时钟
set_property PACKAGE_PIN E3 [get_ports clk_100m]
set_property IOSTANDARD LVCMOS33 [get_ports clk_100m]
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk_100m]
# 复位
set_property PACKAGE_PIN D9 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
# DVP 接口
set_property PACKAGE_PIN A13 [get_ports dvp_pclk]
set_property PACKAGE_PIN B13 [get_ports dvp_href]
set_property PACKAGE_PIN C13 [get_ports dvp_vsync]
set_property PACKAGE_PIN {A14 B14 C14 D14 E14 F14 G14 H14} [get_ports {dvp_data[7:0]}]
set_property IOSTANDARD LVCMOS33 [get_ports dvp_*]
# SCCB 接口
set_property PACKAGE_PIN L18 [get_ports sccb_sda]
set_property PACKAGE_PIN M18 [get_ports sccb_scl]
set_property IOSTANDARD LVCMOS33 [get_ports sccb_*]
set_property PULLUP TRUE [get_ports sccb_sda]
set_property PULLUP TRUE [get_ports sccb_scl]
# HDMI 接口
set_property PACKAGE_PIN D17 [get_ports hdmi_clk_p]
set_property PACKAGE_PIN D18 [get_ports hdmi_clk_n]
set_property PACKAGE_PIN E18 [get_ports {hdmi_d_p[0]}]
set_property PACKAGE_PIN E19 [get_ports {hdmi_d_n[0]}]
set_property IOSTANDARD TMDS_33 [get_ports hdmi_*]
时序约束确保设计满足时序要求。
timing.xdc 示例:
# 多时钟域约束
create_clock -add -name pclk -period 20.00 [get_pins u_pll/clk_out1]
create_clock -add -name clk_5x -period 4.00 [get_pins u_pll/clk_out3]
# 时钟域交叉约束
set_clock_groups -asynchronous -group {sys_clk_pin} -group {pclk}
# 输入延迟约束
set_input_delay -clock pclk -min 2 [get_ports dvp_data*]
set_input_delay -clock pclk -max 8 [get_ports dvp_data*]
# 输出延迟约束
set_output_delay -clock clk_5x -min 0 [get_ports hdmi_*]
set_output_delay -clock clk_5x -max 2 [get_ports hdmi_*]
# 虚拟时钟用于 I/O 约束
create_clock -name virtual_clk -period 20.00
set_input_delay -clock virtual_clk -min 2 [get_ports sccb_*]
set_input_delay -clock virtual_clk -max 8 [get_ports sccb_*]
验证步骤:
常见问题排查:
典型性能指标:
优化建议:
本文详细讲解了 FPGA 摄像头采集到 HDMI 显示的完整链路:
| 模块 | 关键技术 | 核心参数 |
|---|---|---|
| 摄像头采集 | DVP 接口、SCCB 配置 | PCLK、HREF、VSYNC |
| 图像处理 | RGB565 格式、行列计数 | 分辨率、帧率 |
| 缓存管理 | 乒乓操作、帧缓冲 | SDRAM 容量、带宽 |
| 显示输出 | VGA 时序、TMDS 编码 | 分辨率、刷新率 |

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online