3. 前导码与起始码详解
大家好,我是老李。做硬件十几年,MDIO这条总线我打交道最多。很多刚入行的同事觉得前导码和起始码就是几个固定位,没啥好讲的。但说实话,很多通信问题就出在这两段“简单”的序列上。
3.1 32位前导码:全是1,但没那么简单
MDIO帧的开头,是32个连续的1。也就是:
1111 1111 1111 1111 1111 1111 1111 1111
你可能会问:为什么一定要32个?少几个不行吗?我来拆开讲讲它的三个核心作用。
| 作用 | 说明 | 我的经验 |
|---|---|---|
| 时钟同步 | 让从设备(PHY)锁住主设备(MAC)输出的时钟沿和采样窗口 | 曾经遇到过时钟抖动大,前导码少两个1,PHY就丢帧 |
| 电气稳定 | 连续高电平让总线电容充放电达到稳态,避免起始码被误判 | 在长走线场景下,前导码不够长,起始码01会被当成00或11 |
| 状态机复位 | 确保PHY的接收状态机从任意状态回到IDLE,准备接收新帧 | 我记得有一次PHY芯片在异常中断后,收到正常帧之前至少要18个1才能恢复 |
我个人习惯,在写驱动时一定要检查前导码的完整性。因为有些MAC控制器会在省电模式下缩短前导码,这就坑了。
3.1.1 电气特性:为什么是“1的序列”?
MDIO使用推挽输出,平时总线空闲时MDIO引脚处于高阻态,由上拉电阻拉到高电平。但你想想看,如果空闲是1,那前导码也是1,怎么区分?关键在于:空闲时MDC时钟是停的,而前导码期间MDC在正常跳变。
连续32个1,其实是在做一件事:让总线上的电压从“不确定的浮空状态”快速拉到稳定的高电平,同时让接收端的采样时钟锁相环锁定。
我曾经踩过一个坑: 某款PHY在低温下,前导码需要至少36个1才能可靠同步。后来查手册才知道,它的内部锁相环启动时间受温度影响。从那以后,我设计驱动时都主动发40个1,多几个无所谓,少了会翻车。
3.2 2位起始码:01——不能多也不能少
前导码结束后,紧跟着就是起始码01。为什么是01,不是10、00或11?
- 00: 和空闲状态(高阻上拉为1)冲突,且容易误判为总线未激活
- 11: 和前导码的1无法区分,帧边界模糊
- 10: 虽然技术上可行,但IEEE 802.3标准选择了01,为了保证唯一性
说白了,起始码01的功能就是一个帧开始标记。接收端在检测到连续1之后,突然看到一个0,就知道“要开始了”。然后紧跟着的1,确认这是真正的起始码而不是噪声。
我习惯把起始码叫作“握手信号”。它跟前导码配合起来,就像两个人对话前的“喂喂喂——嗯,你听着呢?”
| 字段 | 位宽 | 值 | 检测方式 | 容错 |
|---|---|---|---|---|
| 前导码 | 32 | 全1 | 计数+电平采样 | 可容忍少2–3个1,但不推荐 |
| 起始码 | 2 | 01 | 边沿检测+窗口比较 | 严格,0/1位置不能错 |
3.3 时序与电气要求
MDIO的时序由MDC时钟控制。前导码和起始码都在MDC的上升沿采样。这里有一个容易忽略的点:
关键提醒: MDIO信号相对于MDC必须满足建立时间和保持时间。前导码的32个1就是为了让PHY内部的延迟锁相环稳定,这样后续起始码的采样窗口才准确。我个人建议在PCB layout时,MDIO走线长度不超过MDC走线长度的1.5倍,否则skew会导致起始码被采样错误。
电气特性方面,标准规定MDIO输出高电平≥2.4V(3.3V系统),低电平≤0.4V。前导码全是1,意味着连续32个bit时间的高电平输出。这时候驱动器的驱动能力要能维持电压不跌落。我曾经在一个项目里,因为上拉电阻选太大(10kΩ),前导码后半段电压掉到2.0V以下,PHY直接不认帧。换成4.7kΩ就解决了。
3.4 整体帧开头结构图
下面这张图展示了MDIO帧开头部分的结构,我习惯用1+32+2的方式记:
3.5 实践中的避坑清单
最后,我整理一份我自己的避坑清单,都是真金白银换来的教训:
- 前导码长度不要卡在32: 我个人习惯用40位,多出来的8位不影响兼容性,但能大幅提高长走线或噪声环境下的可靠性。
- 起始码必须严格检测01: 我在某项目里用了软判决,允许10%的偏差,结果在强干扰下误触发,数据全乱了。后来老老实实做硬判决,只认01。
- 上拉电阻选4.7kΩ~10kΩ: 具体根据总线电容和速率调整。速率越高电阻越小,但别低于2.2kΩ,否则驱动电流不够。
- MDC空闲时保持低电平: 很多新手把MDC空闲时拉高,导致前导码的1和空闲难以区分。标准要求空闲时MDC=0,MDIO=高阻(上拉为1)。
- 用示波器观察前导码尾部: 我曾经用逻辑分析仪抓包,明明看到32个1+01,但PHY就是不响应。后来用示波器一看,前导码最后两个1的电压只有2.0V,驱动能力不足。换驱动芯片后解决问题。
重要警告: 不要在图省事而在驱动里跳过前导码检测。有些控制器允许配置“短前导码”模式,但这在多器件总线或级联场景中极易导致冲突。我坚持使用标准前导码,哪怕多花几微秒。