FPGA/数字IC求职笔试面试(2)之IIC协议的FPGA实现

FPGA/数字IC求职笔试面试(2)之IIC协议的FPGA实现


前言

书接上文,本文使用FPGA来实现IIC协议!该文章首发于公众号“FPGA学习者”,更多精彩内容敬请关注。


一、前情回顾

上期说到IIC协议的概述以及具体时序要求等等,本期将基于FPGA作为主控制器,EEPROM作为从机,实现FPGA与EEPROM之间的IIC通信协议。

二、编程思路

在这里插入图片描述
在这里插入图片描述
先来看两个时序图,从图中可以看到,无论是写入数据还是从EEPROM中读出数据,都需要一系列的较多重复的步骤,而每个步骤的核心部分就是8位数据的发送,相伴随着的是是否有起始位、是否有结束位、是否有应答位等等。

既然如此,那我们就可以先抽象出一个单独的关于8bit数据传输的模块,上层再去调用这个模块完成读写任务;

这里使用状态机的编写方式先去编写一个底层的i2c_bit_shift模块

该状态机有七个状态,分别为:

	IDLE      =   7'b0000001,  //空闲状态
    GEN_STA   =   7'b0000010,  //产生起始位状态
    WR_DATA   =   7'b0000100,  //写数据状态
    RD_DATA   =   7'b0001000,  //读数据状态
    CHECK_ACK =   7'b0010000,  //检测应答信号状态
    GEN_ACK   =   7'b0100000,  //产生应答信号(主要用于读数据时FPGA给出反馈)
    GEN_STO   =   7'b1000000;  //产生停止位状态

除此之外,该怎么确定是否经过其中的某些状态呢?可以通过定义不同的命令来指导状态的跳转方向,命令定义如下图所示:

localparam 
    WR   =  6'b000001,  //写请求
    STA  =  6'b000010,  //起始位请求
    RD   =  6'b000100,  //读请求
    STO  =  6'b001000,  //停止位请求
    ACK  =  6'b010000,  //应答位请求
    NACK =  6'b100000;  //无应答请求

例如在下图所示的步骤中,需要经历IDLE、GEN_STA、WR_DATA、CHECK_ACK、IDLE状态,则命令可以定义为:(STA | WR) ;
在这里插入图片描述
根据不同的部分需要的功能,命令设置不同,状态跳转路径也有所差异,最终得到的状态转换图如下:
在这里插入图片描述
还有一些注意事项:
1️⃣SCL时钟信号要满足400kHz左右,则需要通过系统时钟进行计数分频得到;
2️⃣SDA数据的变化,必须在SCL时钟为低电平的时候改变,SCL为高电平时必须保持稳定。
3️⃣SDA为双向数据线,在FPGA中需要使用三态门进行控制双向数据线,具体编程如下:

 inout i2c_sdat;
//******************************//
  reg i2c_sdat_o;
  reg i2c_sdat_oe;
  assign i2c_sdat = i2c_sdat_oe?i2c_sdat_o:1'bz;
//在上述程序中,当i2c_sdat_oe为高电平时,SDA信号线作为输出(对于FPGA来讲)。
//当i2c_sdat_oe为低电平时,SDA信号线为高阻态,其状态受从机影响,可以作为数据输入线。

经过上述处理方法,当SDA需要作为输出信号时,只需将i2c_sdat_oe置为高电平,然后操作i2c_sdat_o即可。

综上所述,该模块可以综合成如下图所示的模块框图:
在这里插入图片描述
在这里插入图片描述
上层模块需要调用上述模块去完成具体的读写任务,故编写i2c_control模块。
具体来说,上层模块需要完成什么任务呢?
①向0XA0这个器件的0Xxxxx地址单元写入数据0Xxx;步骤如下:
1️⃣CMD = STA | WR,Tx_data = dev_id;
2️⃣CMD = WR,Tx_data = addrH,
3️⃣CMD = WR,Tx_data = addrL,
4️⃣CMD = WR | STO, Tx_data = 0Xxx;
②从0XA0这个器件的0Xxxxx地址单元读取数据;步骤如下:
1️⃣CMD = STA | WR,Tx_data = dev_id;
2️⃣CMD = WR,Tx_data = addrH,
3️⃣CMD = WR,Tx_data = addrL,
4️⃣CMD = STA | WR,Tx_data = dev_id | 0X01;(确保最后一位为1)
5️⃣CMD = RD | NACK | STO,Rx_data = 0Xxx;
对于上层模块来说,同样使用状态机的方式去编程,状态定义如下:


localparam
    IDLE         = 7'b0000001,  //空闲状态
    WR_REG       = 7'b0000010,  //写请求状态
    WAIT_WR_DONE = 7'b0000100,  //等待写完成状态
    WR_REG_DONE  = 7'b0001000,  //写请求完成状态
    RD_REG       = 7'b0010000,  //读请求状态
    WAIT_RD_DONE = 7'b0100000,  //等待读完成状态
    RD_REG_DONE  = 7'b1000000;  //读完成状态

在这里插入图片描述
电路综合后的状态转换图如上图所示。该模块的框图如下图所示:
在这里插入图片描述
在这里插入图片描述

三、仿真验证

1 i2c_bit_shift仿真验证

在验证过程中,加载了一个M24LC048文件,该模块可以模拟EEPROM模块产生应答信号等需求。从而简化我们的testbench程序编写。

testbench程序中只需模拟产生命令信号、器件地址信号、写入/读出的地址单元信号即可,可以使用task任务来讲写入过程或者读取过程编写为单独一个任务。具体程序如下:


task write_one_byte;
    input [7:0]device_id;
    input [7:0]mem_address; 
    input [7:0]data;
    begin
      Cmd = WR | STA;
      Go = 1;
      Tx_DATA = device_id;
      #20;
      Go = 0;
      #200;
      @(posedge Trans_Done);
      #20;
      Cmd = WR;
      Go = 1;
      Tx_DATA = mem_address;
      #20;
      Go = 0;
      #200;
      @(posedge Trans_Done);
      #20
      Cmd = WR | STO;
      Go = 1;
      Tx_DATA = data;
      #20;
      Go = 0;
      #200;
      @(posedge Trans_Done); 
    end
  endtask

task read_one_byte;
    input [7:0]device_id;
    input [7:0]mem_address;
    begin
      Cmd = WR | STA;
      Go = 1;
      Tx_DATA = device_id;
      #20;
      Go = 0;
      #200;
      @(posedge Trans_Done);
      #20000;
      Cmd = WR | STO;
      Go = 1;
      Tx_DATA = mem_address;
      #20;
      Go = 0;
      #200;
      @(posedge Trans_Done);
      #20;
      Cmd = WR | STA;
      Go = 1;
      Tx_DATA = device_id | 8'd1;
      #20;
      Go = 0;
      #200;
      @(posedge Trans_Done);
      #20;
      Cmd = RD | NACK | STO;
      Go = 1;
      #20;
      Go = 0;
      #200;
      @(posedge Trans_Done);
      #20;      
    end
  endtask

仿真图如下图所示:
在这里插入图片描述
(文末提供所有源代码供学习使用)

2 i2c_control模块仿真验证

同样的,该testbench文件中例化M24LC048文件,以便简化我们的仿真代码。同样使用task任务编写写入过程和读取过程,具体详见代码分享。不再赘述。
仿真图如下图所示:

四、板级验证

在板级验证中,编写顶层i2c_eeprom模块,在该模块中例化i2c_control模块、按键消抖模块、ISSP工具;

其中按键消抖模块主要用于在按键按下时产生写入/读取数据的请求信号,请求信号为一个时钟周期的高电平信号。

i2c_control模块主要用于将数据通过iic协议的方式传输到EEPROM芯片中。

ISSP工具主要用来写入地址信号、数据信号,以及显示从EEPROM中读取到的数据。

该模块中例化结构如下图所示:
在这里插入图片描述
在这里插入图片描述
使用的硬件平台为:小梅哥FPGA_AC620开发板。
在这里插入图片描述
板级验证成功效果图:
在这里插入图片描述

五、写在后面

本编程思想例程参考小梅哥FPGA,当然了,我自己也写了IIC模块的驱动程序,也进行了仿真验证,只不过出现了小小的问题,目前还没有较好的解决方法,那就只好学习学习小梅哥的FPGA例程了,在此表示感谢。

关注微信公众号“FPGA学习者”后台回复【IIC例程】获取本期内容所有例程。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值