问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 200 人浏览分享

开启左侧

HDMI项目-主讲SerDes IO使用-连载一

[复制链接]
200 0
本帖最后由 UT发布 于 2025-3-25 18:59 编辑

HDMI 广泛应用于音视频领域,探索基于HDMI 实现的原理,为广大音视频领域的客户提供HDMI视频编解码开源技术。在FPGA开发中实现HDMI接口功能时,通常存在两种典型的技术路径:

第一种方案采用专用HDMI编码芯片实现,通过外接物理层转换器件完成信号处理。这种架构下,FPGA主要负责视频时序生成和像素数据预处理,将RGB/YUV格式的视频流通过并行总线传输至编码芯片,由后者完成TMDS编码、串行化处理和差分驱动等物理层操作。

第二种方案则完全基于FPGA的可编程逻辑资源实现,利用IO引脚直接模拟HDMI协议栈。该方案中,开发者需要通过硬件描述语言实现完整的TMDS编码器,将24位像素数据及其同步信号转换为三组差分数据流(D0-D2)和独立的差分时钟通道。

两种方案各有优劣:专用芯片方案开发周期短、信号完整性易保证,但增加BOM成本和PCB复杂度;全FPGA方案具有更高的设计灵活性,能够实现自定义分辨率/刷新率,但需要消耗大量逻辑资源和SerDes模块,对时序收敛要求更高。本文主要介绍第二种方案。

1 基础知识

SerDes是一种通过时分复用(TDM)和差分信号传输技术实现并行数据与高速串行信号转换的接口。其核心组件包括:

1、串行器(Serializer):将低速并行信号转换为高速串行低压差分信号(LVDS),并集成发射器模块。

2、解串器(Deserializer):接收高速串行信号后,通过时钟与数据恢复(CDR)电路、串并转换电路还原为并行信号。

3、关键技术优势:

差分传输:抗噪声和抗干扰能力显著优于单端信号。

时钟恢复技术:消除传统并行接口的时钟偏移问题,支持更高传输速率。

编码与均衡:采用8b/10b编码实现直流平衡,结合自适应均衡(如CTLE、DFE)降低误码率(<10^-17)。

1.1 ISERDESE2
640?wx_fmt=png&from=appmsg



1.1.1参数功能
640?wx_fmt=png&from=appmsg
1.1.2信号功能
596b4da932b628fbb82f4f804be08873.jpg
1.3 数据转换
1.3.1串并转换支持的位宽

ISERDESE2 在SDR模式下数据转换的位宽可以为2、3、4、5、6、7、8bit,在DDR模式时,数据转换位宽为4、6、8bit,2个ISERDESE2级联使用,DDR模式可以支持10、14bit。如下图所示通过2个ISERDESE2级联出10bit,14bit位宽数据接口。


640?wx_fmt=png&from=appmsg

1.3.2串并转换后的数据顺序
如上图所示,可以看到数据的大小端是反了过来。
0c5677d95bdb1c07438c1e8af1e48e16.jpg
1.3.3数据对齐

Bitslip用来实现并行数据的边界对齐。串行输入的8bit的数据,经过串并转换后,数据之间可能会错位,这是串并转换无法识别的,因此Bitslip就专门用来找到用户需要的并行数据边界。

对于SDR模式,Bitslip使能1次,则数据会左移1次,对于8bit并行数据,移动8次完成一个循环,可以这样无止境的循环,直到找到用户定义的并行数据。对于DDR模式,Bitslip工作方式不同,Bitslip使能1次,数据会右移1次或者左移3次,两者交替进行,同样移动8次完成一个循环。


640?wx_fmt=png&from=appmsg 640?wx_fmt=png&from=appmsg
Clock Event 1

第一个字CDAB已被采样到ISERDESE2的输入侧寄存器中。Bitslip引脚未置位,数据没有任何重新对齐。

Clock Event 2

Bitslip引脚被置为有效,这使Bitslip控制器在内部将所有数据位向右移一位。 Bitslip在一个(仅一个)CLKDIV周期内保持高电平。

Clock Event 3

置位Bitslip后的三个CLKDIV周期,Bitslip操作完成,新的移位数据作为BCDA在输出上可用。

Clock Event 4

于ISERDESE2配置为1:4,因此Bitslip最多可以再声明两次。 在第二次移位后(此DDR还剩三个位置),在Q4-Q1上提供了(必需)输出ABCD。 在第三次移位后(右移一个位置),输出DABC在Q4-Q1上可用。 第四次移位(剩下三个位置)之后,原始输出CDAB在Q4-Q1上可用,并且Bitslip已完成所有四个输入组合的循环。

1.3.4时钟
640?wx_fmt=png&from=appmsg
1、网络接口类型时钟要求(NETWORKING Interface Type)

CLK 和CLKDIV必须确保相位相同。

CLK由BUFIO驱动,CLKDIV由BUFR驱动

CLK由MMCM或PLL驱动,CLKDIV由同一MMCM或PLL的CLKOUT [0:6]驱动。

当使用MMCM驱动ISERDESE2的CLK和CLKDIV时,不能混用提供ISERDESE2的缓冲器类型。例如,如果CLK由BUFG驱动,则CLKDIV也必须由BUFG驱动。另外,MMCM可以通过BUFIO和BUFR驱动ISERDESE2。

2、内存接口类型时钟要求(MEMORY Interface Type)

CLK由BUFIO驱动,OCLK由BUFIO驱动并且CLKDIV由BUFR驱动

CLK由MMCM或者PLL驱动,OCLK由MMCM或者PLL驱动,CLKDIV由相同的MMCM或者PLL驱动

CLK由BUFG驱动,OCLK由BUFG驱动,CLKDIV由不同的BUFG驱动

2 IDELAYE2
640?wx_fmt=png&from=appmsg
2.1  参数描述
640?wx_fmt=png&from=appmsg
2.2 信号描述
640?wx_fmt=png&from=appmsg
2.3 IDELAY Timing Diagram
IDELAY_TYPE = VARIABLE, IDELAY_VALUE = 0, and DELAY_SRC = IDATAIN

640?wx_fmt=png&from=appmsg

Clock Event 0

在LD有效前,CNTVALUEOUT输出为未知值;

Clock Event 1

在C的上升沿,检测到复位(LD为高电平),加载预装值IDELAY_VALUE,数据在抽头(抽头为了形象描述数据的位的延迟位置)tap0上。

Clock Event 2

CE和INC上的脉冲在C的上升沿被捕获。这表示递增操作。输出增加1个tap延迟输出,这个时候抽头在tap1上。

Clock Event 3

CE和INC不再有效, 输出会保持在tap1上,直到LD,CE或INC引脚上有进一步的动作。也就是后面的数据都会由1个tap的延迟吗,如果是200M时钟就是78ps

IDELAY timing diagram in VAR_LOAD mode

640?wx_fmt=png&from=appmsg
Clock Event 0

在LD有效前,CNTVALUEOUT输出为未知值;

Clock Event 1

在C的上升沿采样到LD有效,此时DATAOUT延时CNTVALUEIN指定的延时Taps,改变tap Setting到Tap2,CNTVALUEOUT更新到新的Tap值;

Clock Event 2

INC和CE有效,此时指定了增量操作,Tap值加1,DATAOUT输出从Tap2更新到Tap3,CNTVALUEOUT更新到新的Tap值;

Clock Event 3

LD有效,DATAOUT输出延时更新到Tap10,CNTVALUEOUT更新到新的Tap值。

3 hdmi_rx_phy_wrapper.v

此模块负责对数据进行1to10转化,知识点如下。

IBUFDS将差分数据转化成单端数据

  1.   // IBUFDS实例,用于将差分输入转换为单端信号
  2.   IBUFDS #(
  3.       .DIFF_TERM   ("TRUE"),    // 启用差分终端电阻
  4.       .IBUF_LOW_PWR("FALSE"),   // 高性能模式
  5.       .IOSTANDARD  ("TMDS_33")  // 设置I/O标准为TMDS_33
  6.   ) IBUFDS_inst_d0 (
  7.       .O (I_hdmi_rx_data),  // 单端输出信号
  8.       .I (TMDS_RX_P),       // 差分正相位输入信号
  9.       .IB(TMDS_RX_N)        // 差分负相位输入信号
  10.   );
复制代码
IDELAYE2负责对数据进行延迟的调整,使用的是VARIABLE模式,允许我们可以动态的调整数据的延迟值,调整的规则如下表:
640?wx_fmt=png&from=appmsg
初始延迟值我们设置的是0,但是注意,设置为0并不是代表延迟值就是0,IDELAYE2的默认延迟值为600psREFCLK_FREQUENCY值有范围,影响的是一次tap的延迟时间,范围是190.0-210.0290.0-310.0MHz,选择默认200MHz,同时我们需要给IDELAYCTRL提供200MHz时钟,此处必须保持一致。数据类型我们选择DATA,影响的是编译器对于数据抖动的判断。
  1. // IDELAYE2实例,用于调整输入数据的延迟
  2.   IDELAYE2 #(
  3.       .CINVCTRL_SEL         ("FALSE"),     // 禁用动态时钟反转
  4.       .DELAY_SRC            ("IDATAIN"),   // 使用内部数据输入作为延迟源
  5.       .HIGH_PERFORMANCE_MODE("FALSE"),     // 最小化功耗模式
  6.       .IDELAY_TYPE          ("VARIABLE"),  // 可变延迟类型
  7.       .IDELAY_VALUE         (0),           // 初始延迟值为0
  8.       .PIPE_SEL             ("FALSE"),     // 不使用流水线模式
  9.       .REFCLK_FREQUENCY     (200.0),       // 引用时钟频率为200MHz
  10.       .SIGNAL_PATTERN       ("DATA")       // 数据信号模式
  11.   ) IDELAYE2_inst (
  12.       .CNTVALUEOUT(O_cnt_value),     // 当前延迟计数值输出
  13.       .DATAOUT    (w_idelay_o),      // 延迟后的数据输出
  14.       .C          (I_clk_x1),        // 操作时钟输入
  15.       .CE         (I_ce),            // 计数器控制信号
  16.       .CINVCTRL   (1'b0),            // 时钟反转控制信号,默认不反转
  17.       .CNTVALUEIN (1'b0),            // 计数器初始值输入,默认为0
  18.       .DATAIN     (),                // 数据输入(未使用)
  19.       .IDATAIN    (I_hdmi_rx_data),  // 差分输入缓冲后的数据输入
  20.       .INC        (I_inc),           // 增加或减少延迟的控制信号
  21.       .LD         (1'b0),            // 加载延迟值到计数器(未使用)
  22.       .LDPIPEEN   (1'b0),            // 流水线加载使能(未使用)
  23.       .REGRST     (~I_rst)           // 计数器复位信号,高电平有效
  24.   );
复制代码
IDELAYCTRL注意点为REFCLK时钟必须与IDELAYE2设置参数保持一致。
  1.   // IDELAYCTRL实例,用于初始化和控制IDELAYE2
  2.   IDELAYCTRL IDELAYCTRL_inst (
  3.       .RDY   (O_idelay_rdy),  // 就绪输出信号
  4.       .REFCLK(I_clk_200),     // 引用时钟输入,200MHz
  5.       .RST   (~I_rst)         // 复位信号,高电平有效
  6.   );
复制代码
ISERDESE2使用级联模式,使用两个ISERDESE2级联,同时使用DDR模式,INTERFACE_TYPE需要配置成NETWORKING,可以同时输出10bit的数据,手册中对于两个ISERDESE2级联的连接方式如下图:
640?wx_fmt=png&from=appmsg

因为使用IDELAYE2负责数据的延迟,所以需要将延迟后的数据从DDLY输入。
  1. // ISERDESE2实例(主通道),用于将串行数据并行化
  2.   ISERDESE2 #(
  3.       .DATA_RATE        ("DDR"),         // 双数据速率模式
  4.       .DATA_WIDTH       (10),            // 并行数据宽度为10位
  5.       .DYN_CLKDIV_INV_EN("FALSE"),       // 禁用动态时钟分频反转
  6.       .DYN_CLK_INV_EN   ("FALSE"),       // 禁用动态时钟反转
  7.       .INTERFACE_TYPE   ("NETWORKING"),  // 网络接口类型
  8.       .IOBDELAY         ("IFD"),         // 输入延时
  9.       .NUM_CE           (1),             // 一个片选信号
  10.       .OFB_USED         ("FALSE"),       // 不使用反馈路径
  11.       .SERDES_MODE      ("MASTER")       // 主通道模式
  12.   ) ISERDESE2_u0inst (
  13.       .O           (),               // 并行输出(未使用)
  14.       .Q1          (O_raw_data[0]),  // 第1个并行输出位
  15.       .Q2          (O_raw_data[1]),  // 第2个并行输出位
  16.       .Q3          (O_raw_data[2]),  // 第3个并行输出位
  17.       .Q4          (O_raw_data[3]),  // 第4个并行输出位
  18.       .Q5          (O_raw_data[4]),  // 第5个并行输出位
  19.       .Q6          (O_raw_data[5]),  // 第6个并行输出位
  20.       .Q7          (O_raw_data[6]),  // 第7个并行输出位
  21.       .Q8          (O_raw_data[7]),  // 第8个并行输出位
  22.       .SHIFTOUT1   (SHIFTOUT1),      // 数据宽度扩展输出1
  23.       .SHIFTOUT2   (SHIFTOUT2),      // 数据宽度扩展输出2
  24.       .BITSLIP     (1'b0),           // 位滑动控制信号,默认不滑动
  25.       .CE1         (1),              // 片选信号1,始终启用
  26.       .CE2         (0),              // 片选信号2,禁用
  27.       .CLKDIVP     (1'b0),           // 分频时钟相位选择,默认为0
  28.       .CLK         (I_clk_x5),       // 主时钟输入
  29.       .CLKB        (~I_clk_x5),      // 主时钟反相信号
  30.       .CLKDIV      (I_clk_x1),       // 分频时钟输入
  31.       .OCLK        (1'b0),           // 输出时钟(未使用)
  32.       .DYNCLKDIVSEL(1'b0),           // 动态分频时钟反转选择,默认为0
  33.       .DYNCLKSEL   (1'b0),           // 动态时钟反转选择,默认为0
  34.       .D           (),               // 串行数据输入(未使用)
  35.       .DDLY        (w_idelay_o),     // 延迟后的数据输入
  36.       .OFB         (1'b0),           // 反馈数据输入(未使用)
  37.       .OCLKB       (1'b0),           // 输出时钟反相信号(未使用)
  38.       .RST         (~I_rst),         // 复位信号,高电平有效
  39.       .SHIFTIN1    (),               // 数据宽度扩展输入1(未使用)
  40.       .SHIFTIN2    ()                // 数据宽度扩展输入2(未使用)
  41.   );
  42.   // ISERDESE2实例(从通道),用于处理剩余的数据位
  43.   ISERDESE2 #(
  44.       .DATA_RATE        ("DDR"),         // 双数据速率模式
  45.       .DATA_WIDTH       (10),            // 并行数据宽度为10位
  46.       .DYN_CLKDIV_INV_EN("FALSE"),       // 禁用动态时钟分频反转
  47.       .DYN_CLK_INV_EN   ("FALSE"),       // 禁用动态时钟反转
  48.       .INTERFACE_TYPE   ("NETWORKING"),  // 网络接口类型
  49.       .IOBDELAY         ("IFD"),         // 输入延时
  50.       .NUM_CE           (1),             // 一个片选信号
  51.       .OFB_USED         ("FALSE"),       // 不使用反馈路径
  52.       .SERDES_MODE      ("SLAVE")        // 从通道模式
  53.   ) ISERDESE2_u1inst (
  54.       .O           (),               // 并行输出(未使用)
  55.       .Q1          (),               // 第1个并行输出位(未使用)
  56.       .Q2          (),               // 第2个并行输出位(未使用)
  57.       .Q3          (O_raw_data[8]),  // 第3个并行输出位
  58.       .Q4          (O_raw_data[9]),  // 第4个并行输出位
  59.       .Q5          (),               // 第5个并行输出位(未使用)
  60.       .Q6          (),               // 第6个并行输出位(未使用)
  61.       .Q7          (),               // 第7个并行输出位(未使用)
  62.       .Q8          (),               // 第8个并行输出位(未使用)
  63.       .SHIFTOUT1   (),               // 数据宽度扩展输出1(未使用)
  64.       .SHIFTOUT2   (),               // 数据宽度扩展输出2(未使用)
  65.       .BITSLIP     (1'b0),           // 位滑动控制信号,默认不滑动
  66.       .CE1         (1),              // 片选信号1,始终启用
  67.       .CE2         (0),              // 片选信号2,禁用
  68.       .CLKDIVP     (1'b0),           // 分频时钟相位选择,默认为0
  69.       .CLK         (I_clk_x5),       // 主时钟输入
  70.       .CLKB        (~I_clk_x5),      // 主时钟反相信号
  71.       .CLKDIV      (I_clk_x1),       // 分频时钟输入
  72.       .OCLK        (1'b0),           // 输出时钟(未使用)
  73.       .DYNCLKDIVSEL(1'b0),           // 动态分频时钟反转选择,默认为0
  74.       .DYNCLKSEL   (1'b0),           // 动态时钟反转选择,默认为0
  75.       .D           (1'b0),           // 串行数据输入(未使用)
  76.       .DDLY        (1'b0),           // 延迟后的数据输入(未使用)
  77.       .OFB         (1'b0),           // 反馈数据输入(未使用)
  78.       .OCLKB       (1'b0),           // 输出时钟反相信号(未使用)
  79.       .RST         (~I_rst),         // 复位信号,高电平有效
  80.       .SHIFTIN1    (SHIFTOUT1),      // 数据宽度扩展输入1
  81.       .SHIFTIN2    (SHIFTOUT2)       // 数据宽度扩展输入2
  82.   );
复制代码

4 hdmi_rx_phy_wapper.v的RTL功能
hdmi_rx_phy_wapper模块的主要功能
1.完成串行数据的延迟,并且能完成延迟控制
2.完成1:10的串行数据转并行数据
3.输出Taps值下面我们观察仿真信号能否达到上述三个需求
如下图所示,可以看出,O_cnt_value输出当前延迟的Taps值,黄线前的Taps值为00,黄线后的Taps值为01。通过自动校准模块控制的ce和inc信号进行控制。通过SHIFTOUT1和SHIFTOUT2信号,进行两个Iserdes2级联,输出10位的数据
640?wx_fmt=png&from=appmsg
对比延迟前的数据和延迟后的数据,当Taps值为0的时候,看出两个信号之间延迟值为600ps。
640?wx_fmt=png&from=appmsg
对比延迟前的数据和延迟后的数据,当Taps值为1的时候,看出两个信号之间延迟值为678ps。

640?wx_fmt=png&from=appmsg
我们通过上面两种情况可得,一个Taps值大概延迟78ps的时间。通过观察仿真波形图,我们判断该模块满足我们的设计需求。

图片1.jpg
640?wx_fmt=png&from=appmsg
640?wx_fmt=png&from=appmsg
640?wx_fmt=jpeg&from=appmsg
640?wx_fmt=jpeg&from=appmsg
640?wx_fmt=jpeg&from=appmsg
640?wx_fmt=jpeg&from=appmsg
640?wx_fmt=jpeg&from=appmsg
f9e5ab888e0d4d91b18a428f8008f446.jpg
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

0

关注

0

粉丝

253

主题
精彩推荐
热门资讯
网友晒图
图文推荐

  • 微信公众平台

  • 扫描访问手机版