BT656视频输出Verilog实现

AI助手已提取文章相关产品:

BT656 Verilog实现720×576视频输出的技术实践

在工业相机、医疗成像设备和安防监控系统中,常常需要FPGA模拟标准视频信号与传统编解码芯片对接。而ITU-R BT.656作为广泛使用的并行数字视频接口,因其高兼容性和简洁的嵌入式同步机制,成为这类设计中的首选方案。

尤其当目标是生成符合PAL制式的720×576分辨率视频流时,如何用Verilog精确还原BT.656协议的行为,不仅考验对ITU标准的理解深度,也直接影响图像能否被下游处理器稳定锁定与显示。本文将从实际工程角度出发,拆解这一过程的核心逻辑,并提供可综合、易调试的代码框架。


BT656协议的本质:没有H/V Sync的同步艺术

传统TTL RGB接口依赖独立的HSYNC和VSYNC信号来标记帧和行边界,这种方式虽然直观,但占用大量IO资源且抗干扰能力弱。相比之下,BT656巧妙地把同步信息“隐藏”在数据流中,仅通过8位并行总线即可完成完整视频传输。

其核心思想是—— 每行视频数据前后插入特殊的4字节包头 ,即SAV(Start of Active Video)和EAV(End of Active Video)。这些包头不携带图像内容,而是以固定模式 FF FF 00 XY 编码控制标志,接收端据此判断当前是否处于有效区域、属于哪一场、以及是否为垂直消隐期。

例如:
- XY = 0x00 :SAV,位于有效视频区
- XY = 0x10 :EAV,位于有效视频区
- XY = 0x20 :SAV,位于垂直消隐区
- XY = 0x30 :EAV,位于垂直消隐区

其中 X 字节的三个关键位定义如下:

含义
F (bit0) 场标志:0=第一场,1=第二场(隔行扫描)
V (bit1) 垂直同步标志:0=有效行,1=垂直消隐
H (bit2) 行类型:0=SAV,1=EAV

这种设计使得整个系统无需额外引脚传递同步信号,极大简化了PCB布线,特别适合资源受限或高密度集成的应用场景。


720×576 PAL制式的关键时序参数

要让FPGA输出的视频能被标准设备识别,必须严格遵循ITU-R BT.601和BT.656规定的时序规范。对于PAL制式(576i),主要参数如下:

参数 数值
分辨率 720×576(有效像素)
扫描方式 隔行(Field 0 / Field 1)
帧率 25 fps(每秒50场)
行频 15,625 Hz
像素时钟 27 MHz(精确值通常为27.000或27.001 MHz)
每行总周期 864像素时钟
每帧总行数 625行(含消隐)

每一行由以下部分组成:

[Front Porch][HSYNC][Back Porch][Active Video][EAV][...]
     12         64      68          720        4

注意:虽然有效像素是720个,但由于YCbCr 4:2:2采样下每个像素对应两个字节(Y + Cb/Cr交替),因此在一个像素时钟周期内只能传输一个字节。这意味着 720个像素需1440个PCLK周期才能传完

此外,每帧包含625行,分为两个场,各约312.5行。场标志(F)在每帧结束时翻转一次,用于区分奇偶场。若此标志出错,可能导致画面闪烁或撕裂。


Verilog实现:状态机驱动的数据流调度

下面是一个可综合的BT656输出模块实现,采用有限状态机(FSM)精确控制SAV/EAV插入时机和数据流向。

接口定义

module bt656_generator (
    input         clk_27m,        // 27MHz 主时钟
    input         rst_n,          // 复位信号(低有效)
    input  [7:0]  video_y,        // 当前Y分量输入
    input  [7:0]  video_cbcr,     // 当前Cb/Cr分量输入(交替)
    input         valid_pixel,    // 当前像素有效标志
    output reg [7:0]  bt656_data, // BT656输出数据
    output reg        bt656_de,   // 数据使能(辅助诊断)
    output reg        field_out    // 当前场标识输出
);

bt656_de 虽非标准要求,但在调试阶段非常有用,可用于ILA抓取有效数据区间。

内部计数器与状态定义

reg [9:0] pixel_counter;   // 每行内的字节位置计数(最大864*2)
reg [9:0] line_counter;    // 行计数(0~624)
reg       field_flag;      // 场标志(0/1)

localparam 
    ST_IDLE     = 3'd0,
    ST_SAV      = 3'd1,
    ST_ACTIVE   = 3'd2,
    ST_ACTIVE_YC= 3'd3,   // 输出CbCr
    ST_EAV      = 3'd4,
    ST_HBLANK   = 3'd5;

reg [2:0] state;

核心状态机逻辑

always @(posedge clk_27m or negedge rst_n) begin
    if (!rst_n) begin
        state         <= ST_IDLE;
        pixel_counter <= 0;
        line_counter  <= 0;
        field_flag    <= 0;
        bt656_de      <= 0;
        bt656_data    <= 8'hFF;
        field_out     <= 0;
    end else begin
        case (state)

            ST_IDLE: begin
                bt656_data <= 8'hFF;
                if (pixel_counter == 0) begin
                    state <= ST_SAV;
                end else begin
                    pixel_counter <= pixel_counter + 1;
                end
            end

            ST_SAV: begin
                case (pixel_counter)
                    0,1: bt656_data <= 8'hFF;
                    2:   bt656_data <= 8'h00;
                    3: begin
                        // 构造XY字节:F=field_flag, V=0(有效区), H=0(SAV)
                        bt656_data <= {1'b0, field_flag, 1'b0, 1'b0};
                        bt656_de <= 1;
                        state <= ST_ACTIVE;
                    end
                    default: ;
                endcase
                pixel_counter <= pixel_counter + 1;

                if (pixel_counter == 3) begin
                    pixel_counter <= 0;
                end
            end

            ST_ACTIVE: begin
                if (valid_pixel) begin
                    bt656_data <= video_y;
                    state <= ST_ACTIVE_YC;
                end else begin
                    state <= ST_EAV;
                    pixel_counter <= 0;
                end
                bt656_de <= 1;
            end

            ST_ACTIVE_YC: begin
                bt656_data <= video_cbcr;
                bt656_de <= 1;
                state <= ST_ACTIVE;
                // 注意:下一个时钟继续判断valid_pixel
            end

            ST_EAV: begin
                case (pixel_counter)
                    0: bt656_data <= 8'hFF;
                    1: bt656_data <= 8'hFF;
                    2: bt656_data <= 8'h00;
                    3: begin
                        bt656_data <= {1'b0, field_flag, 1'b1, 1'b0}; // H=1 → EAV
                        bt656_de <= 0;
                        state <= ST_HBLANK;
                        pixel_counter <= 0;
                    end
                    default: ;
                endcase
                pixel_counter <= pixel_counter + 1;
            end

            ST_HBLANK: begin
                bt656_data <= 8'hxx; // 可填充测试色或保留
                if (pixel_counter >= (864 - 720 - 8)) begin // 消隐期剩余时间
                    if (line_counter == 624) begin
                        line_counter <= 0;
                        field_flag <= ~field_flag;
                        field_out  <= ~field_flag;
                    end else begin
                        line_counter <= line_counter + 1;
                    end
                    pixel_counter <= 0;
                    state <= ST_SAV;
                end else begin
                    pixel_counter <= pixel_counter + 1;
                end
            end

            default: state <= ST_IDLE;
        endcase
    end
end

关键设计要点说明

  1. 双周期交替输出 :由于Y和CbCr分时复用同一数据线,每个像素需两个PCLK周期完成传输。状态 ST_ACTIVE ST_ACTIVE_YC 配对实现这一点。
  2. valid_pixel信号来源 :通常由地址发生器模块提供,指示当前地址是否落在720×576的有效范围内。
  3. 场切换时机 :必须在第624行结束后立即翻转 field_flag ,否则会导致隔行错位。
  4. EAV后消隐处理 :水平消隐期长度为 864 - 720 = 144 像素时钟,减去SAV/EAV占用的8字节(等效于4像素周期),实际留空140个PCLK周期。

实际应用中的常见问题与对策

接收端无法锁定图像?

这是最常见的问题,原因多集中在同步码格式错误或时钟不稳定:

  • 检查波形 :使用ILA工具捕获 bt656_data ,确认是否存在连续的 FF FF 00 XX 序列。
  • 验证XY字段 :确保SAV/EAV的 H V F 位设置正确,特别是垂直消隐区应使用 V=1
  • 时钟质量 :27MHz时钟建议通过PLL锁相环生成,并走专用全局时钟网络,避免抖动过大导致采样失败。

如何快速验证功能?

初期可接入彩条生成模块作为数据源:

// 简单彩条:每80像素切换一次颜色
assign color_bar = pixel_counter[9:6];
assign video_y = {color_bar, color_bar[2:0]};
assign video_cbcr = ~color_bar;

这样可在监视器上看到明显的竖条图案,便于判断是否同步成功。

能否支持NTSC或其他分辨率?

完全可以。只需调整以下参数:

  • 每行总周期:NTSC为858像素时钟
  • 有效行数:NTSC为480行
  • 帧率:60Hz(场频59.94Hz)
  • 场计数上限改为524或525

原有状态机结构无需改动,仅需修改计数阈值即可适配。

资源优化建议

  • 若使用外部DDR存储图像,建议加入一行缓存(Line Buffer),避免频繁突发读取。
  • 将状态机合并为两级(如SAV→ACTIVE→EAV→BLANK),减少状态分支。
  • 在垂直消隐期间关闭不必要的逻辑模块以降低功耗。

典型系统架构与扩展方向

一个完整的视频生成系统通常包括以下几个模块:

+FPGA+
│
├─ PLL → 27MHz像素时钟
├─ Frame Buffer(SRAM/DDR) → 存储图像数据
├─ Address Generator → 扫描720×576地址空间
├─ Color Pattern Generator → 调试用彩条/棋盘格
└─ BT656 Generator → 输出至ADV7182、TVP5150等解码芯片

未来可拓展的方向包括:

  • 双向BT656收发器 :既能输出也能解析BT656流,构建视频桥接器。
  • 10-bit模式支持 :扩展至BT.656 10位格式,提升色彩精度。
  • OSD叠加功能 :在原始画面上叠加时间戳、LOGO等信息。
  • AXI-Stream集成 :适配Zynq平台,实现与PS端的高效数据交互。

掌握BT656协议的Verilog实现,不仅是理解数字视频底层机制的重要一步,更是通往专业级视频系统设计的必经之路。它教会我们如何在严格的时序约束下,精准调度每一个字节的传输,让看似简单的“数据流”承载起完整的视觉信息。

这种高度集成的设计思路,正引领着智能音视频设备向更可靠、更高效的方向演进。

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

您可能感兴趣的与本文相关内容

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值