当前位置: 首页 > article >正文

FPGA通信之VGA与HDMI

文章目录

  • VGA
    • 基本概念:
      • 水平扫描:
      • 垂直扫描:
    • 时序如下:
    • 端口设计
    • 疑问
      • 为什么需要输出那么多端口
      • 不输出时钟怎么保证电子枪移动速度符合时序
      • VGA转HDMI
    • 仿真电路图
    • 代码
    • 总结:VGA看野火电子教程
  • HDMI
    • TMDS传输原理
    • 为什么使用TMDS
    • HDMI接口结构
      • HDMI_crl: 实现VGA转HDMI
        • 构成1:TMDS encoder模块
        • 构成2:并转串_差分输出模块
          • 调用原语:DDR(时钟沿双边采集)
    • 回顾:

为了做图像处理, 现在我们开始研究VGA与HDMI

VGA

基本概念:

水平扫描:

  • 有效数据段:显示图像的部分。
  • 右边界区域(Right Border):扫描完有效数据后的空白区域。
  • 水平前沿(Front Porch):扫描完有效数据但未收到同步信号前的空白时间段
  • 行同步信号脉冲(Sync Pulse):通知电子枪回到左侧。
  • 水平后沿(Back Porch):电子枪回到左侧的时间段。
  • 左边界区域(LEFT Border):显示图像前的空白区域。

垂直扫描:

  • 有效行段:显示图像的行。
  • 下边界区域(Bottom Border):扫描完所有行后的空白区域。
  • 垂直前沿(Front Porch):扫描完所有行但未收到同步信号前的空白时间段
  • 场同步信号脉冲(Sync Pulse):通知电子枪回到顶部。
  • 垂直后沿(Back Porch):电子枪回到顶部的时间段。
  • 上边界区域(Top Border):显示图像前的空白区域。

时序如下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
基于上述对VGA时序的详细分析,设计一个VGA控制器主要也就包括行计数器、场计数器,以及行、场同步信号在合适的时刻产生低电平脉冲,以及在显示有效区域将图像数据输出

  • 时间节点分析:
    行同步有效: 96个clk --> 0,1,2----95 —>95的下一个时钟加入下一步
    回扫时间: 40个clk --> 96, 97—135 -->135的下一个时钟加入下一步
    左缓冲边界: 8个clk --> 136,137—143 -->143的下一个时钟加入下一步
    数据段: 640个clk–> 144, 145–783 -->783的下一个时钟加入下一步
    右缓冲边界: 8个clk --> 784, 785–791 -->791的下一个时钟加入下一步
    等待回扫: 8个clk --> 792, 793–799 -->799的下一个时钟加入下一步
  • 现在对时钟的感知有以下进步:
    1. 三个点确定两个线段, 也就是两个时间段
    2. 但是现在应该有一个模型在脑子里, 也就是每一个时间点 右方 都有一个自己的时间段
    3. 假如从某个时间节点x开始要维持y个时间单元
    4. 根据第二点结论, 除原点x外我们需要y-1个时间点, 那么我们可以计算出最后一个时间节点的值为x+y-1, 例如从零时刻开始维持8个时钟周期, 那么最后一个时刻对应的节点为7

端口设计

在这里插入图片描述
or
在这里插入图片描述

疑问

为什么需要输出那么多端口

因为这个模块不是顶层模块, 所以需要增加很多输出, 作为内部变量方便顶层访问, 比如输出的计数器, 顶层模块访问后可以知道当前显示屏光标的位置,就可以在特定区域实现特定控制
如下为常用的顶层
module VGA (
input i_clk,
input i_arstn,
input [23:0] i_data,
output o_h_sync,
output o_v_sync,
output [23:0] o_data
// 可选隐藏:o_VGA_clk, o_VGA_BLK, o_VGA_ho_cnt, o_VGA_ve_cnt
);
而且, FPGA在连接显示屏前还需要一个DAC芯片(数字转模拟)

如图:顶层模块只需要三个干净的输出,野火电子教程
在这里插入图片描述

  1. 系统上电后,板卡传入系统时钟(sys_clk)和复位信号(sys_rst_n)到顶层模块;
  2. 系统时钟由顶层模块传入时钟生成模块(clk_gen),分频产生VGA工作时钟(vga_clk),作为图像数据生成模块(vga_pic)和VGA时序控制模块(vga_ctrl)的工作时钟;
  3. 图像数据生成模块以VGA时序控制模块传入的像素点坐标(pix_x,pix_y)为约束条件,生成待显示彩条图像的色彩信息(pix_data);
  4. 图像数据生成模块生成的彩条图像色彩信息传入VGA时序控制模块,在模块内部使用使能信号滤除掉非图像显示有效区域的图像数据,产生RGB色彩信息(rgb),在行、场同步信号(hsync、vsync)的同步作用下,将RGB色彩信息扫描显示到VGA显示器,显示出彩条图像

不输出时钟怎么保证电子枪移动速度符合时序

电子枪移动速度的同步原理
(1) 模拟信号的“自时钟”特性
CRT显示器内部的行扫描电路本质上是一个模拟振荡器,其振荡频率由以下因素锁定:
HSYNC信号的频率:显示器会强制将自身的行扫描频率与输入的HSYNC信号同步(类似锁相环PLL的原理)。
例如:在640x480@60Hz模式下,HSYNC频率为31.47kHz,显示器会自动调整电子枪的水平扫描速度以匹配这一频率。
(2) 电子枪的物理运动控制
行扫描电路:CRT内部的行偏转线圈(由锯齿波电流驱动)控制电子枪的水平移动速度。
锯齿波的斜率(即电子枪移动速度)由显示器电路根据HSYNC频率自动调整。
FPGA的RGB数据速率必须与电子枪的物理扫描速度匹配,但这通过以下方式保证:
FPGA以固定的像素时钟(如25.175MHz)生成RGB数据。
由于HSYNC频率是像素时钟的衍生信号*(如每800个像素时钟触发一次HSYNC),因此电子枪的移动速度自然与FPGA数据同步。

VGA转HDMI

https://blog.csdn.net/gslscyx/article/details/137930810

仿真电路图

调用锁相环IP生成25Mhz信号
在这里插入图片描述

代码

`timescale 1ns / 1ps
//****************************************VSCODE PLUG-IN**********************************// 
//---------------------------------------------------------------------------------------- 
// IDE :                   VSCODE      
// VSCODE plug-in version: Verilog-Hdl-Format-2.4.20240526
// VSCODE plug-in author : Jiang Percy 
//---------------------------------------------------------------------------------------- 
//****************************************Copyright (c)***********************************// 
// Copyright(C)            COMPANY_NAME
// All rights reserved      
// File name:               
// Last modified Date:     2025/05/17 22:22:41 
// Last Version:           V1.0 
// Descriptions:            
//---------------------------------------------------------------------------------------- 
// Created by:             USER_NAME
// Created date:           2025/05/17 22:22:41 
// Version:                V1.0 
// TEXT NAME:              VGA_top.v 
// PATH:                   D:\vivado\VGA\VGA_top.v 
// Descriptions:            
//                          
//---------------------------------------------------------------------------------------- 
//****************************************************************************************// module VGA_top(input                               sys_clk                    ,input                               sys_rst_n                  ,output                              o_horizon_syn              ,output                              o_vertical_syn             ,output             [  23: 0]        o_VGA_data                  
);//---------------------------------------------------------------------------------------// PLL锁相环IP调用, 将时钟频率定义为25MHZ                                                                                    //---------------------------------------------------------------------------------------wire                                PPL_clk                     ;//锁相环wire                                locked                      ;clk_wiz_0 instance_name(// Clock out ports.clk_out1                           (                          ),// output clk_out1.clk_out2                           (                          ),// output clk_out2.clk_out3                           (                          ),// output clk_out3.clk_out4                           (PPL_clk                   ),// output clk_out4// Status and control signals.reset                              (~sys_rst_n                     ),// input reset.locked                             (locked                    ),// output locked// Clock in ports.clk_in1                            (sys_clk)                  );//---------------------------------------------------------------------------------------//                                                                                     //---------------------------------------------------------------------------------------wire               [  23: 0]        w_VGA_data                  ;wire                                w_VGA_clk                   ;wire                                w_VGA_BLK                   ;wire               [   9: 0]        w_cnt_horizon               ;wire               [   9: 0]        w_cnt_vertical              ;
VGA_crl u_VGA(.i_clk                              (PPL_clk                   ),.i_arstn                            (sys_rst_n   && locked     ),.i_data                             (w_VGA_data                ),.o_h_sync                           (o_horizon_syn             ),.o_v_sync                           (o_vertical_syn            ),.o_data                             (o_VGA_data                ),.o_VGA_clk                          (w_VGA_clk                 ),// 输出一个同步时钟, 基于工程实践, 设置为输入时钟的反时钟更佳.o_VGA_BLK                          (w_VGA_BLK                 ),// 设置一个消隐信号, 似乎用不到.o_VGA_ho_cnt                       (w_cnt_horizon             ),// 方便顶层读取当前扫描位置.o_VGA_ve_cnt                       (w_cnt_vertical            ) // 方便顶层读取现在扫描位置
);VGA_pic u_VGA_pic(.clk                                (PPL_clk                   ),.rst_n                              (sys_rst_n    && locked    ),.i_cnt_horizon                      (w_cnt_horizon             ),// 从visible像素开始计算.i_cnt_vertical                     (w_cnt_vertical            ),// 从visible像素开始计算.o_data                             (w_VGA_data                ) 
);endmodule
// verilog 不支持链式条件, 必须分开
`timescale 1ns / 1ps
module VGA_pic(input                               clk                        ,input                               rst_n                      ,input              [   9: 0]        i_cnt_horizon              ,//从visible像素开始计算input              [   9: 0]        i_cnt_vertical             ,//从visible像素开始计算output             [  23: 0]        o_data                      
);//---------------------------------------------------------------------------------------// 时序参数定义:parameter                           VGA_HS_end                 = 10'd96,//水平同步器维持时间VGA_H_bach_Porch=10'd40,VGA_left_border=10'd8,VGA_H_DATA_time=10'd640,VGA_right_border=10'd8,VGA_H_front_Porch=10'd8;parameter                           period_horizon             = VGA_HS_end+VGA_H_bach_Porch+VGA_left_border+VGA_H_DATA_time+VGA_right_border+VGA_H_front_Porch;parameter                           VGA_h_visible_start        = VGA_HS_end+VGA_H_bach_Porch+VGA_left_border-1;parameter                           VGA_h_visible_end          = VGA_h_visible_start+VGA_H_DATA_time;parameter                           VGA_VS_end                 = 10'd2 ,//垂直同步器维持时间VGA_V_bach_Porch=10'd25,VGA_top_border=10'd8,VGA_V_DATA_time=10'd480,VGA_bottom_border=10'd8,VGA_V_front_Porch=10'd2;parameter                           period_vertical            = VGA_VS_end+VGA_V_bach_Porch+VGA_top_border +VGA_V_DATA_time+VGA_bottom_border+VGA_V_front_Porch;parameter                           VGA_v_visible_start        = VGA_VS_end+VGA_V_bach_Porch+VGA_top_border-1;parameter                           VGA_v_visible_end          = VGA_v_visible_start+VGA_V_DATA_time;//---------------------------------------------------------------------------------------//---------------------------------------------------------------------------------------//定义颜色编码localparamBLACK = 24'h000000,                                         //黑色BLUE = 24'h0000FF,                                          //蓝色RED = 24'hFF0000,                                           //红色PURPPLE =24'hFF00FF,                                        //紫色GREEN = 24'h00FF00,                                         //绿色CYAN = 24'h00FFFF,                                          //青色YELLOW = 24'hFFFF00,                                        //黄色WHITE = 24'hFFFFFF;                                         //白色//定义每个像素块的默认显示颜色值localparamR0_C0 = BLACK,                                              //第0行0列像素块R0_C1 = BLUE,                                               //第0行1列像素块R1_C0 = RED,                                                //第1行0列像素块R1_C1 = PURPPLE,                                            //第1行1列像素块R2_C0 = GREEN,                                              //第2行0列像素块R2_C1 = CYAN,                                               //第2行1列像素块R3_C0 = YELLOW,                                             //第3行0列像素块R3_C1 = WHITE;                                              //第3行1列像素块                                                                                    //---------------------------------------------------------------------------------------//---------------------------------------------------------------------------------------// 列检测wire                                C0_act                      ;assign                              C0_act                      = (0 <= i_cnt_horizon && i_cnt_horizon<320);wire                                C1_act                      ;assign                              C1_act                      = (320 <= i_cnt_horizon && i_cnt_horizon<640);// 行检测wire                                R1_act,R2_act,R3_act,R0_act  ;assign                              R0_act                      = (0<=i_cnt_vertical&& i_cnt_vertical<120);assign                              R1_act                      = (120<=i_cnt_vertical&&i_cnt_vertical<240);assign                              R2_act                      = (240<=i_cnt_vertical&& i_cnt_vertical<360);assign                              R3_act                      = (360<=i_cnt_vertical&& i_cnt_vertical<480);//---------------------------------------------------------------------------------------      reg                [  23: 0]        r_VGA_data                  ;always@(*)beginif (R3_act&C1_act) beginr_VGA_data = R3_C1;endelse if (R3_act&C0_act) beginr_VGA_data = R3_C0;endelse if (R2_act&C1_act) beginr_VGA_data = R2_C1;endelse if (R2_act&C0_act) beginr_VGA_data = R2_C0;endelse if (R1_act&C1_act) beginr_VGA_data = R1_C1;endelse if (R1_act&C0_act) beginr_VGA_data = R1_C0;endelse if (R0_act&C1_act) beginr_VGA_data = R0_C1;endelse if (R0_act&C0_act) beginr_VGA_data = R0_C0;endelse r_VGA_data =24'd0;endassign                              o_data                      = r_VGA_data;
endmodule
module VGA_crl (input                               i_clk                      ,input                               i_arstn                    ,input              [  23: 0]        i_data                     ,output                              o_h_sync                   ,output                              o_v_sync                   ,output             [  23: 0]        o_data                     ,output                              o_VGA_clk                  ,//输出一个同步时钟, 基于工程实践, 设置为输入时钟的反时钟更佳output                              o_VGA_BLK                  ,//设置一个消隐信号, 似乎用不到output             [   9: 0]        o_VGA_ho_cnt               ,//方便顶层读取当前扫描位置output             [   9: 0]        o_VGA_ve_cnt                //方便顶层读取现在扫描位置             
);//---------------------------------------------------------------------------------------// 时序参数定义:parameter                           VGA_HS_end                 = 10'd96,//水平同步器维持时间VGA_H_bach_Porch=10'd40,VGA_left_border=10'd8,VGA_H_DATA_time=10'd640,VGA_right_border=10'd8,VGA_H_front_Porch=10'd8;parameter                           period_horizon             = VGA_HS_end+VGA_H_bach_Porch+VGA_left_border+VGA_H_DATA_time+VGA_right_border+VGA_H_front_Porch;parameter                           VGA_h_visible_start        = VGA_HS_end+VGA_H_bach_Porch+VGA_left_border-1;parameter                           VGA_h_visible_end          = VGA_h_visible_start+VGA_H_DATA_time;parameter                           VGA_VS_end                 = 10'd2 ,//垂直同步器维持时间VGA_V_bach_Porch=10'd25,VGA_top_border=10'd8,VGA_V_DATA_time=10'd480,VGA_bottom_border=10'd8,VGA_V_front_Porch=10'd2;parameter                           period_vertical            = VGA_VS_end+VGA_V_bach_Porch+VGA_top_border +VGA_V_DATA_time+VGA_bottom_border+VGA_V_front_Porch;parameter                           VGA_v_visible_start        = VGA_VS_end+VGA_V_bach_Porch+VGA_top_border-1;parameter                           VGA_v_visible_end          = VGA_v_visible_start+VGA_V_DATA_time;//---------------------------------------------------------------------------------------reg                [   9: 0]        r_cnt_h                     ;// horizon counterreg                [   9: 0]        r_cnt_v                     ;// vertical counteralways @(posedge i_clk or negedge i_arstn) beginif (!i_arstn) beginr_cnt_h <= 0;endelse beginif (r_cnt_h == period_horizon-1) beginr_cnt_h <= 0;endelse beginr_cnt_h <= r_cnt_h + 1;endendendalways @(posedge i_clk or negedge i_arstn) beginif (!i_arstn) beginr_cnt_v <= 0;endelse beginif (r_cnt_h == period_horizon-1) beginif (r_cnt_v == period_vertical-1) beginr_cnt_v <= 0;endelse beginr_cnt_v <= r_cnt_v + 1;endendelse r_cnt_v <= r_cnt_v;endendwire                                w_VGA_HS                    ;// 行同步信号wire                                w_VGA_VS                    ;// 场同步信号assign                              w_VGA_HS                    = (r_cnt_h > VGA_HS_end-1);assign                              w_VGA_VS                    = (r_cnt_v > VGA_VS_end-1);
/*时间节点分析:行同步有效: 96个clk --> 0,1,2----95 --->95的下一个时钟加入下一步回扫时间:   40个clk --> 96, 97---135 -->135的下一个时钟加入下一步左缓冲边界: 8个clk  --> 136,137---143 -->143的下一个时钟加入下一步数据段:     640个clk--> 144, 145--783 -->783的下一个时钟加入下一步右缓冲边界: 8个clk  --> 784, 785--791 -->791的下一个时钟加入下一步等待回扫:   8个clk  --> 792, 793--799  -->799的下一个时钟加入下一步*/wire                                w_dat_act                   ;// 数据使能信号, 我们只希望在中间输出数据, 因此在这个阶段使能, 注意不输出数据不代表直接关闭电子枪assign                              w_dat_act                   = (VGA_h_visible_start < r_cnt_h && r_cnt_h <=VGA_h_visible_end) && (VGA_v_visible_start < r_cnt_v && r_cnt_v <= VGA_v_visible_end);//RGB控制wire               [  23: 0]        w_VGA_GRB                   ;assign                              w_VGA_GRB                   = (w_dat_act)? i_data:24'd0;assign                              o_data                      = w_VGA_GRB;//同步时钟控制assign                              o_VGA_clk                   = ~i_clk;//行场同步信号assign                              o_h_sync                    = w_VGA_HS;assign                              o_v_sync                    = w_VGA_VS;//消隐信号, BLK等同于data_act,   高电平代表着输出数据(visible)的时间锻, 可能是低电平有效, 这里和原理不太一样,原理上消隐信号应该只在等待回扫和回扫时间有效assign                              o_VGA_BLK                   = w_dat_act;//行场的计数器输出, 方便顶层读取当前位置assign                              o_VGA_ho_cnt                = (w_dat_act)? (r_cnt_h-VGA_h_visible_start):10'd0;assign                              o_VGA_ve_cnt                = (w_dat_act)? (r_cnt_v-VGA_v_visible_start):10'd0;
endmodule

总结:VGA看野火电子教程

将VGA控制器分成三个子模块:

  1. PLL生成固定时钟
  2. VGA_CRL: 实现VGA协议的基本时序控制, 输出VGA数据以及可视区计数器
  3. VGA_PIC: 通过读取CRL的可视区计数器, 知道当前可视区像素位置, 将要输出的图像写在这里, 并把图像背后的像素数据发送给CRL, CRL会通过内部指针决定什么时候传递出顶层端口
    在这里插入图片描述

HDMI

TMDS传输原理

TMDS(Transition Minimized Differential signal),最小化传输差分信号:

HDMI中的TMDS 传输系统分为两个部分:发送端和接收端。 TMDS 发送端收到HDMI 接口传来的表示 RGB 信号的24 位并行数据(TMDS 对每个像素的 RGB 三原色分别按 8bit 编码,即 R信号有 8 位,G 信号有 8 位,B 信号有 8 位),然后对这些数据和时钟信号进行编码和并/串转换,再将表示 3 个 RGB 信号的数据和时钟信号分别分配到独立的传输通道发送出去。接收端接收来自发送端的串行信号,对其进行解码和串/并转换,然后发送到显示器的控制端。与此同时也接收时钟信号,以实现同步。流程框图如下图所示
在这里插入图片描述
TMDS通道包括 3 个RGB 数据传输通道和 1 个时钟信号传输通道。每一通道都通过编码算法,将 8 位的视频、音频数据转换成最小化传输、直流平衡的 10 位数据.
第一组中,将像素数据中的蓝色(BLUE)分量和控制信号中的行同步(HSYNC)、场同步(VSYNC) 划分成了一组,经过编码器和串行调制器后输出,名为Channel0。
第二组中,将像素数据中的绿色(GREEN)分量和两个空的控制信号 CTL0、CTL1划分成了一组,经过编码器和串行调制器后输出,名为Channel1。在这一组中,CTL0和CTL1接入的是空信号。
第三组中,将像素数据中的红色(RED)分量和两个空的控制信号CTL2、CTL3划分成了一组,经过编码器和串行调制器后输出,名为Channel2。在这一组中CTL2和CTL3接入的是空信号。

为什么使用TMDS

在这里插入图片描述

HDMI接口结构

在这里插入图片描述
在这里插入图片描述

HDMI的彩条显示是基于VGA彩条显示的基础上的,是在VGA彩条显示工程的基础上修改的得到的。其中改动较大的有两部分:一是时钟生成模块的输出时钟频率和时钟个数做了改动;二是增加了HDMI驱动控制模块hdmi_ctrl。

HDMI_crl: 实现VGA转HDMI

HDMI驱动控制模块hdmi_ctrl是HDMI彩条显示的核心模块,功能是将VGA控制模块传入的行场同步信号、图像信息转换为HDMI能读取的差分信号,实现这一功能的转化,需要对输入的VGA图像信息进行TMDS编码、并行串行转换、单端信号转差分信号、单沿采样转双沿采样。其内部实例化若干子模块,模块及模块简介,如下所示
在这里插入图片描述
在这里插入图片描述

构成1:TMDS encoder模块

在这里插入图片描述
编码方式:
像素数据–>最小传输编码(减少数据跳变)+直流平衡编码(传输1个数等于传输0个数)
控制数据–>查表编码
数据周期:
在这里插入图片描述

//使用官方代码
module encode
(input  wire                         sys_clk                    ,//时钟信号input  wire                         sys_rst_n                  ,//复位信号,低有效input  wire        [   7: 0]        data_in                    ,//输入8bit待编码数据input  wire                         c0                         ,//控制信号c0input  wire                         c1                         ,//控制信号c1input  wire                         de                         ,//使能信号output reg         [   9: 0]        data_out                    //输出编码后的10bit数据
);
//\* Parameter and Internal Signal \//

//parameter defineparameter                           DATA_OUT0                  = 10'b1101010100,
DATA_OUT1 = 10'b0010101011,
DATA_OUT2 = 10'b0101010100,
DATA_OUT3 = 10'b1010101011;//wire definewire                                condition_1                 ;//条件1wire                                condition_2                 ;//条件2wire                                condition_3                 ;//条件3wire               [   8: 0]        q_m                         ;//第一阶段转换后的9bit数据//reg definereg                [   3: 0]        data_in_n1                  ;//待编码数据中1的个数reg                [   7: 0]        data_in_reg                 ;//待编码数据打一拍reg                [   3: 0]        q_m_n1                      ;//转换后9bit数据中1的个数reg                [   3: 0]        q_m_n0                      ;//转换后9bit数据中0的个数reg                [   4: 0]        cnt                         ;//视差计数器,0-1个数差别,最高位为符号位reg                                 de_reg1                     ;//使能信号打一拍reg                                 de_reg2                     ;//使能信号打两拍reg                                 c0_reg1                     ;//控制信号c0打一拍reg                                 c0_reg2                     ;//控制信号c0打两拍reg                                 c1_reg1                     ;//控制信号c1打一拍reg                                 c1_reg2                     ;//控制信号c1打两拍reg                [   8: 0]        q_m_reg                     ;//q_m信号打一拍
//\* Main Code \//

//data_in_n1:待编码数据中1的个数
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)data_in_n1 <= 4'd0;elsedata_in_n1 <= data_in[0] + data_in[1] + data_in[2]+ data_in[3] + data_in[4] + data_in[5]+ data_in[6] + data_in[7];//data_in_reg:待编码数据打一拍
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)data_in_reg <= 8'b0;elsedata_in_reg <= data_in;//condition_1:条件1assign                              condition_1                 = ((data_in_n1 > 4'd4) || ((data_in_n1 == 4'd4) && (data_in_reg[0] == 1'b1)));//q_m:第一阶段转换后的9bit数据assign                              q_m[0]                      = data_in_reg[0];assign                              q_m[1]                      = (condition_1) ? (q_m[0] ^~ data_in_reg[1]) : (q_m[0] ^ data_in_reg[1]);assign                              q_m[2]                      = (condition_1) ? (q_m[1] ^~ data_in_reg[2]) : (q_m[1] ^ data_in_reg[2]);assign                              q_m[3]                      = (condition_1) ? (q_m[2] ^~ data_in_reg[3]) : (q_m[2] ^ data_in_reg[3]);assign                              q_m[4]                      = (condition_1) ? (q_m[3] ^~ data_in_reg[4]) : (q_m[3] ^ data_in_reg[4]);assign                              q_m[5]                      = (condition_1) ? (q_m[4] ^~ data_in_reg[5]) : (q_m[4] ^ data_in_reg[5]);assign                              q_m[6]                      = (condition_1) ? (q_m[5] ^~ data_in_reg[6]) : (q_m[5] ^ data_in_reg[6]);assign                              q_m[7]                      = (condition_1) ? (q_m[6] ^~ data_in_reg[7]) : (q_m[6] ^ data_in_reg[7]);assign                              q_m[8]                      = (condition_1) ? 1'b0 : 1'b1;//q_m_n1:转换后9bit数据中1的个数
//q_m_n0:转换后9bit数据中0的个数
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)beginq_m_n1 <= 4'd0;q_m_n0 <= 4'd0;endelsebeginq_m_n1<=q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7];q_m_n0<=4'd8-(q_m[0]+q_m[1]+q_m[2]+q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7]);end//condition_2:条件2assign                              condition_2                 = ((cnt == 5'd0) || (q_m_n1 == q_m_n0));//condition_3:条件3
assign condition_3 = (((~cnt[4] == 1'b1) && (q_m_n1 > q_m_n0))
|| ((cnt[4] == 1'b1) && (q_m_n0 > q_m_n1)));//数据打拍,为了各数据同步
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)beginde_reg1 <= 1'b0;de_reg2 <= 1'b0;c0_reg1 <= 1'b0;c0_reg2 <= 1'b0;c1_reg1 <= 1'b0;c1_reg2 <= 1'b0;q_m_reg <= 9'b0;endelsebeginde_reg1 <= de;de_reg2 <= de_reg1;c0_reg1 <= c0;c0_reg2 <= c0_reg1;c1_reg1 <= c1;c1_reg2 <= c1_reg1;q_m_reg <= q_m;end//data_out:输出编码后的10bit数据//cnt:视差计数器,0-1个数差别,最高位为符号位always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n == 1'b0)begindata_out <= 10'b0;cnt <= 5'b0;endelsebeginif(de_reg2 == 1'b1)beginif(condition_2 == 1'b1)begindata_out[9] <= ~q_m_reg[8];data_out[8] <= q_m_reg[8];data_out[7:0]<=(q_m_reg[8])?q_m_reg[7:0] : ~q_m_reg[7:0];cnt<=(~q_m_reg[8])?(cnt+q_m_n0-q_m_n1):(cnt+q_m_n1-q_m_n0);endelsebeginif(condition_3 == 1'b1)begindata_out[9] <= 1'b1;data_out[8] <= q_m_reg[8];data_out[7:0] <= ~q_m_reg[7:0];cnt<=cnt+{q_m_reg[8],1'b0}+(q_m_n0-q_m_n1);endelsebegindata_out[9] <= 1'b0;data_out[8] <= q_m_reg[8];data_out[7:0] <= q_m_reg[7:0];cnt<= cnt-{~q_m_reg[8],1'b0}+(q_m_n1-q_m_n0);endendendelsebegincase ({c1_reg2, c0_reg2})2'b00: data_out <= DATA_OUT0;2'b01: data_out <= DATA_OUT1;2'b10: data_out <= DATA_OUT2;default:data_out <= DATA_OUT3;endcasecnt <= 5'b0;endendendmodule
构成2:并转串_差分输出模块

使用编码模块可解决图像数据的编码问题,而并行转串行模块的主要功能就是实现

  • 并行串行转换、
  • 单端信号转差分信号、
  • 单沿采样转双沿采样。
    在这里插入图片描述

注:传入的时钟信号clk_5x,频率125MHz,为输出串行差分信号ser_data_p、ser_data_n的同步时钟;传入的并行数据信号par_data,同步时钟信号为clk_1x,频率25MHz,未传入本模块。时钟信号clk_1x与clk_5x,时钟频率为5倍关系,因为并行数据信号par_da ta位宽10bit,若转换为串行信号,需要在时钟信号clk_1x的一个时钟周期内完成数据转换,转换后的串行数据信号的同步时钟频率必须为clk_1x的10倍,使用双沿采样则为5倍

调用原语:DDR(时钟沿双边采集)

在这里插入图片描述
该核可以实现串行输出D1, D2端数据

时序图:
在这里插入图片描述

因此我们可以在五个时钟周期内, 轮流将10位数据发送到D1, D2两端, 从而形成 10位输出的串流
方法: 采用计数器以及多路选择器

回顾:

我在ODDR并转串这里卡了很久
外因:
因为这个原语输出前似乎需要十个clk的准备时间, 而且输出比输入落后一个时钟周期
在这里插入图片描述
内因:
对于移位寄存器的使用不熟! 串转并和并转串应该使用移位寄存器, 否则输入帧更新的时候容易获取错误的值, 比如对于4’b0001转 0, 0, 0, 1然后之后是4’b1111转 1 1 1 1, 假如不使用寄存器, 而是直接cnt指向输入, 在输出 0 0 后假如输入更新, 又输出1 1, 这样获得0 0 1 1不属于任何预设输入

相关文章:

FPGA通信之VGA与HDMI

文章目录 VGA基本概念&#xff1a;水平扫描&#xff1a;垂直扫描&#xff1a; 时序如下&#xff1a;端口设计疑问为什么需要输出那么多端口不输出时钟怎么保证电子枪移动速度符合时序VGA转HDMI 仿真电路图代码总结&#xff1a;VGA看野火电子教程 HDMITMDS传输原理为什么使用TMD…...

Leetcode百题斩-二叉树

二叉树作为经典面试系列&#xff0c;那么当然要来看看。总计14道题&#xff0c;包含大量的简单题&#xff0c;说明这确实是个比较基础的专题。快速过快速过。 先构造一个二叉树数据结构。 public class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode…...

修改 K8S Service 资源类型 NodePort 的端口范围

在 Kubernetes 中&#xff0c;Service 类型为 NodePort 时&#xff0c;默认分配的端口范围为 30000~32767。如果你希望使用自定义端口&#xff08;如 8080、8888 等&#xff09;&#xff0c;就需要修改 kube-apiserver 的默认配置。 本文将详细介绍如何修改 Kubernetes 中 Nod…...

ACM Latex模板:合并添加作者和单位

目录&#xff1a; 1.ACM会议论文Latex模板&#xff0c;逐个添加作者和单位&#xff1a; 1&#xff09;Latex&#xff1a; 2&#xff09;效果&#xff1a; 2. ACM会议论文Latex模板&#xff0c;合并添加作者和单位&#xff1a; 1&#xff09;Latex&#xff1a; 2&#x…...

爬虫IP代理技术深度解析:场景、选型与实战应用

目录 一、代理IP的核心技术架构 二、典型应用场景技术解析 场景1&#xff1a;电商价格监控系统 场景2&#xff1a;社交媒体舆情分析 场景3&#xff1a;金融数据采集 三、代理IP选型方法论 1. 性能评估矩阵 2. 成本优化模型 3. 风险管控体系 四、未来技术演进方向 五、…...

将MCP(ModelContextProtocol)与Semantic Kernel集成(调用github)

文章目录 将MCP&#xff08;ModelContextProtocol&#xff09;与Semantic Kernel集成&#xff08;调用github&#xff09;一、模型上下文协议&#xff08;MCP&#xff09;简介1.1 简介1.2 示例 二、集成步骤2.1 安装环境依赖2.2 构建语义内核&#xff08;Kernel&#xff09;2.3…...

游戏引擎学习第311天:支持手动排序

仓库: https://gitee.com/mrxiao_com/2d_game_7(已满) 新仓库: https://gitee.com/mrxiao_com/2d_game_8 回顾并为今天的内容定下基调 我们接下来要继续完成之前开始的工作&#xff0c;上周五开始的部分内容&#xff0c;虽然当时对最终效果还不太确定&#xff0c;但现在主要任…...

LambdaQueryWrapper、MybatisPlus提供的基本接口方法、增删改查常用的接口方法、自定义 SQL

DAY26.2 Java核心基础 MybatisPlus提供的基本接口方法 分页查询 导入依赖springboot整合Mybatis-plus <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version&g…...

深度学习---可视化

模型可视化 深度学习模型可视化是理解、调试和优化模型的关键技术&#xff0c;涉及模型结构、参数、层输出、数据流动、训练过程等多维度分析。 一、可视化的核心作用 模型理解 解析复杂模型的网络架构&#xff08;如CNN的层级连接、Transformer的注意力机制&#xff09;。揭…...

军事大模型及其应用分析

一、军事大模型概述 在军事智能化浪潮下&#xff0c;大模型技术加速从理论迈向实战&#xff0c;成为重塑军事决策体系的核心力量&#xff0c;推动军事体系数字工程进入新阶段。 美国依托成熟的商业科技生态&#xff0c;率先推进大模型军事应用。Palantir 公司的 AIP 军事智能…...

c++算法题

题目 字符串的替换操作 replace(String &s, String &t, String &v) 是指&#xff1a; 若t是s的子串&#xff0c;则用串v替换串t在串s中的所有出现&#xff1b;若t不是s的子串&#xff0c;则串s不变。例如&#xff0c;若串s为“aabbabcbaabaaacbab”&#xff0c;串…...

云原生安全 SaaS :从基础到实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 1. 基础概念 什么是 SaaS&#xff1f; SaaS&#xff08;Software as a Service&#xff0c;软件即服务&#xff09;是一种基于云计算的软件交付模式。用…...

《Drain日志解析算法》论文阅读笔记

这篇文档介绍了一种名为Drain的在线日志解析方法&#xff0c;它采用固定深度的解析树进行流式日志处理 [cite: 1, 6]。 摘要 日志记录了宝贵的系统运行时信息&#xff0c;广泛应用于Web服务管理中 [cite: 1]。典型的日志分析过程首先需要解析原始日志消息&#xff0c;因为它们…...

MMAction2重要的几个配置参数

embed_dims&#xff08;全称 embedding dimensions&#xff09;是指每个 patch&#xff08;块&#xff09;或特征的通道数/维度&#xff0c;是 Transformer 或 Swin Transformer 等模型中最核心的特征表示维度。 embed_dims 必须能被 num_heads 整除 具体解释 在 Swin Transfo…...

Windows系统如何查看ssh公钥

很多人只是一味的为拿到ssh公钥而努力&#xff0c;往往却会忽略了ssh公钥与私钥背后的作用。 咱们在这里会花两分钟。 一分钟速通概念&#xff0c;一分钟教会你如何获取。 一分钟速通概念&#xff1a; 如何生成&#xff1a; SHH 公钥 与 私钥 是基于非对称加密算法&#xff…...

UniApp+Vue3微信小程序二维码生成、转图片、截图保存整页

二维码生成工具使用uqrcode/js&#xff0c;版本4.0.7 官网地址&#xff1a;uQRCode 中文文档&#xff08;不建议看可能会被误导&#xff09; 本项目采用了npm引入方式&#xff0c;也可通过插件市场引入&#xff0c;使用上会略有不同 准备工作&#xff1a; 安装&#xff1a;pnpm…...

8.2 线性变换的矩阵

一、线性变换的矩阵 本节将对每个线性变换 T T T 都指定一个矩阵 A A A. 对于一般的列向量&#xff0c;输入 v \boldsymbol v v 在空间 V R n \pmb{\textrm V}\pmb{\textrm R}^n VRn 中&#xff0c;输出 T ( v ) T(\boldsymbol v) T(v) 在空间 W R m \textrm{\pmb W}\…...

【2025】嵌入式软考中级部分试题

大题: 大模型 神经网络 机器学习 深度学习的包含关系 不一定对 订阅-发布者模型 发布/订阅模式特点: ①解耦:发布者和订阅者之间没有直接联系,它们通过中间的消息代理(如消息队列或事件总线)进行通信。这种解耦使得系统更加灵活,可以独立地添加或移除发布者和订阅者…...

Antd中Upload组件封装及使用:

1.Upload上传组件功能: 文件校验 : 文件格式校验/文件大小校验/上传文件总个数校验 相关功能 : 拖拽功能/上传到远程(七牛)/文件删除及下载 2.组件效果展示: 3.疑难点及解决方案: Promise.all多文件并行上传到远程(七牛云): (1)在beforeUpload钩子函数中获取token (2)循环fi…...

Linux环境基础开发工具->vim

引入&#xff1a;vim是什么&#xff1f; vs叫作继承开发环境&#xff0c;我们可以在里面编辑代码&#xff0c;调式代码&#xff0c;运行代码....这种叫集成开发环境&#xff1b;而vim只用来编辑代码&#xff0c;也就是类似于在windows上打开一个记事本来写代码的操作 集成开发…...

跳板问题(贪心算法+细节思考)

首先直接看题&#xff1a; 这题直接贪心其实问题不大&#xff1a; 下面先展示我的一个错误代码&#xff1a; # include<iostream> # include<vector> # include<algorithm>using namespace std;int main() {int N,M;cin>>N>>M;vector<vecto…...

RuoYi前后端分离框架集成UEditorPlus富文本编辑器

一、背景 采用若依框架搭建了一个小型的电子书项目,项目前端、后端、移动端就一人,电子书的章节内容是以富文本内容进行呈现的,产品设计人员直接给了一个第三方收费的富文本编辑器截图放到开发文档中,提了一沓需求点,概况下来就是要做成下图中的样子。作为一个后端开发人…...

IPD流程落地:项目任务书Charter开发

目录 简介 第一个方面&#xff0c;回答的是Why的问题。 第二点&#xff0c;要回答做什么的问题&#xff0c;也就是产品定义What的问题。 第三点就是要回答执行策略与计划的问题&#xff0c;也就是How、When、Who的问题。 第四点是对上述这些分析的总结分析&#xff0c;要为…...

Vue 2 混入 (Mixins) 的详细使用指南

1.基本概念 混入 (Mixins) 是 Vue 2 中用于组件代码复用的重要特性&#xff0c;它允许你将可复用的功能分发到多个组件中。 混入是一种灵活的代码复用方式&#xff0c;可以包含任意组件选项&#xff08;data、methods、生命周期钩子等&#xff09;。当组件使用混入时&#xff…...

day020-sed和find

文章目录 1. sed1.1 查找、过滤文本1.1.1 根据行号取行1.1.2 根据行号取范围1.1.3 过滤出指定行1.1.4 过滤出指定范围内容 1.2 替换文件内容1.2.1 将文件中虚拟用户命令解释器替换成/bin/bash1.2.2 修改原文件并备份1.2.3 为每行开头加上# 1.3 反向引用&#xff08;后向引用&am…...

OpenGL Chan视频学习-4 Vertex Buffers and Drawing a Triangle in OpenGL

一、视频链接 【最好的OpenGL教程之一】https://www.bilibili.com/video/BV1MJ411u7Bc?p5&vd_source44b77bde056381262ee55e448b9b1973 二、相关网站 docs.gl 三、代码整理 c #include <GL/glew.h> #include <GLFW/glfw3.h>#include<iostream>int…...

数据库事务的四大特性(ACID)

一、前言 在现代数据库系统中&#xff0c;事务&#xff08;Transaction&#xff09;是确保数据一致性和完整性的重要机制。事务的四大特性——原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consistency&#xff09;、隔离性&#xff08;Isolation&#xff09;…...

网络安全全知识图谱:威胁、防护、管理与发展趋势详解

1 网络安全基础概念 1.1 什么是网络安全 网络安全是指通过技术、管理和法律等手段&#xff0c;保护计算机网络系统中的硬件、软件及其系统中的数据&#xff0c;不因偶然的或者恶意的原因而遭受到破坏、更改、泄露&#xff0c;确保系统连续可靠正常地运行&#xff0c;网络服务不…...

FreeRTOS 在物联网传感器节点的应用:低功耗实时数据采集与传输方案

FreeRTOS 在物联网传感器节点的应用&#xff1a;低功耗实时数据采集与传输方案 二、FreeRTOS 任务划分与优先级设计 任务名称优先级执行周期功能描述Sensor_Collect3100ms多传感器数据采集与预处理Data_Process2事件驱动数据滤波/压缩/异常检测LoRa_Transmit41s低功耗长距离数…...

解决 iTerm2 中 nvm 不生效的问题(Mac 环境)

解决 iTerm2 中 nvm 不生效的问题&#xff08;Mac 环境&#xff09; 标题 《为什么 iTerm2 无法使用 nvm&#xff1f;—— 解决 Mac 终端环境变量冲突指南》 问题描述 许多开发者在 Mac 上使用 nvm 管理 Node.js 版本时&#xff0c;发现&#xff1a; 原生终端&#xff1a;n…...