DW_apb_i2c配置指南及使用svt_i2c_vip验证

非常感谢大家的收藏,最近项目略忙,之前记录在confluence上的内容也比较零散,因此,这篇文章一定会出来的,有时间自己就开始写。写这样一篇文章进行总结也是非常有必要的 

前言

本篇主要记录自己在使用Synopsys的IP DW_apb_i2c时的体会。顾名思义,这个IP是基于I2C总线协议开发的,自己作为verifer的经验不足一年,所以一开始最困扰我的问题是I2C协议和这个IP有什么关系?(听起来能提出这样的问题是挺蠢的)

对此,我的理解是,I2C协议是信息传递的一种规则,而DW_apb_i2c是基于verilog开发的满足I2C协议要求的硬件实体。网上关于I2C协议的解读已经很多了,这篇主要讲这个IP怎么使用。能够使用这个IP的前提是理解协议。

I2C协议简要回顾

这里给出一些自己看到的还不错的参考文章

  1. UM10204(NXP出品的I2C的spec)
  2. 一文搞懂I2C通信总线_i2c通信的详细讲解-CSDN博客
  3. 第一章 I2C介绍_i2c总线仲裁-CSDN博客
  4. I2C(IIC)的仲裁、时钟同步和时钟扩展_i2c,clock stretch波形-CSDN博客
  5. I2C Clock Stretch-CSDN博客
  6. i2c的时钟延展问题_i2c 时钟延伸 分析-CSDN博客

 对于I2C,需要掌握的基本的点:

  1. I2C支持的speed mode,基本的协议规则,I2C的状态机图
  2. start,restart条件,7/10bit address 格式要求
  3. I2C多master仲裁,时钟同步和时钟扩展
  4. Device ID
  5. SMBus/PMBus

这些都可以在I2C spec上找到,需反复研读,协议并不复杂

I2C的速率模式需要明确(当时大老板提问时问了这个问题)

speed moderateSCL cycle
Standard-mode<=100kb/s>=10^4 ns
Fast-mode<=400kb/s>=2500 ns
Fast-mode plus<=1000kb/s>=1000 ns
High-speed mode <=3.4Mb/s>=295 ns
Ultra Fast-mode<=5Mb/s>=200 ns

DW_apb_i2c介绍

DW_apb_i2c可以说是S家的一个非常小的IP了,但即便如此,其中很多点也需要去琢磨。个人感觉能写出这样一个IP的代码,也是非常牛逼的。

关于这个IP的介绍,CSDN上有一些数量不太多的博客,希望自己踩在前人的肩膀上对其使用做一个补充。

  1. DesignWare DW_apb_i2c Databook
  2. 原海青木大哥的几篇文章   第二章 DW_apb_i2c 介绍_i2c designware-CSDN博客
  3. DW_apb_i2c学习笔记之IP微架构-CSDN博客
  4. Synopsys DW_apb_i2c_databook 笔记_synopsys i2c-CSDN博客

DW_apb_i2c,具有slave APB接口,上层通过APB接口去配置DW_apb_i2c的寄存器 ,从而基于I2C协议传递数据。对于这个IP的使用,主要是掌握四种模式的program方法,

  • master transmitter
  • master receiver
  • slave transmitter
  • slave receiver

本文将Dw_apb_i2c和svt_i2c_vip进行连接,从而实现四种模式下的验证,VIP的使用又说来话长,仅记录一下相关的config。

svt_i2c_vip介绍

VIP使用的Synopsys的svt_i2c_vip,基于uvm的验证VIP,具体怎么使用主要还是要看VIP的user guide。VIP的验证环境大致如下图: 

svt_i2c_vip提供的最上层的是system_env,在这个system_env中可以例化多对master_agent和slave_agent。由system_configuration进行配置。具体的代码可以参考VIP提供的example,对VIP的使用还是比较简单明了的。下面给出一个config的例子

function new (string name="Cm2tb_i2c_system_cfg");
      super.new(name);
      // Assign the necessary configuration parameters. 
      this.num_masters = 2;
      this.num_slaves  = 2;
      /** Create port configurations */
      this.create_sub_cfgs(this.num_masters, this.num_slaves);
      /** Set mode  DUT is master and VIP is slave, so master agent is passive*/    
      this.master_cfg[0].is_active = 1;
      this.slave_cfg[0].is_active = 1; 
      this.master_cfg[1].is_active = 1;
      this.slave_cfg[1].is_active = 1;  

      set_bus_speed(FAST_MODE);
      this.master_cfg[0].master_code  = 3'b101;       // only High speed use 
      this.master_cfg[1].master_code  = 3'b001;       // only High speed use 

      this.slave_cfg[0].slave_address = 10'b0001001011;       // 10'b000 1001011  0x4b
      this.slave_cfg[0].enable_10bit_addr = 0;                // 10bit_addr disable
      this.slave_cfg[0].slave_type  =  `SVT_I2C_GENERIC;         
      this.slave_cfg[0].device_id   =   24'h44_55_66

      this.slave_cfg[1].slave_address = 10'b0001101010;        // 10'b000 1001011  0x6a
      this.slave_cfg[1].enable_10bit_addr = 0;                 // 10bit_addr disable
      this.slave_cfg[1].slave_type  =  `SVT_I2C_GENERIC;   
      this.slave_cfg[1].device_id   =  24'h77_88_99; 

      this.enable_chk_for_xz_sda_at_time0  =  1'b0;
      this.enable_chk_for_xz_scl_at_time0  =  1'b0;
endfunction : new

      

关于IP和VIP连接的问题

提到I2C,都知道涉及到两根线SDA和SCL,这两根线都是被上拉电阻拉着的inout类型的线。但是DW_apb_i2c与SCL和SDA有关的端口不是简简单单的两根线,而是分为ic_clk_in_a,ic_data_in_a,ic_clk_oe,ic_data_oe。其中ic_clk_oe,ic_data_oe是开漏输出(open_drain)。

而svt_i2c_vip提供的interface是SCL和SDA两根inout类型的线,IP和VIP如何连接是第一个要解决的问题。这里需要非常清楚的明白开漏输出的含义和意义。学习开漏输出和inout类型的信号的关系

如何正确理解开漏输出和推挽输出_如何理解开漏-CSDN博客

集电极开路输出和漏极开路输出-CSDN博客

晶体管的分类和三极管的介绍 - 知乎 (zhihu.com)

下面是集电极开路(Open-Collector)OC门的例子,漏极开路(Open-Drain)OD门的道理和这个类似,只不过用的器件不同而已。OC门用的是双极性晶体管(三极管的一种),OD门用的是MOSFET(场效应晶体管)(之前在协议和代码注释里总是看到open drain却不明白啥意思)

开漏输出的设计在I2C器件的端口是必须的,一是为了防止多个I2C器件挂在I2C总线上时发生短路,二是开漏输出可以实现多个I2C器件的“线与”(wire-and)模式。同时开漏输出外面的总线必须加上拉电阻以输出高电平。这点在I2C协议里有提到过。

连接代码如下:

assign Mtop.u_DW_apb_i2c.ic_clk_in_a  =  i2c_if.SCL;
assign Mtop.u_DW_apb_i2c.ic_data_in_a  =  i2c_if.SDA; 

assign i2c_if.SCL = Mtop.u_DW_apb_i2c.ic_clk_oe? 1'b0 : 1'bz; 
assign i2c_if.SDA = Mtop.u_DW_apb_i2c.ic_data_oe? 1'b0 : 1'bz;

当ic_clk_oe为1时,SCL为低电平。但ic_clk_oe为高时,输出为高阻态,而SCL又加了上拉电阻,所以表现为高电平。SDA同理。通过上述连接方式将dw_apb_i2c挂到svt_i2c_vip提供的I2C总线上。

 验证环境:

通过前述内容,我们解决了如下问题:

  1. 如何把IP连接到I2C总线上(开漏输出的连接代码逻辑)
  2. 如何把多个VIP的master agent和slave agent挂到I2C总线上(通过配置VIP的system cfg)

最终我们搭建的环境其实是模拟了多个master或者slave的I2C器件挂在I2C总线上进行通讯。其中蓝色的是IP,黄色的是VIP。它们都是支持I2C协议的器件。而我们的验证就是模拟这些器件之间的通讯,比如通过配置IP的寄存器使其作为master发送数据给某个slave VIP。 当然这种验证行为本质是没啥意义的,因为IP是人家公司的产品,可以认为是golden的,验肯定是验不出来什么问题。但是在实际的soc系统中,i2c是被集成到某个子系统,比如外设子系统,再向上集成经过总线fabric,最终到芯片端口的是SCL和SDA的inout类型的pin,我们再走一遍这样的验证,就可以确认内部的I2C发送数据是否能发送出去。 验证,是在没有芯片实体的代码阶段去模拟数据的发送和接受。

搭建完验证环境之后,我们会遇到如下的问题:

  1. 如何配置dw_apb_i2c,使其发送或接收数据?
  2. 如何配置svt_i2c_vip,使其发送或接收数据? 

根据master和slave关系,可以分为四种情况:

  1. dw_apb_i2c为master transmit mode,发送数据给VIP
  2. dw_apb_i2c为master receive mode,从VIP读数据
  3. dw_apb_i2c为slave transmit mode,被VIP读数据
  4. dw_apb_i2c为slave receive mode,被VIP写入数据

dw_apb_i2c作为master,svt_i2c_vip作为slave

master transmit mode 

待续

master receive mode

待续

dw_apb_i2c作为master,svt_i2c_vip作为slave

slave transmit mode

待续

slave receive mode

  • 15
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值