I2C学习——读写eeprom

一.理论学习

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

  • 16
    点赞
  • 159
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您好!对于在嵌入式系统中使用I2C总线读写EEPROM,您可以通过HAL库来实现。以下是一个基本的示例代码: 1. 首先,您需要在STM32的CubeMX工具中配置I2C外设和GPIO引脚。 2. 在代码中包含必要的头文件: ```c #include "stm32f4xx_hal.h" #include "stm32f4xx_hal_i2c.h" ``` 3. 初始化I2C外设: ```c I2C_HandleTypeDef hi2c1; void I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; // I2C总线速度 hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { // 初始化失败处理 Error_Handler(); } } ``` 4. 实现EEPROM的写操作函数: ```c #define EEPROM_ADDRESS 0xA0 // EEPROM的I2C地址 void EEPROM_Write(uint16_t address, uint8_t *data, uint16_t size) { HAL_I2C_Mem_Write(&hi2c1, EEPROM_ADDRESS, address, I2C_MEMADD_SIZE_16BIT, data, size, HAL_MAX_DELAY); } ``` 5. 实现EEPROM的读操作函数: ```c void EEPROM_Read(uint16_t address, uint8_t *data, uint16_t size) { HAL_I2C_Mem_Read(&hi2c1, EEPROM_ADDRESS, address, I2C_MEMADD_SIZE_16BIT, data, size, HAL_MAX_DELAY); } ``` 6. 在主函数中调用这些函数进行读写操作: ```c int main(void) { // 初始化硬件和外设 I2C1_Init(); // 写入数据到EEPROM uint8_t writeData[] = {0x01, 0x02, 0x03}; EEPROM_Write(0x0000, writeData, sizeof(writeData)); // 从EEPROM读取数据 uint8_t readData[3]; EEPROM_Read(0x0000, readData, sizeof(readData)); // 处理读取的数据 // 其他代码 while (1) { // 主循环 } } ``` 这是一个基本的示例代码,您可以根据您的具体需求进行修改和扩展。希望对您有帮助!如果您还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小勇study

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值