跳到主要内容FPGA 摄像头采集到 HDMI 显示完整链路实战 | 极客日志编程语言算法
FPGA 摄像头采集到 HDMI 显示完整链路实战
综述由AI生成基于 FPGA 实现 OV5640 摄像头采集并通过 HDMI 实时显示的完整方案。涵盖 DVP 接口时序、SCCB 配置、SDRAM 乒乓缓存管理以及 HDMI TMDS 编码输出。重点解析了行列计数、RGB565 格式转换、跨时钟域处理及顶层模块集成方法,提供了关键 Verilog 代码与约束配置示例,适合嵌入式视频系统开发参考。
热情13 浏览 FPGA 摄像头采集到 HDMI 显示完整链路实战
在视频监控、工业检测、医疗成像等领域,实时图像采集和显示已成为必不可少的功能。FPGA 因其高并行处理能力和低延迟特性,成为实现高性能视频处理系统的首选方案。
一、摄像头采集显示系统架构
1.1 系统整体框架
一个完整的 FPGA 摄像头采集处理显示系统由以下几个主要部分组成:
- 摄像头采集模块:OV5640 摄像头驱动、SCCB 配置接口(I2C 兼容)、DVP 数据采集(PCLK/HREF/VSYNC)
- 图像处理模块:数据格式转换(RGB565/YUV422)、图像缩放/裁剪、色彩空间转换
- 存储缓存模块:SDRAM/DDR3 存储、双端口 RAM 缓冲、乒乓帧缓冲管理
- 显示输出模块:VGA 时序生成、HDMI 驱动控制、TMDS 编码与差分输出
- 时钟管理模块:PLL 时钟生成、多时钟域同步、时序约束配置
1.2 核心模块功能
| 模块名称 | 功能描述 | 关键参数 |
|---|
| OV5640 驱动 | 摄像头初始化、寄存器配置、数据采集 | 分辨率、帧率、数据格式 |
| SCCB 控制器 | I2C 兼容的摄像头配置接口 | 时钟频率、地址宽度 |
| DVP 采集 | 并行数据采集、时序同步 | 像素时钟、行列同步 |
| 图像缓存 | 帧数据存储、读写管理 | 缓存大小、带宽 |
| VGA 驱动 | 显示时序生成、数据输出 | 分辨率、刷新率 |
| HDMI 驱动 | HDMI 信号编码、差分输出 | 分辨率、色深 |
1.3 数据流向与时序
摄像头 (OV5640) ↓ [DVP 接口:PCLK, HREF, VSYNC, Y[7:0]]
FPGA 采集模块 ↓ [16 位 RGB565 或 YUV422]
图像处理模块 ↓ [处理后的图像数据]
SDRAM/DDR3 缓存 ↓ [读取请求]
VGA/HDMI 驱动 ↓ [HDMI 差分信号]
显示器
关键时序特性:
- 摄像头输出像素时钟 PCLK(通常 24-96MHz)
- 行同步信号 HREF(高电平表示有效数据)
- 帧同步信号 VSYNC(脉冲表示新帧开始)
- 每个 PCLK 周期输出 8 位数据,RGB565 需要 2 个周期
二、OV5640 摄像头基础
2.1 OV5640 摄像头简介
OV5640 是 OmniVision 公司设计的一款高性能 CMOS 图像传感器,广泛应用于监控、医疗、工业检测等领域。
OV5640 核心特性:
- 像素规格:500 万像素(2592×1944 分辨率)
- 视频输出:支持 1080P、720P、VGA、QVGA 等多种分辨率
- :RGB565/RGB555/RGB444、YUV422/420、YCbCr422、JPEG
数据格式
帧率范围:15-60fps 可调(根据分辨率配置)功能支持:自动对焦 (AF)、自动曝光 (AEC)、自动白平衡 (AWB)功耗:150-200mW(工作功率)工作温度:-3070℃(稳定工作 050℃)2.2 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 | 输入 | 掉电/省电模式(高电平有效) |
2.3 DVP 接口时序详解
OV5640 采用 DVP(Digital Video Parallel)接口输出图像数据。
- 数据在 PCLK 上升沿有效
- HREF 高电平表示该行有效数据
- VSYNC 脉冲表示帧开始
- RGB565 格式:每个像素需要 2 个 PCLK 周期(16 位数据分两次输出)
PCLK: ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘
HREF: ┌─────────────────────────┐ └─────────────────────────┘
DATA: [R4R0G5G3][G2G0B4B0][R4R0G5G3]...
↑第 1 字节 ↑第 2 字节 ↑第 3 字节
2.4 SCCB 配置协议
SCCB(Serial Camera Control Bus)是 OV 摄像头的配置接口,与 I2C 协议兼容。
- 发送 START 信号
- 发送摄像头地址(0x78,7 位地址)
- 发送寄存器地址(16 位)
- 发送寄存器数据(8 位)
- 发送 STOP 信号
- 发送 START 信号
- 发送摄像头地址 + 写位
- 发送寄存器地址(16 位)
- 发送 RESTART 信号
- 发送摄像头地址 + 读位
- 读取寄存器数据(8 位)
- 发送 STOP 信号
2.5 OV5640 初始化配置
摄像头初始化需要配置大量寄存器。以 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 |
- 复位摄像头(RESET 拉低后拉高)
- 配置时钟系统(XCLK、PLL)
- 配置输出分辨率(ISP 输入/输出大小)
- 配置输出格式(RGB565/YUV422 等)
- 配置图像处理(白平衡、曝光、饱和度等)
- 启用输出(设置 0x3008 寄存器)
// 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
三、图像采集模块设计
3.1 DVP 采集模块架构
DVP 采集模块是连接摄像头和 FPGA 的关键桥梁,负责接收摄像头的并行数据流并进行时序同步。
- 行列计数与地址生成
- 数据缓冲与格式转换
- 时序同步与边沿检测
- 帧同步与数据有效性判断
3.2 行列计数器设计
- HREF 高电平时,行计数器递增
- HREF 下降沿时,行计数器清零,列计数器递增
- VSYNC 脉冲时,列计数器清零
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)
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
// 行计数器
always @(posedge clk or negedge rst_n)
if(!rst_n) h_cnt <= 0;
else if(href_r) h_cnt <= h_cnt + 1;
else h_cnt <= 0;
// 列计数器
always @(posedge clk or negedge rst_n)
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;
// RGB565 数据拼接(两个 8 位数据组成一个 16 位像素)
always @(posedge clk or negedge rst_n)
if(!rst_n) pix_data <= 0;
else pix_data <= {pix_data[7:0], data_r2};
// 数据有效信号(每两个时钟周期产生一个有效像素)
assign data_vld = href_r && h_cnt[0];
assign haddr = h_cnt[11:1];
assign vaddr = v_cnt;
endmodule
3.3 数据格式转换
OV5640 输出 8 位数据,需要转换为 16 位 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]
- 每个 PCLK 周期接收 8 位数据
- 两个周期后组成 16 位 RGB565 像素
- 使用移位寄存器实现数据拼接
3.4 时序同步与稳定性
- 打一拍处理:对所有输入信号进行打一拍,优化时序
- 边沿检测:使用 {pre_signal, signal} 检测上升/下降沿
- 初帧丢弃:系统启动后丢弃前 10 帧数据,确保图像稳定
- 跨时钟域:使用 FIFO 或同步器处理不同时钟域信号
// 丢弃初始帧
reg [3:0] frame_cnt;
reg output_enable;
always @(posedge clk or negedge rst_n)
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
// 最终数据有效信号
assign data_vld = href_r && h_cnt[0] && output_enable;
3.5 采集模块集成
完整的采集模块需要与 SDRAM 控制器集成,实现数据的写入。
- 输入:clk、rst_n、vsync、href、data[7:0]
- 输出:pix_data[15:0]、haddr[11:0]、vaddr[11:0]、data_vld
- 与 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;
四、图像处理与缓存管理
4.1 SDRAM/DDR3 缓存的必要性
摄像头采集的高速数据流无法直接驱动显示器,需要通过缓存实现采集与显示的解耦。
- 采集速率与显示速率不匹配
- 实现读写分离,避免数据冲突
- 存储完整帧数据,支持图像处理
- 缓冲高速数据流,提高系统稳定性
单帧容量 = 宽度 × 高度 × 字节数
VGA(640×480): 640 × 480 × 2 = 614.4KB
1080P(1920×1080): 1920 × 1080 × 2 = 4.15MB
4.2 乒乓操作原理
乒乓操作是 FPGA 视频处理中的经典设计模式,通过双缓冲实现无缝数据流处理。
时间轴:T0 T1 T2 T3 T4
├──────┼──────┼──────┼──────┤
写入:[缓冲 A 写入第 1 帧][缓冲 B 写入第 2 帧][缓冲 A 写入第 3 帧]
读取:[缓冲 A 读取第 1 帧][缓冲 B 读取第 2 帧]
优势:采集和显示同时进行,无停顿
- 采集与显示完全独立
- 避免读写冲突
- 无缝数据流处理
- 节省缓存空间(相比单缓冲)
4.3 帧缓冲管理
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)
if(!rst_n) write_frame_idx <= 0;
else if({vsync_r, vsync} == 2'b10) // VSYNC 下降沿
write_frame_idx <= (write_frame_idx + 1) % 3;
// 显示帧切换(延迟一帧)
always @(posedge clk or negedge rst_n)
if(!rst_n) read_frame_idx <= 0;
else if({display_vsync_r, display_vsync} == 2'b10)
read_frame_idx <= (read_frame_idx + 1) % 3;
// 地址计算
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
4.4 SDRAM 控制器集成
SDRAM 控制器通常由 FPGA 厂商提供的 IP 核生成。
- 用户侧:地址、数据、读写控制信号
- 芯片侧:行列地址、控制信号、数据总线
写操作:
clk: ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ └─┘ └─┘ └─┘ └─┘ └─┘
wr_en: ┌─────────┐
wr_addr: [地址 A][地址 B]
wr_data: [数据 1][数据 2]
↑写入延迟 (通常 2-3 个周期)
读操作:
rd_en: ┌─────────┐
rd_addr: [地址 A]
rd_data: [数据 1][数据 2]
↑读取延迟 (通常 3-4 个周期)
4.5 图像处理模块
- 色彩空间转换:RGB↔YUV
- 缩放/裁剪:改变分辨率
- 滤波:高斯、中值等
- 特征提取:边缘检测、角点检测
// 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]};
4.6 跨时钟域处理
- 异步 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 显示输出
5.1 HDMI 接口基础
HDMI(High-Definition Multimedia Interface)是现代显示设备的标准接口。
| HDMI 版本 | 最高分辨率 | 带宽 | 发布年份 |
|---|
| HDMI 1.4 | 4K@30Hz | 10.2Gbps | 2008 |
| HDMI 2.0 | 4K@60Hz | 18Gbps | 2013 |
| HDMI 2.1 | 8K@60Hz | 48Gbps | 2017 |
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 电源
5.2 VGA 时序生成
HDMI 显示基于 VGA 时序标准。VGA 时序定义了像素、行、帧的同步关系。
水平时序:
总像素数:2200
有效像素:1920
前廊 (Front Porch): 88
同步脉冲 (Sync): 44
后廊 (Back Porch): 148
垂直时序:
总行数:1125
有效行:1080
前廊:4
同步脉冲:5
后廊:36
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)
if(!rst_n) h_cnt <= 0;
else if(h_cnt == H_TOTAL - 1) h_cnt <= 0;
else h_cnt <= h_cnt + 1;
// 垂直计数器
always @(posedge clk or negedge rst_n)
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
// 同步信号生成
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
5.3 TMDS 编码与差分驱动
HDMI 使用 TMDS(Transition Minimized Differential Signaling)编码传输数据。
- 最小化信号转换,降低 EMI
- 8 位数据编码为 10 位
- 高速串行传输(165MHz-600MHz)
- 支持 HDCP 版权保护
8 位数据 → 8B/10B 编码 → 序列化 → 差分驱动 → HDMI 输出
- 使用 FPGA 内部的 SERDES(串行/并行转换器)
- 或使用外部 HDMI 驱动芯片(如 SiI9134)
- 配置 PLL 生成高速时钟
5.4 HDMI 驱动模块设计
完整的 HDMI 驱动模块集成 VGA 时序和数据输出。
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
5.5 常见 HDMI 驱动芯片
| 芯片型号 | 最高分辨率 | 接口 | 功耗 | 应用 |
|---|
| SiI9134 | 1080P@60Hz | LVDS | 低 | 工业应用 |
| ADV7511 | 4K@30Hz | I2C | 中 | 消费类 |
| TFP410 | 1080P@60Hz | DVI | 低 | 显示器 |
FPGA → 并行 RGB 数据 → SiI9134 → HDMI 输出
I2C 配置接口
5.6 HDMI 显示调试技巧
- 无信号输出
- 检查时钟是否正常
- 验证 VGA 时序参数
- 检查 HDMI 驱动芯片配置
- 显示异常(花屏、闪烁)
- 检查数据有效信号 (DE)
- 验证 RGB 数据格式
- 检查时序约束
- 分辨率不匹配
- 确认显示器支持该分辨率
- 检查 PLL 时钟配置
- 验证 VGA 时序参数
- 逻辑分析仪:观察 HDMI 信号
- 示波器:检查差分信号质量
- HDMI 测试仪:验证 EDID 和 HDCP
六、完整实战案例
6.1 工程架构设计
一个完整的 FPGA 摄像头采集显示工程通常包含以下文件结构:
project_root/
├── rtl/
│ ├── top.v
│ ├── dvp_capture.v
│ ├── frame_buffer_ctrl.v
│ ├── vga_timing.v
│ ├── hdmi_driver.v
│ ├── sccb_master.v
│ └── pll.v
├── sim/
│ ├── tb_dvp_capture.v
│ └── tb_hdmi_driver.v
├── constraints/
│ ├── pins.xdc
│ └── timing.xdc
├── ip/
│ ├── sdram_ctrl.xci
│ └── clk_pll.xci
└── doc/
└── design_spec.md
6.2 顶层模块集成
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
6.3 引脚约束配置
引脚约束文件定义 FPGA 引脚与外部接口的映射。
# 时钟
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_*]
6.4 时序约束配置
# 多时钟域约束
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_*]
6.5 上板验证与调试
- 编译综合,检查是否有错误
- 运行时序分析,确保满足约束
- 生成比特流文件
- 烧写 FPGA
- 观察 LED 指示灯
- 连接显示器,验证图像输出
- 使用逻辑分析仪调试信号
- 无图像输出:检查时钟、复位、SCCB 配置
- 图像异常:检查 DVP 时序、数据格式
- 显示器无信号:检查 HDMI 驱动、VGA 时序
6.6 性能指标与优化
- 分辨率:VGA(640×480)~1080P(1920×1080)
- 帧率:30fps~60fps
- 延迟:50~100ms(采集到显示)
- 资源占用:LUT 30%~50%,BRAM 40%~60%
- 时钟优化:使用 PLL 生成精确时钟
- 流水线设计:增加管道级数,提高吞吐量
- 缓存优化:使用 BRAM 而非 SDRAM 存储中间数据
- 并行处理:多路并行采集与处理
总结
本文详细讲解了 FPGA 摄像头采集到 HDMI 显示的完整链路。
| 模块 | 关键技术 | 核心参数 |
|---|
| 摄像头采集 | DVP 接口、SCCB 配置 | PCLK、HREF、VSYNC |
| 图像处理 | RGB565 格式、行列计数 | 分辨率、帧率 |
| 缓存管理 | 乒乓操作、帧缓冲 | SDRAM 容量、带宽 |
| 显示输出 | VGA 时序、TMDS 编码 | 分辨率、刷新率 |
- 系统设计:理解完整的数据流向与时序关系
- 模块设计:掌握各核心模块的设计方法
- 集成验证:学会顶层集成与约束配置
- 调试技巧:掌握常见问题的排查方法
- 图像处理:实现滤波、缩放、特征提取等算法
- 视频编码:集成 H.264/H.265 编码器
- 网络传输:通过以太网或 USB 传输视频流
- AI 加速:集成深度学习推理引擎
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Gemini 图片去水印
基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown转HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
- HTML转Markdown
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online