4、交换芯片初始化流程:上电时序、复位逻辑、PLL配置、MAC/PHY初始化、SerDes链路训练

交换芯片的初始化,说白了就是给它「接上电、叫醒它、告诉它怎么跑、再把它的手脚(端口)都活动开」。这一步要是没做好,后面所有功能都是空中楼阁。我见过太多开发板,硬件焊得没问题,但就是不通,最后查出来是初始化顺序乱了。

咱们一步步拆开看。这五个环节,环环相扣,一个都不能跳。

4.1 上电时序:别让芯片「饿着」启动

交换芯片内部通常有多个电源域:核心电压(Core,通常是0.9V~1.2V)、IO电压(1.8V或3.3V)、SerDes模拟电压(1.0V或1.2V)。

上电时序的核心原则是:先给核心供电,再给IO供电,最后给SerDes供电。为什么?因为核心电路先稳定,IO才能安全地接收外部信号。SerDes对电源纹波极其敏感,必须最后上电。

典型上电顺序(以BCM56870系列为例):

  1. VDD_CORE (0.9V) → 稳定时间 ≥ 1ms
  2. VDD_IO (1.8V) → 稳定时间 ≥ 1ms
  3. VDD_SERDES (1.0V) → 稳定时间 ≥ 5ms
  4. 所有电源稳定后,释放复位信号

我在项目中遇到过一个问题:某款国产交换芯片,上电顺序反了,结果芯片虽然没烧,但SerDes端口死活锁不住链路。查了两天,最后发现是电源管理芯片的时序配置错了。嗯,从那以后我每次画原理图,都会在电源芯片的EN引脚上串RC延时,确保顺序可控。

注意: 有些芯片支持「电源斜坡」——也就是几个电源同时上升,但斜率不同。这需要仔细看数据手册的Figure 1(通常叫Power-Up Sequence Diagram)。别想当然,每个型号都不一样。

4.2 复位逻辑:别急着松手

复位信号(RESET_N)的时序,比你想的讲究。简单来说:所有电源稳定后,复位信号至少保持低电平10ms,再拉高

为什么是10ms?因为芯片内部的PLL需要时间锁定,内部状态机需要时间初始化。你想想看,如果复位时间太短,PLL还没锁住你就开始配置寄存器,那写进去的值可能都是乱的。

我个人习惯的做法是:

  • 硬件上:用复位监控芯片(如MAX809)保证复位信号干净
  • 软件上:在驱动初始化函数开头,先读一个芯片ID寄存器,确认芯片已经「醒」了
/* 伪代码示例:复位后等待芯片就绪 */
void switch_init(void) {
    uint32_t chip_id;
    
    /* 拉高复位,开始等待 */
    gpio_set_level(RESET_PIN, 1);
    
    /* 等待至少10ms */
    delay_ms(10);
    
    /* 轮询芯片ID,确认芯片已响应 */
    for (int i = 0; i < 100; i++) {
        chip_id = read_reg(REG_CHIP_ID);
        if (chip_id == EXPECTED_ID) {
            break;
        }
        delay_ms(1);
    }
    
    if (chip_id != EXPECTED_ID) {
        /* 芯片没起来,别往下走了 */
        error_handler("Switch chip not responding");
    }
}

小技巧: 有些芯片支持「软复位」——通过写一个特殊寄存器来复位内部逻辑,而不影响PLL。这在调试时特别有用,不用每次都断电重启。

4.3 PLL配置:给芯片一颗「稳定的心脏」

PLL(锁相环)负责产生芯片内部所有时钟。交换芯片的PLL通常有多个:一个给核心逻辑,一个给SerDes,一个给MAC。

配置PLL时,核心参数就三个:参考时钟频率、倍频系数、分频系数。输出频率 = 参考时钟 × 倍频 / 分频。

举个例子,如果你的板子上有25MHz晶振,芯片需要125MHz的MAC时钟,那就需要倍频5倍(25 × 5 = 125)。但实际芯片的PLL可能支持整数倍频或分数倍频,你得看数据手册的PLL配置表。

PLL配置步骤(通用流程):

  1. 将PLL置于旁路模式(Bypass),此时芯片用参考时钟直接工作
  2. 写入倍频系数(M)、分频系数(N)、后分频系数(K)
  3. 等待PLL锁定(通常需要几百微秒到几毫秒)
  4. 读取PLL锁定状态寄存器,确认锁定
  5. 切换回PLL模式,芯片开始用PLL输出的时钟

我曾经踩过一个坑:某款芯片的PLL锁定时间标称是500μs,但实际在低温环境下需要2ms。结果产品在北方冬天启动时,PLL还没锁住我就开始配置SerDes,导致链路训练失败。后来我在代码里把等待时间改成了5ms,问题解决。说白了,数据手册给的是典型值,你得留余量。

4.4 MAC/PHY初始化:让端口「活」起来

MAC和PHY的初始化,是让每个以太网端口具备收发能力。这一步通常包括:

  • MAC层配置: 设置MAC地址、使能流控(Flow Control)、配置帧大小(MTU)、使能CRC校验
  • PHY层配置: 设置速率(10/100/1000M)、双工模式(半双工/全双工)、使能Auto-Negotiation
  • MDIO/MDC总线: 通过管理接口读写PHY寄存器

我个人习惯先把所有端口强制设置为一个已知状态(比如1000M全双工),等链路训练完成后再开启Auto-Negotiation。这样调试时更容易定位问题——如果强制模式都不通,那肯定是硬件或PHY配置有问题。

/* 伪代码:初始化一个千兆端口 */
void port_init(int port_id) {
    /* 1. 配置MAC地址 */
    write_reg(MAC_ADDR_LOW(port_id), mac_low);
    write_reg(MAC_ADDR_HIGH(port_id), mac_high);
    
    /* 2. 设置MTU为1522字节(含VLAN标签) */
    write_reg(MTU_CFG(port_id), 1522);
    
    /* 3. 使能流控 */
    write_reg(FLOW_CTRL(port_id), ENABLE);
    
    /* 4. 通过MDIO配置PHY */
    mdio_write(port_id, PHY_REG_CTRL, 0x1000); /* 复位PHY */
    delay_ms(100);
    mdio_write(port_id, PHY_REG_CTRL, 0x1200); /* 1000M全双工,使能Auto-Neg */
}

注意: 有些交换芯片的MAC和PHY是集成在一起的(比如车载常用的TJA1100系列),有些是分离的。集成芯片的初始化顺序更简单,但分离芯片需要额外注意MDIO总线的时序——我曾经因为MDIO上拉电阻选错了,导致PHY寄存器读写偶尔失败,查了整整一个下午。

4.5 SerDes链路训练:让数据「跑」起来

SerDes(串行器/解串器)是高速数据传输的核心。在车载以太网中,1000BASE-T1和100BASE-T1都依赖SerDes进行链路训练。

链路训练的过程,说白了就是两端互相「握手」:

  1. 发送端: 发送训练序列(Training Pattern)
  2. 接收端: 检测信号,调整均衡器(EQ)、时钟恢复(CDR)参数
  3. 双方协商: 交换能力信息(速率、FEC模式等)
  4. 锁定: 接收端锁定到发送端的时钟,链路建立

你想想看,这个过程有点像两个人打电话——你先说「喂」,对方听到后调整音量,然后说「听到了」,你们再确认用普通话还是方言。链路训练就是干这个的。

SerDes链路训练的关键寄存器:

寄存器 作用 典型值
SerDes Control 启动/停止链路训练 0x01 (启动训练)
SerDes Status 读取链路状态(锁定/未锁定) 0x03 (已锁定)
EQ Control 手动/自动均衡 0x00 (自动)
Signal Detect 检测是否有信号 0x01 (有信号)

我在调试SerDes时,最常用的手段是:先读Signal Detect寄存器,确认物理连接没问题;再读链路状态寄存器,看训练是否完成。如果链路一直锁不住,我会检查PCB走线的阻抗匹配——车载环境下的线束和连接器,经常是罪魁祸首。

调试技巧: 如果SerDes链路训练失败,可以尝试以下步骤:

  • 检查参考时钟是否稳定(用示波器看频率和抖动)
  • 检查电源纹波(SerDes对电源噪声极其敏感)
  • 尝试降低速率(比如从1000M降到100M)
  • 手动设置EQ参数(有些芯片支持手动覆盖)

小结

交换芯片初始化,五个步骤环环相扣:上电时序错了可能烧芯片,复位时间短了芯片起不来,PLL没锁住配置全白费,MAC/PHY没配好端口不通,SerDes训练失败链路连不上。

我个人建议,在写初始化代码时,每一步都加上状态检查和超时处理。别怕代码啰嗦,调试时你会感谢自己的。嗯,今天就聊到这儿,下一章咱们讲讲交换芯片的VLAN配置——那又是一个容易踩坑的地方。