4. RMII 信号详解:REF_CLK, TXD[1:0], RXD[1:0], TX_EN, CRS_DV

好,聊完了 MII 那一堆 16/18 根线的“豪华套餐”,咱们来看看它的精简版——RMII(Reduced MII)。说白了,RMII 就是把 MII 的引脚数从 16 降到 8 或 9,代价是时钟频率翻倍(从 25 MHz 提到 50 MHz),并且用一根 CRS_DV 信号把载波监听和数据有效合并了。

我个人非常喜欢 RMII,尤其在板子面积紧张、引脚不够用的时候。但精简也意味着有些细节必须抠准,不然很容易翻车。本章咱们就把这 5 个信号一个一个说透。

4.1 REF_CLK — 参考时钟

这是 RMII 的“心跳”。不管你用 100M 还是 10M 模式,REF_CLK 都固定是 50 MHz(±50 ppm)。MAC 和 PHY 必须共用同一个时钟源,否则收发时序会乱套。

⚠ 我曾经踩过的坑: 有一块板子,MAC 用有源晶振 50 MHz,PHY 用板上的另一个 50 MHz 晶振……结果两个时钟漂移不一致,偶尔丢包,调了我两天才发现。切记:要么 MAC 输出 REF_CLK 给 PHY,要么共用一个晶振。

REF_CLK 的占空比要求一般是 45%~55%,边沿应该尽量干净。布线时尽量走内层,远离高频干扰源。如果你不放心,可以在靠近 PHY 侧加个 RC 滤波。

4.2 TXD[1:0] — 发送数据总线

两比特的并行发送总线。在 100M 模式下,每个时钟周期(20 ns)发送 2 位,相当于 100 Mbps。在 10M 模式下,每个时钟周期只发送 1 位(另一个位没用?其实规范里会要求重复或填充,但多数 PHY 直接忽略 TXD[1] 的高电平位)。

速率TXD 有效位时钟周期数据率
100M2 位 (TXD[1:0])20 ns100 Mbps
10M1 位 (TXD[0])200 ns(每 10 个时钟传 1 次)10 Mbps

你想想看,10M 模式下为了兼容 50 MHz 时钟,PHY 内部会做降频采样,MAC 侧只需要保证 TXD[0] 在 TX_EN 有效时保持稳定即可。

💡 我建议: 如果在 MCU 上实现 RMII MAC,记得把 TXD 寄存器配置为 2 位模式,否则高位可能被当成“don't care”导致错位数据。

4.3 RXD[1:0] — 接收数据总线

同样两比特。CRS_DV 有效时,PHY 会把从线路上解出的数据逐比特拼成 2 位并行,放在 RXD[1:0] 上。注意:RXD 只有在 CRS_DV 置高后才有效。

我记得有个项目,软件工程师在中断里直接读 RXD 却没检查 CRS_DV 状态,结果读到了一堆噪声。这个问题其实说明了一个设计原则:接收数据必须与 CRS_DV 同步采样。

4.4 TX_EN — 发送使能

高电平表示 MAC 正在发送有效数据。注意:它必须与 TXD 同步变化。如果 TX_EN 在时钟上升沿同时跳变,TXD 应该也已经就绪。

这里有一个常见坑:MAC 在空闲时,TX_EN 必须拉低;某些设计者错误地把 TX_EN 接死在高电平,结果 PHY 一直认为在发送,导致链路两边无法正常协商。我曾经帮客户修过一块板子,就是这个问题,最后在 MAC 初始化里加了一行 GPIO 拉低代码就好了。

4.5 CRS_DV — 载波监听 / 数据有效组合信号

这是 RMII 最“精妙”也最“坑”的信号。它把 MII 的 CRS(载波监听)和 RX_DV(接收数据有效)合并成一根线。

  • 正常接收时:CRS_DV 从第一个有效字节开始拉高,持续到最后一个字节结束。
  • 碰撞检测:如果 PHY 检测到冲突,CRS_DV 也会拉高,但这时候 RXD 上并不是有效数据,而是“碰撞模式”的指示(通常 RXD[0] 和 RXD[1] 有特殊编码)。

所以,MAC 侧不能简单地把 CRS_DV 当作 RX_DV 用,必须同时检查 RXD 的内容来区分是正常数据还是碰撞。很多老外芯片手册里写得很清楚,但我见过不少国产 PHY 的参考设计里直接把它当 RX_DV 用——后果就是碰撞时 MAC 会收异常包。

⚠ 避坑指南: 我曾经在一个工业交换机项目里,因为 CRS_DV 没处理好,导致半双工模式下碰撞时疯狂丢包。最终老老实实加了一个状态机:
1. 检测到 CRS_DV 高→启动接收
2. 判断 RXD[1:0] 是否等于 0b01 或 0b10(碰撞码)→ 如果是,丢弃当前接收帧
3. 否则正常收数据直到 CRS_DV 拉低

另外,CRS_DV 在 10M 模式下会按 50 MHz 时钟采样,但实际有效数据只在每 10 个时钟的某一段内出现。硬件设计时最好加一个窗口计数器,避免误触发。

整体时序关系

为了方便理解,下面我画了一张 RMII 接口的信号连接图,你看看 MAC 与 PHY 之间的信号流向。

RMII 接口信号连接图 MAC (发送/接收控制) MAC 侧接口 PHY (线边收发) PHY 侧接口 REF_CLK (50 MHz) (MAC 输出或共享晶振) TXD[1:0] MAC → PHY TX_EN MAC → PHY RXD[1:0] PHY → MAC CRS_DV PHY → MAC ⚠ 关键提醒 CRS_DV 是组合信号,MAC 需同时检查 RXD 内容区分正常数据与碰撞。

从图上你可以看到,除了 REF_CLK 是时钟(一般由 MAC 提供或共源),其余数据/控制线都是单向的。我个人建议布线时,把 TXD[1:0] 和 TX_EN 走在一起,RXD[1:0] 和 CRS_DV 走在一起,尽量减少交叉干扰。

信号总结表

信号方向宽度说明电平标准
REF_CLKMAC→PHY(或共享)150 MHz 参考时钟,±50 ppm3.3V / 2.5V / 1.8V
TXD[1:0]MAC→PHY2发送数据,与 TX_EN 对齐同 REF_CLK
TX_ENMAC→PHY1发送使能,高有效同上
RXD[1:0]PHY→MAC2接收数据,与 CRS_DV 关联同上
CRS_DVPHY→MAC1载波监听+数据有效,高有效同上

最后再啰嗦一句:RMII 虽然省引脚,但 50 MHz 时钟的 SI 要求比 MII 的 25 MHz 更严格。如果你在 PCB 上看到 REF_CLK 走线过长,记得做阻抗匹配,否则你会看到一些间歇性连接失败——嗯,我在调试一块 4 层板时就吃过这个亏。