vivado技巧|如何在fpga内部实现i2c信号透传(fpga内部两组i2c inout信号互连)

这篇具有很好参考价值的文章主要介绍了vivado技巧|如何在fpga内部实现i2c信号透传(fpga内部两组i2c inout信号互连)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

大家好,我是数字小熊饼干,一个练习时长两年半的ic打工人。我在两年前通过自学跨行社招加入了IC行业。现在我打算将这两年的工作经验和当初面试时最常问的一些问题进行总结,并通过汇总成文章的形式进行输出,相信无论你是在职的还是已经还准备入行,看过之后都会有有一些收获,如果看完后喜欢的话就请关注我吧~谢谢~

最近遇到了这么一个问题:我有一个i2c master,它的管脚与fpga相连接,在fpga内部有一个i2c slave,在fpga外部还有一个i2c slave,但是它的管脚直接与fpga管脚连接了,并没有多余的地方让我能够直接接线和i2c master连接。因此,问题就转换成了——如何在fpga内部实现i2c信号透传,即在fpga内部实现相当于实际用导线直接把两个端口连接在一起的功能。

一、三态门

i2c的scl和sda信号的输出都是漏极开路,只能输出低电平和高阻态,且外接了一个上拉电阻,将i2c总线空闲时的输出电平拉至高电平,最终实现了线与的功能。

而在fpga内部,我们通常将端口处i2c的scl和sda信号定义为inout类型的信号,用verilog代码描述则为:

	inout scl;
    wire scl_out, scl_in;
​
    assign scl = (scl_out==1'b0) ? 1'b0 : 1'bz;
​
    assign scl_in = scl;

其中,scl为fpga端口处的scl信号,scl_out为内部输出的scl信号,scl_in为内部输入的scl信号。上述代码会被综合成三态门的形式,即:
vivado技巧|如何在fpga内部实现i2c信号透传(fpga内部两组i2c inout信号互连),vivado基础,fpga开发,嵌入式硬件
之所以叫三态门,是因为它的第三个状态是高阻态z。在实际电路中高阻态意味着响应的管脚悬空、断开,输出电平既不是0,也不是1,对下级电路无任何影响,和没接一样。当三态门的控制信号EN为真时,三态门导通;控制信号为假时,三态门的输出端是高阻态。

对于inout端口这种双向IO口,是用了两个三态门来实现的,一个负责输出,一个负责输入,通过EN与EN’作为控制信号来实现一个高阻断路,另一个实现输出/输入。因此,虽然说是双向IO口,但是其实它的输入和输出不是同时进行的,需要有一个控制信号EN来控制端口什么时候为输出,什么时候为输入。

对于我们的i2c scl与sda信号来说,若EN有效,则三态门作为输出使用,输出0值,否则则则为高阻态z,此时则是作为输入使用。

二、fpga内部i2c信号的互连

在了解了三态门实现inout端口的原理之后,我们回到最初的那个问题:如何在fpga内部实现i2c信号透传,即实现相当于实际中用导线直接把两个端口连接在一起的功能。

其实问题的解决方法很简单!要想实现fpga内部实现i2c信号透传,关键在于控制一个inout端口为输入,一个inout端口为输出!也就是如下图所示:
vivado技巧|如何在fpga内部实现i2c信号透传(fpga内部两组i2c inout信号互连),vivado基础,fpga开发,嵌入式硬件
于是问题又变成了如何控制三态门的使能,以在i2c master输出,i2c slave输入,与i2c master输入,i2c slave输出之间来回切换。

这个问题也很好解决,我们可以通过状态机中i2c地址阶段,地址应答阶段,读阶段,读应答阶段,写阶段,写应答阶段的跳转,结合对应的i2c信号输入是否为0,来对三态门的使能进行控制,直接上代码:

 localparam DRIVE_IDLE       = 3'b000;
    localparam DRIVE_ADDR       = 3'b001;
    localparam DRIVE_ADDR_ACK   = 3'b010;
    localparam DRIVE_WR         = 3'b011;
    localparam DRIVE_WR_ACK     = 3'b100;
    localparam DRIVE_RD         = 3'b101;
    localparam DRIVE_RD_ACK     = 3'b110;
    reg [2:0] i2c_drive_cs, i2c_drive_ns;
    reg rd_wt;
   
    always @(posedge clk_sys or negedge rst_n) begin
        if (!rst_n) begin
            rd_wt <= 1'b0;
        end else if (start_evt) begin
            rd_wt <= 1'b0;
        end else if ((i2c_drive_cs==DRIVE_ADDR) && (scl_pos_cnt==4'd8)) begin
            rd_wt <= sda_i_sync;
        end
     end
   
    always @(*) begin
        if (stop_evt)begin
            i2c_drive_ns = DRIVE_IDLE;
        end else if (start_evt && i2c_direct_access_en) begin    
            i2c_drive_ns = DRIVE_ADDR;
        end else begin
            i2c_drive_ns = i2c_drive_cs;
            case(i2c_drive_cs)
                //DRIVE_IDLE: i2c_drive_ns = start_evt && i2c_direct_access_en ? DRIVE_ADDR : i2c_drive_cs;
                DRIVE_ADDR: i2c_drive_ns = (scl_pos_cnt==4'd8) && scl_neg ? DRIVE_ADDR_ACK : i2c_drive_cs;
                DRIVE_ADDR_ACK: i2c_drive_ns = scl_neg ? (rd_wt ? DRIVE_RD : DRIVE_WR ) : i2c_drive_cs;
                DRIVE_WR :  i2c_drive_ns = (scl_pos_cnt==4'd8) && scl_neg ? DRIVE_WR_ACK : i2c_drive_cs;
                DRIVE_WR_ACK:   i2c_drive_ns = scl_neg ? DRIVE_WR : i2c_drive_cs;
                DRIVE_RD:   i2c_drive_ns = (scl_pos_cnt==4'd8) && scl_neg ? DRIVE_RD_ACK : i2c_drive_cs;
                DRIVE_RD_ACK:    i2c_drive_ns = scl_neg ? DRIVE_RD : i2c_drive_cs;
                default: i2c_drive_ns = i2c_drive_cs;
            endcase
        end
    end
    always @(posedge clk_sys or negedge rst_n) begin
        if (!rst_n) begin
            i2c_drive_cs <= DRIVE_IDLE;
        end else begin
            i2c_drive_cs <=  i2c_drive_ns;
        end
     end
    reg i2c_sda_mst_drive_oe, i2c_sda_drive_oe, i2c_scl_mst_drive_oe;  
    always @(posedge clk_sys or negedge rst_n) begin                    
        if (!rst_n) begin                                              
            i2c_sda_mst_drive_oe <= 1'b0;                              
            i2c_sda_drive_oe     <= 1'b0;                              
            i2c_scl_mst_drive_oe <= 1'b0;                              
        end else begin                                                  
            i2c_sda_mst_drive_oe <= ((i2c_drive_ns == DRIVE_ADDR) || (i2c_drive_ns == DRIVE_WR) || (i2c_drive_ns == DRIVE_RD_ACK)) && (sda_i_sync==1'b0);    
            i2c_sda_drive_oe     <= ((i2c_drive_ns == DRIVE_ADDR_ACK) || (i2c_drive_ns == DRIVE_WR_ACK) || (i2c_drive_ns == DRIVE_RD)) && (sda_master_in_sync==1'b0);      
            i2c_scl_mst_drive_oe <= (i2c_drive_ns != DRIVE_IDLE) && (scl_i_sync==1'b0);
        end                                                            
    end      
​
​
    assign sda =(i2c_sda_drive_oe) ? 1'b0 : 1'bz ;  
    assign scl = 1'bz ;                                                                                  
    assign sda_i = sda ;
    assign scl_i = scl ;
​
​
    assign sda_mst = (i2c_sda_mst_drive_oe) ? 1'b0 : 1'bz ;        
    assign scl_mst = (i2c_scl_mst_drive_oe) ? 1'b0 : 1'bz ;  
    assign sda_master_in = sda_mst ;
    assign scl_master_in = scl_mst ;


其中scl和sda为输入fpga的i2c master inout端口信号,scl_mst和sda_mst为连接fpga外部i2c slave inout端口信号。

使用vivado跑的波形仿真如下图所示:
vivado技巧|如何在fpga内部实现i2c信号透传(fpga内部两组i2c inout信号互连),vivado基础,fpga开发,嵌入式硬件
第一帧访问fpga内部i2c salve下配置,第二帧为访问fpga外部i2c salve进行2c burst读操作,第三帧为访问fpga外部i2c salve进行i2c burst写操作,第四帧为访问fpga外部i2c salve进行i2c burst读,i2c读写正常工作。

然后我们将vivado生成的bit文件烧写到fpga上进行测试,逻辑分析仪ila的结果如下:
vivado技巧|如何在fpga内部实现i2c信号透传(fpga内部两组i2c inout信号互连),vivado基础,fpga开发,嵌入式硬件
这是一个i2c读序列波形,i2c波形正常,说明我们的代码没有问题。

如果你喜欢这篇文章的话,请关注我的公众号-熊熊的ic车间,里面还有ic设计和ic验证的学习资料和书籍等着你呢~欢迎您的关注!文章来源地址https://www.toymoban.com/news/detail-841302.html

到了这里,关于vivado技巧|如何在fpga内部实现i2c信号透传(fpga内部两组i2c inout信号互连)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【LabVIEW FPGA入门】使用CompactRIO进行SPI和I2C通信

            NI提供了 SPI and I2C Driver API:下载SPI and I2C Driver API - NI         该API使用FPGA数字I / O线与SPI或I2C设备进行通信。         选择数字硬件时,要考虑三个选项: NI Single-Board RIO硬件可同时使用SPI和I2C驱动程序。 NI 9401 C系列模块与SPI驱动程序配合使用效果最佳。

    2024年02月02日
    浏览(48)
  • 【WCH】CH32F203基于内部RTC+I2C SSD1306 OLED时钟和温度显示

    📌相关篇《【WCH】CH32F203基于内部RTC时钟+I2C SSD1306 OLED显示》 📺显示效果: ✨主要是在其基础 上增加温度显示,温度数据来源于DS18B20,更换了OLED驱动显示字体相关内容。 🔰仅作为功能演示,内部RTC精度不高,长时间运行需要依赖第三方数据校准才行。 🔖代码是从STM32工

    2023年04月26日
    浏览(46)
  • 基于FPGA的I2C接口控制器(包含单字节和多字节读写)

      前文对IIC的时序做了详细的讲解,还有不懂的可以获取TI的IIC数据手册查看原理。通过手册需要知道的是IIC读、写数据都是以字节为单位,每次操作后接收方都需要进行应答。主机向从机写入数据后,从机接收数据,需要把总线拉低来告知主机,前面发送的数据已经被接

    2024年02月19日
    浏览(47)
  • I2C协议介绍以及HAL库实现I2C对SHT30温湿度采样

    (1)I2C协议简介 I2C总线是Philips公司在八十年代初推出的一种串行、半双工的总线,主要用于近距离、低速的芯片之间的通信。 12C Bus(IIC, Inter-Integrated Circuit Bus)是由一根数据线SDA用于收发数据,一根时钟线SCL用于通信双方时钟的同步,利用上拉电阻将它们拉成高电平(表示总

    2023年04月24日
    浏览(56)
  • STM32学习笔记(十)丨I2C通信(使用I2C实现MPU6050和STM32之间通信)

    ​  本次课程采用单片机型号为STM32F103C8T6。(鉴于笔者实验时身边只有STM32F103ZET6,故本次实验使基于ZET6进行的) ​  课程链接:江协科技 STM32入门教程   往期笔记链接:   STM32学习笔记(一)丨建立工程丨GPIO 通用输入输出   STM32学习笔记(二)丨STM32程序调试

    2024年01月19日
    浏览(50)
  • STM32软件模拟I2C从机的实现方法

    在使用I2C通信时,一般会用到软件模拟I2C。目前网络上能搜索到的软件模拟I2C一般都是模拟I2C主机,很少有模拟I2C从机的例程。由于I2C主机在进行数据收发时,有明确的可预见性,也就是主机明确知道什么时候要进行数据的收发操作,而且I2C的同步时钟信号也是由主机产生的

    2024年02月01日
    浏览(48)
  • 什么是I2C,I2C怎么用,从实例波形分析I2C读写

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 今天分享的主题是I2C通信。接下来从I2C是什么,怎么用,以及以时钟外设读写作为实例进行分析。 I2C(Inter-Integrated Circuit) ,也可以叫IIC、I2C,译作集成电路总线,是 两线式串行通信总线 ,用于设备

    2024年01月19日
    浏览(44)
  • I2C知识大全系列四 —— I2C驱动之Linux下的I2C

    Linux 系统定义了 I2C 驱动体系结构。在 Linux 系统中, I2C 驱动由三部分组成,即 I2C 核心 、 I2C 总线驱动 和 I2C 设备驱动 。这三部分相互协作,形成了非常通用、可适应性很强的 I2C 框架。 I2C核心 I2C 核心提供了 I2C 总线驱动 和 设备驱动 的 注册 、 注销方法 , I2C 通信方法

    2024年02月07日
    浏览(42)
  • verilog实现I2C控制器 (小梅哥思路)----详细解析

    模块框图如下所示 输入输出信号: 整体的思路如下: 通过输入的命令组合,完成一次8字节数据的传输。定义了6种命令, WR 写数据请求 (6’b000_001) STA 起始位请求(6’b000_010) RD 读数据请求(6’b000_100) STO 停止位请求(6’b001_000) ACK 应答位请求(6’b010_000) NACK 无应答请求(

    2024年02月03日
    浏览(41)
  • I2C总线 | I2C总线介绍

    目录 I2C 总线 | I2C 总线介绍 I2C 总线介绍 I2C有如下特点: I2C 总线术语 I2C 总线位传输 IIC总线数据传输 1.字节格式 2.应答响应 IIC 总线寻址方式 1.7位寻址 2.10位寻址 快速和高速模式 1.快速模式 2.高速模式 I2C ( Inter - Intergrated Circuit )总线(也称 IIC 或 I2C )是由 PHILIPS 公司开发

    2024年02月04日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包