AR8035是业界广泛使用的千兆以太网PHY芯片,我在多个嵌入式项目中都深度使用过这颗芯片。先说说它的几个硬核特性:首先它完美支持10/100/1000M三种速率自适应,兼容IEEE 802.3标准,这个特性在实际组网中特别实用。记得有一次调试工业交换机,当网络中有老旧的100M设备接入时,AR8035能自动降速兼容,省去了手动配置的麻烦。
芯片的RGMII接口支持2.5V/1.8V/1.5V/3.3V多种I/O电压,这个设计太贴心了。去年做矿机控制板时,就遇到过主控芯片IO电压是1.8V而PHY芯片是3.3V的尴尬情况,幸亏AR8035有电压适配功能,直接通过硬件跳线就解决了电平匹配问题。这里要特别提醒:硬件设计时一定要仔细核对原理图中RGMII接口的电压配置,我见过不少工程师在这个问题上栽跟头。
时钟方面,AR8035内置25MHz晶振驱动电路,CLK_25M引脚可以输出25MHz或125MHz时钟。实测发现当配置为125MHz输出时,时钟抖动小于50ps,完全能满足高速数据传输需求。有个小技巧:在PCB布局时,这个时钟走线要尽量短,最好做包地处理,否则容易引起EMI问题。
AR8035的寄存器系统分为标准寄存器和扩展寄存器两大类。标准寄存器就是IEEE 802.3定义的那套,地址范围0x00-0x1F,比如基本的控制寄存器(0x00)、状态寄存器(0x01)等。而扩展寄存器才是AR8035的精华所在,需要通过MMD(管理数据接口)机制访问。
这里有个坑我踩过:AR8035有两个MMD设备地址——MMD3和MMD7。MMD3主要管时钟配置,MMD7负责各种高级功能。第一次调试时没注意这个区别,结果配置了半天时钟参数都不生效,后来查手册才发现地址搞错了。正确的访问流程应该是:
c复制// 访问MMD7的示例代码
phy_write(phydev, 0xD, 0x0007); // 选择MMD7设备
phy_write(phydev, 0xE, 0x8016); // 指定要操作的寄存器地址
phy_write(phydev, 0xD, 0x4007); // 使能读写模式
uint16_t val = phy_read(phydev, 0xE); // 读取寄存器值
MDIO总线看似简单,实际调试时却有很多门道。首先要注意时序问题,特别是当MDIO时钟频率超过2.5MHz时。我有次为了省事直接用了25MHz的MDC时钟,结果读写一直失败,后来用示波器抓波形才发现建立时间不够。建议新手先用1MHz以下的时钟频率调试,稳定后再逐步提高。
分享一个实用技巧:在Linux系统下,可以直接通过sysfs接口读写PHY寄存器,不用重新编译驱动:
bash复制# 读取PHY寄存器示例
echo 0x1 > /sys/class/mdio_bus/xx-xx/device/regnum
cat /sys/class/mdio_bus/xx-xx/device/regval
这个功能在快速验证寄存器配置时特别有用,省去了反复烧写程序的麻烦。
AR8035的时钟系统相当灵活,但也容易配置出错。重点说下CLK_25M引脚的配置,这个引脚可以输出25MHz或125MHz时钟,具体由MMD7的0x8016寄存器控制。配置流程如下:
c复制// 配置125MHz时钟输出
phy_write(phydev, 0xD, 0x0007); // 选择MMD7
phy_write(phydev, 0xE, 0x8016); // 指定0x8016寄存器
phy_write(phydev, 0xD, 0x4007); // 使能读写
uint16_t val = phy_read(phydev, 0xE);
val &= 0xFFE3; // 清除原有配置
val |= 0x0018; // 设置125MHz输出
phy_write(phydev, 0xE, val);
这里有个细节要注意:配置完成后最好延时10ms再读取寄存器值进行验证,因为时钟切换需要时间稳定。
环回测试是验证PHY芯片功能的重要手段。AR8035支持数字环回和模拟环回两种模式,数字环回的配置相对简单:
c复制// 千兆数字环回配置
phy_write(phydev, 0x00, 0x4140);
// 百兆数字环回
phy_write(phydev, 0x00, 0x6100);
// 十兆数字环回
phy_write(phydev, 0x00, 0x4100);
实测中发现一个现象:启用环回模式后,链路指示灯可能会异常闪烁,这是正常现象,不要误以为是硬件故障。建议测试完成后立即恢复原始配置,否则会影响正常通信。
在Linux环境下开发AR8035驱动时,主要需要实现phy_driver结构体的几个关键回调函数。下面是我常用的初始化模板:
c复制static struct phy_driver ar8035_driver = {
.phy_id = 0x004dd072,
.name = "AR8035",
.phy_id_mask = 0xffffffff,
.features = PHY_GBIT_FEATURES,
.config_init = &ar8035_config_init,
.soft_reset = &genphy_soft_reset,
.config_aneg = &genphy_config_aneg,
.read_status = &genphy_read_status,
.suspend = &genphy_suspend,
.resume = &genphy_resume,
.driver = {.owner = THIS_MODULE,},
};
特别要注意phy_id的匹配,AR8035的PHY ID由两个寄存器组成:0x03和0x02。有次调试时发现驱动死活不匹配,最后发现是phy_id_mask设置成了0xffffff00,导致低位匹配失败。
根据我的踩坑经验,硬件设计时要特别注意以下几点:
曾经有个项目因为省成本没加22欧姆匹配电阻,结果千兆模式下误码率高达10^-5,后来补上电阻后立刻降到10^-12以下。这个教训让我明白:硬件设计该省的不能省。