草庐IT

I2C学习——读写eeprom

小勇study 2023-11-12 原文

一.理论学习

I2C 通讯协议(Inter-Integrated Circuit)是由Philips公司开发的一种简单、双向二线制同步串行总线,只需要两根线即可在连接于总线上的器件之间传送信息。

I2C物理层


特点如下:
1.在一个I2C通讯总线中,可挂载多个设备,这些设备既可做主机也可做从机。(一般总线上挂载的设备所在的地址,在出厂的时候已经设置好了,一般来说器件地址是7位,当然也有其他的情况,比如说在eeprom,它的地址设置了高4位,剩下的3位可由用户自己设置)
2.一个I2C总线只使用两条总线线路,一条双向串行数据线(SDA) ,一条串行时钟线 (SCL)。
3.每个连接到总线的设备都有一个独立的地址,主机通过地址去访问相应的设备。
4.总线通过上拉电阻接到电源。当I2C设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。
5.多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。
6.具有三种传输模式:标准模式传输速率为100kbit/s ,快速模式为400kbit/s ,高速模式下可达3.4Mbit/s,但目前大多I2C设备尚不支持高速模式。
7.连接到相同总线的 IC 数量受到总线的最大电容 400pF 限制 。

I2C协议层

看一下整体的时序图,分为4个状态:

1.空闲态:SCL和SDA都为高阻态的时候;
2.起始状态:SCL空闲的时候检测到SDA的下降沿的时候产生一个起始信号,此时总线上的设备检测到该信号会跳出空闲态,等待字节的输入。
3.数据读/写状态:这个状态的具体时序如下:

主机向从机写数据或指令的时候,在SCL为高电平的时候,串行数据总线SDA向从机写入一位数据,在SCL为低电平的时候,SDA上的数据进行更新;当数据传输满足1byte的时候,从机正确接收到这个字节后,会拉低SDA,向主机发送1bit的应答信号,表示该字节写入成功。如果从机给的是正确应答,就可以结束本字节或者开始下个字节的传输;若给的是错位应答,主机考虑放弃写入或者重新写入。
4.停止状态:SCL高电平时检测到SDA的上升沿的时候产生一个停止信号,此时总线跳转回到空闲状态。

器件地址和存储地址

1.主机想要和从机建立通讯,首先会发将控制命令(器件地址 + 读/写控制位)发送到SDA上,挂载在I2C总线上的器件会接收主机的控制指令和自身进行对比。如果地址相同,会给主机一个应答信号,主机接收到信号之后,主从设备才能建立通讯,进行数据传输。前面说过了,器件地址在出厂的时候就进行了设置。
2.挂载在总线上的设备,他们的内部都有着一些可进行读/写操作的寄存器或存储器。根据设备的不同,存储地址分为单字节和双字节。
以EEPROM存储芯片为例,在ATMEL公司生产的AT24C系列EEPROM存储芯片中选取两款存储芯片AT24C04和AT24C64。AT24C04的存储容量为1Kbit(128byte),7位存储地址即可满足所有存储单元的寻址,存储地址为单字节即可;而AT24C64的存储空间为64 Kbit(8Kbyte),需要13位存储地址才可满足所有存储单元的寻址,存储地址为2字节。

I2C读/写操作

对传入从机的控制命令最低位读写控制位写入不同数据值,主机可实现对从机的读/写操作。读写控制位为0时,表示主机要对从机进行数据写入操作;读写控制位为1时,表示主机要对从机进行数据读出操作。在这里将其分为读操作和写操作进行理解。

写操作

讲解I2C写操作,由于一次写入数据量的不同,I2C的写操作可分为单字节写操作页写操作,详细讲解如下。
单字节写操作中,主机一次向从机中写入单字节数据。

单字节写操作时序图【1个字节的存储地址】:

单字节写操作时序图【2个字节的存储地址】:

单字节时序的描述:
1.主机产生并发送起始信号到从机,把控制命令写入从机设备【控制命令最后一位设为低,表示对从机的写操作】,控制命令从高位到低位依次写入;
2.从机接收到控制命令后,回传应答信号ACK,主机接收到之后开始写入存储地址。若存储地址是2个字节的话,顺序执行下面的操作3;若存储地址是单字节的话,跳转到5步骤;
3.主机对从机先写入高8位地址,按照先高位后低位的顺序;
4.主机接收到从机的应答信号后,继续写入低8位的地址【先高后低】,如果是两个字节的地址,转到步骤6;
5.按照先高位后低位的顺序写入单字节的数据写入;
6.两个字节的存储地址写完之后,主机收到应答信号后,开始写入单字节的数据;
7.单字节数据写入完成,主机接收到应答信号后,向从机发送停止信号,单字节数据写入完成。
单字节存储地址的步骤:1-2-5-6-7
2个字节的存储地址步骤:1-2-3-4-6-7

页写操作中,主机一次可向从机写入多字节数据。

页写操作时序图(单字节存储地址)

页写操作时序图(2字节存储地址)

页写时序的描述:
1.主机产生并发送起始信号到从机,将控制命令写入从机设备,读写控制位设置为低电平,表示对从机进行数据写操作,控制命令的写入高位在前低位在后;
2.从机接收到控制指令后,回传应答信号,主机接收到应答信号后开始存储地址的写入。若为2字节地址,顺序执行操作;若为单字节地址跳转到步骤(5);
3.先向从机写入高8位地址,且高位在前低位在后;
4.待接收到从机回传的应答信号,再写入低8位地址,且高位在前低位在后,若为2字节地址,跳转到步骤(6);
5.按高位在前低位在后的顺序写入单字节存储地址;
6.地址写入完成,主机接收到从机回传的应答信号后,开始第一个单字节数据的写入;
7.数据写入完成,主机接收到应答信号后,开始下一个单字节数据的写入;
8.数据写入完成,主机接收到应答信号。若所有数据均写入完成,顺序执行操作流程;若数据尚未完成写入,回到步骤(7);
9.主机向从机发送停止信号,页写操作完成。
单字节存储地址的步骤:1-2-5-6-7-8-9
2个字节存储地址的步骤:1-2-3-4-6-7-8-9

注意:所有I2C设备均支持单字节数据写入操作,但只有部分I2C设备支持页写操作;且支持页写操作的设备,一次页写操作写入的字节数不能超过设备单页包含的存储单元数。 

读操作

根据一次读操作读取数据量的多少,读操作可分为随机读操作和顺序读操作。

随机读操作
I2C随机读操作可以理解为单字节数据的读取。

随机读操作时序图【单字节存储地址】:

随机读操作时序图【2个字节存储地址】:

随机读操作的时序描述:
1.主机产生并发送起始信号到从机,将控制命令写入从机设备,读写控制位设置为低电平,表示对从机进行数据写操作,控制命令的写入高位在前低位在后;
2.从机接收到控制指令后,回传应答信号,主机接收到应答信号后开始存储地址的写入。若为2字节地址,顺序执行操作;若为单字节地址跳转到步骤(5);
3.先向从机写入高8位地址,且高位在前低位在后;
4.待接收到从机回传的应答信号,再写入低8位地址,且高位在前低位在后,若为2字节地址,跳转到步骤(6);
5.按高位在前低位在后的顺序写入单字节存储地址;
6.地址写入完成,主机接收到从机回传的应答信号后,主机再次向从机发送一个起始信号;
7.主机向从机发送控制命令,读写控制位设置为高电平,表示对从机进行数据读操作;
8.主机接收到从机回传的应答信号后,开始接收从机传回的单字节数据;
9.数据接收完成后,主机产生一个时钟的高电平无应答信号;
10.主机向从机发送停止信号,单字节读操作完成。
单字节存储地址的随机读的步骤:1-2-5-6-7-8-9-10
2字节存储地址的随机读的步骤:1-2-3-6-7-8-9-10

顺序读操作
I2C顺序读操作就是对寄存器或存储单元数据的顺序读取。假如要读取n字节连续数据,只需写入要读取第一个字节数据的存储地址,就可以实现连续n字节数据的顺序读取。
顺序读操作时序图(单字节存储地址):

顺序读操作时序图(2字节存储地址):

顺序读时序的描述:
1.主机产生并发送起始信号到从机,将控制命令写入从机设备,读写控制位设置为低电平,表示对从机进行数据写操作,控制命令的写入高位在前低位在后;
2.从机接收到控制指令后,回传应答信号,主机接收到应答信号后开始存储地址的写入。若为2字节地址,顺序执行操作;若为单字节地址跳转到步骤(5);
3.先向从机写入高8位地址,且高位在前低位在后;
4.待接收到从机回传的应答信号,再写入低8位地址,高位在前低位在后,若为2字节地址,转到步骤(6);
5.按高位在前低位在后的顺序写入单字节存储地址;
6.地址写入完成,主机接收到从机回传的应答信号后,主机再次向从机发送一个起始信号;
7.主机向从机发送控制命令,读写控制位设置为高电平,表示对从机进行数据读操作;
8.主机接收到从机回传的应答信号后,开始接收从机传回的第一个单字节数据;
9.数据接收完成后,主机产生应答信号回传给从机,从机接收到应答信号开始下一字节数据的传输,若数据接收完成,执行下一操作步骤;若数据接收未完成,在此执行步骤(9);
10.主机产生一个时钟的高电平无应答信号;
11.主机向从机发送停止信号,顺序读操作完成。
单字节存储地址的顺序读的步骤:1-2-5-6-7-8-9-10
2字节存储地址的顺序读的步骤:1-2-3-6-7-8-9-10

实验内容

设计一个使用I2C通讯协议的EEPROM读写控制器,使用按键控制数据写入或读出EEPROM。写按键按下,向EEPROM写入10字节数据【1-10】,按下读控制的按键,读出之前写入的数据并在数码管上显示。

程序设计

整体框架设计
首先,实验目标要求要使用I2C通讯协议,那么工程中要包含一个I2C驱动模块【i2c_ctrl】;其次,使用按键控制数据读/写,并要求将读出数据显示到数码管上,我们可以直接调用前面章节的按键消抖模块【key_filter】数码管动态显示模块【seg_595_dynamic】;再次,我们需要设计一个**数据收发模块【i2c_rw_data】控制数据的收发;最后,需要顶层模块【eeprom_byte_rd_wr】**将各子功能模块例化起来,连接个 功能模块对应信号。框架结构如下:

整体工作流程
按下数据写操作按键,写触发信号传入按键消抖模块(key_filter),经消抖处理后的写触发信号传入数据收发模块(i2c_rw_data),模块接收到有效的写触发信号后,生成写使能信号、待写入数据、数据地址传入I2C驱动模块(i2c_ctrl),I2C驱动模块按照I2C协议将数据写入EEPROM存储 芯片;

数据写入完成后,按下数据读操作按键,读触发信号传入按键消抖模块(key_filter),经消抖处理后的读触发信号传入数据收发模块(i2c_rw_data),模块接收到有效的读触发信号后,生成读使能信号、数据地址传入I2C驱动模块(i2c_ctrl),I2C驱动模块自EEPROM存储芯片读取数据,将读 取到的数据回传给数据收发模块(i2c_rw_data),数据收发模块将数据暂存,待所有数据均读取完成后,将数据传至数码管动态显示模块(seg_595_dynamic),自EEPROM中读取的数据在数码管显示出来。
这里主要介绍I2C驱动模块。

I2C驱动模块

该模块的内容就是通过I2C对EEPROM进行读写操作。框图如下:

信号说明如下:

根据上述信号,对该模块的整体的描述:
输入信号中,sys_clk、sys_rst_n是必不可少的系统时钟和复位信号;wr_en、rd_en为写使能信号,由数据收发模块生成并传入,高电平有效;i2c_start信号为单字节数据读/写开始信号;与i2c_sta rt信号同时传入的还有数据存储地址byte_addr和待写入字节数据wr_data;当写使能wr_en和i2c_start信号同时有效,模块执行单字节数据写操作,按照数据存储地址byte_addr,向EEPROM对应地址写入数据wr_data;当读使能信号rd_en和i2c_start信号同时有效, 模块执行单字节数据读操作,按照数据存储地址byte_addr读取EEPROM对应地址中的数据;前文中我们提到, I2C设备存储地址有单字节和2字节两种,为了应对这一情况,我们向模块输入addr_num信号,当信号为低电平时,表示I2C设备存储地址为单字节,在进行数据读写操作时只写入数据存储地址byt e_addr的低8位;当信号为高电平时,表示I2C设备存储地址为2字节,在进行数据读写操作时要写入数据存储地址byte_addr的全部16位。

输出信号中,i2c_clk是本模块的工作时钟,由系统时钟sys_clk分频而来,它的时钟频率为串行时钟i2c_scl频率的4倍,时钟信号i2c_clk要传入数据收发模块(i2c_rw_data)作为模块的工作时钟;输出给数据收发模块(i2c_rw_data)的单字节数据读/写结束信号i2c_end, 高电平有效,表示一次单字节数据读/写操作完成;rd_data信号表示自EEPROM读出的单字节单字节数据,输出至数据收发模块(i2c_rw_data);i2c_scl、i2c_sda分别是串行时钟信号和串行数据信号,由模块产生传入EEPROM存储芯片。

注:对EERPROM的数据读写操作均使用单字节读/写操作,即每次操作只读/写单字节数据;若想要实现数据的连续读/写,可持续拉高读/写使能rd_en/wr_en,并输入有效的单字节数据读/写开始信号i2c_start即可。

具体如何设计:
1.参照I2C设备单字节写操作和随机读操作的操作流程,绘制I2C读/写操作状态转移图如下:

上述的状态机可以分为三条主线:第一条是主机主机访问设备和对应设备存储地址;第二条是进入主机对从机写操作;第三条是主机对从机的读操作。对于状态机的具体描述就不再赘述了。

画波形图:
波形图是设计中的关键一环,通过波形的方式更加直观的展现出时序,便于代码的编写以及后面的仿真和调试。这里主要介绍了单字节的写操作时序和单字节的读操作时序。

在进入读写操作前的时序时相同,也就是状态机图中的路径1,对应的时序图如下:

信号说明:
cnt_i2c_clk是对i2c_clk进行计数,计满4【也就是一个串行时钟】,传输一个bit 的数据,传输多少个bit通过cnt_bit来计数;
sda_en信号【高有效】控制主机对总线的占用,在这个信号有效的时候把数据传进i2c_sda_reg这个寄存器中,在从寄存器中取出进入到数据总线i2c_sda传给设备;
ack信号仅在应答状态由sda_in给出,因为sda_in接收数据总线i2c_sda中的数据【包含读出的数据和应答的数据】;
读出的数据会进入到rd_data_reg寄存器中保存,然后传到端口的rd_data;

写操作的波形:

读操作的波形:

时钟部分的波形:

根据上面的波形和信号的说明,就可以去写代码了,代码就不再展示了,你可以去B站搜野火的教程,有详细的说明。这部分的学习主要是为了后面老师布置的一个通过温度芯片读取温度的小练习做准备的。

文章参考自野火FPGA

有关I2C学习——读写eeprom的更多相关文章

  1. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  2. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  3. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  4. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  5. ruby - 我如何学习 ruby​​ 的正则表达式? - 2

    如何学习ruby​​的正则表达式?(对于假人) 最佳答案 http://www.rubular.com/在Ruby中使用正则表达式时是一个很棒的工具,因为它可以立即将结果可视化。 关于ruby-我如何学习ruby​​的正则表达式?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1881231/

  6. 深度学习12. CNN经典网络 VGG16 - 2

    深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG

  7. 机器学习——时间序列ARIMA模型(四):自相关函数ACF和偏自相关函数PACF用于判断ARIMA模型中p、q参数取值 - 2

    文章目录1、自相关函数ACF2、偏自相关函数PACF3、ARIMA(p,d,q)的阶数判断4、代码实现1、引入所需依赖2、数据读取与处理3、一阶差分与绘图4、ACF5、PACF1、自相关函数ACF自相关函数反映了同一序列在不同时序的取值之间的相关性。公式:ACF(k)=ρk=Cov(yt,yt−k)Var(yt)ACF(k)=\rho_{k}=\frac{Cov(y_{t},y_{t-k})}{Var(y_{t})}ACF(k)=ρk​=Var(yt​)Cov(yt​,yt−k​)​其中分子用于求协方差矩阵,分母用于计算样本方差。求出的ACF值为[-1,1]。但对于一个平稳的AR模型,求出其滞

  8. Unity Shader 学习笔记(5)Shader变体、Shader属性定义技巧、自定义材质面板 - 2

    写在之前Shader变体、Shader属性定义技巧、自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用,方便后续回顾查看,如有以偏概全、不祥不尽之处,还望海涵。1、Shader变体先看一段代码......Properties{ [KeywordEnum(on,off)]USL_USE_COL("IsUseColorMixTex?",int)=0 [Toggle(IS_RED_ON)]_IsRed("IsRed?",int)=0}......//中间省略,后续会有完整代码 #pragmamulti_c

  9. ruby-on-rails - 这个 C 和 PHP 程序员如何学习 Ruby 和 Rails? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它

  10. jquery - 使用 Rails 3 学习 Ajax 的资源 - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。有没有学习Ajax(jQuery)和Rails3的好资源?

随机推荐