IIC Master 设计实现

写个IIC的主机来玩一玩。

  1. 仅100M时钟输入
  2. SCL波形工整,任意两个上升沿之间均为整数倍周期,占空比50%
  3. 发送数据时SDA严格对其到SCL低电平正中间
  4. 尽可能少的状态机
  5. 不浪费资源
  6. 数据逻辑和时序逻辑分离

接口设计中,我的思路是将数据与时序分离开,将和输入输出时序相关的逻辑放在最后面的模块中。使用stream接口实现数据交互。
找一个EEPROM来当从机:
仿真文件:
MicroChip 24XX04

先仿真一个IIC主机:

interface iic_master_sim (
    inout   sda,
    inout   scl
);

    task init;
    task start;
    task re_start;
    task stop;
    task write;
    task read;

endinterface

通过delay实现完美的主机,仿真:

在这里插入图片描述
观察波形,分割出有规律的部分:
在这里插入图片描述
在这一部分,可以看出1和0明显不一样。
在这里插入图片描述
显然可以得到:

DATA1:SDA 1111
       SCL 0110
DATA0: SDA 0000
       SCL 0110

那么,Start,ReStart,Stop:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Start  : SDA 1100
         SCL 1110
Restart: SDA 1100
         SCL 0110
Stop   : SDA 0011
         SCL 0111

为了方便描述,将这些称呼为iic符号。每个IIC符号均为2*4bit

那么这里就是串化了,接下来借助GTX的思路来设计。

先用逻辑实现一个oserdes,ODDR模式。数据内部存储1小拍。
发送一些东西:
在这里插入图片描述
ACK在发送侧看来就是DATA1。由于整个系统都是100M来驱动的,所以这里的phy_sync其实是逻辑,并不是真正的时钟。
用phy_sync[1]产生ready,往前送,整一组数据:
在这里插入图片描述
效果不错,波形很完美。由于SCL的生成依赖于phy_sync,所以SCL一定是频率稳定的。

一个字节+ACK一共9个IIC符号,而其他控制位均为1个IIC符号。

需要一个编码模块,将符号与用户数据分离开:
iic_master_encode
再将字节的串化也做进去。

"Start"   encode => 11001110
"ReStart" encode => 11000110
"Stop"    encode => 00110111
"0xA0"    encode => "DATA1", "DATA0", "DATA1", "DATA0", "DATA0", "DATA0", "DATA0", "DATA0", "DATA1"
                 => 11110110 00000110 11110110 00000110 00000110 00000110 00000110 00000110 11110110

数据就用Stream接口传入,8bit数据放不下,用user来标识是数据还是控制符。

user
000 未定义
001 写数据,不带ACK,SDA让从机去拉SDA
010 读数据,数据自动改为0xFF,带ACK,连续读取
011 读数据,数据自动改为0xFF,不带ACK,结束连续读取
100 Start
101 ReStart
110 Stop
111 未定义

用ready信号做反压,控制,反压一个IIC符号的时间,数据,反压9个IIC符号时间:

写

读

这样就实现发送部分。接下来就是接收部分。

接收部分,iserdes->decode->data。

数据采样时钟比发送时钟晚了半周期:

在这里插入图片描述
这样就能完美的采样到数据。

decode无法分辨是发送的数据还是接收的数据,所以一律按读数据来算:

user
010 读数据,带ACK
011 读数据,不带ACK
100 Start
101 ReStart
110 Stop

仿真:
在这里插入图片描述

下面需要一个模块来产生phy_sync信号。这个也是非常简单,用计数器就可以生成了。

case (sync)
    {2'b00, 2'b00} : sync <= {2'b11, 2'b00};
    {2'b11, 2'b00} : sync <= {2'b11, 2'b11};
    {2'b11, 2'b11} : sync <= {2'b10, 2'b11};
    {2'b10, 2'b11} : sync <= {2'b10, 2'b10};
    {2'b10, 2'b10} : sync <= {2'b01, 2'b10};
    {2'b01, 2'b10} : sync <= {2'b01, 2'b01};
    {2'b01, 2'b01} : sync <= {2'b00, 2'b01};
    {2'b00, 2'b01} : sync <= {2'b00, 2'b00};
endcase
assign {tx_sync, rx_sync} = sync;

软件配置时,需要100K,那么就直接在寄存器中写入12500/100=(125)即可。

整个IIC最核心的部分已经完成了,没有状态机。


考虑软件层如何操作代码。
操作语句可以一次性都执行完,IIC的波形就是连续的。
也可以一条确认生效后再执行下一条,IIC的波形就是不连续的。
在这里插入图片描述

也把底层做到最简单:

iic_start();
iic_write(0b10100000);
iic_write(0x00);
iic_write(0x11);
iic_write(0x22);
iic_write(0x33);
iic_write(0x44);
iic_write(0x55);
iic_stop();

iic_start();
iic_write(0b10100000);
iic_write(0x01);
iic_restart();
iic_write(0b10100001);
rd_data[0] = iic_read(CONTINUE); // 0x22
rd_data[1] = iic_read(CONTINUE); // 0x33
rd_data[2] = iic_read(CONTINUE); // 0x44
rd_data[3] = iic_read(STOP);     // 0x55
iic_stop();

每条指令均会产生一个tx_stream数据,并接收到一个rx_stream数据。

addr   
0x00  w  0x01 总线发送Start
      r  0x00 总线未检测到Start
      r  0x01 总线已完成Start发送,读取清零
0x01  w  0x01 总线发送Restart
      r  0x00 总线未检测到Restart
      r  0x01 总线已完成Restart发送,读取清零
0x02  w  0x01 总线发送Stop
      r  0x00 总线未检测到Stop
      r  0x01 总线已完成Stop发送,读取清零
0x03  w  0x00 此时通过0x04发送数据的ACK被主机拉低
      w  0x01 此时通过0x04发送数据的ACK被主机释放
      r  0x00 此时通过0x06读出的数据ACK为低电平
      r  0x01 此时通过0x06读出的数据ACK为高电平
0x04  w  0x55 发送数据0x55
0x05  w  0x01 清空发送FIFO
      r  0x02 发送FIFO中有2个数据
0x06  r  0x55 读取数据为0x55
0x07  w  0x01 清空读取FIFO
      r  0x02 读取FIFO中有2个数据

写操作流程:

0x00 w 0x01       发送Start
0x03 w 0x01       接下来发送的数据释放ACK
0x04 w 0b10100000 发送器件地址
0x04 w 0x00       寄存器地址
0x04 w 0x11       写数据
0x04 w 0x22       写数据
0x04 w 0x33       写数据
0x04 w 0x44       写数据
0x04 w 0x55       写数据
0x02 w 0x01       发送Stop

0x02 r 0x00       还未检测到Stop
0x02 r 0x00       还未检测到Stop
0x02 r 0x00       还未检测到Stop
0x02 r 0x00       还未检测到Stop
0x02 r 0x01       检测到Stop

读操作流程:

0x00 w 0x01       发送Start
0x03 w 0x01       接下来发送的数据释放ACK
0x04 w 0b10100000 发送器件地址,写
0x04 w 0x01       寄存器地址
0x01 w 0x01       发送ReStart
0x04 w 0b10100001 发送器件地址,读
0x03 w 0x00       接下来发送的数据拉低ACK
0x04 w 0xFF       写数据
0x04 w 0xFF       写数据
0x04 w 0xFF       写数据
0x03 w 0x01       接下来发送的数据释放ACK
0x04 w 0xFF       写数据
0x02 w 0x01       发送Stop

0x02 r 0x00       还未检测到Stop
0x02 r 0x00       还未检测到Stop
0x02 r 0x00       还未检测到Stop
0x02 r 0x00       还未检测到Stop
0x02 r 0x01       检测到Stop

0x06 r 0x22       读取到数据0xA0
0x06 r 0x22       读取到数据0x01
0x06 r 0x22       读取到数据0xA1
0x06 r 0x22       读取到数据0x22
0x06 r 0x33       读取到数据0x33
0x06 r 0x44       读取到数据0x44
0x06 r 0x55       读取到数据0x55

看样子需要增加一些机制,能把接收到的数据做区分?

整理一下:

    ┌────────┐    ┌─────────┐    ┌────────┐
───►│ encode ├───►│ oserdes ├───►│        │
    └────────┘    └─────────┘    │ open   │
                                 │ drain  │◄───►
    ┌────────┐    ┌─────────┐    │ buffer │
◄───┤ decode │◄───┤ iserdes │◄───┤        │
    └────────┘    └─────────┘    └────────┘

最简单的方发,在oserdes上发送sda的辅助信号,经过iserdes让decode解码出是读还是写。

    ┌────────┐    ┌─────────┐     ┌────────┐
───►│ encode ├───►│ oserdes ├──┬─►│        │
    └────────┘    └─────────┘  │  │ open   │
                               ▼  │ drain  │◄───►
    ┌────────┐    ┌─────────┐  │  │ buffer │
◄───┤ decode │◄───┤ iserdes │◄─┴──┤        │
    └────────┘    └─────────┘     └────────┘

解码器的user这次多了状态:

3'b000   WriteData & ack
3'b001   WriteData & Nack
3'b010   ReadData & Ack
3'b011   ReadData & Nack
3'b100   Start
3'b101   Re-Start
3'b110   Stop

把rx的数据做一下解码:

  52665 ns, rx: Start
 142665 ns, rx: WriteData a0, with Ack 
 232665 ns, rx: WriteData 00, with Ack 
 322665 ns, rx: WriteData 11, with Ack 
 412665 ns, rx: WriteData 22, with Ack 
 502665 ns, rx: WriteData 33, with Ack 
 592665 ns, rx: WriteData 44, with Ack 
 682665 ns, rx: WriteData 55, with Ack 
 692665 ns, rx: Stop

5752665 ns, rx: Start
5842665 ns, rx: WriteData a0, with Ack 
5932665 ns, rx: WriteData 01, with Ack 
5942665 ns, rx: Re-Start
6032665 ns, rx: WriteData a1, with Ack 
6122665 ns, rx: ReadData  22, with Ack 
6212665 ns, rx: ReadData  33, with Ack 
6302665 ns, rx: ReadData  44, with Ack 
6392665 ns, rx: ReadData  55, Without Ack 
6402665 ns, rx: Stop

这样发出的数据和读回的数据就可以区别了。

寄存器说明

addr   
0x00  w  0x01 总线发送Start
      r  0x00 总线未检测到Start
      r  0x01 总线已完成Start发送,读取清零
0x01  w  0x01 总线发送Restart
      r  0x00 总线未检测到Restart
      r  0x01 总线已完成Restart发送,读取清零
0x02  w  0x01 总线发送Stop
      r  0x00 总线未检测到Stop
      r  0x01 总线已完成Stop发送,读取清零
0x03  w  0x00 此时通过0x04,0x06发送数据的ACK被主机拉低
      w  0x01 此时通过0x04,0x06发送数据的ACK被主机释放
      r  0x00 此时通过0x06读出的数据ACK为低电平
      r  0x01 此时通过0x06读出的数据ACK为高电平
0x04  w  0x55 发送数据0x55
0x05  w  0x01 清空发送FIFO
      r  0x02 发送FIFO中有2个数据
0x06  w  0x00 回读一个数据
      r  0xAA 读取数据为0xAA
0x07  w  0x01 清空读取FIFO
      r  0x02 读取FIFO中有2个数据

回读流程

0x00 w 0x01       发送Start
0x03 w 0x01       接下来发送的数据释放ACK
0x04 w 0b10100000 发送器件地址,写
0x04 w 0x01       寄存器地址
0x01 w 0x01       发送ReStart
0x04 w 0b10100001 发送器件地址,读
0x03 w 0x00       接下来发送或读取的数据拉低ACK
0x06 w 0x00       读数据
0x06 w 0x00       读数据
0x06 w 0x00       读数据
0x03 w 0x01       接下来发送或读取的数据释放ACK
0x06 w 0x00       读数据
0x02 w 0x01       发送Stop

0x02 r 0x00       还未检测到Stop
0x02 r 0x00       还未检测到Stop
0x02 r 0x00       还未检测到Stop
0x02 r 0x00       还未检测到Stop
0x02 r 0x01       检测到Stop

0x07 r 0x04       读取FIFO中由4个数据
0x06 r 0x22       读取到数据0x22
0x06 r 0x33       读取到数据0x33
0x06 r 0x44       读取到数据0x44
0x06 r 0x55       读取到数据0x55
0x03 r 0x01       0x55数据没有ACK

读取数据的过程中,读取0x03不是必须的。
保险起见,可以在回读前清空回读FIFO。
如果有超长的IIC操作,为了防止FIFO溢出,需要读取0x05,0x07寄存器已确认操作空间。
当然这个大小也取决于FIFO的大小。一般情况下操作数量不会超过256。
扫描主机的操作:

0x00 w 0x01       发送Start
0x03 w 0x01       接下来发送的数据释放ACK
0x04 w 0b00000000 发送器件地址,写
0x02 w 0x01       发送Stop
0x02 r 0x00       还未检测到Stop
0x02 r 0x01       检测到Stop
0x03 r 0x01       没有ACK

0x00 w 0x01       发送Start
0x03 w 0x01       接下来发送的数据释放ACK
0x04 w 0b00000010 发送器件地址,写
0x02 w 0x01       发送Stop
0x02 r 0x00       还未检测到Stop
0x02 r 0x01       检测到Stop
0x03 r 0x01       没有ACK

0x00 w 0x01       发送Start
0x03 w 0x01       接下来发送的数据释放ACK
0x04 w 0b00000100 发送器件地址,写
0x02 w 0x01       发送Stop
0x02 r 0x00       还未检测到Stop
0x02 r 0x01       检测到Stop
0x03 r 0x01       没有ACK

0x00 w 0x01       发送Start
0x03 w 0x01       接下来发送的数据释放ACK
0x04 w 0b00000110 发送器件地址,写
0x02 w 0x01       发送Stop
0x02 r 0x00       还未检测到Stop
0x02 r 0x01       检测到Stop
0x03 r 0x00       有ACK

具体总线与FIFO部分之后再说。

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: TOF050是一种采用IIC(Inter-Integrated Circuit)通信协议的设备。IIC是一种用于数字设备之间进行短距离通信的串行通信协议。它的特点是使用双线制(即SDA线和SCL线),数据传输速度较快。IIC协议允许多个设备通过相同的引脚线连接到共同的总线上,这使得设备之间可以直接进行数据传输和通信。 TOF050作为一个使用IIC通信协议的设备,可以通过将其连接到其他支持IIC的设备来实现数据的传输和通信。通过使用IIC,TOF050可以与其他设备进行双向的串行数据传输,并且可以通过IIC总线上的IIC地址来识别和寻址其他设备。这个特性使得多个IIC设备可以通过IIC总线点对点连接,实现数据的传输和通信。 TOF050使用IIC通信协议的好处是,它具有高效、简洁、可靠的特点。同时,由于IIC协议只需要两根引脚线来传输数据,因此可以减少设备的硬件成本和占用的接口数量。此外,IIC还支持多主模式,即多个主设备可以控制IIC总线上的通信。这使得TOF050可以作为主设备或从设备,并与其他设备进行有效的通信和交互。 综上所述,TOF050作为一个使用IIC通信协议的设备,可以通过与其他支持IIC的设备连接,实现数据的传输和通信。使用IIC协议可以带来高效、简洁和可靠的通信方式,并减少硬件成本和接口数量。同时,TOF050还可以作为主设备或从设备,与其他设备进行多主模式下的通信和交互。 ### 回答2: iic,全称为Inter-Integrated Circuit,是一种串行通信协议。使用IIC通信协议可以实现多个设备之间的数据传输和通信。对于tof050而言,它可以通过使用IIC来与其他设备进行通信和交互。 tof050是一种具有时间飞行(TOF)原理的光电传感器模块。它可以测量从光电元件发出的光线被物体反射并返回的时间,从而计算出物体与模块的距离。使用IIC通信协议,tof050可以通过与其他电子设备连接和交互,提供更多的功能和应用。 通过IIC通信,tof050可以与其他传感器或控制器进行数据的收发和传递。比如,tof050可以与微处理器或微控制器连接,将测量到的距离数据传输给主控制器进行处理和分析。这种连接方式可以实现丰富的功能,如障碍物检测、距离测量等。 另外,tof050还可以与其他传感器模块进行串联或并联连接,实现多传感器协同工作。通过IIC通信,tof050可以与其他传感器模块(如温度传感器、湿度传感器等)进行信息交换,从而实现多种数据的采集和综合应用。 总之,tof050使用IIC通信协议可以实现与其他设备的连接和通信,从而拓展其功能和应用范围。通过与其他传感器模块的连接和交互,tof050可以实现更多的数据采集和处理,满足不同应用领域的需求。 ### 回答3: IIC是一种串行通信协议,全称是Inter-Integrated Circuit,也称为I2C。IIC通信协议常用于在多个芯片之间进行数据传输。TOF050是一种基于Time of Flight(飞行时间)技术的传感器,用于测量物体与传感器之间的距离。 TOF050使用IIC通信协议来与其他设备进行通信和数据传输。通过IIC接口,TOF050传感器可以直接与单片机、微控制器、开发板或其他集成电路连接。 IIC通信协议使用两根传输线(SDA和SCL)进行数据传输。SDA线用于数据传输,而SCL线用于时钟同步。在TOF050与其他设备之间的通信过程中,TOF050可以作为主设备(Master)或从设备(Slave)。 作为主设备时,TOF050可以发出启动信号,并控制整个通信过程。作为从设备时,TOF050根据主设备的指令或请求进行响应,并提供所需的数据。 TOF050使用IIC通信协议的好处之一是简化了传感器与其他设备之间的连接。只需通过两根传输线即可实现数据传输,而不需要进行复杂的硬件设计。 除了TOF050,许多其他传感器和器件也使用IIC通信协议,例如温度传感器、光传感器、陀螺仪等等。通过统一的通信协议,这些设备可以方便地与其他设备进行数据交换和信息传输。 总之,TOF050使用IIC通信协议,可以与其他设备进行简单、高效的数据传输和通信。这为TOF050的使用和集成提供了便利。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值