3. 100BASE-T1 PHY自协商配置与验证
任务说明
本案例通过 MDIO 接口配置 100BASE-T1 PHY 的自协商寄存器,触发与对端 PHY 的速率/双工协商,然后读取协商结果寄存器并校验双方一致性。核心寄存器:
BMCR (0x00):bit12 使能自协商,bit9 重启自协商BMSR (0x01):bit5 表示自协商完成ANLPAR (0x05):对端通告能力(100BASE-T1 全双工 = 0x01C1)ANLPA (0x06):本地通告能力
执行流程
完整代码
#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 地址是否正确。