4、硬件接口层设计:MII/RMII接口时序、PHY芯片配置(KSZ8081/DP83822)、时钟域同步策略、复位逻辑设计

各位同学,咱们今天聊点实在的。硬件接口层,说白了就是FPGA和PHY芯片之间的“握手协议”。你算法写得再漂亮,数据出不了芯片,一切都是白搭。我这些年调试过的板子,十有八九的问题都出在这一层——不是时序没调好,就是复位逻辑有bug。

嗯,咱们一步步来拆解。

4.1 MII与RMII接口:选哪个?

先看接口。MII(Media Independent Interface)是标准接口,25根信号线。RMII(Reduced MII)是简化版,只有9根线。你可能会问:为什么要有RMII?

说白了,就是为了省引脚。FPGA的引脚资源很宝贵,尤其是BGA封装的芯片,一个引脚就是一分钱。RMII把数据线从4位砍到2位,时钟频率翻倍(从25MHz提到50MHz),用时间换空间。

我个人习惯:

  • 引脚够用:选MII。时序更宽松,调试方便。
  • 引脚紧张:选RMII。但要注意,50MHz时钟的PCB走线要更小心。

我在项目中遇到过一件事:某次用RMII接口,PCB走线长了3厘米,结果50MHz时钟的上升沿变缓,数据采样出错。后来加了个时钟缓冲器才搞定。所以,选RMII的话,PCB布局要提前规划好。

4.2 MII接口时序详解

MII接口的信号分组如下:

信号组 信号名 方向 说明
发送 TXD[3:0], TX_EN, TX_ER, TX_CLK MAC→PHY 数据、使能、错误、时钟
接收 RXD[3:0], RX_DV, RX_ER, RX_CLK PHY→MAC 数据、有效、错误、时钟
管理 MDC, MDIO 双向 配置PHY寄存器
状态 CRS, COL PHY→MAC 载波侦听、冲突检测

时序上,MII是时钟上升沿采样。发送时,FPGA在TX_CLK上升沿之前把数据准备好;接收时,FPGA在RX_CLK上升沿采样RXD。这里有个坑:TX_CLK和RX_CLK是PHY提供的,频率是25MHz(100Mbps)或2.5MHz(10Mbps)。

注意:TX_CLK和RX_CLK是异步的!它们来自不同的PLL,频率可能相同,但相位完全随机。千万不要假设它们同步。

我曾经犯过一个错误:在FPGA内部直接用TX_CLK去采样RX_CLK域的数据,结果偶尔出现亚稳态。后来老老实实加了异步FIFO,问题才解决。

4.3 RMII接口时序要点

RMII的时序更紧凑:

  • 时钟频率50MHz,由外部晶振或PHY提供
  • 数据线只有2位:TXD[1:0]和RXD[1:0]
  • 使能信号:TX_EN和CRS_DV(合并了CRS和RX_DV)

RMII的参考时钟有两种模式:

  1. 时钟由PHY提供:PHY输出50MHz给FPGA。简单,但PHY的时钟抖动可能影响FPGA内部逻辑。
  2. 时钟由FPGA提供:FPGA输出50MHz给PHY。控制力更强,但FPGA的IO口要能输出50MHz时钟,有些低端芯片做不到。

我个人建议用第一种模式。PHY芯片的时钟输出质量通常不错,而且省了FPGA的时钟资源。

4.4 PHY芯片配置:KSZ8081 vs DP83822

这两款芯片我都用过,各有千秋。

特性 KSZ8081(Microchip) DP83822(TI)
接口 MII/RMII MII/RMII
管理接口 MDIO(Clause 22) MDIO(Clause 22/45)
自协商 支持,默认开启 支持,默认开启
中断 有,可配置 有,可配置
温度范围 0~70°C(商用) -40~125°C(工业)
价格 略低 略高

配置流程基本一致:

  1. 上电后等待PHY复位完成(约10ms)
  2. 通过MDIO读取PHY ID寄存器(寄存器2和3),确认芯片型号
  3. 配置基本控制寄存器(寄存器0):设置速度、双工模式、自协商等
  4. 配置接口模式寄存器:选择MII或RMII
  5. 配置中断使能(如果需要)
  6. 启动自协商或强制模式
  7. 等待链路建立(Link Up)

避坑指南:我曾经在DP83822上踩过一个坑——它的寄存器地址偏移和标准不完全一样。比如接口模式配置,KSZ8081在寄存器0x1F,而DP83822在寄存器0x14。所以,一定要看数据手册,不要想当然。

4.5 时钟域同步策略

这是整个设计中最容易出问题的地方。咱们的系统里至少有三个时钟域:

  • PHY时钟域:TX_CLK和RX_CLK(MII)或REF_CLK(RMII)
  • FPGA内部逻辑时钟域:比如125MHz的MAC处理时钟
  • CPU/总线时钟域:比如AXI总线时钟

跨时钟域同步,我总结了三板斧:

  1. 异步FIFO:用于数据流传输。比如从RX_CLK域到内部逻辑时钟域,用双口RAM+格雷码指针。
  2. 两级触发器同步:用于控制信号。比如Link Status信号,用两级D触发器打两拍。
  3. 握手协议:用于慢速控制。比如MDIO配置,用请求-应答机制。

你想想看,为什么异步FIFO要用格雷码?因为格雷码相邻值只变化1位,能有效降低亚稳态概率。我刚开始做的时候直接用二进制计数器,结果偶尔出现指针错乱,数据读出来全是乱的。

小技巧:异步FIFO的深度怎么选?对于100Mbps以太网,RX_CLK是25MHz,内部时钟是125MHz,深度选16就够。但如果你要做1588时间同步,深度要更大,因为时间戳插入会引入延迟。

4.6 复位逻辑设计

复位逻辑看似简单,其实门道很多。我见过太多人直接把外部复位信号接到所有触发器上,结果系统上电后各种莫名其妙的问题。

好的复位设计应该做到:

  • 异步复位,同步释放:避免复位撤销时的亚稳态
  • 每个时钟域有自己的复位同步器:不要跨时钟域复位
  • PHY复位和FPGA复位分开:PHY复位后需要等待稳定,FPGA可以先跑起来

我常用的复位同步器代码:

// 异步复位,同步释放
module reset_sync (
    input  wire clk,
    input  wire rst_async_n,
    output wire rst_sync_n
);

reg [1:0] rst_meta;

always @(posedge clk or negedge rst_async_n) begin
    if (!rst_async_n) begin
        rst_meta <= 2'b00;
    end else begin
        rst_meta <= {rst_meta[0], 1'b1};
    end
end

assign rst_sync_n = rst_meta[1];

endmodule

这个电路用了两级触发器,第一级可能亚稳态,但第二级基本稳定。嗯,这里要注意:复位信号是低有效,所以代码里用negedge rst_async_n

重要:PHY芯片的复位引脚(RST_N)要单独处理。不要和FPGA的复位连在一起。PHY复位后需要至少10ms的稳定时间,而FPGA复位后可能立即开始配置MDIO。如果连在一起,MDIO配置可能失败。

我一般这样处理:FPGA上电后,先拉低PHY的RST_N,保持10ms,然后释放。释放后再等1ms,才开始MDIO配置。这个时序在状态机里实现,很简单。

4.7 知识体系总览

说了这么多,咱们用一张图来总结本章的核心逻辑:

硬件接口层设计知识体系 接口选择:MII vs RMII MII接口时序 RMII接口时序 PHY芯片配置:KSZ8081 / DP83822 时钟域同步策略 复位逻辑设计 异步FIFO 两级同步器 异步复位同步释放 PHY复位时序

这张图把咱们今天讲的内容串起来了。从接口选择开始,到具体时序,再到PHY配置,最后落到时钟域同步和复位逻辑。你照着这个框架去设计,基本不会出大问题。

好了,硬件接口层就讲到这里。记住一句话:接口时序是基础,时钟同步是关键,复位逻辑是保障。这三样做好了,你的以太网设计就成功了一半。

专注资料整理