4. 100BASE-T1 PHY主从模式配置与切换
任务说明
100BASE-T1 链路要求两端 PHY 一主一从:主端发送时钟,从端恢复时钟。本案例通过寄存器配置主从模式,读取 BMSR 链路状态位,验证切换对链路建立的影响。
寄存器与流程
使用标准寄存器:BMCR(0x00) 的 bit12 选择主从(1=主,0=从),BMSR(0x01) 的 bit2 为 Link Status。流程:软复位 → 写主从位 → 轮询 BMSR 直到链路建立或超时。
完整代码
#include <stdio.h>
#include <stdint.h>
#include <unistd.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 BMCR 0x00
#define BMSR 0x01
#define BMCR_RESET (1u << 15)
#define BMCR_MASTER (1u << 12)
#define BMSR_LINK (1u << 2)
/* 配置主从模式:master=1 主,0 从 */
int phy_set_master_slave(uint8_t phy, int master)
{
uint16_t v;
if (mdio_read(phy, BMCR, &v)) return -1;
v |= BMCR_RESET;
if (mdio_write(phy, BMCR, v)) return -1;
usleep(2000); /* 等待复位完成 */
if (mdio_read(phy, BMCR, &v)) return -1;
if (master) v |= BMCR_MASTER;
else v &= ~BMCR_MASTER;
return mdio_write(phy, BMCR, v);
}
/* 轮询链路状态,返回 1 建立 / 0 超时 / -1 错误 */
int phy_wait_link(uint8_t phy, int timeout_ms)
{
uint16_t v;
for (int i = 0; i < timeout_ms; i++) {
if (mdio_read(phy, BMSR, &v)) return -1;
if (v & BMSR_LINK) return 1;
usleep(1000);
}
return 0;
}
int main(void)
{
uint8_t phy = 0;
int modes[2] = {1, 0}; /* 先主后从 */
const char *name[2] = {"MASTER", "SLAVE"};
for (int i = 0; i < 2; i++) {
if (phy_set_master_slave(phy, modes[i])) {
printf("%s: config error\n", name[i]);
continue;
}
int r = phy_wait_link(phy, 3000);
printf("%s: link %s\n", name[i],
r == 1 ? "UP" : r == 0 ? "TIMEOUT" : "ERROR");
}
return 0;
}
运行与验证
将 mdio_read/mdio_write 对接实际 MAC 的 MDIO 驱动后编译运行:gcc phy_ms.c mdio_impl.c -o phy_ms && ./phy_ms。
判定标准:对端配置为相反模式时,对应模式应打印 link UP;若两端同为 MASTER 或同为 SLAVE,则打印 link TIMEOUT,即验证主从切换对链路建立的影响。