1. 读取并解析SFF-8472 EEPROM基础结构

读取并解析SFF-8472 EEPROM基础结构 学习卡片

任务说明

本案例目标为:通过I2C总线读取SFF-8472光模块EEPROM的A0h地址段(0x00~0x7F),解析其中的基础结构字段,包括标识符(Byte 0)、连接器类型(Byte 2)、收发器编码(Byte 3~10)、速率标识(Byte 13~14)以及长度等级(Byte 14~17),并以可读格式输出解析结果。代码将使用Linux用户态I2C设备驱动接口(/dev/i2c-N)实现,适用于带有SFP端口且已加载i2c-dev内核模块的嵌入式Linux平台。

硬件连接与I2C拓扑

SFF-8472 EEPROM 读取拓扑 CPU/SoC I2C控制器 /dev/i2c-0 SDA SCL SFP笼子 连接器 EEPROM A0h 地址 I2C从机地址 A0h (写) / A1h (读) 7位地址: 0x50

代码实现


#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <string.h>

#define EEPROM_ADDR  0x50   /* 7位I2C地址,对应A0h/A1h */
#define EEPROM_SIZE  128    /* A0h段大小 */
#define I2C_DEV      "/dev/i2c-0"

/* 读取A0h段全部128字节 */
static int read_eeprom(int fd, uint8_t *buf) {
    /* 先写寄存器地址0x00 */
    uint8_t reg = 0x00;
    if (write(fd, &reg, 1) != 1) {
        perror("write reg");
        return -1;
    }
    /* 连续读取128字节 */
    if (read(fd, buf, EEPROM_SIZE) != EEPROM_SIZE) {
        perror("read eeprom");
        return -1;
    }
    return 0;
}

/* 解析并打印基础结构字段 */
static void parse_and_print(const uint8_t *buf) {
    const char *id_str;
    const char *conn_str;

    /* Byte 0: 标识符 */
    switch (buf[0]) {
        case 0x00: id_str = "Unknown"; break;
        case 0x01: id_str = "GBIC"; break;
        case 0x02: id_str = "SFP/SFP+/SFP28"; break;
        case 0x03: id_str = "XBI"; break;
        case 0x04: id_str = "Xenpak"; break;
        case 0x08: id_str = "XFP"; break;
        case 0x0C: id_str = "QSFP"; break;
        case 0x0D: id_str = "QSFP+"; break;
        case 0x11: id_str = "QSFP28"; break;
        default:   id_str = "Reserved"; break;
    }

    /* Byte 2: 连接器类型 */
    switch (buf[2]) {
        case 0x00: conn_str = "Unknown"; break;
        case 0x01: conn_str = "SC"; break;
        case 0x02: conn_str = "FC Style 1"; break;
        case 0x03: conn_str = "FC Style 2"; break;
        case 0x04: conn_str = "BNC/TNC"; break;
        case 0x05: conn_str = "FC Coax"; break;
        case 0x06: conn_str = "FiberJack"; break;
        case 0x07: conn_str = "LC"; break;
        case 0x08: conn_str = "MT-RJ"; break;
        case 0x09: conn_str = "MU"; break;
        case 0x0A: conn_str = "SG"; break;
        case 0x0B: conn_str = "Optical Pigtail"; break;
        case 0x0C: conn_str = "MPO"; break;
        default:   conn_str = "Reserved"; break;
    }

    printf("=== SFF-8472 A0h 基础结构解析 ===\n");
    printf("Byte 0  (标识符)        : 0x%02X - %s\n", buf[0], id_str);
    printf("Byte 2  (连接器类型)    : 0x%02X - %s\n", buf[2], conn_str);
    printf("Byte 3  (收发器编码[0]) : 0x%02X\n", buf[3]);
    printf("Byte 4  (收发器编码[1]) : 0x%02X\n", buf[4]);
    printf("Byte 5  (收发器编码[2]) : 0x%02X\n", buf[5]);
    printf("Byte 6  (收发器编码[3]) : 0x%02X\n", buf[6]);
    printf("Byte 7  (收发器编码[4]) : 0x%02X\n", buf[7]);
    printf("Byte 8  (收发器编码[5]) : 0x%02X\n", buf[8]);
    printf("Byte 9  (收发器编码[6]) : 0x%02X\n", buf[9]);
    printf("Byte 10 (收发器编码[7]) : 0x%02X\n", buf[10]);
    printf("Byte 13 (速率标识[0])   : 0x%02X\n", buf[13]);
    printf("Byte 14 (速率标识[1])   : 0x%02X\n", buf[14]);
    printf("Byte 14 (长度(SMF),km)  : 0x%02X\n", buf[14]);
    printf("Byte 15 (长度(OM2),m)   : 0x%02X\n", buf[15]);
    printf("Byte 16 (长度(OM1),m)   : 0x%02X\n", buf[16]);
    printf("Byte 17 (长度(铜缆),m)  : 0x%02X\n", buf[17]);
}

int main(void) {
    int fd;
    uint8_t eeprom_data[EEPROM_SIZE];

    fd = open(I2C_DEV, O_RDWR);
    if (fd < 0) {
        perror("open i2c dev");
        return 1;
    }

    if (ioctl(fd, I2C_SLAVE, EEPROM_ADDR) < 0) {
        perror("ioctl I2C_SLAVE");
        close(fd);
        return 1;
    }

    if (read_eeprom(fd, eeprom_data) < 0) {
        close(fd);
        return 1;
    }

    parse_and_print(eeprom_data);

    close(fd);
    return 0;
}

编译与运行


# 交叉编译(若在目标板上原生编译则直接gcc)
arm-linux-gnueabihf-gcc -o sfp_eeprom sfp_eeprom.c

# 在目标板上运行(需root权限访问I2C设备)
./sfp_eeprom

验证方法与判定标准

将SFP光模块插入笼子后运行程序,观察输出。判定通过的准则为:

  • 程序正常退出且无I2C读写错误;
  • Byte 0输出为0x02且标识符显示为SFP/SFP+/SFP28(对于标准SFP模块);
  • Byte 2输出与模块实际连接器类型一致(如LC连接器输出0x07 - LC);
  • Byte 3~10收发器编码与模块规格书标注一致(例如10G SR模块Byte 3为0x10);
  • Byte 14~17长度字段与模块标称传输距离对应(如SR模块Byte 14为0x00,Byte 15为0x64即100m OM2)。

若输出与上述预期不符,首先检查I2C总线号是否正确(可通过i2cdetect -l确认),其次确认模块是否插紧、笼子供电是否正常。