1. IIC通信与AT24CM01芯片概述
在HDMI设备开发中,IIC(Inter-Integrated Circuit)总线是最常用的低速串行通信协议之一。它采用简单的两线制(SCL时钟线和SDA数据线)实现主从设备间的数据传输。AT24CM01是Microchip公司生产的1Mbit(128KB)串行EEPROM存储器,广泛应用于显示设备的EDID数据存储。
重要提示:本开发板上的AT24CM01芯片由HDMI接口供电而非开发板直接供电。这意味着在进行任何读写操作前,必须确保HDMI线缆一端连接开发板HDMI输入端口,另一端连接电脑HDMI输出端口,否则芯片将无法正常工作。
2. AT24CM01读时序详解
2.1 随机地址读取流程
随机读取允许从指定地址读取单个数据字节,其完整时序包含13个关键步骤:
- 起始条件:主设备(FPGA/MCU)拉低SDA线(在SCL高电平时)产生起始信号
- 发送器件地址+写标志:发送7位器件地址(0x50)和写标志位(0)
- 等待应答:从设备(AT24CM01)拉低SDA作为ACK
- 发送地址高字节:发送要读取的内存地址高8位(A16-A8)
- 等待应答:从设备再次应答ACK
- 发送地址低字节:发送内存地址低8位(A7-A0)
- 等待应答:从设备第三次应答ACK
- 重复起始条件:主设备再次产生起始信号
- 发送器件地址+读标志:发送相同器件地址但读标志位改为1
- 等待应答:从设备第四次应答ACK
- 读取数据:从设备输出指定地址的数据字节
- 非应答信号:主设备发送NACK表示读取结束
- 停止条件:主设备拉高SDA(在SCL高电平时)产生停止信号
verilog复制// FPGA实现示例(Verilog片段)
task i2c_read;
input [16:0] addr;
output [7:0] data;
begin
// 第一阶段:写入目标地址
i2c_start();
i2c_send_byte(8'hA0); // 器件地址 + 写
i2c_wait_ack();
i2c_send_byte(addr[15:8]); // 高字节地址
i2c_wait_ack();
i2c_send_byte(addr[7:0]); // 低字节地址
i2c_wait_ack();
// 第二阶段:重新启动并读取数据
i2c_start();
i2c_send_byte(8'hA1); // 器件地址 + 读
i2c_wait_ack();
data = i2c_recv_byte();
i2c_send_nack();
i2c_stop();
end
endtask
2.2 顺序读取机制
顺序读取可以显著提高连续地址数据的读取效率。其特点包括:
- 由随机读取发起,读取第一个字节后不发送停止信号
- 主设备对每个接收到的数据字节应答ACK
- 从设备内部地址指针自动递增(跨页时高位地址不变)
- 主设备发送NACK+停止信号终止传输
实际应用技巧:读取EDID数据时通常需要连续读取128或256字节,顺序读取可将传输时间缩短约40%(相比单字节读取)。
3. AT24CM01写时序深度解析
3.1 字节写入模式
字节写入适用于单个地址的数据修改,关键特性包括:
- 完整地址需要17位(A16-A0)
- 地址分三次发送:
- 器件地址字节包含P0(A16)
- 后续发送A15-A8(高字节)和A7-A0(低字节)
- 写入后需要等待典型的5ms写周期(tWR)
c复制// 单片机实现示例(C语言片段)
void AT24CM01_ByteWrite(uint32_t addr, uint8_t data) {
I2C_Start();
I2C_WriteByte(0xA0 | ((addr >> 16) & 0x01)); // 包含P0位
I2C_WaitAck();
I2C_WriteByte((addr >> 8) & 0xFF); // 高字节地址
I2C_WaitAck();
I2C_WriteByte(addr & 0xFF); // 低字节地址
I2C_WaitAck();
I2C_WriteByte(data);
I2C_WaitAck();
I2C_Stop();
delay_ms(5); // 等待写入完成
}
3.2 页面写入模式
页面写入可一次性写入最多256字节,但需要注意:
- 地址对齐:写入起始地址的低8位决定页面边界
- 自动回卷:超过256字节会覆盖同页面起始位置
- 实际限制:建议单次写入不超过32字节以保证可靠性
硬件设计经验:在HDMI EDID编程中,通常使用页面写入快速初始化整个EDID区域。但要注意VESA规范要求EDID必须包含有效校验和,错误的写入可能导致显示器无法识别。
4. EDID编程实战技巧
4.1 典型问题排查指南
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 读取全FF | 1. 芯片未供电 2. IIC上拉电阻缺失 3. 地址错误 |
1. 检查HDMI供电 2. 添加4.7K上拉 3. 验证器件地址 |
| 写入失败 | 1. 未等待tWR 2. 页面边界溢出 3. 电压不足 |
1. 增加延时 2. 分页写入 3. 检查电源质量 |
| 数据错误 | 1. 时序不符合规范 2. 信号干扰 3. 未正确处理ACK |
1. 用逻辑分析仪抓波形 2. 缩短走线长度 3. 完善错误处理 |
4.2 性能优化建议
-
时钟速率选择:
- 标准模式:100kHz
- 快速模式:400kHz(需确认芯片支持)
- 实际测试显示,在1米HDMI线缆下建议不超过200kHz
-
错误重试机制:
python复制# Python示例(使用smbus库)
def reliable_read(address, retry=3):
for attempt in range(retry):
try:
return i2c.read_byte(address)
except IOError:
if attempt == retry-1: raise
time.sleep(0.01)
- EDID校验和计算:
c复制// EDID块校验和计算(第128字节应为校验和)
void update_checksum(uint8_t *edid) {
uint8_t sum = 0;
for(int i=0; i<127; i++) sum += edid[i];
edid[127] = 256 - sum;
}
5. 硬件设计注意事项
-
PCB布局要点:
- SCL/SDA走线尽可能等长(偏差<50mm)
- 远离高频信号线(如HDMI差分对)
- 预留测试点(建议直径0.8mm)
-
上拉电阻选择:
总线速度 推荐阻值 电源电压 100kHz 4.7KΩ 3.3V 400kHz 2.2KΩ 5V -
ESD防护措施:
- 在HDMI接口处添加TVS二极管(如SRV05-4)
- 确保芯片VCC引脚有0.1μF去耦电容
在实际项目中,我们发现使用FPGA实现IIC控制器时,采用状态机设计比纯软件模拟更可靠。以下是我们验证过的状态机状态定义:
verilog复制localparam [3:0]
IDLE = 4'd0,
START = 4'd1,
ADDR = 4'd2,
ACK1 = 4'd3,
ADDR_HI = 4'd4,
ACK2 = 4'd5,
ADDR_LO = 4'd6,
ACK3 = 4'd7,
RESTART = 4'd8,
READ_ADDR = 4'd9,
ACK4 = 4'd10,
DATA = 4'd11,
NACK = 4'd12,
STOP = 4'd13;
对于需要批量生产的环境,建议制作专用的EDID编程治具,包含:
- USB转IIC接口板
- 带LED指示的HDMI插槽
- 自动化测试脚本
- 序列号写入功能
通过实际测量,在3.3V供电、25℃环境下,AT24CM01的关键时序参数如下:
| 参数 | 符号 | 典型值 | 单位 |
|---|---|---|---|
| 时钟频率 | fSCL | 100 | kHz |
| 起始保持 | tHD;STA | 4.0 | μs |
| 数据保持 | tHD;DAT | 0.9 | μs |
| 停止建立 | tSU;STO | 4.0 | μs |
最后分享一个调试技巧:当遇到通信不稳定时,可以先用示波器捕获SCL/SDA波形,重点检查:
- 起始/停止条件的建立时间
- ACK/NACK响应位置
- 数据有效窗口(SCL高电平期间SDA稳定)