4. EEPROM内存映射(SFF-8636):Lower Memory与Upper Page
好,咱们今天聊聊光模块的“大脑”——EEPROM内存映射。说白了,这就是模块和主机之间沟通的“协议语言”。你插上一个100G光模块,交换机怎么知道它是100G还是40G?怎么知道它的厂商、序列号、告警状态?全靠这片EEPROM里的数据。
我个人习惯,拿到一个新模块,第一件事就是读它的Lower Memory。这就像看一个人的身份证,基本信息全在这儿。
4.1 Lower Memory(0x00-0x7F)——模块的“身份证”
Lower Memory一共128个字节,地址从0x00到0x7F。这部分是强制要求的,所有符合SFF-8636标准的模块都必须支持。我把它分成几个关键区域:
| 地址范围 | 内容 | 我关注的点 |
|---|---|---|
| 0x00-0x01 | 标识符(Identifier) | 一眼看出是QSFP28还是SFP+ |
| 0x02 | 状态寄存器(Status) | 模块是否准备好,有没有告警 |
| 0x03-0x15 | 中断标志、告警、警告阈值 | 调试时最常翻的区域 |
| 0x16-0x21 | 模块温度、电压、偏置电流、TX功率、RX功率 | 实时监控性能,看模块“健康”不 |
| 0x22-0x7F | 保留、校验和、应用选择等 | 偶尔用,但别忽略校验和 |
举个例子,地址0x00的值如果是0x0D,那就是QSFP28模块。如果是0x03,那就是SFP+。我在项目中遇到过好几次,客户说模块不工作,我一读0x00,发现他插了个SFP+模块到QSFP28端口上……嗯,这锅模块不背。
重点:地址0x02的Bit 0是“模块准备好”标志位。上电后如果这个位一直为0,说明模块初始化没完成。我曾经排查过一个案例,模块上电后等了5秒这个位才置1,最后发现是电源纹波太大,模块内部MCU启动慢。
4.2 Upper Page 00——模块的“简历”
Upper Page 00从地址0x80开始,一直到0xFF。这部分存的是模块的静态信息,比如厂商名、PN码、SN码、速率等级等等。说白了,就是模块的“简历”。
你想想看,一个数据中心里几千个模块,怎么管理?全靠读Upper Page 00里的序列号。我建议你在做系统集成时,一定要把序列号和端口号做映射,不然出了问题你都不知道哪个模块在哪个口上。
| 地址 | 字段 | 长度 |
|---|---|---|
| 0x80-0x83 | 标识符(重复) | 4字节 |
| 0x84-0x87 | 扩展标识符 | 4字节 |
| 0x88-0x97 | 厂商名(Vendor Name) | 16字节 |
| 0x98-0x9F | 厂商OUI | 8字节 |
| 0xA0-0xAF | PN码(Part Number) | 16字节 |
| 0xB0-0xB3 | 版本号 | 4字节 |
| 0xB4-0xB7 | 序列号(Serial Number) | 4字节起始,实际16字节 |
小技巧:读PN码时注意ASCII码是左对齐还是右对齐。有些厂商喜欢在字符串后面补空格,有些补0x00。我习惯用十六进制读一遍,再转ASCII,避免被空格坑了。
4.3 Upper Page 01/02/03——模块的“详细档案”
Upper Page 01、02、03是可选的,但100G模块基本都会实现。它们分别存什么?
- Page 01:告警和警告阈值。比如温度超过多少度告警,RX功率低于多少dBm告警。调试时如果模块频繁报错,先看这里阈值设得合不合理。
- Page 02:用户可写区。有些厂商会把校准系数、DSP配置写在这里。我建议不要随便改,除非你清楚后果。
- Page 03:增强型选项。比如通道控制、速率协商、FEC配置等。100G模块的FEC开关就在这页里。
为什么会分这么多页?因为EEPROM空间有限,SFF-8636用“页面切换”的方式来扩展地址空间。你写0x7F寄存器选择页面,然后读0x80-0xFF就是对应页的内容。这个机制我刚开始也觉得绕,后来习惯了就好。
注意:Page 03的地址0x80-0x81是“速率选择”寄存器。如果你改了速率,模块需要重新初始化。我曾经在调试时改了速率没复位模块,结果光口死活不亮……折腾了半天才发现是这个问题。
4.4 标识符与状态寄存器——模块的“红绿灯”
标识符(Identifier)在地址0x00,状态寄存器(Status)在地址0x02。这两个寄存器我每次调试必看。
标识符的值决定了模块类型:
- 0x00:未定义
- 0x03:SFP+
- 0x0D:QSFP28
- 0x11:QSFP-DD
状态寄存器里,Bit 0是“模块准备好”,Bit 1是“模块故障”,Bit 2是“LOS(信号丢失)”。如果Bit 1亮了,说明模块内部有故障,比如激光器失效、DSP锁不住等。这时候别急着换模块,先读一下告警寄存器(0x03-0x06),看看具体是哪个通道、哪个参数出了问题。
我记得有一次,客户反馈某个端口频繁闪断。我远程登录读状态寄存器,发现Bit 2(LOS)间歇性置1。再读告警寄存器,发现是RX功率低于阈值。最后排查下来,是光纤接头脏了。擦一擦,问题解决。你看,读寄存器比换模块快多了。
4.5 知识体系结构图
下面这张图帮你理清EEPROM内存映射的整体结构。我画图时习惯把Lower Memory比作“前台”,Upper Page比作“后台档案室”。
4.6 调试实战:怎么读EEPROM
最后,我分享一个读EEPROM的Python脚本片段。你可以在调试时直接用,省得每次手动算地址。
import smbus
import time
# I2C地址:QSFP28通常是0x50
I2C_ADDR = 0x50
bus = smbus.SMBus(1)
def read_lower_memory():
"""读取Lower Memory 0x00-0x7F"""
data = []
for addr in range(0x00, 0x80):
val = bus.read_byte_data(I2C_ADDR, addr)
data.append(val)
return data
def read_upper_page(page):
"""读取指定Upper Page"""
# 先选择页面
bus.write_byte_data(I2C_ADDR, 0x7F, page)
time.sleep(0.01) # 等页面切换稳定
data = []
for addr in range(0x80, 0x100):
val = bus.read_byte_data(I2C_ADDR, addr)
data.append(val)
return data
# 示例:读标识符和状态
lower = read_lower_memory()
print(f"标识符: 0x{lower[0]:02X}")
print(f"状态寄存器: 0x{lower[2]:02X}")
print(f"模块准备好: { (lower[2] & 0x01) > 0 }")
提示:读Upper Page时,页面切换后一定要加延时。有些模块切换慢,不加延时读到的是上一页的数据。我吃过这个亏,后来统一加了10ms延时,再没出过问题。
好了,EEPROM内存映射这块就聊到这儿。记住:Lower Memory是基础,Upper Page是扩展。调试时先读标识符确认模块类型,再看状态寄存器判断模块是否正常,最后读监控参数定位问题。这套流程我用了好多年,基本没翻过车。
公众号:蓝海资料掘金营,微信deep3321