3. 100BASE-T1 PHY自协商配置与验证

100BASE-T1 PHY自协商配置与验证 学习卡片

任务说明

本案例通过 MDIO 接口配置 100BASE-T1 PHY 的自协商寄存器,触发与对端 PHY 的速率/双工协商,然后读取协商结果寄存器并校验双方一致性。核心寄存器:

  • BMCR (0x00):bit12 使能自协商,bit9 重启自协商
  • BMSR (0x01):bit5 表示自协商完成
  • ANLPAR (0x05):对端通告能力(100BASE-T1 全双工 = 0x01C1)
  • ANLPA (0x06):本地通告能力

执行流程

写 BMCR 使能+重启AN 轮询 BMSR bit5=1? 读 ANLPAR 对端能力 比对一致性 输出结果 超时重试

完整代码

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

/* ---- 平台相关:MDIO 读写,需按实际硬件实现 ---- */
extern int mdio_read(uint8_t phy, uint8_t reg, uint16_t *val);
extern int mdio_write(uint8_t phy, uint8_t reg, uint16_t val);

#define PHY_ADDR        0x01
#define REG_BMCR        0x00
#define REG_BMSR        0x01
#define REG_ANLPAR      0x05
#define REG_ANLPA       0x06

#define BMCR_ANENABLE   (1u << 12)
#define BMCR_ANRESTART  (1u << 9)
#define BMSR_ANCOMPLETE (1u << 5)

/* 100BASE-T1 全双工通告字:selector=0x01, tech=0x40, fd=0x20, hd=0x40 */
#define AN_100BT1_FD    0x01C1u

static int wait_an_complete(uint32_t timeout_ms)
{
    uint16_t bmsr;
    for (uint32_t i = 0; i < timeout_ms; i++) {
        if (mdio_read(PHY_ADDR, REG_BMSR, &bmsr) != 0) return -1;
        if (bmsr & BMSR_ANCOMPLETE) return 0;
    }
    return -2; /* 超时 */
}

int main(void)
{
    uint16_t bmcr, anlpar, anlpa;

    /* 1. 配置本地通告能力为 100BASE-T1 全双工 */
    if (mdio_write(PHY_ADDR, REG_ANLPA, AN_100BT1_FD) != 0) {
        printf("write ANLPA failed\n"); return 1;
    }

    /* 2. 使能自协商并重启 */
    if (mdio_read(PHY_ADDR, REG_BMCR, &bmcr) != 0) {
        printf("read BMCR failed\n"); return 1;
    }
    bmcr |= BMCR_ANENABLE | BMCR_ANRESTART;
    if (mdio_write(PHY_ADDR, REG_BMCR, bmcr) != 0) {
        printf("write BMCR failed\n"); return 1;
    }

    /* 3. 等待协商完成 */
    int rc = wait_an_complete(3000);
    if (rc != 0) {
        printf("autoneg %s (rc=%d)\n", rc == -2 ? "timeout" : "io error", rc);
        return 1;
    }

    /* 4. 读取双方通告能力 */
    if (mdio_read(PHY_ADDR, REG_ANLPAR, &anlpar) != 0 ||
        mdio_read(PHY_ADDR, REG_ANLPA,  &anlpa)  != 0) {
        printf("read ANLPAR/ANLPA failed\n"); return 1;
    }

    printf("ANLPA  = 0x%04X\n", anlpa);
    printf("ANLPAR = 0x%04X\n", anlpar);

    /* 5. 验证一致性:双方均支持 100BASE-T1 全双工 */
    if ((anlpa & AN_100BT1_FD) == AN_100BT1_FD &&
        (anlpar & AN_100BT1_FD) == AN_100BT1_FD) {
        printf("PASS: 100BASE-T1 full-duplex negotiated\n");
        return 0;
    }
    printf("FAIL: capability mismatch\n");
    return 1;
}

运行与验证

将 mdio_read/mdio_write 对接实际 MAC 的 MDIO 驱动(或 Linux 下 SIOCGMIIREG/SIOCSMIIREG ioctl),编译后运行:

gcc -Wall -o aneg aneg.c mdio_port.c && ./aneg

通过条件:程序输出 PASS: 100BASE-T1 full-duplex negotiated,且 ANLPA 与 ANLPAR 的 bit0 与 bit6 均为 1(即 0x01C1)。若输出 timeout,检查对端 PHY 是否上电、链路是否连接、PHY 地址是否正确。