本文内容:本文主要基于一篇外文手册 24AA04/24LC04B 设备,采用 IIC 协议进行数据传输,用 FPGA 模拟从机 24AA04/24LC04B,PC 为主机进行数据传输,深入学习 IIC 协议
一、IIC 原理
1.1 概述
- 根据 24AA04/24LC04B 手册,可以知晓该设备采用 100kHz 或者 400 kHz 的速度进行数据传输,同时有一个 16 字节的缓存器,所以项目中要定义一个 16 字节的缓存器

- 同时需要定义两块 256×8 的数据块

- 管脚种类:VCC、GND、SCL、SDA
VCC:电源
GND:接地
SCL:时钟线
SDA:数据传输单总线 - IIC 协议采用同步时钟、半双工的方式运行

- 从上图可以看出,用 FPGA 模拟从机时,同步时钟信号由 PC 上位机传输过来
- SDA 数据传输为单总线的方式,当主机发送数据时,SDA 单总线由主机占用,当从机发送数据时,SDA 单总线由从机占用
1.2 写操作
比特写:
- 比特写的方式如下,记住这个图,下面逐段讲解

- 首先由主机发送一个 START 信号给从机,让从机知道主机要送数据过来了
- START 信号

当 SCL 为高电平的时候,SDA 从高电平跳变为低电平,则标志着有 START 信号
从机就进入接收主机发送的数据的状态 - Control Byte 字节

IIC 协议传输数据时,先发送字节的高位,再发送字节的低位,先高后低
先发送 1010 ,这四个 bit 表示 24AA04/24LC04B 设备地址,固定的
再发送 xxB0,这三个 bit 前两个无所谓,B0 表示哪一个数据块,0 表示第 0 个 256×8 数据块,1 表示第 1 个 256×8 数据块 - ACK 信号

前面所有的 bit 都是由主机发过来的
而 ACK 由接收设备发出,现在主机是发送设备,FPGA 为接收设备,所以现在是由 FPGA 发出 ACK 信号
如果 FPGA 作为发送设备,PC 作为接收设备,那么就由 PC 发出 ACK 信号
接收设备每接受到一个字节,就要发送一个 ACK 信号,它是低电平 - Word Address 字节

写控制字节后面一定是跟上一个地址字节
这个字节表示,256×8 数据块的地址,范围为 0——255 - Data 字节

一个 8 bit 的数据,先高后低 - STOP 信号

当 SCL 为高电平的时候,SDA 从低电平跳变为高电平,则标志着有 STOP 信号
从机就进入空闲状态,没数据接收了
页写:
- 页写过程图:

相比较于比特写,无非就是多增加了几个数据而已,只有当从机发送了 ACK 信号之后,主机再发送 STOP 信号
这样就完成了页写的操作
如果写了超过 16 个比特的数据,那么就存储最后发送的 16 个比特到数据块中
1.3 读操作
当前地址读:
- 读控制字节图:

流程:主机先发送一个 START,然后主机再发送一个读控制字节,然后从机发送一个比特数据,然后主机再发送一个 NACK 信号,再发送一个 STOP 信号
相比较于写控制字节,读控制字节只是 B0 后面的那个 bit 为 1,1 表示读操作,0表示写操作
256×8 这么大的数据块,发送哪一个比特数据呢?
比如说:前面写了 n 个字节数据,数据指针最后指向的是 n+1 的地址,现在再读一个字节数据,那么从机发送的数据,就是 n+1 地址的数据,然后指针再指向 n+2,等待下一次操作(上图中应该是 n+1 )
随机读:
- 随机读结构:

流程:主机先发送一个 START,然后主机再发送一个写控制字节,然后从机发送一个 ACK 信号,主机再发送一个地址字节,从机再发送一个 ACK 信号,主机再发送一个 START 信号,主机再发送一个读控制信号,从机发送一个 ACK,从机发送一个比特数据,主机发送一个 NACK,最后主机发送一个 STOP 信号
说明:这个过程必须搞清楚,前面两个字节是为了将地址写入 FPGA 中,赋值给地址指针,然后再发送一个读控制读取数据
顺序读:
- 结构图:

和前面随机读的区别就在于,主机接收多个字节后,再发送 NACK 信号,也就顺序接收多个字节了
1.4 总线数据传输时间
- 先来看看图,这表示 START 信号、一个 bit 数据的保持与变化以及 STOP 信号的时长约束

先讲讲每个部分的意义吧,自己再结合下面的表格对上相应的时长 - 7 与 6 的交界处就是一个 START 信号的产生,7 表示 SCL 上升沿来了后,必须保持 7 对应的时长才产生 START 信号,再保持 6 对应时长的低电平
10 与 12 的交界处就是一个 STOP 信号的产生,10 表示 SCL 上升沿来了后,必须保持 10 对应时长才产生 STOP 信号,再保持 12 对应时长的高电平
5 与 4 表示 SCL 信号边沿的持续时长
3 表示 SCL 低电平的保持时长
2 表示 SCL 高电平保持时长
8 表示 SDA 电平变化点距离SCL 下降沿的时长
9 表示 SDA 电平变化点距离 SCL 上升沿的时长 - 上面每个序号所需的时长约束表(不要觉得是英文就头大哈,工作时读的手册大多都是英文的)

- 结合上面讲的部分,可以比较详细的知晓其中每一段的意义,再集合表格就知道每一个地方需要大概多大的时长,结合电气标准这里我们用红框内的部分
- 举个例子:7 与 6 的交界处就是一个 START 信号的产生,其中 7 必须 > 600 ns,6 必须 > 600 ns,其它的就不一一例举了
二、项目设计
说明:时间不太充裕,就写这么多了,源码也有些注释,信号的命令也中规中矩,语块分明,也比较容易理解哈
2.1 概述
功能需求:
- 主机可以发送一个或多个 byte 数据,从机能成功缓存,并写入 2×256×8 的数据块中
- 主机发送超过 16 byte 的数据,则只将最后 16 byte 数据写入数据块中
- 主机发送读控制信号后,从机能发送相应长度的数据
- 从机写入数据块中的所有数据,能够在数码管上滚动显示出来
器件需求:
- 硬件:USB 转 IIC 模块
- 软件:USB2I2C_CN.exe 用于 PC 发送 IIC 协议数据给 FPGA
项目工程:https://github.com/zcj-debug/IIC_2_256_8_data_blocks
- 我的 github 有整个工程,自行下载

系统设计:
- 模块设计图

- 这里我采用三段式状态机的方式实现,比较好理解一点

- IDLE:从机没有干任何事,空闲状态
- START:从机检测到 SDA 中的 START 信号后,进入 START 状态
- CTRL_BYTE:从机开始接收一个 byte 的控制字节
- ADDRESS_BYTE:控制字节为写控制,则进入接收地址字节状态
- SEND_DATA:控制字节为读控制,则进入发送数据状态
- RECEIVE_DATA:接收完地址字节后进入接收数据状态
- STOP:从机接收到 NACK 或者 STOP 信号后进入 STOP 状态
独热码:
parameter IDLE = 7'b000_0001 ,
START = 7'b000_0010 ,
CTRL_BYTE = 7'b000_0100 ,
ADDRESS_BYTE = 7'b000_1000 ,
SEND_DATA = 7'b001_0000 ,
RECEIVE_DATA = 7'b010_0000 ,
STOP = 7'b100_0000 ;
2.3 波形仿真
- 安装了 ModelSim 后,双击 bat 文件即可开始仿真


2.3 效果演示
- 原始数据:
17(16 进制表示,10 进制为 23)
a01b0102030405060708090a0b0c0d0e0f101112131415
a0为设备地址
1b为数据块地址
后面的都是数据 - 当写入数据超过 16 个时,只存入了最后 16 个字节数据,数码管也在滚动显示这 16 个字节数据
- 读数据时,先写入两个字节(一个写控制字节、一个地址字节),然后再输入需要读取的数据长度即可