FPGA实战:从零构建IIC控制器驱动LM75与AT24C128
在嵌入式系统开发中,IIC总线因其简洁的两线制设计和多设备支持能力,成为传感器与存储器件连接的理想选择。本文将带您深入理解IIC协议核心机制,并手把手指导如何用Verilog实现一个稳健的IIC主控制器,最终完成对LM75温度传感器和AT24C128 EEPROM的读写操作。
1. IIC协议精要与设计考量
IIC(Inter-Integrated Circuit)总线由Philips(现NXP)开发,仅需SCL(时钟线)和SDA(数据线)两根信号线即可实现多主多从通信。其核心特征包括:
- 地址寻址机制:7位或10位设备地址,支持同一总线上挂载多个从设备
- 半双工通信:同一时刻只能进行单向数据传输
- 时钟同步:主设备产生时钟信号,从设备可拉低SCL实现时钟扩展
- 应答机制:每个字节传输后跟随ACK/NACK应答位
在设计FPGA实现的IIC控制器时,需要特别注意几个关键时序参数:
| 时序参数 | 标准模式(100kHz) | 快速模式(400kHz) | 单位 |
|---|---|---|---|
| tSU;STA | 4.7 | 0.6 | μs |
| tHD;STA | 4.0 | 0.6 | μs |
| tSU;DAT | 250 | 100 | ns |
| tHD;DAT | 0 | 0 | ns |
| tSU;STO | 4.0 | 0.6 | μs |
提示:实际设计中应留有时序裕量,建议在标准模式按150kHz设计,快速模式按300kHz设计,以应对PCB走线延迟等不确定因素。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 状态机架构设计
一个完整的IIC控制器本质上是一个精密的状态机,需要处理起始条件、停止条件、数据传输和应答等多个状态。我们采用分层状态机设计,将控制流程分为顶层事务状态机和底层比特状态机。
2.1 顶层事务状态机
顶层状态机负责完整的IIC事务控制,典型状态包括:
verilog复制parameter MAIN_IDLE = 'd20; // 空闲状态
parameter MAIN_STAR = 'd21; // 起始条件
parameter MAIN_DEV0 = 'd22; // 发送设备地址(写)
parameter MAIN_ADDR = 'd23; // 发送内存地址
parameter MAIN_REST = 'd24; // 重复起始条件
parameter MAIN_DEV1 = 'd25; // 发送设备地址(读)
parameter MAIN_R8BI = 'd26; // 读取数据字节
parameter MAIN_W8BI = 'd27; // 写入数据字节
parameter MAIN_STOP = 'd28; // 停止条件
2.2 底层比特状态机
底层状态机精确控制每个比特位的传输时序,包括时钟高低电平的持续时间管理:
verilog复制// 写数据状态
parameter W1BY_SCLL = 'd6; // SCL低电平期间准备数据
parameter W1BY_SCLH = 'd7; // SCL高电平期间保持数据
parameter W1AK_SCLL = 'd8; // 等待ACK的SCL低电平
parameter W1AK_SCLH = 'd9; // 采样ACK的SCL高电平
// 读数据状态
parameter R1BY_SCLL = 'd11; // SCL低电平期间释放SDA
parameter R1BY_SCLH = 'd12; // SCL高电平期间采样数据
parameter R1AK_SCLL = 'd13; // 发送ACK的SCL低电平
parameter R1AK_SCLH = 'd14; // 发送ACK的SCL高电平
状态转换的关键在于精确的时序控制,以下是典型的状态转换代码片段:
verilog复制always@(posedge clk or posedge rst) begin
if(rst) begin
cur_state <= MAIN_IDLE;
end else begin
case(cur_state)
MAIN_IDLE: if(req) cur_state <= MAIN_STAR;
MAIN_STAR: if(down_ack) cur_state <= MAIN_DEV0;
MAIN_DEV0: if(down_ack) cur_state <= (err_ack) ? MAIN_STOP : MAIN_ADDR;
// ...其他状态转换逻辑
endcase
end
end
3. LM75温度传感器驱动实现
LM75是数字温度传感器,通过IIC接口提供9位至12位精度的温度测量。其关键特性包括:
- 温度分辨率:0.125°C/LSB
- 测量范围:-55°C至+125°C
- 默认地址:0x48(可通过地址引脚配置)
3.1 温度读取流程
读取LM75温度值的完整流程如下:
- 发送起始条件(START)
- 发送设备地址+写位(0x90)
- 发送温度寄存器地址(0x00)
- 发送重复起始条件(Repeated START)
- 发送设备地址+读位(0x91)
- 读取两个字节的温度数据
- 发送停止条件(STOP)
温度数据格式处理示例代码:
verilog复制// 温度值转换
wire signed [15:0] temp_raw = {rdata[15:8], rdata[7:5], 3'b000};
wire real temperature = $itor(temp_raw) * 0.125;
注意:LM75的温度寄存器返回16位数据,但实际有效位为[15:5],需要左移3位后再乘以0.125得到实际温度值。
3.2 配置寄存器设置
LM75提供配置寄存器(0x01)用于设置工作模式:
| 位域 | 功能 | 设置值 |
|---|---|---|
| [7:5] | 故障队列 | 00-11(触发次数) |
| [4:3] | 报警极性 | 0-1 |
| [2] | 工作模式 | 0:比较器,1:中断 |
| [1:0] | 关断模式 | 1:关断 |
配置示例:
verilog复制// 设置LM75为比较器模式,故障队列4次
send(0x01, 0b00100000); // 配置寄存器地址0x01,值0x20
4. AT24C128 EEPROM驱动实现
AT24C128是128Kbit(16K×8)串行EEPROM,支持标准IIC接口,具有以下特点:
- 页写模式:支持64字节页写入
- 写保护:支持硬件写保护
- 地址范围:16位地址空间(0x0000-0x3FFF)
4.1 写操作时序
单字节写入时序要点:
- 发送起始条件
- 发送设备地址+写位(0xA0)
- 发送高字节地址
- 发送低字节地址
- 发送数据字节
- 发送停止条件
Verilog实现关键代码:
verilog复制MAIN_DEV0: begin
per_main_state <= MAIN_DEV0;
wdata_shft <= {DEV_ADDR[6:0], 1'b0}; // 设备地址+写
bit_cnt <= 0;
end
MAIN_ADDR: begin
if(ADDR_NUM == 2) begin
wdata_shft <= (addr_cnt==0) ? addr[15:8] : addr[7:0];
end else begin
wdata_shft <= addr[7:0];
end
end
重要提示:AT24C128完成写入操作需要约5ms的周期时间(tWR),在此期间不应发起新的写操作。
4.2 读操作时序
随机地址读取操作流程:
- 发送起始条件
- 发送设备地址+写位(0xA0)
- 发送高字节地址
- 发送低字节地址
- 发送重复起始条件
- 发送设备地址+读位(0xA1)
- 读取数据字节(可连续读取)
- 发送停止条件
多字节读取的状态机处理:
verilog复制MAIN_R8BI: begin
if(down_ack && (data_cnt >= DATA_NUM+1)) begin
cur_state <= MAIN_STOP;
end else begin
cur_state <= R1BY_SCLL;
end
end
R1BY_SCLH: begin
if((delay_cnt == tHIGH-3) && (~state_change)) begin
rdata[15:0] <= {rdata[14:0], sda_i}; // 移位接收数据
bit_cnt <= bit_cnt + 1;
end
end
5. 调试技巧与常见问题
在实际硬件调试IIC控制器时,以下几个工具和技巧非常有用:
5.1 逻辑分析仪配置
使用Saleae逻辑分析仪捕获IIC信号时建议设置:
- 采样率:至少4倍于SCL频率(400kHz IIC需1.6MHz以上)
- 触发条件:SDA下降沿(START条件)
- 解码设置:选择IIC协议,设置正确的地址格式
5.2 常见问题排查
问题1:从设备无ACK响应
可能原因及解决方案:
- 设备地址错误:检查设备手册确认7位地址
- 设备未上电:测量VCC电压
- 总线冲突:检查是否有其他设备拉低SDA
问题2:数据读取错误
调试步骤:
- 确认SCL频率在设备支持范围内
- 检查建立/保持时间是否满足要求
- 使用示波器观察信号质量,排除毛刺干扰
问题3:EEPROM写入失败
注意事项:
- 确保两次写入间隔大于tWR(5ms)
- 页写入不能跨页(地址64字节边界)
- 写保护引脚(WP)需正确配置
verilog复制// 写入延时处理示例
always @(posedge clk) begin
if (write_done) begin
write_timer <= 250000; // 5ms @50MHz
end else if (write_timer > 0) begin
write_timer <= write_timer - 1;
end
end
wire write_ready = (write_timer == 0);
通过本文的实践,您不仅能够掌握IIC控制器的Verilog实现方法,还能获得FPGA与常用外设交互的宝贵经验。在实际项目中,这种可复用的IIC控制器核可以大大加速后续开发进程。
