首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >串口通信系列(二)、I2C通信方式

串口通信系列(二)、I2C通信方式

作者头像
根究FPGA
发布2020-06-30 11:15:08
2K0
发布2020-06-30 11:15:08
举报
文章被收录于专栏:根究FPGA根究FPGA
一、I2C简介

IIC全称为Inter Integrated Circuit:两根通信线:一根时钟线SCL一根数据线SDA,只有一根数据线,所以是半双工通信。数据的传输速率在标准模式下可达100kbit/s,在快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s。

IIC总线的器件输出基本为开漏输出,所以需要接总线需要接上拉电阻,连接示意图:

起始信号:

由于总线上接有上拉电阻,在空闲状态时SCL与SDA都是高电平。所以起始位为:

当SCL为高电平时,SDA总线拉低。

数据传输:

IIC总线在进行数据传输时,时钟信号为高电平期间,数据线上的数据必须保持稳定只有在SCL为低电平期间,数据线上的电平状态才允许有变化。

停止信号:

上面提到了在SCL为高电平时数据线不允许有变化,这时为了防止触发停止位,停止位为:

在SCL为高电平时,SDA从低电平跳变到高电平。

IIC传输时序图:

分析IIC时序图可以看到:在SCL为高时,SDA拉低表示起始位;之后开始数据传输,SCL拉低,在SCL为低期间给SDA赋值,SCL的0+1作为一个完整时钟,传输8bit数据需要8个完整SCL时钟;在第8个时钟末,主机释放SDA等待从机应答,如果第9个周期从机将SDA拉低,表示应答成功。在第九个时钟周期末,从机释放SDA使主机继续传输数据,如果主机发送停止信号,此次传输结束。

在数据发送期间,最先发送的是最高位!

二、 器件地址

每个I2C器件都有一个器件,器件地址由固定与部分可编程两种。对于E2PROM器件地址为1010+3bit可硬件设置地址,当硬件电路上分别将这三个管脚连接到GND或VCC时候,就可以设置不同的可编程地址。

当AT24C64的可编程管脚全部接地,传输格式为:

进行数据传输时,主机首先向总线上发送起始信号,然后按照从高到低的位序发送器件地址,第8bit为读写控制位R/W_N,N表示低电平有效。1:主机对从机读取操作,然后接收从机响应。

三、读写操作

对 器件中的存储单元进行读写操作时,首先要指定存储单元的地址,然后向该地址读写内容。该地址的长度为1个或2个字节。当一个存储单元数量不超过8bit,用一个字节表示。超过一个字节所能表示的最大容量时,使用2个字节表示。

Example:

AT24C02存储单元容量为2Kb,每个存储单元存储8bit数据,一共2^8的存储单元,。需要1个字节的传输地址。在成功启动AT24C02后,未发送停止位,而是发送要进行操作的地址,单字节地址分布

AT24C64的存储单元容量为64Kb,每个存储单元存储一个字节,则一个8K个字节,需要2^13个地址,地址宽度为13bit,需要两个字节传输地址。在传输地址时。低8位在第二次地址传输,5位在第一次地址传输的低5位,双字节地址传输

主机发送完字地址,从机正确应答正确后就把内部存储单元地址指针指向该存储单元。写数据:分为单次写(对于EEPROM称为字节写)和连续写(对于EEPROM称为页写),两者的区别在于发送完一字节数据后,是发送结束信号还是继续发送下一字节数据。如果发送的是结束信号,就是单次写。如果继续发送下一字节数据就称为连续写。

读数据:如果读写控制位为1即为读命令,主机就处于接收数据的状态,从机从该地址单元输出数据。数据读取有三种方式:当前地址读、随机读、连续读。

(1)、当前地址读:

在一次读或写操作之后发起读操作,由于I2C器件在读写操作之后,内部的地址指针自动加一,所以当前地址读读取的是下一字地址的数据。

(2)、随机读:

第一次发送器件地址时后面的控制位为0(写指令),第二次发送器件地址时候后面的读写控制位为1(读指令)。因为需要使从机内存储单元地址指针指向想要读取的存储单元,所以先发送一次Dummy Write(虚写操作), 并不是真的写入数据,而是通过虚写操作使地址指针指向虚写操作中字地址的位置,等从机应答后就可以以当前地址读的方式读取数据。

(3)、连续读:

当前地址读和随机读都是一次读取一个字节,将当前地址读或随机读的主机应答改为主机非应答,表示继续读取数据。

四、 分频时钟的计算

这是最近看到的一个很骚的代码,想起来就想笑,绝对是大神写的,骚的不行哈哈哈哈,真心佩服。

首先,CLK_FREQ是系统的输入时钟频率,I2C_FREQ是设定的IIC通信时钟频率。要生成IIC_SCL这样一个时钟的话肯定要分频,分多少?

CLK_FREQ/I2C_FREQ是一个SCL周期包含的系统时钟个数,一个SCL包含一个高电平一个低电平,那么就需要再除以2,(CLK_FREQ/I2C_FREQ)>> 2'd1;表示半个SCL包含的系统时钟个数。

在每半个SCL时钟周期翻转一个SCL,那么就还需要一个这样的时钟信号,在这个时钟的上升沿使得SCL翻转,该时钟是SCL频率的二倍,那么这个时钟包含的系统时钟个数就是:(CLK_FREQ/I2C_FREQ) >> 2'd2。

本来这样就可以了,可是顾虑到SCL为低电平时候才允许数据发送变化,索性再分一次,将SCL拉低的时间与SDA变化的时间分隔开,这样操作更加稳定。

所以最后就是生成一个4倍SCL的时钟。

代码:

//产生二倍速率的驱动时钟,模块驱动时钟的分频系数assign clk_divide = (CLK_FREQ/I2C_FREQ) >> 2'd2;//生成I2C的SCL的四倍频率的驱动时钟用于驱动i2c的操作always @(posedge clk or negedge rst_n) begin if(!rst_n) begin dri_clk <= 1'b0; clk_cnt <= 10'd0; end else if(clk_cnt == clk_divide[8:1] - 1'd1) begin clk_cnt <= 10'd0; dri_clk <= ~dri_clk; end else clk_cnt <= clk_cnt + 1'b1;end

五、状态机设计

上面已经设置好IIC_SCL的驱动时钟,接下来就是设计IIC的状态机。分析系统的控制信号输入:

(1)、IIC_EXEC:IIC通信执行的触发信号

(2)、bit_ctrl:地址控制信号,是8bit还是16bit的地址

(3)、i2c_rh_wl:读写类型控制信号输入

(4)、i2c_addr:I2C器件地址

(5)、i2c_data_w:IIC要写的数据

(6)、i2c_data_r:IIC读取的数据

(7)、i2c_done: IIC一次操作完成

(8)、i2c_ack: IIC的应答信号 0:应答 1:非应答

分析工作状态:

平时肯定是处于空闲状态——之后接收到IIC执行信号——要看是读取还是写入操作——与从机建立通信即发送从机地址——然后传输要读取或写入的地址——之后进行数据读取或写入——结束

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 根究FPGA 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、I2C简介
  • 二、 器件地址
  • 三、读写操作
  • 四、 分频时钟的计算
  • 五、状态机设计
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档