第1章:PHY芯片初始化流程
各位同学,咱们今天聊聊PHY芯片的初始化。说实话,这步搞不定,后面所有网络通信都是白搭。我刚开始做驱动时,就吃过这个亏——芯片上电后死活不通,折腾了两天才发现是复位时序没处理好。
1.1 硬件复位
硬件复位,说白了就是给PHY芯片一个明确的启动信号。一般通过RST_N引脚来控制,低电平有效。
关键时序要求:
- 复位脉冲宽度:通常需要≥10ms(具体看芯片手册)
- 复位完成后:等待至少1ms再开始访问寄存器
- 时钟稳定后:才能释放复位信号
我遇到过一种情况:某款PHY芯片手册写的是1ms复位脉冲,结果实际测试发现要10ms才稳定。嗯,这里要注意——芯片手册的典型值不一定适用于所有工况,尤其是温度变化大的环境。
// 硬件复位示例(GPIO控制)
void phy_hardware_reset(void) {
// 拉低复位引脚
gpio_set_level(PHY_RST_PIN, 0);
// 保持至少10ms
delay_ms(10);
// 释放复位
gpio_set_level(PHY_RST_PIN, 1);
// 等待芯片稳定
delay_ms(20);
}
注意:有些PHY芯片在复位期间会消耗较大电流,电源设计要留足余量。我曾经因为电源纹波过大,导致复位后芯片状态不稳定,查了好久才发现是电源问题。
1.2 软件复位
硬件复位之后,我习惯再做一次软件复位。为什么?因为有些芯片的硬件复位只重置了数字部分,模拟部分可能还残留着之前的状态。
软件复位通过PHY的BMCR寄存器(Basic Mode Control Register,地址0x00)的bit 15来实现。写1触发复位,复位完成后硬件自动清零。
// 软件复位示例
int phy_soft_reset(void) {
uint16_t reg_val;
// 写BMCR寄存器,bit15置1
reg_val = 0x8000;
phy_write_reg(PHY_ADDR, 0x00, reg_val);
// 等待复位完成(bit15自动清零)
for (int i = 0; i < 100; i++) {
phy_read_reg(PHY_ADDR, 0x00, ®_val);
if ((reg_val & 0x8000) == 0) {
return 0; // 复位成功
}
delay_ms(1);
}
return -1; // 超时
}
我的经验:软件复位后,建议再读一次PHYID寄存器(地址0x02和0x03),确认芯片型号正确。我遇到过焊接错误导致地址冲突的情况,这一步能快速定位问题。
1.3 时钟配置
时钟是PHY的心脏。配置不对,数据根本传不出去。常见的时钟方案有几种:
| 时钟模式 | 时钟源 | 典型频率 | 适用场景 |
|---|---|---|---|
| 晶振直供 | 外部25MHz晶振 | 25MHz | RMII/RGMII |
| MAC提供 | MAC输出时钟 | 50MHz/125MHz | MII/GMII |
| PLL倍频 | 内部PLL | 可配置 | 灵活应用 |
你想想看,如果MAC用的是RMII模式,需要50MHz时钟,但PHY只配了25MHz,那数据速率就减半了。我调试时遇到过这种低级错误,查了半天才发现是时钟频率没对上。
时钟配置要点:
- 确认MAC和PHY的时钟频率一致
- 检查时钟抖动是否在允许范围内
- 注意时钟引脚的电压电平(1.8V/2.5V/3.3V)
1.4 MAC接口模式配置
这一步决定了PHY和MAC之间怎么通信。常见的接口模式有四种:
MII模式
标准接口,16根信号线。数据位宽4位,时钟25MHz。说白了就是并行传输,速度125Mbps。现在用得少了,因为占用的引脚太多。
RMII模式
简化版MII,只有8根信号线。数据位宽2位,时钟50MHz。我比较喜欢这个模式,引脚少,布线方便。但要注意,RMII需要50MHz参考时钟,而且收发时钟是共用的。
GMII模式
千兆以太网接口,24根信号线。数据位宽8位,时钟125MHz。这个模式对PCB布线要求很高,我建议新手尽量别用,容易出信号完整性问题。
RGMII模式
简化版GMII,12根信号线。数据位宽4位,时钟125MHz。DDR双沿采样,所以等效速率还是1000Mbps。嗯,这里要注意——RGMII对时钟和数据之间的延迟要求很严格,一般需要加TCLK延迟调整。
// 配置RGMII模式示例
void phy_config_interface(void) {
uint16_t reg_val;
// 读PHY控制寄存器
phy_read_reg(PHY_ADDR, 0x00, ®_val);
// 清除接口模式位(假设bit6:5控制接口模式)
reg_val &= ~(0x0060);
// 设置为RGMII模式(假设编码为10)
reg_val |= (0x0040);
// 写回寄存器
phy_write_reg(PHY_ADDR, 0x00, reg_val);
// 配置RGMII时钟延迟
// 有些PHY需要调整TXCLK和RXCLK的延迟
phy_write_reg(PHY_ADDR, 0x1D, 0x000B); // 访问扩展页
phy_write_reg(PHY_ADDR, 0x1E, 0x0008); // 设置TX延迟
}
避坑指南:我曾经在RGMII模式下遇到数据错位的问题,原因是MAC和PHY的时钟相位没对齐。后来在PHY的扩展寄存器里调整了TXCLK的延迟值,问题才解决。所以,RGMII模式下一定要检查时钟延迟配置。
1.5 完整的初始化流程
好了,把上面几步串起来,就是一个完整的PHY初始化流程:
- 硬件复位:拉低RST_N引脚≥10ms,释放后等待20ms
- 软件复位:写BMCR寄存器bit15,等待自动清零
- 验证芯片ID:读PHYID寄存器,确认型号正确
- 配置时钟:根据接口模式设置时钟源和频率
- 配置接口模式:设置MII/RMII/GMII/RGMII
- 配置其他参数:如自动协商、流控等(后续章节详述)
我的习惯:每次初始化完成后,我都会读一下基本状态寄存器(BMSR,地址0x01),看看链路状态、自动协商能力等是否正常。这一步能快速判断初始化是否成功。
说实话,PHY初始化看起来步骤不多,但每个细节都可能让你卡住好几天。我建议你在调试时,每做完一步就打印一下关键寄存器的值,这样出了问题能快速定位。好了,这一章就到这里,下一章咱们聊聊自动协商的细节。