资讯详情

【正点原子MP157连载】第二十五章 I2C光照&接近传感器实验-摘自【正点原子】STM32MP1 M4裸机CubeIDE开发...

在这里插入图片描述

第二十五章 I2C光照&接近传感器实验

I2C 它是最常用的通信接口,许多传感器提供 I2C 接口与陀螺仪、 因此,加速度计、触摸屏等 I2C 必须掌握嵌入式开发,STM32MP157 有 6个 I2C 接口,可通过此 6 个 I2C 连接一些接口 I2C 外设。正点原子的STM32MP157开发板使用 I2C5接口连接到距离传感器 AP3216C,让我们学习如何使用本章STM32MP157的 I2C 5接口来驱动 AP3216C,并读取AP3216C 传感器数据。 本章分为以下几个部分: 25.1、IIC简介; 25.2、STM32MP157 I2C简介; 25.3、I2C寄存器介绍; 25.4、I2C的HAL库驱动; 25.5、AP3216C简介; 25.6、硬件I2C通信实验; 25.7、软件I2C通信实验;

25.1 IIC简介 IIC(Inter-Integrated Circuit)总线是一种由PHILIPS连接微控制器及其外围设备(又称设备)的公司开发的两线串行总线。IIC也可以写成I2C,数据线有两条线(不是地线)SDA和时钟线SCL串行总线可以在CPU与被控IC之间、IC与IC双向传输。随着科学技术的发展,现在已经存在了I3C也许有些朋友已经在了Intel路线图和DDR这个名字在相关的内存规格中看到,I3C向下兼容I2C。 25.1.1 I2C总线特点 I2C总线具有以下特点: ①总线由串行数据线组成SDA串行时钟线SCL数据线用于传输数据,时钟线用于同步数据收发。 ②I2C所有设备都挂接 SDA 和 SCL 在这两条线上,总线上的每个设备都有一个唯一的地址识别,即设备地址,所以I2C 可通过主控制器 I2C 设备的器件地址访问指定的 I2C设备。 ③数据线SDA和时钟线SCL它们都是双向线,通过电流源或上拉电阻连接到正电压,所以当总线空闲时,这两条线都处于高电平状态。 ④在标准模式下,总线数据的传输速率可以达到 100kbit/s ,在快速模式下可达 400kbit/s ,随着科学技术的发展,高速模式可达3.4Mbit/s,不过,对于STM32MP157其I2C在高速模式下可以达到1Mbit/s。 ⑤使用总线支持设备连接I2C通信总线可以有多个I2C同时支持多个主机和多个从机持多个主机和多个从机。理论上,当它是七位地址时I2C可以挂载2^7-1=127(地址0x00不需要,所以从设备中减去1)个,I2C协议中没有规定总线上可以挂载的设备的最大数量,但规定总线电容不得超过400pF,因此,连接到总线的设备接口数量由总线400pF限制电容。I2C多个设备的示意图挂载在总线上,如下图所示:

图25.1.1.1 I2C多个装置挂载在总线上 25.1.2 I2C总线时序图 下面来学习I2C总线协议,I2C总线时序图如下:

图25.1.2.1 I2C总线时序图 为了方便大家更好的了解I2C协议从时序图中的起始位置、停止位置、响应信号、数据有效性、数据传输和空闲状态六个方面进行解释。 ① 起始位 顾名思义,也就是说I2C通信开始的标志由主机发出。开始信号生成后,总线将被占用,准备开始数据传输。 SCL 高电平时,SDA 起始信号是一种电平跳变时序信号,而不是电平信号。

图25.1.2.2 起始位 ② 停止位 停止信号由主机发出。停止信号发出后,总线将处于空闲状态。停止是停止I2C与起始位功能相反的通信标志位。SCL高电平期,SDA上升边缘的出现意味着停止,停止信号也是电平跳变时序信号,而不是电平信号。

图25.1.2.3 停止位 ⑤ 数据传输 在I2C总线上传输的每个数据都有一个时钟脉冲对应(或同步控制),即在SCL在串行时钟的配合下,SDA每个数据串行传输。I2C总线通过SDA通过数据线传输数据SCL时钟线进行数据同步,SDA数据线在 SCL每个时钟周期传输一个数据。 当数据传输时,当SCL 高电平期,SDA 上述数据有效(稳定)。当 SCL低电平时,SDA数据无效(不稳定),即此时,SDA 进行电平切换,SDA 上述数据发生变化,为下一次数据传输做准备,数据在SCL需要在上升沿到来之前做好准备。并且在下降边到来之前必须稳定。

图25.1.2.4 I2C数据传输 ③ 应答信号 当I2C每次主机发送一个字节数据,数据线就会在时钟脉冲9期间释放。SDA 设置为输入状态,等待I2C从机应答,即等待I2C从机器告诉主机它收到了数据,响应信号是从机器发出的,主机需要提供响应信号所需的时钟,主机发送后 8 位数据后跟随的时钟信号用于响应信号,从机通过将 SDA 降低表示响应信号,表示通信成功,否则表示通信失败。当响应信号为低电平时,规定有效响应位置(ACK简称应答位),应答信号为高电平时,规定为非应答位(NACK)。 如果接收器是主机,如果想在收到最后一个字节后终止数据传输,主机会发送一个NACK通知被控发送器结束数据发送并释放信号SDA以便主机接收器发送停止信号。 ④ 数据有效性 I2C当总线传输数据时,SCL高电平期,SDA上述数据有效;SCL为低电平期间,SDA上述数据无效。 ⑥ 空闲状态 I2C总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。 在了解了I2C在上述时序的基本概念之后,下面介绍一下I2C读写通信的基本过程。 25.1.3 I2C总线时序

  1. 写时序 先看一下操作通信流程图,如下图所示:

图25.1.3.1 编写操作通信流程图 对于IIC从机器不能主动发送数据,开始条件由主机生成。主机首先在I2C总线发送起始信号,然后总线上的从机器将等待接收主机发送的数据。主机接着由 发送从机地址 0(写操作位) 组成的8bit所有从机接收8的数据bit数据完成后,自行检查是否为自己的设备地址。如果是自己的设备地址,相应设备地址的机器会发出响应信号。只有在主机在总线上收到响应信号后,才能继续向从机发送数据。数据包的大小是 8位。每次主机发送字节数据,都要等待从机响应信号。当主机向从机发送停止信号时,数据传输结束。注意:I2C总线传输的数据信号是广义的,包括地址信号和真实数据信号。 2. 读时序 然后解释一下IIC阅读总线的读操作过程,先看读操作通信过程图,如下图所示。

图25.1.3.2 读操作通讯过程图 从主机读取数据的操作,最初的操作有点类似于写作操作,观察两张图片也可以发现主机发送起始信号,然后发送 从机地址 1(读操作位) 组成的8bit数据,从机接收数据验证是否为自己的地址,在验证为自己的设备地址后,相应的设备地址将发出响应信号,并返回主机8bit数据,发送后,机器将等待主机的响应信号。如果主机一直返回响应信号,则从机器可以一直发送数据,即图中(n byte 应答信号)直到主机发出非应答信号,数据才会从机器中停止发送。当主机发出非应答信号时,主机将发出停止信号并停止I2C通信。 25.2 STM32MP157 I2C简介 25.2.1 I2C特性 STM32MP157D有6个I2C接口,其中I2C4和I2C6可以在A7安全模式或A7非安全模式下使用,M4无法使用。I2C可以控制多主模式的所有功能I2C总线的特定序列、协议、仲裁和时序,STM32MP157的 I2C 部分特点如下: ①、兼容 I 2 C 总线规范第 03 版; ②、从模式和主模式支持多主模式功能; ③、支持标准模式 (S)、快速模式 (Fm) 和超快速模式 (Fm+),其中,标准模式(高达 100 kHz),快速模式(高达 400 kHz),超快速模式(高达 1 MHz); ④、7 位和 10 位寻址模式; ⑤、多个 7 位从地址,所有 7 位地址应答模式; ⑥、软件复位; ⑦、带 DMA 功能的 1 字节缓冲; ⑧、独立时钟:选择独立时钟源可使 I2C 通信速度不受 i2c_pclk 重新编程的影响; ⑨、地址匹配时从停止模式唤醒; ⑩、广播呼叫。 25.2.2 I2C框图 STM32MP157的I2C框图如下所示:

图25.2.2.1 I2C总线框图

  1. I2C时钟源 2C 的时钟由独立时钟源提供,这使得 I2C 能够独立于 i2c_pclk 频率工作。I2C 内核的时钟由 i2c_ker_ck 提供,而I2C1、I2C2、I2C3和I2C5的内核时钟源可以选择pclk1、pll4_r_ck、hsi_ker_ck和csi_ker_ck,而I2C4和I2C6的内核时钟源可以选择pclk5、pll3_r_ck、hsi_ker_ck和csi_ker_ck。

图25.2.2.2 I2C时钟 i2c_ker_ck 周期 tI2CCLK必须遵循以下条件: tI2CCLK < (tLOW - tfilters ) / 4 且 tI2CCLK < tHIGH 其中,tLOW:SCL 低电平时间;tHIGH:SCL 高电平时间;tfilters:滤波器使能时模拟滤波器和数字滤波器引入的延时总和。 当I2C内核由i2c_pclk提供时钟时,该时钟必须遵守tI2CCLK的条件,i2c_pclk 时钟周期 tPCLK 必须遵循以下条件: tPCLK < 4/3 tSCL 其中,tSCL:SCL 周期 2. I2C的通讯总线 每个I2C有两根通讯总线SDA和SCL,这些总线的接口接到不同的GPIO上,通过《STM32MP157A&D数据手册》可以查询具体接到哪个GPIO上,如下:

表25.2.2.1 I2C引脚 3. 报警控制状态 在该功能模块的介绍前,我们先来了解SMBus。SMBus 是 System Management Bus 的缩写,即系统管理总线,是Intel与Duracell(金顶电池)研发的,它基于I2C操作原理进行设计,主要应用于移动PC和桌面PC系统中的低速率通讯,在低功耗方面优于I2C。SMBus和I2C在诸多方面是相似的,它也是两条总线,SMBus的时钟线称SMBCLK,数据线为SMBDAT,它工作在主/从模式:主器件提供时钟,在其发起一次传输时提供一个起始位,在其终止一次传输时提供一个停止位;从器件拥有一个唯一的7或10位从器件地址。 SMBus相较于I2C,它具有一种特用的ALERT(警讯)机制,用于Slave向Master报警,ALERT其实和中断(Interrupt)类似,ALERT 是低电平有效的,当Slave将SMBSUS线路的电位拉低时,SMBSUS系统向Master发出一个中断警讯,要求Master尽速为某一Slave提供传输服务,Master响应该服务。从框图中可以看到报警控制和状态的接口是I2C_SMBA,只具备从功能的器件可通过I2C_SMBA引脚向主机发出信号,指示它想要通信,主机会处理该中断并通过报警响应地址 (0b0001 100) 同时访问所有器件,只有那些将I2C_SMBA 拉到低电平的器件会应答报警响应地址。 STM32的I2C适配器兼容SMBus协议,可以说SMBus是I2C的一个子集,I2C和SMBus两者在一般应用下,区别不大,甚至大多数情况下可以把smbus等同于I2C来设置和使用。

图25.2.2.3 SMBus总线 SMBus与I2C进行比较,它和I2C有着相似和不同之处:

表25.2.2.2 SMBus与I2C对比 4. I2C的数据控制和时钟控制部分 数据控制部分 I2C的SDA数据传输由发送和接收数据寄存器(I2C_TXDR和I2C_RXDR)以及移位寄存器来管理。 接收情况:数据移位寄存器把SDA信号线采样到的数据一位一位地存储到I2C_RXDR中。在第 8 个 SCL 脉冲后,如果I2C_RXDR 寄存器为空 (RXNE=0),则移位寄存器的内容会复制到I2C_RXDR中;如果 RXNE=1(意味着尚未读取上一次接收到的数据字节),则将延长 SCL 线的低电平时间,直到读取数据I2C_RXDR为止。 发送情况:数据移位寄存器把I2C_TXDR的数据一位一位地通过 SDA信号线发送出去。如果 I2C_TXDR 寄存器不为空 (TXE=0),则其内容会在第 9 个 SCL 脉冲(应答脉冲)后复 制到移位寄存器中,然后移位寄存器的内容会移出到 SDA 线上;如果 TXE=1(意味I2C_TXDR 内尚未写入任何数据),则将延长 SCL 线的低电平时间,直到写入了 I2C_TXDR 为止。 可以看到框图中有SMBus,SMBus规范中引入了数据包错误校验机制来提高可靠性和通信稳定性,如果开启了数据校验(控制寄存器的PECEN位为1,PEC 使能),接收到的数据会经过 PCE进行运算,运算结果存储在PEC寄存器 (I2C_PECR)中。 时钟控制部分 时序配置需要通过时序寄存器 (I2C_TIMINGR)来控制,配置时序的目的是保证主模式和从模式下使用正确的数据保持和建立时间,配置方法是编程 I2C_TIMINGR 寄存器中PRESC[3:0]、SCLDEL[3:0] 和 SDADEL[3:0] 位。必须配置好时序后才可以使用I2C,后面我们讲解改寄存器的时候会分析配置方法,因为配置的过程繁琐,之前ST官方提供的I2C Timing Configuration Tool工具对I2C时钟频率有限制,对于不大于72MHz的I2C时钟频率才可以通过该工具进行配置,这里我们可以直接使用STM32CubeMX来配置,如下图,Timing参数的值就是最终要写入TIMINGR 寄存器的值,即时序配置:

图25.2.2.4 使用STM32CubeMX配置Timing值 这里说明一下数据保持和建立时间: 系统的大部分器件的动作都是在时钟的条边沿上进行,例如I2C的数据变化是在SCL为低电平期间,在这个跳变沿期间数据会被打入触发器,如果时钟信号延时差较大,那么这些数据就不能够稳定打入触发器了,得到的数据就不准确了,所以,数据稳定传输必须满足建立和保持时间的要求。 建立时间:指在时钟沿到来之前数据从不稳定到稳定所需的时间,如果建立的时间不满足要求那么数据将不能在这个时钟上升沿被稳定的打入触发器。 保持时间:指数据稳定后保持的时间,如果保持时间不满足要求,那么数据同样也不能被稳定的打入触发器 5. 寄存器部分 这部分主要涉及I2C外设的工作状态控制,涉及几个重要的寄存器,例如控制寄存器(I2C_CR1和I2C_CR2),控制寄存器配置I2C的工作方式,例如,开启PEC、SMBus 报警使能、DMA 发送/接收请求使能、数字噪声滤波器设置、中断是能、外设使能等等,此外还有中断和状态寄存器(I2C_ISR),当外设工作时,外设的工作状态修改可以通过该寄存器的对应位来查询,关于寄存器我们后面会进行介绍。 6. 噪声滤波器 图中,模拟噪声滤波器和SDA以及SCL接口连接,默认情况下,SDA 和 SCL 输入上集成了模拟噪声滤波器,从SDA和SCL总线进入的信号先经过噪声滤波器再经过数字滤波器。该模拟滤波器符合I2C规范,此规范要求在快速模式和超快速模式下对脉宽在 50ns 以下的脉冲都要抑制。如果要使能噪声滤波器,按照要求配置I2C_CR1寄存器相应的位即可,要注意的是,使能 I2C 时(PE 位置 1),不允许更改滤波器配置。 25.2.3 主从模式和地址 I2C总线既可以作为从模式(Slave),也可以作为主模式(Master),作为主模式和从模式的配置在STM32CubeMX上是一样的,不同的是I2C设备的地址。在主模式下,有主发送器和主接收器,在从模式下,有从发送器和从接收器,I2C接口在工作时可选用这4种模式之一。 默认情况下,它以从模式工作。接口在生成起始位后会自动由从模式切换为主模式,并在出现仲裁丢失或生成停止位时从主模式切换为从模式,从而实现多主模式功能。在从模式下,该接口能够识别其自身地址(7 或 10 位)以及广播呼叫地址,广播呼叫地址检测可由软件使能或禁止。

  1. I2C主模式 I2C主模式特性:时钟生成、起始位和停止位生成。I2C 接口会启动数据传输并生成时钟信号(SCL),串行数据传输始终是在出现起始位时开始,在出现停止位时结束,起始位和停止位均在主模式下由软件生成。 使能外设前,必须通过设置 I2C_TIMINGR 寄存器中的 SCLH 和 SCLL 位来配置 I2C 主时钟。I2C 经过tSYNC1延时后检测其自身的 SCL 低电平,I2C 经过tSYNC2延时后检测其自身的 SCL 高电平,SCL主时钟周期计算方法为: tSCL = tSYNC1 + tSYNC2 + {[(SCLH+1) + (SCLL+1)] * (PRESC+1) *tI2CCLK } tSYNC1 的持续时间取决于: SCL 下降斜率、模拟滤波器(使能时)引入的输入延时、数字滤波器(使能时)引入的输入延时、SCL 与 i2c_ker_ck 时钟建立同步而产生的延时。 tSYNC2延时取决: SCL 上升沿、SCL 输入噪声滤波器(模拟 + 数字)以及 SCL 与i2c_ker_ck时钟的同步。 公式中, (SCLH+1) * (PRESC+1) *tI2CCLK表示SCL高电平周期tSCLH,(SCLL+1) * (PRESC+1) *tI2CCLK表示SCL低电平周期tSCLL,那么SCL的周期tSCL=tSCLH+tSCLL,频率为1/tSCL。SCLH和SCLL 以及PRESC的值可以通过时序寄存器 (I2C_TIMINGR)得到,知道该寄存器的值,也就能计算出SCL周期和频率的理论值。

图25.2.3.1 I2C时序图 主模式通信初始化(地址阶段)过程: 如果主机要发起通信,需要配置I2C_CR2 寄存器,为寻址的从器件配置以下参数: ①、配置ADD10位以实现寻址模式:7 位(ADD10位为0)或 10 位(ADD10位为1); ②、配置SADD[9:0]位以确定主机要发送的从地址; ③、配置RD_WRN位以确定数据传输方向:主机请求写传输(0)、主机请求读取传输(1); ④、当读取 10 位地址时,对应HEAD10R位进行相应配置; ⑤、配置NBYTES[7:0]确定待传输的字节数; ⑥、以上配置完成后,将 I2C_CR2 寄存器中的 START 位置 1生成起始位,当START 位置 1 时,以上所有位不能再更改。 ⑦、之后,当主器件检测到总线空闲时,它会在经过一定时间的延时后自动发送起始位,随后发出从器件地址。当仲裁丢失时,主器件将自动切换回从模式,如果作为从器件被寻址,还可对其自身地址进行应答。只要已在总线上发送从地址,START位便会由硬件复位。如果仲裁丢失,START位也会由硬件复位。 2. 从模式 I2C从模式特性:可编程I2C地址检测、双寻址模式,可对2个从地址应答,停止位检测,7位/10位寻址以及广播呼叫的生成和检测、支持不同的通信速度等。 如果STM32MP157要在从模式下工作,即CPU作为从机,用户必须至少使能一个从地址,主机通过该地址找到从机。从机地址可使用 I2C_OAR1 和 I2C_OAR2 这两个寄存器来编程,从设备自身的地址为 OA1 和 OA2,关于该寄存器我们后面会介绍。OA1 既可配置为7位寻址模式(默认),也可通过将 I2C_OAR1 寄存器的 OA1MODE位置 1 配置为 10 位寻址模式,如果需要额外的从地址,可配置第2个从地址 OA2,注意的是,I2C_OAR2只支持7位寻址。 这里还是再提醒,当CPU作为从机时才需要配置OA1 和 OA2,如果CPU作为主机时,就不需要配置OA1 和 OA2了,但是OA1 和 OA2的值还是存在的,只是要注意OA1 和 OA2的值不能和从设备的地址一致,不然就有冲突了,毕竟从设备的地址标识是唯一的。STM32CubeMX生成的工程中,主模式和从模式的配置一样,生成的初始化代码中OA1 和 OA2默认为0,如果需要将CPU作为从机,再手动修改OA1 和 OA2的值即可。 从模式初始化过程: ①、先将I2C_OAR1 和 I2C_OAR2的OA1EN和OA2EN清零,禁止从设备自身地址 1和2; ②、配置I2C_OAR1 和 I2C_OAR2设置寻址模式并使能使能设备自身地址 1和2; ③、将 I2C_CR1 寄存器中的 GCEN 位置 1 来使能广播呼叫地址; 3. 地址左移和右移 I2C标准的文件中介绍到,在起始位后,发送的第一个数据字节包括:从机地址和数据处理方向,字节格式为:从机地址[7:1]+读/写位(0:发送数据,1:读数据),该字节格式如下:

表25.2.3.2 I2C地址 播呼叫地址用于寻址连接到I2C上的每个器件,在从模式时,I²C接口能识别它自己的地址(7位或10位)和广播呼叫地址,通过软件能够控制开启(如果ENGC=1)或禁止广播呼叫地址的识别。下面我们来看看7位地址和10位地址。 1)7位地址 I2C协议里地址为左对齐的,即从左到右高位在前低位在后,如果I2C的从机地址是7位时,I2C读写过程中总要在后面再加1个读/写位(在最低位加,0表示写,1表示读),也就构成了8位地址,所以将这个7位地址左移1位后,最后1位就是0,表示对从机进行写操作。I2C发送地址数据时,先发送高位,再发送低位,也就是说最后才发送读写位,所以很多地方也会说第8位是读/写位。

图 25.2.3.2 7位地址 2)8位地址 一些芯片手册上可能提供的是带了读写位的8位地址模式,也就是8个位,最后一个位是0或者1(读或者写位),那么,将这8位右移1位后,就会得到这个器件的7位地址(不带读写位)

图25.2.3.3 8位地址 3)10位地址 10位寻址用的不是很多,I2C的7位地址和10位地址是兼容的,即7位地址和10位地址的设备可以同时连接到相同的I2C上。我们先来看看10位地址的格式,我们先以主发送器向从机写的过程为例子进行分析:

图25.2.3.4 10位地址写过程 第一位START是起始位,起始位后面跟着的是第一个字节的8位,即由第一个7位加上一个读/写位,第一个7位的格式是:11110 XX,X表示可以是0也可以是1,XX属于10位地址的高2位,另外的低8位位于第二个字节中,该格式的7位用来指示当前传输的是10位地址。那么,10位从机地址就是前面为XX的两位和第二个字节组合成,如上示意图。 写过程 ①、主机发送起始位,总线上的从机等待主机继续发送数据; ②、主机发送第一个字节,即第一个7位加一个写位(0),所有从机把自己的地址和这第一个字节(1111 0XX0)进行比较,此时可能有多个从机匹配然后产生第一个应答信号A1; ③、主机发送第二个字节,也就是10位地址的低8位,所有从机把自己地址的低8位和这第二个字节进行比较,这是只有一个从机可以匹配成功,该从机发出第二个应答信号A2; ④、从机发送一个8位数据DATA,已经匹配的从机保持被寻址的状态,接收接下来主机发送的数据,当接收到数据后,从机返回一个应答位A,该过程和7位地址的数据发送和接收类似,直到从机接收到主机发送的终止条件§,或者接收到重复开始信号(SR)跟着另一个8位字节。 读过程 如果主机要读数据,在第二个应答信号A2之前的过程和上面写数据的过程类似,只不过到了A2之后紧跟着的是一个起始信号(我们叫重复起始信号SR)和带读位(1)的第一个字节,匹配的从机会产生应答信号A3,并保持被寻址的状态和主机进行通信,直到从机接收到主机发送的终止条件§,或者接收到重复开始信号(SR)跟着另一个8位字节。该过程如下:

图25.2.3.5 10位地址读过程 4)单片机下的地址和Linux操作系统下设备树的地址 经过前面的分析,单片机裸机程序开发使用的地址都要带一个读/写位,如果后期学习Linux操作系统的驱动开发部分必定少不了修改设备树,在设备树中,I2C相关的配置节点中,从机地址是不带读写位的,一般用7位地址,这点大家稍微注意即可。关于Linux部分的资料,可参考《【正点原子】STM32MP1嵌入式Linux驱动开发指南》。 25.3 I2C寄存器介绍 下面我们来看I2C相关的寄存器: 25.3.1 控制寄存器 控制寄存器有控制寄存器 1 (I2C_CR1)和控制寄存器 2 (I2C_CR2),介绍如下:

  1. 控制寄存器1(I2C_CR1)

图25.3.1.1 I2C_CR1寄存器 该寄存器的位比较多,这里我们介绍一些比较重要的位: PE为外设使能位,0:禁止外设;1:使能外设。当PE=0时,I2C SCL 线和SDA 线被释放。 TXIE为发送中断使能位,0:禁止发送中断;1:使能发送中断。 RXIE为接收中断使能位,0:禁止接收中断;1:使能发送中断。 ADDRIE为从模式下地址匹配中断使能位,0:禁止地址匹配(ADDR)中断,1使能地址匹配(ADDR)中断。 STOPIE为停止位检测中断使能位,0:禁止停止位检测(STOPF)中断;1:使能停止位检测(STOPF)中断。 TCIE为传输完成中断使能位,0:禁止传输完成中断;1:使能传输完成中断。 DNF[3:0] 用于配置 SDA 和 SCL 输入端的数字噪声滤波器,0000:禁止数字滤波器,其它配置表示使能数字滤波器并配置不同宽度的可滤除的噪声尖峰脉宽。 ANFOFF表示模拟噪声滤波器使能位,0:使能模拟噪声滤波器;1:禁止模拟噪声滤波器。 TXDMAEN和RXDMAEN分别是DMA 发送请求使能和DMA 接收请求使能位,0表示禁止,1表示使能。 ALERTEN是SMBus 报警使能位,要使用SMBus 报警功能的话,将该位置1即可。 PECEN是PEC 使能位,只在支持 SMBus功能下使用,PEC 即数据包错误校验机制。 2. 控制寄存器 2(I2C_CR2)

图25.3.1.2 I2C_CR2寄存器 SADD0为主模式下的从设备地址位0,只在10位寻址模式下有意义,在10位寻址模式下,该位是待发送从地址的第 0 位。 SADD[7:1]为主模式下从设备地址的7~1位,不管是7位寻址还是10位寻址下,这些位为待发送从地址的第 1 到第 7 位。 SADD[9:8]为主模式下从设备地址的第 8 到第 9 位,只针对10位寻址模式有效。 RD_WRN是传输方向位,也就是读/写位,0:主器件请求写传输;1:主器件请求读传输。注意的是,当发送起始位(START=1)时不能再更改此位; ADD10是主模式下寻址模式选择位,0:主器件工作在 7 位寻址模式下;1:主器件工作在 10 位寻址模式下。同样的,当发送起始位(START=1)时不能再更改此位; START是主模式下起始位生成,向该位写入0无效,读取该位时,0:不生成起始位;1:生成重复起始/起始位。如果要软件清除此位,向 I2C_ICR 寄存器中的 ADDRCF位写入1即可。 STOP是主模式下停止位生成,该位由软件置 1,并可在检测到停止位时或 PE = 0 时由硬件清零,向该位写入0 不起作用。读取该位时,0:不生成停止位;1:在当前字节传输完成后生成停止位。 NACK是从模式下应答和非应答信号生成位,向该位写入“ 0 ”不起作用,此位由软件置 1。当接收到停止位或匹配地址时、在发送 NACK 时或者 PE=0 ,该位硬件清零。读取该位时,0:在当前接收的字节后发送 应答信号ACK,1:在当前接收的字节后发送 非应答信号NACK NBYTES[7:0]用于设置待发送/接收的字节数。 25.3.2 设备自身地址寄存器 设备自身地址寄存器有设备自身地1寄存器(I2C_OAR1)和设备自身地址2寄存器 (I2C_OAR2),这两个地址是STM32在从模式下时需要设置的,在主模式下可以设置或者不设置这两个寄存器,即当CPU做主机时不需要设置,做从机时就要设置,所设置的地址就是CPU作为从机时的地址。注意的是,CPU在主模式下时,这两个地址不能与从机地址相同,否则会引起冲突,毕竟从机地址是唯一的,主机要通过从机的这个唯一的标识来找到要通信的从设备。 此外,如果使用STM32CubeMX进行配置生成初始化代码,不管STM32的CPU是做为从机还是主机时,在STM32CubeMX上的配置步骤都一样,最后生成的初始化代码也是一样的,默认I2C_OAR1和I2C_OAR2寄存器的OA1以及OA2都是0,那如果要将CPU做为从机,手动修改OA1和OA2即可,要是CPU做为从机,可以不用管,毕竟从设备地址不是0。

  1. 设备自身地址1寄存器(I2C_OAR1)

图25.3.2.1 I2C_OAR1寄存器 OA1[9:0]:在从模式下,即STM32的CPU作为从机时的地址1(主机是其它设备,也可以是另外一块STM32),这里分为两种情况: 当为7位寻址模式时,OA1 [7:1]就是STM32作为从机时的地址1,此时OA1 [9]、OA1 [8]和OA1 [0]位没有用到;当为10位寻址模式时,OA1[9:0]就是STM32作为从机时的10位地址1。 OA1MODE:用于配置是7位地址模式还是10位地址模式。当该位为0时,表示STM32作为从机时的地址1为7位模式,当该位为0时,表示STM32作为从机时的地址1为10位模式. OA1EN:用于是否使能STM32作为从机时的地址1,该位为0表示禁用STM32的地址1,该位为1表示启用STM32的地址1。 以上是STM32作为从机时STM32的地址1,下面我们看看STM32作为从机时,它的地址2: 2. 设备自身地址2寄存器(I2C_OAR2) I2C_OAR2只是在7位地址模式下使用,该寄存器各位如下:

图25.3.2.2 I2C_OAR2寄存器 OA2 [7:1]是STM32作为从机时,STM32的地址2,为7位,且仅当OA2EN = 0时才能写入这些位。改寄存器第0位属于保留位。 OA2MSK [2:0]位是设置STM32作为从机时,STM32自身的地址2的哪个位被屏蔽,被屏蔽的位就变成无关位,没有被屏蔽的位就可以用于寻址比较。这些位仅在OA2EN=0时可写入,这些位配置如下: 000:无屏蔽,7个地址都会进行比较; 001:OA2[1] 被屏蔽,为无关位,仅比较 OA2[7:2]; 010:OA2[2:1] 被屏蔽,为无关位,仅比较 OA2[7:3]; 011:OA2[3:1] 被屏蔽,为无关位,仅比较 OA2[7:4]; … 111:OA2[7:1] 被屏蔽,为无关位。不进行比较,对接收到的全部 7 位地址(保留位除外) 应答。 OA2EN是STM32作为从机时,STM32的地址2使能位,该位为0时,禁止STM32的地址2,为1时,使能STM32的地址2。 25.3.3 时序寄存器 时序寄存器I2C_TIMINGR如果要手动配置的话比较麻烦,这里推荐大家使用STM32CubeMX来配置,在I2C配置项处可以自动生成需要的Timing值,即I2C_TIMINGR的值。

图25.3.3.1 I2C_TIMINGR寄存器 SCLL[7:0]:是主模式下SCL 低电平周期,tSCLL = (SCLL+1) * tPRESC; SCLH[7:0]:是主模式下SCL 高电平周期,tSCLH = (SCLH+1) * tPRESC; 最终,主时钟SCL的周期是tSCLL+ tSCLH=[ (SCLL+1)+ (SCLH+1)] * tPRESC。 SDADEL[3:0]:是数据保持时间配置位,数据保持时间tSDADEL = SDADEL * tPRESC; SCLDEL[3:0]是数据建立时间配置位,数据建立时间tSCLDEL = (SCLDEL+1) * tPRESC; PRESC[3:0]是时序预分频因子配置位,该字段用于对 i2c_ker_ck 进行预分频,以生成用于数据建立和保持计数器以及 SCL 高电平和低电平计数器可用的时钟周期 tPRESC。时钟周期: tPRESC = (PRESC+1) x tI2CCLK 25.3.4 中断和状态寄存器 读取I2C_ISR寄存器的对应位可以知道此时的中断和I2C工作状态,在I2C设备工作时,外设的工作状态会被写入I2C_ISR寄存器中,我们来看看这些位:

图25.3.4.1 I2C_ISR寄存器 该寄存器对应位很多,我们这里就不一一介绍了,这里会介绍部分位: TXE为发送数据寄存器为空时的标志位。I2C_TXDR 寄存器为空时,该位由硬件置 1。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。该位可由软件写入“1”,以刷新发送数据寄存器 I2C_TXDR。 TXIS是发送中断状态标志位,当 I2C_TXDR 寄存器为空时,该位由硬件置 1,待发送的数据必须写入 I2C_TXDR 寄存器。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。 RXNE是接收数据寄存器不为空标志位,当接收到的数据已复制到 I2C_RXDR 寄存器且准备就绪可供读取时,该位由硬件置 1。读取I2C_RXDR 时,将清零该位。 ADDR是地址匹配(从模式)标志位,地址匹配(从模式)。 NACKF是接收到应答标志位,传输完字节后接收到 NACK 时,该标志由硬件置 1。该标志由软件清零,方法是将 NACKCF位置 1。 STOPF是停止位检测标志位,当在总线上检测到停止位,且外设也参与本次传输时,该标志由硬件置 1。 TC是传输完成(主模式)标志位,当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 START位或 STOP 位置 1 时,该标志由软件清零 。 ALERT是SMBus 报警标志位,仅在支持 SMBus 功能时有效。当 SMBHEN=1(SMBus 主机配置)、ALERTEN=1 且在 SMBA 引脚上检测到 SMBALERT 事件(下降沿)时,该标志由硬件置 1,该位为1时则报警,为0时不报警。 BUSY是总线繁忙标志,忙时该位为1,不忙时该位为0。该标志用于指示总线上正在进行通信。当检测到起始位时,该位由硬件置 1。当检测到停止位或 PE = 0 时,该位由硬件清零。 DIR是传输方向(从模式)标志位,该位为0:写传输,从器件进入接收器模式;1:读传输,从器件进入发送器模式。 ADDCODE[6:0]是地址匹配代码(从模式)时标志位,发生地址匹配事件时 (ADDR = 1),这些位更新为接收到的地址。 25.3.5 中断清零寄存器 如果要清除中断标志位,对中断清零寄存器(I2C_ICR)的对应位中写入1即可清除,该寄存器属于只写寄存器,我们来看看该寄存器:

图25.3.5.1 I2C_ICR寄存器 如下表是该寄存器的相关位描述:

表25.3.5.1 I2C_ICR寄存器的位描述 25.3.6 PEC 寄存器 PEC寄存器的低8位PEC[7:0]用于保存数据包错误校验值,改寄存器只读,读取该位即可得到数据包错误校验值。

图 25.3.6.1 I2C_PECR寄存器 25.3.7 接收数据寄存器和发送数据寄存器

  1. 接收数据寄存器 (I2C_RXDR) I2C_RXDR的低8位RXDATA[7:0]存储从I2C总线接收的数据字节,读取该位即可得到设备接收到的数据。

图25.3.7.1 I2C_RXDR寄存器 2. 发送数据寄存器 (I2C_TXDR) I2C_TXDR寄存器的低8位TXDATA[7:0]保存的是待发送到I2C总线的数据字节,可将要发送的数据写入TXDATA[7:0]中,注意的是,仅当TXE=1时才可以写入这些位。

图25.3.7.2 I2C_TXDR寄存器 25.4 I2C的HAL库驱动 I2C相关的API函数在stm32mp1xx_hal_i2c.c和stm32mp1xx_hal_i2c.h文件中。本小节我们介绍和本实验相关的API函数。 25.4.1 结构体和句柄

  1. I2C_InitTypeDef I2C_InitTypeDef结构体在stm32mp1xx_hal_i2c.h文件中有定义,用于初始化I2C,我们来看看此函数:
typedef struct
{ 
        
  uint32_t Timing;            /* 指定I2C_TIMINGR寄存器的值 */
  uint32_t OwnAddress1;      /* 指定从设备自己的地址1,此参数可以是7位或10位地址 */
  uint32_t AddressingMode;   /* 指定地址的长度模式是选择7位还是10位寻址模式 */
  uint32_t DualAddressMode; /* 指定是否选择双地址模式 */
  uint32_t OwnAddress2;      /* 若使用双地址模式,指定从设备自己的地址2,此地址只能是7位 */
  uint32_t OwnAddress2Masks; /* 如果使用双地址模式,确认I2C_OAR2的OA2MSK[2:0]位的值 */
  uint32_t GeneralCallMode; /* 指定广播呼叫模式 */
  uint32_t NoStretchMode;   /* 指定禁止时钟延长模式 */
} I2C_InitTypeDef;      
Timing的值就是时序寄存器I2C_TIMINGR的值,通过该值可以计算出数据保持时间、数据建立时间、时序预分频值、主时钟SCL的周期,关于这些参数的计算可以参考前面寄存器介绍部分。
OwnAddress1是STM32作为从设备时的地址1,实际上就是I2C_OAR1寄存器的OA1[9:0]指,可配置为7位或10位地址模式。如果使用双地址模式,那么还需要配置I2C_OAR2寄存器,OA2 [7:1]位的值就是STM32作为从机时的地址2,即以上结构体中OwnAddress2的值。如果STM32作为主机,以上OwnAddress1和OwnAddress2可以不配置,但要确定其值不能和从设备的地址相同。关于这些注意事项我们前面都有介绍。
  1. I2C_HandleTypeDef I2C_HandleTypeDef 句柄定义如下:
typedef struct __I2C_HandleTypeDef
{ 
        
  I2C_TypeDef                 *Instance;        /* I2C寄存器的基地址 */
  I2C_InitTypeDef             Init;             /* I2C通讯参数 */
  uint8_t                      *pBuffPtr;        /* 指向I2C发送缓冲区的指针 */
  uint16_t                      XferSize;        /* I2C传输数据的大小 */
  __IO uint16_t                XferCount;       /* I2C发送数据的个数 */
  __IO uint32_t                XferOptions;    /* I2C定量转移选项 */
  __IO uint32_t                PreviousState;  /* I2C通讯先前状态 */
  HAL_StatusTypeDef(*XferISR)(struct __I2C_HandleTypeDef *hi2c, uint32_t ITFlags,\ 					uint32_t ITSources);     /* I2C传输IRQ处理程序函数指针 */
  DMA_HandleTypeDef           *hdmatx;          /* I2C Tx DMA句柄参数 */
  DMA_HandleTypeDef           *hdmarx;          /* I2C Tx DMA句柄参数 */
#ifdef HAL_MDMA_MODULE_ENABLED
  MDMA_HandleTypeDef         *hmdmatx;         /* I2C Tx MDMA句柄参数 */
  MDMA_HandleTypeDef         *hmdmarx;         /* I2C Rx MDMA句柄参数 */
#endif
  HAL_LockTypeDef              Lock;             /* I2C定对象 */
  __IO HAL_I2C_StateTypeDef  State;            /* I2C通讯状态 */
  __IO HAL_I2C_ModeTypeDef   Mode;             /* I2C通讯模式 */
  __IO uint32_t                ErrorCode;        /* I2C错误代码 */
  __IO uint32_t                AddrEventCount;  /* I2C地址事件计数器 */
} I2C_HandleTypeDef;         
此句柄内容有很多,我们先关注几个重要的:

(1)Instance I2C_TypeDef结构体在stm32mp157dxx_cm4.h头文件中有声明,声明的Instance指针变量指向I2C寄存器基地址,通过此变量即可操作对应的结构体成员(寄存器)。 (2)Init I2C_InitTypeDef结构体前面我们已经介绍了,此处声明I2C_InitTypeDef结构体变量Init,可以通过Init来设置I2C的Timing值以及地址等信息。 (3)pBuffPtr、XferSize、XferCount pBuffPtr、XferSize、XferCount分别是指向I2C发送缓冲区的指针、I2C传输数据的大小、I2C发送数据的个数 (4)PreviousState PreviousState表示I2C外围设备的状态,如主发送器忙I2C_STATE_MASTER_BUSY_TX、主接收器忙I2C_STATE_MASTER_BUSY_RX、从发送器忙I2C_STATE_SLAVE_BUSY_TX、从接收器忙I2C_STATE_SLAVE_BUSY_RX等。 (5)Lock Lock是对资源操作增加操作锁保护功能,可选HAL_UNLOCKED或者HAL_LOCKED两个参数。如果State的值等于HAL_I2C_STATE_RESET,则可认为I2C未被初始化,此时,将Lock标记为HAL_UNLOCKED,并且调用HAL_I2C_MspInit函数来对I2C的GPIO和时钟进行初始化。 (6)State State 是HAL_I2C_StateTypeDef结构体变量,HAL_I2C_StateTypeDef结构体定义如下:

typedef enum
{ 
        
  HAL_I2C_STATE_RESET            = 0x00U,  /* 外围设备没有初始化 */
  HAL_I2C_STATE_READY            = 0x20U,  /* 外围设备已经初始化且可以使用 */
  HAL_I2C_STATE_BUSY             = 0x24U,  /* 内部流程正在进行中 */
  HAL_I2C_STATE_BUSY_TX          = 0x21U,  /* 数据在发送 */
  HAL_I2C_STATE_BUSY_RX          = 0x22U,  /* 数据在接收 */
  HAL_I2C_STATE_LISTEN            = 0x28U,  /* 地址监听模式正在进行中 */
  HAL_I2C_STATE_BUSY_TX_LISTEN   = 0x29U, /* 地址监听模式和数据在发送 */
  HAL_I2C_STATE_BUSY_RX_LISTEN   = 0x2AU, /* 地址监听模式和数据在接收 */
  HAL_I2C_STATE_ABORT              = 0x60U,  /* 正在中止用户请求 */
  HAL_I2C_STATE_TIMEOUT            = 0xA0U,  /* 超时状态 */
  HAL_I2C_STATE_ERROR              = 0xE0U   /* 错误 */
} HAL_I2C_StateTypeDef;  
通过读取State可知道当前I2C的状态。

(7)Mode Mode 用于配置I2C设备的工作模式,HAL_I2C_ModeTypeDef结构体如下:

typedef enum
{ 
        
  HAL_I2C_MODE_NONE               = 0x00U,   /* 没有I2C通讯在进行 */
  HAL_I2C_MODE_MASTER             = 0x10U,   /* I2C通讯在主模式下 */
  HAL_I2C_MODE_SLAVE              = 0x20U,   /* I2C通讯在从模式下 */
  HAL_I2C_MODE_MEM                = 0x40U    /* I2C通信处于内存模式 */
} HAL_I2C_ModeTypeDef;       
以上模式中,我们比较常见的是从模式和主模式。

25.4.2 HAL库的API函数 HAL库的API函数在stm32mp1xx_hal_i2c.c文件中有定义,涉及的函数有很多。I2C的通讯模式可以分为阻塞模式和非阻塞模式,阻塞模式下,通信以轮询模式进行,非阻塞模式下,可以使用中断或DMA进行。当使用中断模式时,将通过专用的I2C IRQ指示数据处理的结束;当使用DMA模式时,将通过DMA IRQ指示数据处理的结束。 阻塞模式功能常用的API函数有:

HAL_I2C_Master_Transmit	在主模式下传输大量数据
HAL_I2C_Master_Receive	在主模式下接收大量数据
HAL_I2C_Slave_Transmit	在从属模式下传输大量数据
HAL_I2C_Slave_Receive	在从属模式下接收大量数据
HAL_I2C_Mem_Write	将大量数据写入特定内存地址
HAL_I2C_Mem_Read	从特定的内存地址读取大量数据
HAL_I2C_IsDeviceReady	检查目标设备是否已准备好进行通信

表25.4.2.1 I2C阻塞模式相关API函数 非塞模式(中断方式)功能常用的API函数有:

HAL_I2C_Master_Transmit_IT	在主模式下以中断方式传输大量数据
HAL_I2C_Master_Receive_IT	在主模式下通过中断接收大量数据
HAL_I2C_Slave_Transmit_IT	在从模式下以中断发送大量数据
HAL_I2C_Slave_Receive_IT	在从模式下以中断接收大量数据
HAL_I2C_Mem_Write_IT	以中断方式将大量数据写入特定的内存地址
HAL_I2C_Mem_Read_IT	以中断方式从特定的内存地址读取大量数据
HAL_I2C_EnableListen_IT	以中断方式启用地址侦听模式
HAL_I2C_DisableListen_IT	以中断方式禁用地址侦听模式
HAL_I2C_Master_Abort_IT	以中断方式终止I2C通信。

表25.4.2.2 I2C中断方式相关API函数 非塞模式(DMA方式)功能常用的API函数有:

HAL_I2C_Master_Transmit_DMA	以DMA方式以主模式发送大量数据
HAL_I2C_Master_Receive_DMA	以DMA方式以主模式接收大量数据
HAL_I2C_Slave_Transmit_DMA	以DMA方式在从模式下传输大量数据
HAL_I2C_Slave_Receive_DMA	以DMA方式在从属模式下接收大量数据
HAL_I2C_Mem_Write_DMA	以DMA方式将大量数据写入特定内存地址
HAL_I2C_Mem_Read_DMA	以DMA方式从存储器地址读取大量数据。

表25.4.2.3 I2CDMA方式相关API函数 非塞模式下的一些回调函数:

HAL_I2C_MasterTxCpltCallback	主发送传输完成回调函数
HAL_I2C_MasterRxCpltCallback	主接收完成回调函数
HAL_I2C_SlaveTxCpltCallback	从发送完成回调函数
HAL_I2C_SlaveRxCpltCallback	从接收完成回调函数
HAL_I2C_MemTxCpltCallback	内存发送传输完成回调函数
HAL_I2C_MemRxCpltCallback	内存接收传输完成回调函数
HAL_I2C_AddrCallback	从地址匹配回调函数
HAL_I2C_ListenCpltCallback	监听完成回调函数
HAL_I2C_ErrorCallback	I2C通信过程错误回调函数
HAL_I2C_AbortCpltCallback	I2C停止回调函数

表25.4.2.4 回调函数 上函数中,我们这里仅介绍和本实验有关的函数以及一些常用的函数,其它函数大家想了解的可以直接通过stm32mp1xx_hal_i2c.c文件查询。

  1. HAL_I2C_Master_Transmit函数 函数声明如下: HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, \ uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout) 函数描述: 用于主模式下以阻塞模式传输大量数据(写数据)。 函数形参: hi2c :I2C指针,指明使用哪个I2C,如的是I2C1还是I2C2等; DevAddress :目标器件地址,即要发送数据的从机地址(从机也可以是一个寄存器); pData :指向要写入数据缓冲区的指针,存放的是要发送的数据,注意大小为8位; Size :要发送的数据大小,单位为字节: Timeout :超时时间,如果在给定时间没收到ACK则超时退出写入。 函数返回值: HAL状态,HAL_StatusTypeDef枚举类型的值。
  2. HAL_I2C_Mem_Write 函数声明如下: HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t \ DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData,\ uint16_t Size, uint32_t Timeout) 函数描述: 将大量数据写入特定内存地址。 函数形参: hi2c :I2C指针,指明使用哪个I2C; DevAddress :目标器件地址,即要发送数据的从机地址,(从机也可以是一个寄存器); MemAddress :要写入的内存地址,也就是从从机的某个内存地址开始写入,即寄存器地址,每写入一个字节数据,地址就会自动+1。注意的是,这里内存地址的位数可以8位或者16位,16位地址会调用I2C_MEM_ADD_MSB(MemAddress),8位地址会调用I2C_MEM_ADD_LSB(MemAddress)。 MemAddSize:内存地址的位数,是8位还是16位,0表示8bit地址,1表示16bit地址; 这里是一个16位数据,是准备写入寄存器的数据的大小; pData :指向要写入数据缓冲区的指针,存放的是要发送的数据,注意大小为8位; Size :准备写入的数据大小,单位为字节: Timeout :超时时间,如果在给定时间没收到ACK则超时退出写入。 函数返回值: HAL状态,HAL_StatusTypeDef枚举类型的值。 注意事项: 对比HAL_I2C_Master_Transmit函数,HAL_I2C_Mem_Write函数多了两个参数MemAddress和MemAddSize,HAL_I2C_Mem_Write函数可以写I2C设备寄存器的某个地址。
  3. HAL_I2C_Slave_Transmit HAL_I2C_Slave_Transmit函数声明如下: HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData,\ uint16_t Size, uint32_t Timeout) 函数描述: 用于在从模式下以阻塞模式传输大量数据。 函数形参: hi2c :I2C指针,指明使用哪个I2C,如的是I2C1还是I2C2等; pData :指向要写入数据缓冲区的指针,存放的是要发送的数据,注意大小为8位; Size :要发送的数据大小,单位为字节: Timeout :超时时间,如果在给定时间没收到ACK则超时退出写入。 函数返回值: HAL状态,HAL_StatusTypeDef枚举类型的值。
  4. HAL_I2C_Master_Receive HAL_I2C_Master_Receive函数声明如下: HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, \ uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout) 函数描述: 用于在主模式下以阻塞模式接收大量数据(读数据)。 函数形参: hi2c :I2C指针,指明使用哪个I2C,如的是I2C1还是I2C2等; DevAddress :目标器件地址,即要读取数据的从机地址; pData :读到的数据存放的位置; Size :要读取的数据大小: Timeout :超时时间,如果在给定时间没收到ACK则超时退出读取。 函数返回值: HAL状态,HAL_StatusTypeDef枚举类型的值。
  5. HAL_I2C_Slave_Receive HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData,\ uint16_t Size, uint32_t Timeout) 函数描述: 用于在从模式下以阻塞模式接收大量数据。 函数形参: hi2c :I2C指针,指明使用哪个I2C,如的是I2C1还是I2C2等; pData :读到的数据存放的位置; Size :要读取的数据大小: Timeout :超时时间,如果在给定时间没收到ACK则超时退出读取。 函数返回值: HAL状态,HAL_StatusTypeDef枚举类型的值。 25.5 AP3216C简介 25.5.1 AP3216C特点 正点原子的STM32MP157开发板的I2C5接了一个三合一环境传感器:AP3216C。 AP3216C是由敦南科技推出的一款芯片,该芯片集成了光强传感器(ALS)、接近传感器(PS)和红外LED(IR LED),其支持近距离感应(ps)、光照强度(als)和红外线强度(IR)这3个环境参数检测。AP3216C 常被用于手机、平板、导航设备等,其内置的接近传感器可以用于检测是否有物体接近,比如在手机上可用来检测耳朵是否接触听筒,如果检测到耳机接近听筒的话就表示正在打电话,手机就会关闭屏幕,避免用户误触屏幕。环境光传感器可以用于检测光照强度,例如可以实现手机自动背光亮度调节。 AP3216C采用I2C通讯方式,并且提供了硬件中断的可选功能,其特点如下: ①、I2C 接口,快速模式下速度可达400k Hz; ②、多种工作模式可选择:ALS、PS+IR、ALS+PS+IR、PD 等等。 ③、内建温度补偿电路。 ④、宽工作温度范围(-30°C ~ +80°C)。 ⑤、超小封装,4.1mm x 2.4mm x 1.35mm ⑥、环境光传感器具有 16 位分辨率。 ⑦、接近传感器和红外传感器具有 10 位分辨率。 AP3216C 结构如下图所示:

图25.5.1.1 AP3216C结构 AP3216C的芯片手册位于开发板光盘A-基础资料\6、硬件资料\1、芯片资料\《AP3216C》。 25.5.2 AP3216C设备地址和寄存器

  1. AP3216C设备地址 一般芯片厂家都会在芯片手册中提供I2C设备的地址,我们也可以在AP3216C中查询该地址,如下:

图25.5.2.1 AP3216C的设备地址 AP3216C的从设备地址为0X1E,有7位,不带读/写位,二进制为 001 1110,裸机程序中要带读写位,带读位的地址为:0x3D,写地址为0x3C。我们使用STM32相AP3216C写数据,直接使用地址0x3C。 2. AP3216C存器地址 AP3216C寄存器,通过配置这些寄存器我们可以设置AP3216C的工作模式,并读取相应的数据,下面我们来了解AP3216C的寄存器,如下表所示:

表25.5.2.1 AP3216C相关寄存器 发生ALS或PS或(ALS + PS)中断事件时,INT引脚将被设置为低电平并设置INT状态位,用户在读取寄存器0xD(ALS)时可以清除INT位和单个状态位。 1)控制寄存器 0X00是模式控制寄存器的地址,用于打开/关闭设备电源以及设置 AP3216C 的工作模式,一般设置步骤为: ①、先将其设置该寄存器为 0X04,即先软件复位一次 AP3216C; ②、接下来根据实际使用情况选择合适的工作模式,比如设置为 0X03,也就是开启 ALS+PS+IR。 此外,要注意的是,AP3216C芯片手册有提到软件复位时,设备的所有寄存器将在10毫秒后变为默认值,所以在复位的这10ms时间内,不要对AP3216C执行任何命令,所以我们在程序设计的时候,复位后尽量要延时10ms以上的时间以后再对AP3216C进行读写操作。 2)中断状态寄存器 地址为0x01和0x02的两个寄存器和中断有关,本节实验我们不涉及中断。如果地址0x01的位0为1,表示发生ALS中断,如果为0,表示ALS中断已经被清除或者未发生ALS中断;如果地址0x01的位1为1,表示发生PS中断,如果为0,表示PS中断已经被清除或者未发生PS中断;复位后,这两位默认为0。 3)中断清除寄存器 0X02这个地址对应的寄存器用于清除中断标志位的,将1写入位0则清除ALS中断,将1写入位1则清除PS中断。 4)数据寄存器 连续的地址为0X0A~0X0F 的这6个寄存器就是数据寄存器,保存着 ALS、PS 和 IR 这三个传感器获取到的数据值,读取这些寄存器就可以得到传感器采集到的数据,这里注意,AP3216C芯片手册有提到:ALS的典型转换时间为100ms、IR的典型转换时间为12.5ms,所以如果同时打开ALS+IR+PS的话,读取数据时,两次数据读取的时间间隔要大于112.5ms,所以在程序设计时,记住此时间不能小于112.5ms:

图25.5.2.2 数据寄存器的转换时间 此外要注意,读取数据寄存器的值时: 如果读取寄存器0X0A的最高位(位7)得到1时,说明IR和PS 的数据无效,否则有效; 如果读取寄存器0X0E的第6位得到1时,说明IR和PS 数据无效,否则有效。 以上在程序设计时一定要注意。经过I2C以及AP3216C工作模式的了解,下面我们使用I2C5来对AP3216C进行控制。 25.5.3. AP3216C数据传输时序 如要对AP3216C进行操作,我们先了解AP3216C的通信时序。如下图是AP3216C的读写时序图,其中: S是主机发送的起始信号位,Sr是主机发送的重复起始信号位;Slave address是AP3216C的设备地址,不带读写位就共7位;Register address是AP3216C的寄存器的地址,共8位;Register Comand是要写到AP3216C的寄存器的值;W是写信号位(0),R是读信号位(1);P是停止信号位。这里,STM32MP157主控是主机,AP3216C是从机。

  1. 写时序 如下图所示,主机先发送起始位,然后发送AP3216C的设备地址+写信号,这个是主机发送的第一个字节;当主机收到AP3216C的应答信号后,主机再发送要操作的AP3216的寄存器地址,这是主机发送的第二个字节;当主机第二次收到AP3216C的应答信号后,接着再发送要写入寄存器里的值,这是主机发送的第三个字节;当收到AP3216的应答信号后,主机发送停止信号停止传输。

图25.5.3.1 写时序 2. 读时序 如下图,AP3216C的读时序比较特殊,它是先写再读。主机发送起始位,然后发送AP3216C的设备地址,由于是写操作,所以设备地址后再跟1个写位(0),这个是主机发送的第一个字节;当主机收到AP3216C的应答信号后,主机发送第二个字节:AP3216C的寄存器地址;主机接收到AP3216返回的应答信号后,接着先发送一个重复起始位,然后再发送AP3216的从机地址外加一个读位(1),这是第三个字节;当主机接收到AP3216C的应答信号后,就发送要写到AP3216C的寄存器的数值,这是第四个字节;最后主机发送非应答位和停止位,读取操作停止。

图25.5.3.2 读时序 25.6 硬件I2C通信实验 本实验配置好的实验工程已经放到了开发板光盘中,路径为:开发板光盘A-基础资料\1、程序源码\11、M4 CubeIDE裸机驱动例程\CubeIDE_project\ 18-1 I2C_Hardware。 25.6.1 硬件设计

  1. 例程功能 STM32MP157开发板的I2C5上接了AP3216C,我们将STM32MP157作为主设备,AP3216C作为从设备,读取AP3216C采集到的ALS+IR+PS值,并将这3个值通过串口打印出来。AP3216C在开发板底板的位置如下:

图25.6 3.1开发板硬件示意图 程序下载后,通过用手靠近或者遮挡AP3216C,即可得到变化的值。 2. 硬件资源 1)LED灯:LED0 2)UART4 3)I2C5 4)AP3216C LED0 AP3216C I2C5_SCL I2C5_SDA UART4_TX UART4_RX PI0 接在I2C5上 PA11 PA12 PG11 PB2 表25.6 2.1硬件资源 3. 原理图 如下图,AP3216C的时钟引脚和数据引脚分别接在I2C5_SCL和I2C5_SDA上:

图25.6.1.2原理图部分 25.6.2 软件设计

  1. 新建和配置工程 (1)新建工程和配置时钟 新建工程名为I2C_Hardware,并配置时钟源为HSE,MCU时钟为209MHz,APB1的时钟为104.5MHz,I2C5挂在APB1上,同时,我们配置APB1的时钟来自PCLK1(即APB1),即I2C5的时钟频率为104.5MHz:

图25.6.2.1 I2C5时钟源选择 (2)配置I2C5 本实验还会用到LED0和串口,关于这两个外设的配置我们就不再重复讲解了。下面我们讲解配置I2C5部分。配置I2C5的两个引脚PA11和PA12,为开漏输出、上拉模式,如下:

图25.6.2.2 I2C5引脚的配置 找到I2C5配置项,按步骤配置如下:

图25.6.2.3 I2C5参数配置 在步骤3中,可以选: I2C:使用的I2C进行通信,这里我们要选I2C; SMBus-Alert-mode:SMBus警报模式; SMBus-two-wire-Interface:SMBus两线接口,即使用SMBus进行通信,前面我们分析过,SMBus其实和I2C是很相似的,也是两根总线。 在步骤4中,我们要手动配置I2C的参数,实际上不管STM32是处于从模式下还是主模式下,这些参数配置都是一样的,我们解释一下

标签: 5接近传感器电路板用接近传感器推挽式传感器3p2261接近传感器ps4稳定传感器bsp62三极管

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台