STM32F429IIC通信协议介绍
I2C 通讯协议(Inter-Integrated Circuit)是由Phiilps 公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要USART、CAN 等通讯协议的外部收发设备,现在被广泛地使用在系统内多个集成电路(IC)间的通讯。
1.物理层连接
I2C 通讯设备之间的常用连接方式见下图
它的物理层有如下特点:
(1) 它是一个支持多设备的总线。“总线”指多个设备共用的信号线。在一个I2C 通讯总
线中,可连接多个I2C 通讯设备,支持多个通讯主机及多个通讯从机。
(2) 一个I2C 总线只使用两条总线线路,一条双向串行数据线(SDA) ,一条串行时钟线
(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。
(3) 每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之
间的访问。
(4) 总线通过上拉电阻接到电源。当I2C 设备空闲时,会输出高阻态,而当所有设备都空
闲,都输出高阻态时,由上拉电阻把总线拉成高电平。
(5) 多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用
总线。
(6) 具有三种传输模式:标准模式传输速率为100kbit/s ,快速模式为400kbit/s ,高速模式
下可达 3.4Mbit/s,但目前大多I2C 设备尚不支持高速模式。
(7) 连接到相同总线的 IC 数量受到总线的最大电容 400pF 限制 。
2.协议层
I2C 的协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地
址广播等环节。
主机写数据到从机
主机由从机中读数据
I2C 通讯复合格式
斜杠部分,数据由主机传输至从机 S : 传输开始信号
SLAVE_ADDRESS: 从机地址
空白部分,数据由从机传输至主机 R/W: 传输方向选择位,1 为读,0 为写
A/A: 应答(ACK)或非应答(NACK)信号
这些图表示的是主机和从机通讯时,SDA 线的数据包序列。
其中S 表示由主机的I2C 接口产生的传输起始信号(S),这时连接到I2C 总线上的所有
从机都会接收到这个信号。
起始信号产生后,所有从机就开始等待主机紧接下来广播 的从机地址信号
(SLAVE_ADDRESS)。在I2C 总线上,每个设备的地址都是唯一的,当主机广播的地址与
某个设备地址相同时,这个设备就被选中了,没被选中的设备将会忽略之后的数据信号。
根据I2C 协议,这个从机地址可以是7 位或10 位。
在地址位之后,是传输方向的选择位,该位为0 时,表示后面的数据传输方向是由主
机传输至从机,即主机向从机写数据。该位为1 时,则相反,即主机由从机读数据。
从机接收到匹配的地址后,主机或从机会返回一个应答(ACK)或非应答(NACK)信号,
只有接收到应答信号后,主机才能继续发送或接收数据。
若配置的方向传输位为“写数据”方向,即第一幅图的情况,广播完地址,接收到应
答信号后,主机开始正式向从机传输数据(DATA),数据包的大小为8 位,主机每发送完一
个字节数据,都要等待从机的应答信号(ACK),重复这个过程,可以向从机传输N 个数
据,这个N 没有大小限制。当数据传输结束时,主机向从机发送一个停止传输信号§,表
示不再传输数据。
若配置的方向传输位为“读数据”方向,即第二幅图的情况,广播完地址,接收到应
答信号后,从机开始向主机返回数据(DATA),数据包大小也为8 位,从机每发送完一个数
据,都会等待主机的应答信号(ACK),重复这个过程,可以返回N 个数据,这个N 也没有
大小限制。当主机希望停止接收数据时,就向从机返回一个非应答信号(NACK),则从机自
动停止数据传输。
除了基本的读写,I2C 通讯更常用的是复合格式,即第三幅图的情况,该传输过程有
两次起始信号(S)。一般在第一次传输中,主机通过 SLAVE_ADDRESS 寻找到从设备后,
发送一段“数据”,这段数据通常用于表示从设备内部的寄存器或存储器地址(注意区分它
与SLAVE_ADDRESS 的区别);在第二次的传输中,对该地址的内容进行读或写。也就是
说,第一次通讯是告诉从机读写地址,第二次则是读写的实际内容。
通讯的起始和停止信号
前文中提到的起始(S)和停止§信号是两种特殊的状态,见下图。当 SCL 线是高电
平时 SDA 线从高电平向低电平切换,这个情况表示通讯的起始。当 SCL 是高电平时 SDA
线由低电平向高电平切换,表示通讯的停止。起始和停止信号一般由主机产生。
数据有效性
I2C 使用SDA 信号线来传输数据,使用SCL 信号线进行数据同步。见下图。SDA
数据线在SCL 的每个时钟周期传输一位数据。传输时,SCL 为高电平的时候SDA 表示的
数据有效,即此时的SDA 为高电平时表示数据“1”,为低电平时表示数据“0”。当SCL
为低电平时,SDA 的数据无效,一般在这个时候SDA 进行电平切换,为下一次表示数据
做好准备。每次数据传输都以字节为单位,每次传输的字节数不受限制。
地址及数据方向
I2C 总线上的每个设备都有自己的独立地址,主机发起通讯时,通过SDA 信号线发送
设备地址(SLAVE_ADDRESS)来查找从机。I2C 协议规定设备地址可以是7 位或10 位,实
际中7 位的地址应用比较广泛。紧跟设备地址的一个数据位用来表示数据传输方向,它是
数据方向位(R/W
——
),第8 位或第11 位。数据方向位为“1”时表示主机由从机读数据,该
位为“0”时表示主机向从机写数据。
读数据方向时,主机会释放对SDA 信号线的控制,由从机控制SDA 信号线,主机接
收信号,写数据方向时,SDA 由主机控制,从机接收信号。
响应
I2C 的数据和地址传输都带响应。响应包括“应答(ACK)”和“非应答(NACK)”两种
信号。作为数据接收端时,当设备(无论主从机)接收到I2C 传输的一个字节数据或地址
后,若希望对方继续发送数据,则需要向对方发送“应答(ACK)”信号,发送方会继续发
送下一个数据;若接收端希望结束数据传输,则向对方发送“非应答(NACK)”信号,发送
方接收到该信号后会产生一个停止信号,结束信号传输。
传输时主机产生时钟,在第9 个时钟时,数据发送端会释放SDA 的控制权,由数据接
收端控制SDA,若SDA 为高电平,表示非应答信号(NACK),低电平表示应答信号
(ACK)。
STM32 的I2C 特性及架构
如果我们直接控制STM32 的两个GPIO 引脚,分别用作SCL 及SDA,按照上述信号
的时序要求,直接像控制LED 灯那样控制引脚的输出(若是接收数据时则读取SDA 电平),
就可以实现I2C 通讯。同样,假如我们按照USART 的要求去控制引脚,也能实现USART通讯。所以只要遵守协议,就是标准的通讯,不管您如何实现它,不管是ST 生产的控制
器还是ATMEL 生产的存储器, 都能按通讯标准交互。
由于直接控制GPIO 引脚电平产生通讯时序时,需要由CPU 控制每个时刻的引脚状
态,所以称之为“软件模拟协议”方式。
相对地,还有“硬件协议”方式,STM32 的I2C 片上外设专门负责实现I2C 通讯协
议,只要配置好该外设,它就会自动根据协议要求产生通讯信号,收发数据并缓存起来,
CPU 只要检测该外设的状态和访问数据寄存器,就能完成数据收发。这种由硬件外设处理
I2C 协议的方式减轻了CPU 的工作,且使软件设计更加简单。
STM32 的I2C 外设简介
STM32 的I2C 外设可用作通讯的主机及从机,支持100Kbit/s 和400Kbit/s 的速率,支
持7 位、10 位设备地址,支持DMA 数据传输,并具有数据校验功能。它的I2C 外设还支
持SMBus2.0 协议,SMBus 协议与I2C 类似,主要应用于笔记本电脑的电池管理中,本教
程不展开,感兴趣的读者可参考《SMBus20》文档了解。
通讯引脚
I2C 的所有硬件架构都是根据图中左侧SCL 线和SDA 线展开的(其中的SMBA 线用于
SMBUS 的警告信号,I2C 通讯没有使用)。STM32 芯片有多个I2C 外设,它们的I2C 通讯信
号引出到不同的GPIO 引脚上,使用时必须配置到这些指定的引脚,见表 23-1。关于GPIO
引脚的复用功能,可查阅《STM32F4xx 规格书》,以它为准。
STM32F4xx 的I2C 引脚(整理自《STM32F4xx 规格书》)
引脚
I2C号
I2C1 I2C2 I2C3
SCL PB6/PB10 PH4/PF1/PB10 PH7/PA8
SDA PB7/PB9 PH5/PF0/PB11 PH8/PC9
时钟控制逻辑
SCL 线的时钟信号,由I2C 接口根据时钟控制寄存器(CCR)控制,控制的参数主要为时
钟频率。配置I2C 的CCR 寄存器可修改通讯速率相关的参数:
可选择I2C 通讯的“标准/快速”模式,这两个模式分别I2C 对应100/400Kbit/s 的
通讯速率。
在快速模式下可选择SCL时钟的占空比,可选Tlow/Thigh=2 或Tlow/Thigh=16/9 模式,
我们知道I2C 协议在SCL 高电平时对SDA 信号采样,SCL 低电平时SDA 准备下
一个数据,修改SCL 的高低电平比会影响数据采样,但其实这两个模式的比例差
别并不大,若不是要求非常严格,这里随便选就可以了。
CCR 寄存器中还有一个12 位的配置因子CCR,它与I2C 外设的输入时钟源共同
作用,产生SCL 时钟,STM32 的I2C 外设都挂载在APB1 总线上,使用APB1 的
时钟源PCLK1,SCL 信号线的输出时钟公式如下:
标准模式:
Thigh=CCRTPCKL1 Tlow = CCRTPCLK1
快速模式中Tlow/Thigh=2 时:
Thigh = CCRTPCKL1 Tlow = 2CCRTPCKL1
快速模式中Tlow/Thigh=16/9 时:
Thigh = 9CCRTPCKL1 Tlow = 16CCRTPCKL1
例如,我们的PCLK1=45MHz,想要配置400Kbit/s 的速率,计算方式如下:
PCLK 时钟周期: TPCLK1 = 1/45000000
目标SCL 时钟周期: TSCL = 1/400000
SCL 时钟周期内的高电平时间: THIGH = TSCL/3
SCL 时钟周期内的低电平时间: TLOW = 2TSCL/3
计算CCR 的值: CCR = THIGH/TPCLK1 = 37.5
计算结果为小数,而CCR 寄存器是无法配置小数参数的,所以我们只能把CCR 取值
为38,这样I2C 的SCL 实际频率无法达到400KHz (约为394736Hz)。要想它实际频率达到
400KHz,需要修改STM32 的系统时钟,把PCLK1 时钟频率改成10 的倍数才可以,但修
改PCKL 时钟影响很多外设,所以一般我们不会修改它。SCL 的实际频率不达到
400KHz,除了通讯稍慢一点以外,不会对I2C 的标准通讯造成其它影响
数据控制逻辑
I2C 的SDA 信号主要连接到数据移位寄存器上,数据移位寄存器的数据来源及目标是
数据寄存器(DR)、地址寄存器(OAR)、PEC 寄存器以及SDA 数据线。当向外发送数据的时候,数据移位寄存器以“数据寄存器”为数据源,把数据一位一位地通过SDA 信号线发送出去;当从外部接收数据的时候,数据移位寄存器把SDA 信号线采样到的数据一位一位地存储到“数据寄存器”中。若使能了数据校验,接收到的数据会经过PCE 计算器运算,运算结果存储在“PEC 寄存器”中。当STM32 的I2C 工作在从机模式的时候,接收到设备地址信号时,数据移位寄存器会把接收到的地址与STM32 的自身的“I2C 地址寄存器”的值作比较,以便响应主机的寻址。STM32 的自身I2C 地址可通过修改“自身地址寄存器”修改,支持同时使用两个I2C 设备地址,两个地址分别存储在OAR1 和OAR2 中。
整体控制逻辑
整体控制逻辑负责协调整个I2C 外设,控制逻辑的工作模式根据我们配置的“控制寄存器(CR1/CR2)”的参数而改变。在外设工作时,控制逻辑会根据外设的工作状态修改“状态寄存器(SR1 和SR2)”,我们只要读取这些寄存器相关的寄存器位,就可以了解I2C的工作状态了。除此之外,控制逻辑还根据要求,负责控制产生I2C 中断信号、DMA 请求及各种I2C 的通讯信号(起始、停止、响应信号等)。
通讯过程
使用I2C 外设通讯时,在通讯的不同阶段它会对“状态寄存器(SR1 及SR2)”的不同数
据位写入参数,我们通过读取这些寄存器标志来了解通讯状态。
I2C 初始化结构体详解
跟其它外设一样,STM32 标准库提供了I2C 初始化结构体及初始化函数来配置I2C 外
设。初始化结构体及函数定义在库文件“stm32f4xx_i2c.h”及“stm32f4xx_i2c.c”中,编程
时我们可以结合这两个文件内的注释使用或参考库帮助文档。了解初始化结构体后我们就
能对I2C 外设运用自如了
初始化结构体
1 typedef struct {
2 uint32_t I2C_ClockSpeed; /!< 设置 SCL 时钟频率,此值要低于 40 0000/
3 uint16_t I2C_Mode; /*!< 指定工作模式,可选 I2C 模式及 SMBUS 模式 /
4 uint16_t I2C_DutyCycle; /指定时钟占空比,可选 low/high = 2:1 及 16:9 模式/
5 uint16_t I2C_OwnAddress1; /!< 指定自身的 I2C 设备地址 /
6 uint16_t I2C_Ack; /!< 使能或关闭响应(一般都要使能) /
7 uint16_t I2C_AcknowledgedAddress; /!< 指定地址的长度,可为 7 位及 10 位 */
8 } I2C_InitTypeDef;
这些结构体成员说明如下,其中括号内的文字是对应参数在STM32 标准库中定义的
宏:
(1) I2C_ClockSpeed
本成员设置的是I2C 的传输速率,在调用初始化函数时,函数会根据我们输入的数值经过运算后把时钟因子写入到I2C 的时钟控制寄存器CCR。而我们写入的这个参数值不得高于400KHz。实际上由于CCR 寄存器不能写入小数类型的时钟因子,影响到SCL 的实际频率可能会低于本成员设置的参数值,这时除了通讯稍慢一点以外,不会对I2C 的标准通讯造成其它影响。
(2) I2C_Mode
本成员是选择I2C 的使用方式,有I2C 模式(I2C_Mode_I2C )和SMBus 主、从模式(I2C_Mode_SMBusHost、 I2C_Mode_SMBusDevice ) 。I2C 不需要在此处区分主从模式,直接设置I2C_Mode_I2C 即可。
(3) I2C_DutyCycle
本成员设置的是I2C 的SCL 线时钟的占空比。该配置有两个选择,分别为低电平时间
比高电平时间为2:1 ( I2C_DutyCycle_2)和16:9 (I2C_DutyCycle_16_9)。其实这两个模式
的比例差别并不大,一般要求都不会如此严格,这里随便选就可以了。
(4) I2C_OwnAddress1
本成员配置的是STM32 的I2C 设备自己的地址,每个连接到I2C 总线上的设备都要有
一个自己的地址,作为主机也不例外。地址可设置为7 位或10 位(受下面
I2C_AcknowledgeAddress 成员决定),只要该地址是I2C 总线上唯一的即可。
STM32 的I2C 外设可同时使用两个地址,即同时对两个地址作出响应,这个结构成员
I2C_OwnAddress1 配置的是默认的、OAR1 寄存器存储的地址,若需要设置第二个地址寄
存器OAR2,可使用I2C_OwnAddress2Config 函数来配置,OAR2 不支持10 位地址。
(5) I2C_Ack_Enable
本成员是关于I2C 应答设置,设置为使能则可以发送响应信号。该成员值一般配置为
允许应答(I2C_Ack_Enable),这是绝大多数遵循I2C 标准的设备的通讯要求,改为禁止应答
(I2C_Ack_Disable)往往会导致通讯错误。
(6) I2C_AcknowledgeAddress
本成员选择I2C 的寻址模式是7 位还是10 位地址。这需要根据实际连接到I2C 总线上
设备的地址进行选择,这个成员的配置也影响到I2C_OwnAddress1 成员,只有这里设置成
10 位模式时,I2C_OwnAddress1 才支持10 位地址。
配置完这些结构体成员值,调用库函数I2C_Init 即可把结构体的配置写入到寄存器
中。