stm32之SPI通信外设

embedded/2024/10/18 19:23:59/

系列文章目录

1. stm32SPI通信协议
2. stm32之软件SPI读写W25Q64存储器应用案例


文章目录

  • 系列文章目录
  • 前言
  • 一、SPI通信外设
    • 1.1 SPI外设简介
    • 1.2 SPI外设特性
    • 1.3 软件模拟和硬件实现的区别
  • 二、SPI外设电路结构
    • 2.1 SPI框图
    • 2.2 SPI基本结构
  • 三、SPI外设时序
    • 3.1 主模式全双工连续传输
    • 3.2 主模式全双工非连续传输


前言

提示:本文主要用作在学习江科大自化协STM32入门教程后做的归纳总结笔记,旨在学习记录,如有侵权请联系作者

本文主要探讨stm32SPI通信外设的相关概念以及基本结构等,最后详细地分析了SPI外设的时序,为进一步学习SPI通信打下基础。


一、SPI通信外设

1.1 SPI外设简介

STM32微控制器集成了硬件SPI(Serial Peripheral Interface,串行外设接口)模块,用于实现高速、低引脚数的同步数据传输。SPI外设通过主从结构进行通信,广泛应用于传感器、存储器、显示屏、通信设备等外设的连接。STM32的SPI模块具有丰富的功能特性,能有效减轻CPU负担并提高系统性能。

1.2 SPI外设特性

以下表格总结了STM32微控制器硬件SPI模块的一些主要特性:

功能特性说明
数据帧格式支持8位或16位可配置的数据帧,允许用户根据应用需求选择。
数据传输的位序可以设置为高位先行(MSB First)或低位先行(LSB First)。
时钟控制SPI时钟由PCLK(外设时钟)通过分频器生成,分频范围为 fPCLK / (2, 4, 8, 16, 32, 64, 128, 256)
多主机支持STM32的SPI硬件模块支持多主机(Multi-Master)通信模式,允许在总线上有多个主机。
用户可以配置SPI模块为主机或从机(Master/Slave)工作模式以适应各种网络通信拓扑。
通信模式全双工模式:数据同时在MOSI和MISO线上进行传输,双向通信。
半双工模式:数据可以双向传输,但同一时刻只能进行一个方向的数据传输。
单工模式:数据仅单向传输,适用于需要精简引脚或通信的场景。
DMA支持支持DMA(直接存储器访问),可在大数据量传输中使用DMA,提高传输效率,减少CPU干预。
I2S协议兼容兼容I2S(Inter-IC Sound)音频协议,可用于音频数据传输,如音频解码和音频流传输。
SPI资源(STM32F103C8T6)SPI1(APB2):连接高速外设或高优先级外设。
SPI2(APB1):用于较低优先级的通信任务。

注意:SPI和I2C一般都是采用高位先行的策略,而串口采用的则是低位先行的策略。

1.3 软件模拟和硬件实现的区别

比较维度软件模拟SPI硬件实现SPI
工作原理使用GPIO(通用输入输出口)通过软件控制数据传输时序和逻辑。使用STM32内置的硬件SPI模块进行数据传输,由硬件自动生成时钟、数据收发。
处理器负载高,数据传输需要CPU轮询和手动控制,处理数据传输期间占用大量CPU时间。低,数据传输由硬件自动执行,减少了CPU的负担,尤其是结合DMA使用时。
传输速度慢,速度受限于处理器的执行速度、GPIO切换速度和软件代码的优化程度。快,传输速率可由硬件时钟控制,能够实现高达几十Mbps的高速传输。
实现复杂度较高,需手动编写数据传输、时序控制等代码,实现较为复杂,容易出现时序问题。简单,配置相关寄存器即可,由硬件处理复杂时序和通信细节。
灵活性高,传输逻辑可以根据需求灵活修改,不受限于硬件的约束。较低,虽然可以配置一些参数(如时钟频率、数据帧格式等),但受硬件约束较大。
时序精度精度较差,时序由软件控制,易受中断、任务调度等影响,精确时序难以保证。精度高,硬件产生的时钟信号时序稳定,能够保证精确的时钟和数据同步。
资源占用使用GPIO口,不占用硬件SPI资源,但会占用大量CPU时间和其他中断资源。占用硬件SPI外设资源,但不会占用CPU大量时间,支持DMA进一步减少CPU干预。
多任务处理能力较弱,模拟SPI时CPU需要参与数据传输,难以在传输过程中处理其他任务。较强,数据传输由硬件控制,CPU可处理其他任务,尤其在使用DMA时效率更高。
时钟频率控制软件实现,难以精确控制时钟频率,通常较低。硬件控制,时钟频率可以精确设定,支持多种时钟分频选项,最高可达fPCLK/2。
应用场景适合简单的、对速度要求不高且不使用专用SPI硬件的场景,或仅有少量数据需要传输的应用。适合对速度、精度要求较高的场景,如高速数据传输、大数据量的通信或需要保持精确时序的应用。

简而言之就是,硬件SPI适用于更复杂且高速的通信场景,而软件模拟SPI在灵活性和资源占用上有一定优势。

二、SPI外设电路结构

2.1 SPI框图

在这里插入图片描述

从整体框架来看我们大致可以把它分成两部分,左上角这部分就是数据寄存器和移位寄存器打配合的过程,主要是为了实现连续的数据流,然后右下角这部分就是一些控制的逻辑电路。

在这里插入图片描述

我们先来看一下左上角这部分电路,这一块电路是比较重要的,它是SPI通信的核心部分,体现了发送和接收的执行流程,也是我们写程序的依据,所以需要重点掌握。

在这里插入图片描述

首先是左上角的核心部分,移位寄存器。首先,移位寄存器右边数据的低位,一位一位地从MOSI依次移出去,然后MISO的数据,一位一位地从移位寄存器左边数据的高位依次移入。移位寄存器右下角有个LSBFIRST的控制位,这一位可以控制是低位先行还是高位先行,SPI一般设置为高位先行。然后移位寄存器左边这里有个方框,里面把MOSI和MISO做了个交叉,这一块主要是用来进行主从模式引脚切换的,我们这个SPI外设既可以做主机,也可以做从机。

接下来,上下两个缓冲区。这两个缓冲区实际上就是数据寄存器DR,下面发送缓冲区就是发送数据寄存器TDR,上面接收缓冲区就是接收数据寄存器RDR,TDR和RDR占用同一个地址,统一叫作DR。

数据寄存器和移位寄存器打配合可以实现连续的数据流,具体的流程是,比如我们需要连续发送一批数据。

首先,第一个数据写入到TDR,当移位寄存器没有数据移位时,TDR的数据会立刻转入到移位寄存器,开始移位。这个转入的时刻会置状态寄存器的TXE为1表示发送寄存器为空,当我们检查TXE置1后紧跟着下一个数据就可以提前写入到TDR里候着了。一旦上一个数据发完,下一个数据就可以立即跟进实现不间断的连续传输。然后移位寄存器这里,一旦有数据过来了它就会自动产生时钟将数据移出去。

在移出的过程中,MISO的数据也会移入,一旦数据移出完成,数据移入是不是也完成了?这时,移入的数据就会整体地从移位寄存器转入到接收缓冲器RDR,这个时刻会置状态寄存器的RXNE为1表示接收寄存器非空。当我们检查RXNE置1后,就要尽快把数据从RDR中读出来,在下一个数据到来之前读出RDR就可以实现连续接收,否则,如果下一个数据已经收到了,上一个数据还没从RDR读出来,那RDR的数据就会被覆盖不能实现连续的数据流了。

这就是移位寄存器配合数据寄存器实现连续数据流的过程。简而言之就是,发送数据先写入TDR再转到移位寄存器发送,发送的同时接收数据,接收到的数据转到RDR,我们再从RDR读出数据。

接下来我们看一下右下角这部分电路,这部分的电路主要是一些控制逻辑。

在这里插入图片描述

首先是波特率发生器,这个主要是用来产生SCK时钟的。它的内部主要就是一个分频器,输入时钟是PCLK 72MHz或者36MHz,经过分频器之后输出到SCK引脚。当然这里生成的时钟肯定是和移位寄存器同步的了,每产生一个周期的时钟移入移出一个Bit。

然后右边SPI_CR1控制寄存器,CR1的三个位BR0、BR1、BR2用来控制分频系数。根据手册可知,这里 BR[2:0] 是波特率控制,这三位写入下面这些值可以对PCLK时钟执行2~256的分频,分频之后就是SCK时钟了。

在这里插入图片描述

接着剩下的这些通信电路和各种寄存器都是一些黑盒子电路,如果你要具体研究可以看一下这些位的寄存器描述,在这里我们只挑几个重点的来讲一下。

先来看一下SPI_CR1控制寄存器。比如,LSBFIRST,这一位可以控制是低位先行还是高位先行。SPE(SPI Enable),SPI使能,就是SPI_Cmd函数配置的位。BR(Baud Rate),配置波特率,就是SCK时钟频率。MSTR(Master),配置主从模式。CPOL和CPHA,选择SPI的4种交换字节模式。

在这里插入图片描述

再来看一下SPI_CR2控制寄存器。TXE,发送寄存器空。RXNE,接收寄存器非空。这两个比较重要,我们发送和接收的时候需要关注这两位。

在这里插入图片描述

最后,左下角还有个NSS引脚,总的来说这个NSS我们并不会用到,SS引脚,我们直接用一个GPIO模拟就行了。

2.2 SPI基本结构

接下来我们来看一下这个简化的SPI基本结构吧,显然这是一个SPI主机的基本结构简化图,这里就简单介绍一下吧。

在这里插入图片描述
首先是移位寄存器这里,数据从左边最高位移出去,通过GPIO口到达MOSI输出,之后,移入的数据从MISO进来,通过GPIO到达移位寄存器的右边最低位移入,如此循环8次完成主机和从机一个字节的交换。

然后TDR和RDR的配合,可以实现连续的数据流。另外,TDR数据整体转入移位寄存器的时刻置TXE标志位,移位寄存器数据整体转入RDR的时刻置RXNE标志位。

波特率发生器,产生时钟输出到SCK引脚。数据控制器,可以看成一个管理员,它控制着所有电路的运行。最后,开关控制,就是SPI_Cmd,使能SPI外设。

注意:这里并没有画SS从机选择引脚,这个引脚我们直接使用普通的GPIO模拟即可,在一主多从的模型下,GPIO模拟的SS是最佳选择。

三、SPI外设时序

SPI通信中,主模式全双工通信允许主设备与从设备在MOSI和MISO线上同时进行数据的发送和接收。在全双工模式下,根据时钟的时序,可以有两种不同的传输流程:连续传输和非连续传输。

3.1 主模式全双工连续传输

在这里插入图片描述
可以看出,这个例子使用的是SPI的模式3并且数据位传输的方式是低位先行的:
CPOL=1:空闲状态时,SCK为高电平
CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据

首先有些标志位要清楚,TXE=1表示为发送数据寄存器空,RXNE=1表示为接收数据寄存器非空。

从整体上来看,上面这部分演示的是输出的流程和现象,然后下面这部分演示的是输入的流程和现象。

在这里插入图片描述

首先,SS置低电平,开始时序。在刚开始时TXE为1表示TDR为空,可以写入数据开始传输。

我们先来分析一下发送部分的时序。

首先,软件写入0XF1至SPI_DR,同时TXE置为0表示TDR已经有数据了。那由于TDR是缓冲区而移位寄存器才是真正的发送区(移位寄存器刚开始肯定是没有数据的),所以在缓冲区TDR里的0xF1就会立刻被转入到移位寄存器里进行发送并产生发送数据时序波形。当0xF1被整体移入移位寄存器之后TXE被置为1表示发送数据寄存器为空,可以写入第二个数据了。为了保证数据的不间断性,检测到TXE为1后我们就要把第二个数据0xF2写入到TDR里等着了,然后TXE被置为0表示发送数据寄存器非空,然后主机发送完数据1后再将数据2转入到移位寄存器里继续发送并产生时序波形,数据3的操作同理,这就是发送的流程。

在这里插入图片描述

我们再来分析一下接收部分的时序。

SPI是全双工的通信方式,发送的同时还有接收,所以可以看到在发送完一个字节之后,接收一个字节的时序也完成了。接收到的数据1是0xA1,这时移位寄存器的数据整体转入RDR,转入的同时RXNE的标志位置为1表示收到数据了,此时我们就可以读出第一个数据了。读完第一个数据之后,RXNE置为0,然后又转入数据2,然后EXNE置为1,然后再读取第二个数据,数据3同理。

在这里插入图片描述
总结一下步骤就是:

写入0xF1至SPI_DR -> 等待TXE为1 -> 写入0xF2至SPI_DR -> 等待RXNE为1 -> 从SPI_DR中读出0xA1 -> 等待TXE为1 -> 写入0xF3至SPI_DR -> 等待RXNE为1 -> 从SPI_DR中读出0xA2 -> 等待RXNE为1 -> 从SPI_DR中读出0xA3

注意:当发送时SPI_DR为TDR,接收时SPI_DR为RDR,他们共用同一个DR数据寄存器的地址

这个连续数据流对软件的配合要求比较高,发送与接收数据直接没有什么空隙,传输的效率比较高,如果你对这个传输效率要求比较高的话可以选用这种方式,但是一般情况下我们更倾向于接下来要讲的这个,非连续传输方式。

3.2 主模式全双工非连续传输

在这里插入图片描述
非连续传输对于程序设计非常友好,只需要4行代码就可以完成,接下来让我们继续分析一下这个主模式全双工的非连续传输时序,这里只画出了发送部分的时序图。

首先,这个配置还是SPI模式3,一开始SCK默认为高电平。

当我们想要发送数据时,当检测到TXE标志位为1也就是TDR发送数据寄存器为空,这时就可以写入第一个数据0xF1至SPI_DR。这时TDR的值变为0xF1,TXE被置为0。由于移位寄存器为空,所以这个0xF1的数据会立刻被转入到移位寄存器进行发送并产生发送时序波形,同时TXE被置为1表示发送寄存器为空。此时本来是可以继续写入第二个数据的,但是这里先不写,软件先等待RXNE标志位为1进行数据1的读取。那么在发送完数据1的同时软件也接收到了第一个数据,此时RXNE被置为1表示RDR非空,此时软件读取接收的第一个数据0xA1。完了之后软件检查TXE标志位为1,然后再写入第二个数据0xF2,那么接收数据2也是同理,如此循环发送数据3,接收数据3,这就是非连续的时序流程了。

总结一下步骤就是:

等待TXE标志位为1 -> 写入TDR -> 等待RXNE标志位为1 -> 读取RDR -> 等待TXE标志位为1 -> 写入TDR … -> 等待RXNE标志位为1 -> 读取RDR

以上为主机与从机连续交换三个字节数据的流程,那实际中我们可以封装一个交换一个字节时序单元的函数,然后连续调用该函数即可完成多字节交换的时序啦,比如在SPI1外设上进行数据交换的代码逻辑如下:

uint8_t MySPI_SwapByte(uint8_t ByteSend)
{while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);SPI_I2S_SendData(SPI1, ByteSend);while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);return SPI_I2S_ReceiveData(SPI1);
}

简而言之就是:等待TXE标志位为1 -> 写入TDR -> 等待RXNE标志位为1 -> 读取RDR

那从以上的非连续传输时序图可以看出,非连续传输发送数据的时间间隔较为宽松影响了数据的传输速度。这种差异性在SCK频率低的时候影响不大,但是在SCK频率非常高时这种差异性就很明显了,你可以根据实际项目的需求来选择一种合适的方式。


http://www.ppmy.cn/embedded/109545.html

相关文章

LeetCode找出字符串中第一个匹配项的下标

题目描述 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。 示例 1: 输入:hay…

使用lspci命令获取加速卡型号

文章目录 前言一、lspci -nn 获取具体厂商及设备ID二、使用步骤三、使用3080Ti再查询一下 前言 新到的实验机器和加速卡,安装好之后发现lspci命令没有显示型号,这里记录下使用 Vendor ID和Device ID 通过网页查询获取加速卡具体型号的过程。 一、lspci …

Python--列表简介

列表是什么 列表让你能够在⼀个地方存储成组的信息,其中既可以只包含几个元素,也可以包含数百万个元素。列表是新手可直接使用的最强大的Python 功能之⼀。 列表(list)是一种可变的序列类型,用于存储一系列有序的元素…

13款常用AI编程工具

AI编程工具的选择和使用,主要取决于具体的项目需求、编程语言、以及AI任务的类型(如机器学习、自然语言处理、计算机视觉等)。下面是一些广泛使用的AI编程工具合集,涵盖了从开发、训练、到部署的各个环节: Jupyter Not…

Java代码审计篇 | ofcms系统审计思路讲解 - 篇1 | 环境搭建、路由机制

文章目录 Java代码审计篇 | ofcms系统审计思路讲解 - 篇1 | 环境搭建、路由机制1. 前言2. 项目环境搭建3. 项目路由机制3.1. 1)先搜索pom.xml文件,看看使用了什么框架3.2. 2)确定是否是spring的路由机制3.3. 3)确定自写路由机制的…

网页时装购物系统:Spring Boot技术的实际应用

第2章相关技术 2.1 B/S架构 B/S结构的特点也非常多,例如在很多浏览器中都可以做出信号请求。并且可以适当的减轻用户的工作量,通过对客户端安装或者是配置少量的运行软件就能够逐步减少用户的工作量,这些功能的操作主要是由服务器来进行控制的…

ios 项目中设置左侧徽标

// // CategoryViewController.m // scxhgh // // Created by xmkjsoft on 2024/7/16. // #import "CategoryViewController.h" #import "SideMenuViewController.h" // 引入侧边栏控制器的头文件 #import "NavigationBarUtils.h" int…

yum源配置与静态配置地址

网络yum源 备份配置文件 下载新的CentOS-Base.repo文件到/etc/yum.repos.d/目录下 执行yum clean all清除原有 yum 缓存 执行yum makecache(刷新缓存) 本地yum 将/etc/yum/repos.d/下的文件a都移走,此处移到了该目录下的bak中 找到光盘路…