FPGA基础知识之IIC协议读写解析

时间:2025-07-29  作者:Diven  阅读:0

很多数字传感器、数字控制的芯片(DDS、串行ADC、串行DAC)都是通过IIC总线来和控制器通信的。不过IIC协议仍然是慢速的通信方式,标准IIC速率为100kbit/s,快速模式速率为400kbit/s。本文致力于讲述如何用计数器控制和分频时钟控制两种方式完成IIC的读写操作。

FPGA基础知识之IIC协议读写解析

IIC协议

IIC协议是多机通讯,由SDA数据线和SCL时钟线构成串行总线,所有的IIC设备都可以挂载到总线上,但每个设备都有唯一的设备读地址和设备写地址。在使用IIC作为数字接口的芯片datasheet中都可以看到该设备的设备读/写地址情况,并可以查找到相应的读写时序,以及对速率的要求。下图是一个通用的IIC协议时序:

我们可以出五种IIC协议的时序状态:
  1. 空闲状态,当SDA和SCL两条信号线都处于高电平时总线处于空闲状态。
  2. 开始信号,SCL为高电平期间SDA信号线上产生了下降沿标志着的一次数据传输的开始。开始信号应当由主机发起。
  3. 数据传输,在SCL同步控制下SDA串行的传送每一位,因此传送8bits的数据需要8个SCL时钟。SCL为高电平时期SDA电平状态必须稳定;SCL为低电平期间才允许SDA改变状态。
  4. 应答信号,IIC总线上每传送一个8位字节,第9个脉冲期间便会释放总线,由接收器发出一个应答信号,反馈有没有成功接收。
  5. 停止信号,在SCL保持高电平期间,将SDA信号线释放恢复到高电平,标志一次数据传输的结束,IIC总线也重新回到了空闲状态。

计数器控制IIC读写

在“FPGA基础设计(三):UART串口通信”中已经接触到了使用计数器控制时序的方法,这个方法在控制IIC通信时同样实用。一次完整的写入操作如下所示:

case( i )

0: // iic Start

begin

isOut 《= 1; //SDA端口输出

if( C1 == 0 ) rSCL 《= 1‘b1;

else if( C1 == 200 ) rSCL 《= 1’b0; //SCL由高变低

if( C1 == 0 ) rSDA 《= 1‘b1;

else if( C1 == 100 ) rSDA 《= 1’b0; //SDA先由高变低

if( C1 == 250 -1) begin C1 《= 9‘d0; i 《= i + 1’b1; end

else C1 《= C1 + 1‘b1;

end

1: // Write Device Addr

begin rData 《= {4’b1010, 3‘b000, 1’b0}; i 《= 5‘d7; Go 《= i + 1’b1; end

2: // Wirte Word Addr

begin rData 《= Addr_Sig; i 《= 5‘d7; Go 《= i + 1’b1; end

3: // Write Data

begin rData 《= WrData; i 《= 5‘d7; Go 《= i + 1’b1; end

4: //iic Stop

begin

isOut 《= 1‘b1;

if( C1 == 0 ) rSCL 《= 1’b0;

else if( C1 == 50 ) rSCL 《= 1‘b1; //SCL先由低变高

if( C1 == 0 ) rSDA 《= 1’b0;

else if( C1 == 150 ) rSDA 《= 1‘b1; //SDA由低变高

if( C1 == 250 -1 ) begin C1 《= 9’d0; i 《= i + 1‘b1; end

else C1 《= C1 + 1’b1;

end

5:

begin isDone 《= 1‘b1; i 《= i + 1’b1; end //写I2C 结束

6:

begin isDone 《= 1‘b0; i 《= 5’d0; end

7,8,9,10,11,12,13,14: //发送Device Addr/Word Addr/Write Data

begin

isOut 《= 1‘b1;

rSDA 《= rData[14-i]; //高位先发送

if( C1 == 0 ) rSCL 《= 1’b0;

else if( C1 == 50 ) rSCL 《= 1‘b1;

else if( C1 == 150 ) rSCL 《= 1’b0;

if( C1 == F250K -1 ) begin C1 《= 9‘d0; i 《= i + 1’b1; end

else C1 《= C1 + 1‘b1;

end

15: // waiting for acknowledge

begin

isOut 《= 1’b0; //SDA端口改为输入

if( C1 == 100 ) isAck 《= SDA;

if( C1 == 0 ) rSCL 《= 1‘b0;

else if( C1 == 50 ) rSCL 《= 1’b1;

else if( C1 == 150 ) rSCL 《= 1‘b0;

if( C1 == F250K -1 ) begin C1 《= 9’d0; i 《= i + 1‘b1; end

else C1 《= C1 + 1’b1;

end

16:

if( isAck != 0 ) i 《= 5‘d0;

else i 《= Go;

endcase

向IIC总线写数据时,需要依次写入待写入的设备写地址、设备中的写地址和待写入的数据共3个8bits字节数据。i代表总线上不同的状态,通过计数器来控制状态之间的跳转。i为0时发出开始信号;i为7~14时控制8bits数据的发送;i为1、2、3时分别为设备地址、字节地址和数据,依次调用7-14完成数据的传输;其余还有停止位、应答位、IIC通信完成置位等状态。

从器件中读取数据的方法与此一样,只不过通常都需要先向IIC总线写入待读取的设备地址和器件地址,之后再读数据。读数据整体过程比写数据要麻烦一点,但只要控制好状态之间跳转的过程即可。

  分频时钟控制IIC读写

由计数器控制通信时序的方法优点是很灵活,几乎所有的时序方法都可以用这种方法完成;缺点就是太麻烦,需要控制好状态之间的跳转,时序越复杂使用越麻烦,其实在“FPGA采集-传输-显示系统(二):基于FPGA的温度采集和以太网传输”中,我对DS18B20的时序控制就是采用计数器控制的方法。DS18B20的时序要求较多,因此其中的状态跳转已经相当复杂。

其实在控制IIC这种时钟速率固定的串行协议时,还可以在外部分频或PLL生成一个低频的通信时钟,用这个时钟来控制数据传输过程。如下所示:

always@(posedge clock_i2c)

begin

if(reset_n==1’b0) begin

tr_end《=0;

ack1《=1;

ack2《=1;

ack3《=1;

sclk《=1;

reg_sdat《=1;

end

else

case(cyc_count)

0:begin ack1《=1;ack2《=1;tr_end《=0;sclk《=1;reg_sdat《=1;end

1:reg_sdat《=0; //开始传输

2:sclk《=0;

3:reg_sdat《=i2c_data[23];

4:reg_sdat《=i2c_data[22];

5:reg_sdat《=i2c_data[21];

6:reg_sdat《=i2c_data[20];

7:reg_sdat《=i2c_data[19];

8:reg_sdat《=i2c_data[18];

9:reg_sdat《=i2c_data[17];

10:reg_sdat《=i2c_data[16];

11:reg_sdat《=1; //应答信号

12:begin reg_sdat《=i2c_data[15];ack1《=i2c_sdat;end

13:reg_sdat《=i2c_data[14];

14:reg_sdat《=i2c_data[13];

15:reg_sdat《=i2c_data[12];

16:reg_sdat《=i2c_data[11];

17:reg_sdat《=i2c_data[10];

18:reg_sdat《=i2c_data[9];

19:reg_sdat《=i2c_data[8];

20:reg_sdat《=1; //应答信号

21:begin reg_sdat《=i2c_data[7];ack2《=i2c_sdat;end

22:reg_sdat《=i2c_data[6];

23:reg_sdat《=i2c_data[5];

24:reg_sdat《=i2c_data[4];

25:reg_sdat《=i2c_data[3];

26:reg_sdat《=i2c_data[2];

27:reg_sdat《=i2c_data[1];

28:reg_sdat《=i2c_data[0];

29:reg_sdat《=1; //应答信号

30:begin ack3《=i2c_sdat;sclk《=0;reg_sdat《=0;end

31:sclk《=1;

32:begin reg_sdat《=1;tr_end《=1;end //IIC传输结束

endcase

可以看到这个always块的敏感目标为分频后的IIC时钟信号clock_i2c,整个传输过程一目了然。这两种控制时序的方法不仅适合于IIC协议,还适合于其串行协议。

猜您喜欢

您是否想过,为什么您的手机在充电时不会因为电压波动而损坏?为什么您的电脑即使在电压不稳定的环境下也能正常工作?这都要归功于一个看似不起眼却很重要的电子元件——线...
2024-08-05 00:00:00

0402贴片电容是电子元件中常用的。尺寸为0.04英寸×0.02英寸。这个尺寸在电路设计中非常重要。本文将介绍0402贴片电容对照表的相关信息。0402贴片电容...
2025-04-12 21:31:41

电脑的精密世界里,稳定的电力供应很重要。DC-DC电源作为电脑的心脏,默默地将电源适配器提供的电压转换为电脑各组件所需的精确电压,保障电脑稳定运行。如同一位幕后...
2024-11-10 00:00:00

电阻器作为基础且关键的元件,应用于各种电路设计中。Walsin(华新)作为全球知名的电子元件制造商,其铝壳电阻系列因高性能和稳定性深受市场青睐。本文将全面介绍W...
2021-08-11 11:28:30

敲击扳手是应用于机械维修和汽车保养的工具,其规格和尺寸直接影响到使用效果和操作便利性。敲击扳手的规格通常驱动端的尺寸来划分,常见的有1/4英寸、3/8英寸、1/...
2016-06-09 00:00:00

在选择LED驱动时,规格尺寸是一个重要的考虑因素。不同类型的LED驱动器在尺寸上可能存在差异,通常取决于其功率输出和设计用途。常见的LED驱动规格包括小型模块、...
2012-01-12 00:00:00

现代电子设备中,贴片电阻作为关键的电子元器件,被应用于各种电路中。贴片电阻体积小、重量轻、易于自动化贴装等优点,逐渐取代了传统的引线电阻。本文将对贴片电阻的封装...
2025-03-18 20:31:38

在选择洗眼器时,了解其规格尺寸非常重要。洗眼器通常分为便携式和固定式两种,便携式洗眼器一般尺寸较小,方便携带,适合个人使用,尺寸大约在30厘米高,直径约15厘米...
2011-10-06 00:00:00

现代工业和制造领域,材料的选择非常重要。PM_40X25.4MM_TM作为新型材料,因其独特的物理和化学特性,正在逐渐受到关注。本文将为您详细解析PM_40X2...
2025-04-20 05:00:36

电解电容和固态电容是电子设备中常见的元件。的正负极设计不同,影响使用。本文将详细介绍这两种电容的特点及其正负极的区别。电解电容的结构电解电容器主要由铝箔和电解液...
2025-03-27 14:01:39