第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, &reg_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, &reg_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初始化流程:

  1. 硬件复位:拉低RST_N引脚≥10ms,释放后等待20ms
  2. 软件复位:写BMCR寄存器bit15,等待自动清零
  3. 验证芯片ID:读PHYID寄存器,确认型号正确
  4. 配置时钟:根据接口模式设置时钟源和频率
  5. 配置接口模式:设置MII/RMII/GMII/RGMII
  6. 配置其他参数:如自动协商、流控等(后续章节详述)

我的习惯:每次初始化完成后,我都会读一下基本状态寄存器(BMSR,地址0x01),看看链路状态、自动协商能力等是否正常。这一步能快速判断初始化是否成功。

说实话,PHY初始化看起来步骤不多,但每个细节都可能让你卡住好几天。我建议你在调试时,每做完一步就打印一下关键寄存器的值,这样出了问题能快速定位。好了,这一章就到这里,下一章咱们聊聊自动协商的细节。