尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

ARM裸机开发-I2C-E2PROM

发布时间:2026/9/29 10:31:43

资讯中心
01
ARTICLE

ARM裸机开发-I2C-E2PROM

ARM裸机开发-I2C-E2PROM
目录一.背景二.时序1.基本时序2.I2c读写时序三.AT24C02四.I2c寄存器IADRIFDRI2CRI2SRI2DR五.实现1.复用功能2.电气属性3.读写时序实现一.背景IICInter-Integrated Circuit又称I2C是是IICBus简称所以中文应该叫集成电路总线。是飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备芯片与芯片之间而发展而来的一种同步串行半双工通信总线方式。该总线允许同时连接多个设备(芯片)。每块芯片在总线上拥有特定的地址。自2006年10月1日起使用I²C协议已经不需要支付专利费低速免费高速付费但制造商仍然需要付费以获取IIC从属设备地址。上图所示是IIC的总线的使用场景所有挂载在IIC总线上的设备都有两根信号线一根是数据线SDA另一根是时钟线SCL。这两个信号线都是双向的。作为一种通信方式IIC总线在某一时刻总线只允许有一个设备处于发送状态所发生的数总线上所有的设备所接收。IIC通信协议包含有设备地址只有发送方携带的地址与某个接收方址相同时接收方才真正执行相关的指令。显然用一根SDA传输数据为串行一个bit的发半双工不能同时发SCL时钟线同步时钟速率所以为同步。此外类似Modbus协议整个网络只有一个主机多个从机默认所有从机保持静默主机发数据从机应答主机根据从机地址传输数据。该I2C则有两个主机但一般为单主机模式。IIC总线规定设备在空闲时两根总线都处于高电平状态。为保证这种状态数据线SDA和时钟线SCL都要外接上拉电阻4.7-10k从机释放总线时由于上拉电阻所以总线保持为高电平)。对于I.MX来说这个上拉电阻也可以在引脚电器配置中设置。二.时序1.基本时序高位先行数据线默认高电平。起始信号SCL时钟信号线为高电平时SDA数据信号线由高变低出现下降沿数据传输SCL时钟信号线为高电平时SDA数据信号线电平保持稳定此时接收方采样数据SCL时钟信号线为低电平时SDA数据信号线电平可以改变此时发送方发送数据应答信号第9个时钟周期接收方需要向发送方回复应答信号ACK低电平NACK高电平每发一个字节接收方回复应答信号。接收方不一定一直是主机发送方也不一定一直是从机。发送方发送一个字节结束后把电平拉高线与特性释放总线交给接收方若接收方拉低电平则表示回复ACK若接收方拉高电平则表示回复NACK发送一个字节后可接着发不用再发起始信号结束信号SCL时钟信号线为高电平时SDA数据信号线由低变高出现上升沿。由于结束信号是上升沿触发所以当接收方拉高电平NACK)之后要发送结束信号则应该先拉低再拉高电平。若是低电平即回复ACK则直接拉高最后注意所有起始和结束信号都是由主机发起包括时钟信号起始信号后第一个字节:设备地址(高7位)数据流向位(低1位0x100001 0001 理论128个从机实际会空出一个只有127个从机0:主机发送数据给从机(写)1:从机发送数据给主机(读)2.I2c读写时序I2c写时序:1.主机发送起始信号设备地址写位等待从机ACK应答2.主机发送寄存器地址等待从机ACK应答3.主机向从机发送数据等待从机ACK应答4.主机发送停止信号I2c读时序:1.主机发送起始信号设备地址写位等待从机ACK应答2.主机发送寄存器地址等待从机ACK应答3.主机重发起始信号设备地址读位等待从机ACK应答4.主机接收从机数据主机回复ACK应答5.当主机接收完最后一个字节数据向从机回复NACK应答6.主机发送停止信号读写位和设备地址连着所以要改变读写位就要重发设备地址而设备地址通常为起始信号后的第一个字节所以重发起始信号三.AT24C02AT24C02 是一款 2Kbit256 字节的串行 EEPROM电可擦除可编程只读存储器芯片。它通过 I2C 总线接口与主控芯片如单片机通信常用于存储需要掉电保存的小量数据例如配置参数或用户设置。 核心参数速览· 存储容量2Kbit即 256 字节256 x 8bit。· 接口类型I2C 两线串行接口SCL, SDA。· 工作电压1.8V ~ 5.5V宽电压范围兼容 3.3V 使用的imx6ull和 5V 系统。· 通信速率100KHZ1.8V2.5V2.7V)400kHz5V。· 支持页写一页8B。· 擦写寿命100 万次。· 数据保存100 年。黑色芯片如下结构A0,A1,A2默认接GND即默认低电平。设备地址0101 0000即0x50四.I2c寄存器IADR当imx6ull芯片作为从机时应在该寄存器传输地址本篇作为主机使用。IFDR配置分频由于采用ipg时钟在上篇中有所提及应为66MHZ而本次应设置为100KHZ计算没有具体值采用相近的分频因子640I2CRTXAK当主机为发送模式此位置0表示检测从机发送的ACK置1表示检测从机发送的NACK当主机为接收模式此位置0表示主机回复给从机的ACK置1表示主机回复给从机的NACKI2SRICF只判断确认位之前的数据是否传输IBB判断总线是否占用0空闲1占用发送停止位之后清零IAL总线仲裁置0表示不丢失总线仲裁用于多主机情况下置1表示仲裁丢失没有抢到总线控制权本次不需要配0即可。IIF中断标记位判断包括确认位之前的数据是否接收即使GIC失能但外设中断位也会产生只是到不了内核。接收或发送数据之前清零接收ACK或NACK之后置1然后要再发送数据的话再清零。主机作为接收方时标记接收应答置1作为发送方时标记发送应答置1I2DR五.实现1.复用功能引脚43的UART4 TXD被复用为I2C1的时钟线引脚42的UART4 RXD 被复用为I2C1的数据线// 配置引脚复用功能 IOMUXC_SetPinMux(IOMUXC_UART4_TX_DATA_I2C1_SCL, 1); IOMUXC_SetPinMux(IOMUXC_UART4_RX_DATA_I2C1_SDA, 1);2.电气属性由于I2c配置了上拉电阻所以此处应修改PUS位为11选择22k的上拉电阻与芯片电阻并联同时PUE为选择拉保持是电压输入几伏就保持不改变PKE位选择失能所以12-15位为1111配置电气属性为0xF0B0// 配置引脚电气属性 IOMUXC_SetPinConfig(IOMUXC_UART4_TX_DATA_I2C1_SCL, 0xF0B0); IOMUXC_SetPinConfig(IOMUXC_UART4_RX_DATA_I2C1_SDA, 0xF0B0);3.读写时序实现//与上面的复用功能和电气属性皆为初始化部分 I2C1-I2CR ~(1 7); // I2C1失能 I2C1-IFDR 0x15; // 640分频 I2C1-I2CR | (1 7); // I2C1使能void i2c_write(I2C_Type *base, unsigned char dev_address, unsigned char reg_address, const unsigned char *data, int len) { // 通信前 仲裁丢失标志位清零 中断标记位清零 base-I2SR ~((1 IIF) | (1 IAL)); // 通信前等待数据传输完毕 while ((base-I2SR (1 ICF)) 0); // 发送起始信号 base-I2CR | (1 MSTA); // 主机模式发送模式 base-I2CR | (1 MTX); // 后续检测从机ACK信号 base-I2CR ~(1 TXAK); // 中断标记位清零 base-I2SR ~(1 IIF); // 发送设备地址 写位 base-I2DR dev_address 1; // 101 0000 0 // 等待从机ACK while ((base-I2SR (1 IIF)) 0); // 中断标记位清零 base-I2SR ~(1 IIF); // 发送寄存器地址 base-I2DR reg_address; // 等待从机ACK while ((base-I2SR (1 IIF)) 0); while (len--) { // 中断标记位清零 base-I2SR ~(1 IIF); // 发送数据 base-I2DR *data; // 等待从机ACK while ((base-I2SR (1 IIF)) 0); } // 发送停止信号 base-I2CR ~(1 MSTA); // 等待总线空闲 while ((base-I2SR (1 IBB)) ! 0) { delay_us(100); } } void i2c_read(I2C_Type *base, unsigned char dev_address, unsigned char reg_address, unsigned char *data, int len) { // 通信前 仲裁丢失标志位清零 中断标记位清零 base-I2SR ~((1 IIF) | (1 IAL)); // 通信前等待数据传输完毕 while ((base-I2SR (1 ICF)) 0); // 发送起始信号 base-I2CR | (1 MSTA); // 主机模式发送模式 base-I2CR | (1 MTX); // 后续检测从机ACK信号 base-I2CR ~(1 TXAK); // 中断标记位清零 base-I2SR ~(1 IIF); // 发送设备地址 写位 base-I2DR dev_address 1; // 等待从机ACK while ((base-I2SR (1 IIF)) 0); // 中断标记位清零 base-I2SR ~(1 IIF); // 发送寄存器地址 base-I2DR reg_address; // 等待从机ACK while ((base-I2SR (1 IIF)) 0); // 重发起始信号 base-I2CR | (1 RSTA); // 中断标记位清零 base-I2SR ~(1 IIF); // 重发设备地址 读位 base-I2DR dev_address 1 | 1; // 等待从机回复ACK信号 while ((base-I2SR (1 IIF)) 0); // 主机模式接收模式 base-I2CR ~(1 MTX); // 中断标记位清零 base-I2SR ~(1 IIF); // 代表只需要读取一个字节 if (len 1) { // 代表收到一个字节后后续回复NACK base-I2CR | (1 TXAK); } // 假读,在半双工模式下发送和接收都用I2DR寄存器读一次才能启动读数据data不下次读取要覆盖此次读取发送时残留的数据 *data base-I2DR; // 读取len个字节数据 while (len-- ! 0) { // 代表收到一个字节数据,并且主机回复了ACK while ((base-I2SR (1 IIF)) 0); // 中断标记位清零 base-I2SR ~(1 IIF); // 代表数据全部接收完 if (len 0) { // 发送停止信号 base-I2CR ~(1 MSTA); // ACK,以便下次通信发送数据时发送方检测ACK base-I2CR ~(1 TXAK); // 等待总线空闲 while ((base-I2SR (1 IBB)) ! 0) { delay_us(100); } } else if (len 1) { // NACK base-I2CR | (1 TXAK); } *data base-I2DR; } }i2c_read(I2C1, 0x50, 0, buffer, 5);设备地址0x0101 0000即0x50寄存器地址0是AT24C02 内部的存储单元地址也叫字地址Word Address。AT24C02 的存储空间是256 字节2K bit地址范围是0x00 ~ 0xFF。你传0表示要从第 0 个字节开始读写。你传0x10表示从第 16 个字节开始。容易混淆的两个“地址”名称含义例子谁决定的设备地址I2C 总线上识别哪个芯片0x50芯片型号 A0/A1/A2 引脚字地址EEPROM 内部存储单元的偏移量0x00 ~ 0xFF你在代码里自己分配
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。