news 2026/4/21 4:15:18

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从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的时钟同步是设计中最容易出问题的部分。我们需要实现:

  1. 根据系统时钟和Prescale值生成标准SCL
  2. 处理多Master场景下的时钟同步
  3. 确保建立/保持时间满足规范要求

时钟分频的核心代码如下:

always @(posedge clk or negedge rst_n) begin if (!rst_n) begin clk_cnt <= 16'd0; scl_out <= 1'b1; end else if (i2c_enable) begin if (clk_cnt >= prescale_val) begin clk_cnt <= 16'd0; scl_out <= ~scl_out; // 翻转SCL时钟 end else begin clk_cnt <= clk_cnt + 1; end end end

关键时序参数:

模式标准速率建立时间保持时间
标准模式100kHz250ns300ns
快速模式400kHz100ns200ns
高速模式3.4MHz50ns100ns

3. I2C协议状态机实现

I2C协议的核心是一个精确的状态机,需要处理以下状态转换:

  • IDLE:等待传输开始
  • START:生成起始条件
  • ADDR:发送设备地址+R/W位
  • DATA_TX/RX:数据传输阶段
  • ACK/NACK:应答处理
  • STOP:生成停止条件

状态机Verilog实现片段:

parameter [2:0] IDLE = 3'b000, START = 3'b001, ADDR = 3'b010, DATA = 3'b011, ACK = 3'b100, STOP = 3'b101; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin state <= IDLE; sda_out <= 1'b1; end else begin case(state) IDLE: if (start_cond) state <= START; START: begin sda_out <= 1'b0; state <= ADDR; end // 其他状态处理... endcase end end

4. 典型应用:读取温度传感器数据

以常见的LM75温度传感器为例,演示完整的读写流程:

  1. 初始化配置

    • 设置Prescale寄存器产生100kHz SCL
    • 使能I2C控制器(CTRL.I2C_EN=1)
  2. 写入传感器地址

    // 写入设备地址(0x48) + 写方向 I2C->TXDATA = 0x90; // 0x48 << 1 | 0
  3. 写入寄存器指针

    I2C->TXDATA = 0x00; // 选择温度寄存器
  4. 重新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Ω)
  • 避免与其他高速信号平行走线
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/21 4:13:24

ICL8038信号发生器DIY全攻略:从原理图到波形调试(附AD源文件)

ICL8038信号发生器DIY全攻略&#xff1a;从原理图到波形调试 在电子工程领域&#xff0c;信号发生器是实验室和研发工作中不可或缺的基础设备。市面上的专业信号发生器往往价格昂贵&#xff0c;而基于ICL8038芯片的DIY方案&#xff0c;能以极低成本实现实验室级别的多功能波形输…

作者头像 李华
网站建设 2026/4/21 4:09:15

Python 作业一

0920笔记1.print(1,2,3,sep"--",end" ") 输出内容在屏幕上&#xff0c;打印变量的时候不能带引号2.input("提示词")获取到数据是字符串3.变量&#xff1a;实际上存储的是真实数据的引用&#xff0c;为存储数据引用的容器4.name "zhangsan&…

作者头像 李华
网站建设 2026/4/21 4:08:15

Handlebars-helpers高级用法:自定义辅助函数与扩展技巧

Handlebars-helpers高级用法&#xff1a;自定义辅助函数与扩展技巧 【免费下载链接】handlebars-helpers 188 handlebars helpers in ~20 categories. Can be used with Assemble, Ghost, YUI, express.js etc. 项目地址: https://gitcode.com/gh_mirrors/ha/handlebars-help…

作者头像 李华
网站建设 2026/4/21 4:07:15

深圳同袍存储解说DDR内存及SSD价格现状

DDR内存及SSD价格现状 近期&#xff0c;DDR内存和SSD价格呈现快速上涨趋势。根据市场监测数据&#xff1a;截至2025年10月中旬&#xff0c;最新涨价情况如下&#xff1a; DDR4内存&#xff1a;主流16GB模组价格涨幅达20%-30%&#xff0c;部分品牌高频条涨幅更高。DDR5内存&…

作者头像 李华
网站建设 2026/4/21 4:06:11

10个fsql实战案例:高效管理大型项目文件的终极指南

10个fsql实战案例&#xff1a;高效管理大型项目文件的终极指南 【免费下载链接】fsql Search for files using a fun query language 项目地址: https://gitcode.com/gh_mirrors/fs/fsql fsql是一款功能强大的文件搜索工具&#xff0c;它允许用户使用类SQL的查询语言在文…

作者头像 李华