STM32硬件IIC驱动设计

前言

stm32的硬件IIC一直是令人诟病的地方,以至于很多情况下我们不得不选择使用模拟IIC的方式来在stm32上进行iic通讯。我在stm32 iic通讯上也浪费了几多青春。。。经过不断地探索最终还是成功了(可喜可贺啊),现在把我的探索成功的经验分享出来,如果能减少读者在硬件iic上面浪费的时间,那真是太棒了!
我把驱动的一些描述做成了表格如下:

问题 描述
MCU型号 STM32F407VET6
库函数 标准外设库
操作系统 FreeRTOS

关于IIC通讯

众所周知IIC是一种通讯方式。。。所以有必要先介绍一下IIC通信,省的下面不知道不知道我在写什么。当然这些都是基础,你可以选择跳过,直接看第三部分STM32的IIC

IIC是什么

说实话这个问题有点难,我就百度了一下,描述如下

IIC 即Inter-Integrated Circuit(集成电路总线),这种总线类型是由飞利浦半导体公司在八十年代初设计出来的一种简单、双向、二线制、同步串行总线,主要是用来连接整体电路(ICS) ,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。这种方式简化了信号传输总线接口。

通过这几句描述我发现——我更加不知道它是什么了。不过至少我看到一个关键字——二线制,那就表明IIC需要两根线进行通讯(不算电源和地),那么就先看一下iic硬件接口吧,这是我唯一可以看到的东西。

接口1 接口2
SCL SDA

从名称可以看出这两个接口SCL为clock即时钟线,SDA为date即数据线。就是通过这两根线进行iic通信,相当精简的硬件连接!但是就我所知越是精简的硬件接口其软件越复杂。比如并行通信的话我们的软件直接读高低电平就好了。。。建议不懂什么是并行通信的人直接百度之,当然这并不是重点。我们的重点是串行通信,而串行通信的理论支撑是其内在的通信协议,当然iic也是个有协议的人。。。那么接下来就该我们的主角出场了——IIC协议,

IIC协议

说起协议我不知道你想到了什么,于是百度之:协议:共同计议,协商。其实就是人为规定了一种通讯规则,不过这个规则是给机器执行的。所以不要让协议两个字吓到。下面是两个基本的规则:

  • 1、只要求两条总线线路 一条串行数据线 SDA 一条串行时钟线 SCL
  • 2、每个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机关系软件设定地址;主机可以作为主发送器或主机接收器

其中第一条我们已经知道了,第二条是说iic通信需要主机和从机,至于什么是主机什么是从机,一般情况下比如我使用stm32读取MPU6050那么stm32就是主机,mpu6050就是从机。还有一点iic可以支持一主多从的模式,这也就表示如果我们有多个从机设备如我既想读取MPU6050,又想读取HMC5883数据(这两个都支持iic通信)我们不需要为这两个设备分别引出两个iic接口,只需要把stm32、mpu6050、hmc5883三者的SCL和SDA引脚对应连接起来即可。那么问题来了:主机是怎么知道现在在跟哪个从机通信?其实这个问题很白痴。如果换个问题类比一下,把主机想象成一个老地主,他手下有N个奴仆(从机),地主是怎么知道现在他在跟谁说话?当然是通过名字啊。于是每个iic设备就被人为规定了“名字”,我们称为地址。如MPU6050的地址为0x68(在AD0引脚为低电平情况下)。
iic的协议还是很多的,这里就不一一列举了,新手的话知道这两个就好了。如果这些内容理解起来没毛病的话就该进入iic时序这个环节了。

IIC通信时序

时序即电平变化的顺序,对于iic来说即SCL和SDA两根线上的电平变化顺序。对于IIC其信号主要有一下几个
开始信号、结束信号和应答/非应答信号。这就像上面的地主和奴仆例子里的,地主要命令仆役工作要有开始的信号,命令结束工作也要有停止信号,地主还要根据仆役的反馈来判断仆役是否能完成任务,如果仆役回答能够完成工作就是应答信号,若回答无法完成工作就是非应答信号。对于iic其规定了这几种信号的电平变化时序如下:

开始和结束信号

起始和终止信号

开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。
结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。

应答/非应答 信号

应答信号

应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。

对时序的总结如下:

  • 1、IIC通信进行数据传输时,时钟信号为高电平期间数据线信号必须保持稳定,只有时钟信号为低电平时才允许数据信号变化。

  • 2、SCL高电平期间,SDA由高电平变为低电平则代表起始信号,SDA由低电平变为高电平时代表停止信号。

  • 3、起始信号和停止信号都是由主机发起,当有起始信号发出后总线处于占用状态,当停止信号被发出后总线处于空闲状态。

当我们了解到这几种时序的原理后便可以通过操作两个IO的高低电平来实现IIC通信了,这就是常说的模拟IIC的方式。以上这些知识只需要知道原理即可,如果真要写一个模拟iic的程序你还需要精确的时序,比如起始信号SDA脉冲持续的最短时间,其变为低电平后SCL至少需要保持高电平时间等等问题,所以你需要一个比较精确的微秒级延时函数。。。但这一切并不是今天我们的重点。我们的重点是STM32的硬件IIC驱动设计。

STM32的IIC

STM32的IIC还是很强大的,只是很多功能我们根本用不上。如下是数据手册的里关于IIC的描述:

I 2 C(内部集成电路)总线接口用作微控制器和 I 2 C 串行总线之间的接口。它提供多主模式功
能,可以控制所有 I 2 C 总线特定的序列、协议、仲裁和时序。它支持标准和快速模式。它还
与 SMBus 2.0 兼容。
它可以用于多种用途,包括 CRC 生成和验证、SMBus(系统管理总线)以及 PMBus(电源
管理总线)。
根据器件的不同,可利用 DMA 功能来减轻 CPU 的工作量。

我设计驱动的目的是通过STM32读取MPU6050所以该驱动的特性是stm32作为主机而不是从机,所以想了解关于从机部分的就不用往下看了。其次由于stm32的IIC支持DMA的并且我的stm32大部分时间是在读取传感器数据。所以该驱动设计时把IIC接收部分设计为DMA接收,而发送部分没有使用DMA。关于是否使用中断,我的回答是一定要用中断,排除STM32采用查询方式各种堵死在while(1)里的囧状,使用中断还可以提升系统的性能,while(xxx);查询是要占据一定的时间的啊。所以果断采取中断处理的方式,只是stm32的中断情况比较多。所以。。。我们需要冷静地缕一缕。以下是数据手册时间。有该宝典的同学一定要珍惜啊,特别是中文版的,很好很强大。

stm32硬件IIC通信流程

首先stm32的iic分四种模式:从发送器、从接收器、主发送器、主接收器。而上面我们也提到了只用到了主机模式,所以我们只关注主发送器、主接收器两种模式。
在主模式下,I 2 C 接口会启动数据传输并生成时钟信号。串行数据传输始终是在出现起始位时开始,在出现停止位时结束。起始位和停止位均在主模式下由软件生成
数据和地址均以 8 位字节传输,MSB 在前。起始位后紧随地址字节(7 位地址占据一个字节;10 位地址占据两个字节)。地址始终在主模式下传送。
其设计框图如下
stm32 IIC设计框图

这幅图列出了所有关于iic的寄存器,而我们真正用到最多的也就是两个控制寄存器CR1和CR2,两个状态寄存器SR1、SR2。
以下是我对这四个寄存器进行的总结性描述:

  • CR1:主要是控制IIC的一些信号生成(起始和结束信号等)以及是否使能IIC的某些特定功能,如应答使能是、数据校验使能等。
  • CR2主要控制一些IIC中断或者DMA是否开启以及配置IIC的通讯速率。因为此次设计的驱动中需要用到iic中断,所以需要了解下iic的中断。如下表:
中断名称 描述
ITBUF 缓冲中断
ITEVT 事件中断
ITERR 错误中断

在这里不细讲,下面会有介绍。只需要知道这些中断的开启都需要配置CR2相应位。

  • SR1和SR2里面的内容就比较杂了,不过好多功能我们用不到,只需要知道这两个寄存器存储了很多标识,如是否发送了起始位,应答失败?等状态,在程序里会有体现。

具体内容还是要参考数据手册里关于iic寄存器的描述,当然这部分也不需要记住,因为我们要调用库函数来实现很多的功能。

接下来分析stm32的iic通讯流程,我们主要分析在主模式下如何发送以及通过DMA方式接收数据。

1、主模式下发送数据:

  • 1、生成起始信号:CR1里的START 位置 1 后,接口会在 SR2的BUSY 位清零后生成一个起始位并切换到主模式。生成起始信号成功后SR1的SB 位会由硬件置 1 ,如果使能了事件中断(CR2的 ITEVFEN 位置 1 )则生成一个中断。这个中断在数据手册里官方命名为EV5。即为事件5中断。至于为什么从5开始,因为事件1到4在从机部分用了。。。接下来主设备会等待软件对 SR1 执行读操作,然后把从设备地址写入 DR 寄存器。只有这样才能清零SR1的SB位。

  • 2、从地址传输,接下来从地址会通过内部移位寄存器发送到 SDA 线。stm32支持10位和7位地址。因为大多数我们接触到的都是7位地址的,所以这里只介绍7位地址位的。在 7 位寻址模式下,会发送一个地址字节。地址字节被发出后,SR1的ADDR 位会由硬件置 1 如果使能了事件中断(CR2的 ITEVFEN 位置 1 )则生成一个中断EV6。接下来主设备会等待对 SR1 寄存器执行读操作,然后对 SR2 寄存器执行读操作,只有这样才能清零SR1的ADDR 位。

  • 3、主发送器,在发送出地址并将 ADDR 清零后,主设备会通过内部移位寄存器将 DR 寄存器中的字节发送到 SDA 线。在向数据寄存器写数据前如果开启了事件中断会进入中断EV8,接收到应答脉冲后,TxE 位会由硬件置 1 并在 ITEVFEN 和 ITBUFEN 位均置 1 时生成一个中断EV8。如果在上一次数据传输结束之前 TxE 位已置 1 但数据字节尚未写入 DR 寄存器,则 BTF 位会置 1,而接口会一直延长 SCL 低电平,等待I2C_DR 寄存器被写入,以将 BTF 清零。结束通信当最后一个字节写入 DR 寄存器后,软件会将 STOP 位置 1 以生成一个停止位EV8_2。接口会自动返回从模式(M/SL 位清零)。

  • 结束通信:主设备会针对自从设备接收的最后一个字节发送 NACK。在接收到此 NACK 之后,从设备会释放对 SCL 和 SDA 线的控制。随后,主设备可发送一个停止位/重复起始位。

    1. 为了在最后一个接收数据字节后生成非应答脉冲,必须在读取倒数第二个数据字节后(倒数第二个 RxNE 事件之后)立即将 ACK 位清零。
    2. 要生成停止位/重复起始位,软件必须在读取倒数第二个数据字节后(倒数第二个 RxNE事件之后)将 STOP/START 位置 1。
    3. 在只接收单个字节的情况下,会在 EV6 期间(在 ADDR 标志清零之前)禁止应答并在EV6 之后生成停止位。
    4. 生成停止位后,接口会自动返回从模式(M/SL 位清零)。

以上是stm32的iic主发送模式通信流程,俗话说一图顶千字,数据手册把这个流程以图表展现出来如下:

这里写图片描述

还是比较清楚的,只需要对照该图结合上面的文字描述来分析stm32的iic通信流程。

2、使用 DMA 进行接收

将 I2C_CR2 寄存器中的 DMAEN 位置 1 可以使能 DMA 模式进行接收。接收数据字节时,数据会从 I2C_DR 寄存器加载到使用 DMA 外设配置的存储区中(参见 DMA 规范)。要映射一个 DMA 通道以便进行 I 2 C 接收,请按以下步骤操作:其中的 x 表示通道编号。
1. 设置 DMA_CPARx 寄存器中的 I2C_DR 寄存器地址。每次发生 RxNE 事件后,数据都会从此地址移动到存储器。
2. 设置 DMA_CMARx 寄存器中的存储器地址。每次发生 RXNE 事件后,数据都会从 I2C_DR寄存器加载到此存储区。
3. 在 MA_CNDTRx 寄存器中配置要传输的总字节数。在每次 RxNE 事件后,此值都会递减。
4. 使用 DMA_CCRx 寄存器中的 PL[0:1] 位来配置通道优先级。
5. 在完成半数传输或全部传输(取决于应用的需求)之后,将 DMA_CCRx 寄存器中的 DIR位重新置 1 并配置中断。
6. 将 DMA_CCRx 寄存器中的 EN 位置 1 以激活通道。
当传输的数据量达到 DMA 控制器中编程设定的值时,DMA 控制器会发送一个结束传输EOT/EOT_1 信号给 I 2 C 接口,而 DMA 会在 DMA 通道中断向量上生成一个中断(如果已使能):
注意: 如果使用 DMA 进行接收,请勿使能 I2C_CR2 寄存器中的 ITBUFEN 位。

IIC驱动设计

终于到了最重要的环节,(鼓掌)。在这里我们需要坐下来静静地分析一下该怎样设计这个驱动。设计驱动的目的是尽量使得调用者方便调用。所以应该尽量封装一些不常更改的变量和方法,如在这里就忽略了stm32作为从机,并且默认是使能中断的。暴露给调用者经常要变更的变量和方法,如对于stm32经常要根据实际情况更改使用的iic外设编号ÿ

  • 64
    点赞
  • 246
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值