IIC通信协议详解 & PCF8591应用(Verilog实现FPGA)

您所在的位置:网站首页 fpga数模转换实现 IIC通信协议详解 & PCF8591应用(Verilog实现FPGA)

IIC通信协议详解 & PCF8591应用(Verilog实现FPGA)

2023-09-02 15:23| 来源: 网络整理| 查看: 265

IIC通信协议详解 & PCF8591应用(Verilog实现/FPGA)

该文章结合PCF8591 8-bit AD/DA 模数/数模转换器来详细介绍IIC通信协议,尽量做到条理清晰,通俗易懂。该文图片均从PCF8591手册中截取,一定程度上引导读者学习阅读data sheet。

之后可能会更新如何将IIC的Verilog实现变为一个IP核,并在pynq-Z2板子上使用。

1. PCF8591引脚

PCF8591引脚

2. 功能介绍 2.1 地址位

在I2C总线系统中,每个PCF8591设备都通过发送一个有效地址来激活。地址由固定部分和可编程部分组成。可编程部分必须根据地址引脚A0、A1和A2进行设置。在I2C总线协议中,地址必须始终作为起始条件后的第一个字节发送。地址字节的最后一位是读/写位,它设置了后续数据传输的方向。 地址位 PCF8591原理图

在市面上我们所购买到的PCF8591 模数/数模转换器已经被集成到了PCB板上,根据博主的调研,其PCB的原理图绘制如上图所示。

其中A0,A1,A2均接GND,所以在进行DA转换时,发送的写地址位应为8‘h90;在进行AD转换时,先发送的写地址位应为8’h90,再发送读地址位为8‘h91。

2.2 控制位

发送到PCF8591设备的第二个字节将被存储在其控制寄存器中,并用于控制设备功能。

控制寄存器的高四位用于启用模拟输出,并将模拟输入编程为单端或差分输入。低四位选择由高四位定义的一个模拟输入通道。

如果设置了自动递增标志,每次A/D转换后通道号将自动递增。

如下图所示,假设我们要进行D/A转换,即将数字信号输入转换为模拟信号输出:

我们要允许模拟输出,即把control byte第6位(从0开始,从右往左数)设为1;此时不需要模拟信号输入,所以将第5位和第4位均设为0;第1位和第0位为选择的模拟输出通道,在这里我们选择channel 0通道输出,则第1位和第0位为00;不需要自动递增,则将第2位设为0。

综上所述,我们需要发送的control byte为8‘b0100_0000,即8’h40。

假设我们要进行A/D转换,即将模拟信号输入转换为数字信号输出:

我们要关闭模拟输出,即把control byte第6位(从0开始,从右往左数)设为0;此时需要模拟信号输入,选择每个信号均为单通道输入,所以将第5位和第4位均设为0;第1位和第0位为选择的模拟输入通道,在这里我们选择channel 0通道输出,则第1位和第0位为00;不需要自动递增,则将第2位设为0。

综上所述,我们需要发送的control byte为8‘b0000_0000,即8’h00。

控制位

2.3 D/A 转换

发送到PCF8591设备的第三个字节存储在DAC数据寄存器中,并使用芯片内的D/A转换器将其转换为相应的模拟电压。

D/A转换序列的波形如下图所示。在PCF8591的D/A转换中,我们需要先发送写地址位8’h90,再发送控制位8‘h40,最后再发送想要转换的数字信号数据。

DA转换序列

2.4 A/D 转换

A/D转换器采用逐次逼近转换技术。在发送有效的读取模式地址到PCF8591设备后,始终会启动A/D转换周期。 A/D转换周期在应答时钟脉冲的下降沿触发,并在传输上一次转换的结果时执行,详情参见下图所示。

一旦触发了转换周期,所选通道的输入电压样本将存储在芯片上,并转换为相应的8位二进制代码。

转换结果存储在ADC数据寄存器中,并等待传输。如果设置了自动递增标志,则选择下一个通道。

A/D转换序列的波形如下图所示。

AD转换序列

3. D/A转换及IIC通信协议波形详解

在有了上面的基本认识后,我们开始详细介绍IIC通信协议中SDA和SCL的波形。

在开始D/A转换时,即IIC通信中主设备向从设备发送信号,我们需要模拟主设备的SDA和SCL信号。

在该例子中主设备可以为包括FPGA在内的任意设备,而从设备为PCF8591,其他从设备也可以类比。

3.1 空闲状态

如下图所示,在总线空闲时,数据线(SDA)和时钟线(SCL)都保持高电平。

3.2 开始状态(START condition)

如下图所示,当D/A转换开始时,时钟线(SCL)仍为高电平,数据线(SDA)从高电平跳变到低电平,这被定义为起始条件。

从设备在检测到起始条件后,会等待主设备发送地址和读/写位,以确定是否需要参与到通信过程中。

开始状态

3.3 写状态

如2.1部分及2.2部分所说,在PCF8591的D/A转换中,我们需要先发送写地址位8’h90,再发送控制位8‘h40,最后再发送想要转换的数字信号数据。

归根结底,我们向从机发送地址位、控制位和数字信号数据其实都是在向从机写入数据,并且每个数据都是8-bit,所以在这三个阶段时钟线(SCL)和数据线(SDA)所遵循的规则是一样的。

时序约束 8-bit信号序列 现在详细解释一下,在一个发送8-bit数据时,SDA和SCL的信号变化(数据由高位到低位传输)。

在IIC通信协议中,发送数据过程中,SCL信号为低电平时SDA信号可以发生变化,而在SCL为高电平时,SDA信号有效,应保持不变,所以SDA信号1bit、1bit地传输数据时,SCL信号也对应地由低变高再由低边高。

!!!!!!!!!!!!!!!!!!!以下开始为重点!!!!!!!!!!!!!!!!!!!!

如上图所示,承接开始状态时SDA从高电平跳转为低电平,向从机发送数据,写状态开始。

在开始状态SDA变为低电平后,SCL需要至少经过 t H D ;   S T A t_{HD;\ STA} tHD; STA​ μ s \mu s μs,即4.7 μ s \mu s μs后才能下拉为低电平。并且SCL低电平的时间至少要持续 t L O W t_{LOW} tLOW​ μ s \mu s μs,即4.7 μ s \mu s μs才能再度变为高电平,在这期间,SDA开始传输数据,即这段时间内SDA信号可以发生变化。在 t L o w t_{Low} tLow​ μ s \mu s μs过去后,SCL变为高电平,此时SDA信号有效(即SDA所表示的0、1数据被写入从机对应的寄存器中),SCL高电平的时间至少维持 t H I G H t_{HIGH} tHIGH​ μ s \mu s μs,即4.0 μ s \mu s μs。在此期间SDA信号不能发生改变,否则会导致信号传输错误。在 t H I G H t_{HIGH} tHIGH​ μ s \mu s μs过去后,SCL又变为低电平,此时进入下 1 bit的传输,重复1~4步骤的内容,循环8次,直到传输完8-bit的数据为止(每循环一次代表传输1bit)。在传输完8-bit的数据后,从机会返回一个Acknowledge信号(ACK信号,即应答信号),此时主机应该释放SDA信号线(特别注意,SDA信号线是inout类型,可以由外部传输数据进来,也可以由内部传输信号出去),以便从机控制SDA信号线传输ACK信号(应答信号),即该阶段的SDA信号线表示的是ACK信号。如果ACK信号为低电平时(因为SDA信号线在默认状态下会被拉为高电平,所以将下拉为低电平作为有效信号),说明传输成功,可以继续进行下一个8-bit数据的传输或是结束传输,转为终止状态(STOP condition);如果ACK信号为高电平时,说明传输失败,转为空闲状态。在接收ACK信号时,SCL信号和在发送1 bit的数据时一样,先经过 t L O W t_{LOW} tLOW​ μ s \mu s μs变为高电平,再经过 t H I G H t_{HIGH} tHIGH​ μ s \mu s μs后变为低电平,此时ACK信号接收完成。 3.4 终止状态(STOP)

在终止状态时SCL信号先变成高电平,在至少经过 t S U ;   S T O t_{SU;\ STO} tSU; STO​ μ s \mu s μs,即4.0 μ s \mu s μs后SDA才能变为高电平,至此D/A转换结束,IIC通信协议结束。

3.5 D/A转换代码(Verilog实现) module DAC_I2C ( input clk_in, //系统时钟 input rst_n_in, //系统复位,低有效 output reg dac_done, //DAC采样完成标志 input [7:0] dac_data, //DAC采样数据 output scl_out, //I2C总线SCL inout sda_out //I2C总线SDA ); parameter CNT_NUM = 15; localparam IDLE = 3'd0; localparam MAIN = 3'd1; localparam START = 3'd2; localparam WRITE = 3'd3; localparam STOP = 3'd4; //根据PCF8591的datasheet,I2C的频率最高为100KHz, //我们准备使用4个节拍完成1bit数据的传输,所以需要400KHz的时钟触发完成该设计 //使用计数器分频产生400KHz时钟信号clk_400khz //其中CNT_NUM控制分配器的分频,例如如果FPGA的时钟为50MHz,则CNT_NUM = 125,因为400K*125 = 50MHz reg clk_400khz; reg [9:0] cnt_400khz; always@(posedge clk_in or negedge rst_n_in) begin if(!rst_n_in) begin cnt_400khz = CNT_NUM-1) begin cnt_400khz = CNT_NUM-1) begin cnt_400khz


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3