FPGA 摄像头到屏幕完整链路:从 OV5640 采集到 HDMI 实时显示
概述
在视频监控、工业检测、医疗成像等领域,实时图像采集和显示已成为必不可少的功能。FPGA 因其高并行处理能力和低延迟特性,成为实现高性能视频处理系统的首选方案。
本文详细介绍基于 FPGA 的摄像头采集与 HDMI 显示系统设计,涵盖 OV5640 配置、DVP 数据采集、SDRAM 缓存管理、HDMI 时序驱动及工程实战验证。
基于 FPGA 实现 OV5640 摄像头采集并通过 HDMI 实时显示的完整系统架构。内容涵盖系统框架设计、OV5640 传感器基础与 SCCB 配置、DVP 接口时序与数据采集模块、SDRAM 乒乓缓存管理、VGA 时序生成及 TMDS 编码驱动,最后提供了顶层模块集成、引脚约束及时序约束的实战案例。重点讲解了图像数据流处理、跨时钟域同步及常见调试技巧,适用于视频监控与工业检测等嵌入式视频处理场景。
在视频监控、工业检测、医疗成像等领域,实时图像采集和显示已成为必不可少的功能。FPGA 因其高并行处理能力和低延迟特性,成为实现高性能视频处理系统的首选方案。
本文详细介绍基于 FPGA 的摄像头采集与 HDMI 显示系统设计,涵盖 OV5640 配置、DVP 数据采集、SDRAM 缓存管理、HDMI 时序驱动及工程实战验证。
一个完整的 FPGA 摄像头采集处理显示系统由以下几个主要部分组成:
FPGA 摄像头采集处理显示系统架构
├─ 1️⃣ 摄像头采集模块
│ ├─ OV5640 摄像头驱动
│ ├─ SCCB 配置接口(I2C 兼容)
│ └─ DVP 数据采集(PCLK/HREF/VSYNC)
├─ 2️⃣ 图像处理模块
│ ├─ 数据格式转换(RGB565/YUV422)
│ ├─ 图像缩放/裁剪
│ └─ 色彩空间转换
├─ 3️⃣ 存储缓存模块
│ ├─ SDRAM/DDR3 存储
│ ├─ 双端口 RAM 缓冲
│ └─ 乒乓帧缓冲管理
├─ 4️⃣ 显示输出模块
│ ├─ VGA 时序生成
│ ├─ HDMI 驱动控制
│ └─ TMDS 编码与差分输出
└─ 5️⃣ 时钟管理模块
├─ PLL 时钟生成
├─ 多时钟域同步
└─ 时序约束配置
| 模块名称 | 功能描述 | 关键参数 |
|---|---|---|
| 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