寄存器访问方法:四种手段,一个目标
寄存器怎么读、怎么写,这事看起来基础,但坑特别多。我最早做PHY调试时,就因为搞混了访问方式,花了两天查一个根本不存在的"bug"。说白了,不同芯片、不同板级环境,你能用的访问手段完全不同。这一章,我把四种主流方法掰开来讲。
核心要点:没有万能的方法。看硬件连线、看芯片手册、看你手头有什么工具,选对了事半功倍。
直接内存映射——最快,但也最"挑食"
什么叫直接内存映射?就是PHY的寄存器被映射到CPU的地址空间里。你写一个指针,就能读写。这种方式在嵌入式SoC里最常见。
// 一个简单的例子:通过MMIO读取PHY ID寄存器
uint32_t *phy_base = (uint32_t *)0x1C000000;
uint32_t phy_id = *(phy_base + 0x02); // 偏移0x02通常是PHYIDR1
printf("PHY ID: 0x%08X\n", phy_id);
我在项目中遇到过这么个情况:板子跑起来后PHY死活不通,用MMIO读回来的ID全是0xFFFFFFFF。嗯,这里要注意——不是寄存器坏了,是时钟还没稳定。你想想看,PHY的时钟域跟CPU不完全同步,复位后需要等一段时间才能访问。
个人习惯:MMIO访问前,先读一个已知的固定值寄存器确认总线连通。比如PHY ID寄存器,或者Vendor Specific寄存器。读回来不是预期的值,就别往下做了。
MDIO/MDC接口——PHY调试的"标准手语"
MDIO/MDC是IEEE 802.3定义的PHY管理接口。几乎所有带PHY的以太网设备都支持这种方式。它只有两根线:MDIO(数据)和MDC(时钟)。
操作时序其实很简单:
- MDC时钟持续产生
- MDIO线上先发32位前导码
- 接着是操作码(读=10,写=01)
- 然后是PHY地址和寄存器地址
- 最后是数据
我曾经犯过一个大错:以为所有PHY的MDIO地址都是芯片手册上写的那个。结果呢?有些PHY的地址可以通过外部电阻配置,板子上焊的是不同的值。那次我花了整整半天,最后拿万用表量了才发现。
避坑指南:MDIO访问前,先用读操作确认PHY地址。如果返回全是0或0xFFFF,很可能地址配置错了。别死磕软件,先查硬件。
I2C接口——慢,但灵活
有些PHY为了省引脚,把管理接口做成了I2C。这个在PON、车载以太网PHY里特别常见。I2C相比MDIO的优点是:你可以挂多个设备在一条总线上,而且I2C的寄存器地址空间更大(通常8位或16位)。
但代价是什么?慢。I2C标准模式只有100kHz,即使快模式也才400kHz。你想想看啊,做实时调试时,连续监控十几个寄存器,I2C的方式可能跟不上。
| 属性 | MDIO/MDC | I2C |
|---|---|---|
| 线数 | 2根(MDIO+MDC) | 2根(SDA+SCL) |
| 标准速率 | 2.5MHz | 100kHz/400kHz |
| 地址空间 | 5位PHY地址 + 5位寄存器地址 | 7位设备地址 + 8/16位寄存器地址 |
| 多设备支持 | 通过PHY地址区分(最多32个) | 通过设备地址区分(最多128个) |
我记得有次调试某个车载PHY,芯片手册上说支持MDIO,但板子上走的是I2C。被坑过一次后,我现在看手册第一件事就是确认管理接口类型。
PCIe配置读写——不常用,但必须会
现在很多高速PHY直接集成在PCIe网卡里。这种情况下,寄存器需要通过PCIe配置空间来访问。
PCIe访问PHY寄存器有两种层次:
- PCIe Configuration Space:标准配置寄存器,包括Vendor ID、Device ID等
- PCIe BAR Space:通过BAR映射到内存空间,访问PHY内部寄存器
做PCIe网卡调试时,我最常用的工具是lspci -xxx读配置空间,然后通过devmem2或者自己写的mmap程序读BAR空间。
# 读取PCIe设备配置空间
lspci -s 04:00.0 -xxx
# 通过sysfs访问BAR空间
cat /sys/bus/pci/devices/0000:04:00.0/resource0 | hexdump -C
# 或者用devmem2访问物理地址
devmem2 0xFC000000 w
重要提示:PCIe配置空间读回来的数据,要注意字节序。x86是小端序,但PHY寄存器定义可能是大端序。我踩过这个坑,读回来的寄存器值怎么算都对不上,最后发现是字节序弄反了。
好,四种方法讲完了。你可能会问:到底该用哪种?我个人的选择逻辑是这样的——
- 嵌入式SoC平台,CPU直连:直接内存映射,最快的选择
- 独立PHY芯片,标准以太网系统:MDIO/MDC,最稳妥
- PON或车载模块:I2C,看硬件连线
- PCIe网卡:PCIe配置读写,先用lspci确认设备枚举成功
下面这张图把这四种方法的适用场景和特点总结了一下,方便你对照。
方法都是好方法,关键别用错地方。