从APB到SDA:手把手教你用Verilog搭建一个可配置的I2C Master控制器

张开发
2026/4/21 4:15:20 15 分钟阅读

分享文章

从APB到SDA:手把手教你用Verilog搭建一个可配置的I2C Master控制器
从APB到SDA手把手教你用Verilog搭建一个可配置的I2C Master控制器在嵌入式系统和FPGA设计中I2C总线因其简单的两线制结构和多设备支持能力成为连接低速外设的首选方案。本文将带你从零开始用Verilog实现一个基于APB总线的可配置I2C Master控制器重点解决实际工程中的时序同步、状态机设计和调试难题。1. I2C Master控制器的核心架构一个完整的I2C Master控制器需要处理协议时序、总线仲裁、时钟同步等多个复杂问题。我们的设计采用分层架构APB接口层负责与处理器通信接收配置参数和传输数据寄存器组包括时钟分频、控制状态、数据缓冲等寄存器协议引擎实现START/STOP条件生成、ACK检测等状态机时钟生成模块根据Prescale值产生符合标准的SCL时钟数据移位单元处理并行-串行转换和信号同步典型的寄存器映射如下寄存器名地址偏移宽度功能描述CTRL0x008控制寄存器使能/中断PRESCALE0x0416时钟分频系数TXDATA0x088发送数据缓冲RXDATA0x0C8接收数据缓冲STATUS0x108状态标志BUSY/ACK等提示APB总线采用小端模式寄存器地址偏移需按32位对齐2. 时钟生成与同步设计I2C的时钟同步是设计中最容易出问题的部分。我们需要实现根据系统时钟和Prescale值生成标准SCL处理多Master场景下的时钟同步确保建立/保持时间满足规范要求时钟分频的核心代码如下always (posedge clk or negedge rst_n) begin if (!rst_n) begin clk_cnt 16d0; scl_out 1b1; end else if (i2c_enable) begin if (clk_cnt prescale_val) begin clk_cnt 16d0; scl_out ~scl_out; // 翻转SCL时钟 end else begin clk_cnt clk_cnt 1; end end end关键时序参数模式标准速率建立时间保持时间标准模式100kHz250ns300ns快速模式400kHz100ns200ns高速模式3.4MHz50ns100ns3. I2C协议状态机实现I2C协议的核心是一个精确的状态机需要处理以下状态转换IDLE等待传输开始START生成起始条件ADDR发送设备地址R/W位DATA_TX/RX数据传输阶段ACK/NACK应答处理STOP生成停止条件状态机Verilog实现片段parameter [2:0] IDLE 3b000, START 3b001, ADDR 3b010, DATA 3b011, ACK 3b100, STOP 3b101; always (posedge clk or negedge rst_n) begin if (!rst_n) begin state IDLE; sda_out 1b1; end else begin case(state) IDLE: if (start_cond) state START; START: begin sda_out 1b0; state ADDR; end // 其他状态处理... endcase end end4. 典型应用读取温度传感器数据以常见的LM75温度传感器为例演示完整的读写流程初始化配置设置Prescale寄存器产生100kHz SCL使能I2C控制器(CTRL.I2C_EN1)写入传感器地址// 写入设备地址(0x48) 写方向 I2C-TXDATA 0x90; // 0x48 1 | 0写入寄存器指针I2C-TXDATA 0x00; // 选择温度寄存器重新START并读取数据// 发送重复START // 写入设备地址(0x48) 读方向 I2C-TXDATA 0x91; // 0x48 1 | 1 // 读取两个字节数据 temp_high I2C-RXDATA; temp_low I2C-RXDATA;5. 调试技巧与常见问题在实际调试中以下几个工具和技术特别有用逻辑分析仪抓取SCL/SDA波形验证时序仿真测试构建完整的Testbench环境状态机跟踪通过LED或串口输出当前状态常见问题排查表现象可能原因解决方案无ACK响应设备地址错误/设备未就位检查地址/供电数据采样错误建立/保持时间不足调整SCL相位总线死锁异常中断未发送STOP硬件复位/重新初始化仲裁失败多Master竞争增加重试机制在FPGA开发板上实测时发现SCL信号质量对传输稳定性影响极大。建议在PCB设计时保持SCL/SDA走线等长使用合适的上拉电阻(通常4.7kΩ)避免与其他高速信号平行走线

更多文章