stm32----SPI协议

一、概述

SPI(Serial Peripheral Interface,串行外围设备接口),是Motorola公司提出的一种同步串行接口技术,是一种高速、全双工、同步通信总线,在芯片中只占用四根管脚用来控制及数据传输,节约了芯片pin的数目,同时为PCB在布局上节省了空间。正是由于这种简单易用的特性,现在越来越多的芯片上都集成了SPI技术。这4根线分别是:MOSI(主机输出从机输入)、MISO(主机输入从机输出)、SCLK(时钟同步)、CS(片选线)。

寻址方式:和IIC不同的是,IIC采用的是通过广播目标从机ID的方式来找到想要通信的从机设备。而SPI里面则是通过使能片选线CS(即chip select)的方式来选择目标从机,至于片选信号是高电平还是低电平则需视实际情况而定,通常采用较多的是低电平进行片选操作。还需要注意一点,同一时刻主机只能与一个从机进行通信。

二、特点

  1. 采用主从模式(Master-Slave)的控制方式,支持单Master多Slave

SPI规定了两个SPI设备之间通信必须由主设备Master来控制从设备Slave。一个Master可以通过提供clock以及对Slave进行片选(Slave Select)来控制多个Slave,但同一时刻只能选择一个从机进行通信。SPI协议还规定Slave设备的clock由Master通过SCK管脚提供给Slave,Slave本身不能产生或控制clock,没有clock则Slave不能正常工作。

2、采用同步方式(Synchronous)传输数据

Master会根据将要交换的数据产生相应的时钟脉冲,组成时钟信号,时钟信号通过时钟极性(CPOL)和时钟相位(CPHA)控制两个SPI设备何时交换数据以及何时对接收数据进行采样,保证数据在两个设备之间是同步传输的。

3、数据交换

SPI设备间的数据传输被称为数据交换,因为SPI协议规定一个SPI设备不能在数据通信过程中仅仅充当一个发送者(Transmitter)或者接受者(Receiver)。在每个clock周期内,SPI设备都会发送并接收1 bit数据,相当于有1 bit数据被交换了。数据传输高位在前,低位在后(MSB first)。

在数据传输过程中,每次接收到的数据必须在下一次数据传输之前被采样也就是要马上从信号线中读取过来,可以理解为一个只能存放一个快递的快递站中的快递到了,得马上去取,不然会影响接下来的快递,如果之前接收到的数据没有被读取,那么这些已经接收完成的数据将有可能被丢弃,导致SPI物理模块最终失效。因此在程序中一般都会在SPI传输完数据后,读取SPI设备里的数据,即使这些数据在程序里是无效的。

SPI总线四种工作方式 

SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。

   时序详解:

CPOL:时钟极性选择,为0时SPI总线空闲为低电平,为1时SPI总线空闲为高电平

CPHA:时钟相位选择,为0时在SCK第一个跳变沿采样,为1时在SCK第二个跳变沿采样

通信过程举例 

比如当CPOL = 1,CPHA=1的时候,此时,SCK空闲电平状态为高电平,并在第二个时钟沿开始采样,第一个时钟沿开始进行输出。

在时钟线第一个跳变沿,发送器将会在数据线上发送一位数据,如果要发送1则将数据线拉高,如果要发送0则将数据线拉低,过段时间以后,此时数据线上的状态已经确定,即数据已经发出了,紧接着在第二个跳变沿,接收器将会从数据线上接收一位数据。一个字节占8位,所以只需要8个时钟周期(一个时钟周期有两个边沿)即可完成一个字节数据的传输。与IIC不同的是,SPI是没有应答信号的

三、数据传输

SPI是一个环形总线结构,由SS (CS)、SCK、SDI、SDO构成,时序很简单,在SCK的控制下,两个双向移位寄存器进行数据交换。寄存器中的内容全部移出时,相当于完成了两个寄存器内容的交换。SSPSR控制数据移入移出SSPBUF,controller确定SPI总线的通信模式。

SSPBUF:Synchronous Serial Port Buffer,泛指SPI设备里面的内部缓冲区,一般在物理上是以FIFO的形式,保存传输过程中的临时数据;

SSPSR:Synchronous Serial Port Shift Register,泛指SPI设备里面的移位寄存器,根据设置好的数据位宽把数据移入或移出SSPBUF;

Controller:泛指SPI设备里面的控制寄存器,通过配置寄存器来设置SPI总线的传输模式。

通常情况下,只需要对四个pin进行编程即可控制SPI设备之间的数据通信:

SCK(Serial Clock):主要作用是Master向Slave传输时钟信号,控制数据交换的时机和速率;

SS/CS(Slave Select/Chip Select):用于Master片选Slave,使被选中的Slave能够被Master访问;

SDO/MOSI(Serial Data Output/Master Out Slave In):在Master上也被称为Tx-channel,作为数据的出口,主要用于SPI设备发送数据;

SDI/MISO(Serial Data Input/Master In Slave Out):在Master上也被称为Rx-channel,作为数据的入口,主要用于SPI设备接收数据。

四线制SPI:CS,SCK(同步时钟),MOSI(master out slaver in),MISO:全双工

三线制SPI:CS,SCK,DIO:半双工,只能分时进行收发

注意在主机开始接收从机数据的时候,同时要发一个0xFF给从机。

原来是spi 主机在接收的时候也把移位寄存器中的数据通过mosi发送出去了,从slave看,它通过miso发送数据给master的同时也接收来自master mosi上的数据。因为spi协议是没有反馈信号的,所以slave在发送数据的同时接收到的数据如果是slave能够识别的一个命令值的话那么这时就会对slave产生影响了。这时slave就会按照新的命令运行,然而这个命令是master在接收slave数据时不经意发送出去的,它本身是不打算发送出去的。为了解决master在接收数据的同时误发命令,所以在接收数据之前先写0xff进入移位寄存器。这样master在接收来自slave的数据的同时发送0xffslaveslave不识别0xff这个命令自然就不会影响它本身的运行了。

上面说了一大堆东西,现在你就会发送其实也不一定要写0xff是不是啊?是的,只要接收数据之前往移位寄存器写一个slave无法识别的数据就行了。

四、IIC和SPI协议之间的异同

相同点:

  1. 均采用串行同步的通信方式
  2. 均采用TTL电平,传输举例和应用场景较为类似。(RS232则采用负逻辑电平)
  3. 均采用主从工作方式。

不同点:

  1. IIC为半双工,SPI为全双工(也可配置为半双工模式)
  2. IIC有应答机制、SPI无应答机制
  3. IIC通过总线广播从机设备地址方式进行寻址,SPI通过片选线进行寻址
  4. IIC空闲电平状态固定为高电平(上拉电阻),SPI的SCLK空闲电平状态取决于时钟极性CPOL。

五、STM32F1芯片上的SPI

1、STM32F1的SPI 接口提供两个主要功能,支持 SPI 协议或 I2S 音频协议。STM32F1的SPI时钟最高可以到 36MHz,支持 DMA功能。STM32F1的SPI内部结构图:

标号1

SPI接口引脚,其中有MOSI、MISO、SCK、NSS(即CS)。

我们在配置的时候,需要查看原理图,其中MOSI、MISO、SCK需要单独配置,至于片选线NSS我们通常使用一个普通IO口就可以了,具体引脚参考电路原理图通过软件拉高拉低来产生片选信号。

我们可以查看中文参考手册关于芯片架构章节发现SPI1是挂接在APB2总线上的,SPI2和SPI3挂接在APB1总线上,根据SPI工作频率特性,SPI理论最大频率是其所在总线的一半,即SPI1理论最大工作频率可达72/2=36MHz,SPI2和SPI3理论最大工作频率可达36/2=18MHz。

标号2

是用于产生SCK频率的波特率发生器,我们是SCK时钟信号是波特率发生器根据SPI_CR1寄存器的BR0~BR2这几个位进行控制的。这几个位可以绝对时钟分频因子。

具体可以查看中文参考手册:

 

 

标号3

数据控制逻辑。SPI的MOSI和MISO都连接在数据移位寄存器当中。数据移位寄存器内容来源于接收缓冲区和发送缓冲区,还有MOSI和MISO。

假设将此SPI设备(即单片机)配置为主模式,如果是发送数据,则数据通过发送缓冲区进入到移位寄存器,再通过MOSI将数据发送出去。接收数据则是通过MISO将数据接收进来,接收到移位寄存器并进入接收缓冲区,再进入到总线进行传输。

 

 

标号4

寄存器单元。用于控制SPI的相关工作模式,包括主从模式,低位先行还是高位先行,波特率分频是多少,一次传送8位还是16位等等,具体的参考中文参考手册。

  1. SPI配置步骤(只是例子,具体的还得看实际芯片原理图和手册)

(1)使能SPI及对应GPIO端口时钟并配置引脚的复用功能

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );

RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PB13/14/15复用推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOB, &GPIO_InitStructure);

(2)初始化SPI,包括数据帧长度、传输模式、MSB和LSB顺序等

void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);

typedef struct

{

uint16_t SPI_Direction;   //设置SPI的单双向模式

uint16_t SPI_Mode;       //设置 SPI 的主/从机端模式

uint16_t SPI_DataSize;  //设置 SPI 的数据帧长度,可选 8/16 位

uint16_t SPI_CPOL;     //设置时钟极性 CPOL,可选高/低电平

uint16_t SPI_CPHA;    //设置时钟相位,可选奇/偶数边沿采样

uint16_t SPI_NSS;  //设置 NSS 引脚由 SPI 硬件控制还是软件控制

uint16_t SPI_BaudRatePrescaler;//设置时钟分频因子

uint16_t SPI_FirstBit;   //设置 MSB/LSB 顺序

uint16_t SPI_CRCPolynomial; //设置 CRC 校验的表达式

}SPI_InitTypeDef;

SPI_Direction:用于设置 SPI 的通信方向,可设置为双线全双工(SPI_Direction_2Lines_FullDuplex),双线只接收(SPI_Direction_2Lines_RxOnly),单线只接收(SPI_Direction_1Line_Rx)、单线只发送模式(SPI_Direction_1Line_Tx)。

SPI_Mode:用于设置 SPI 工作在主机模式(SPI_Mode_Master)或从机模式(SPI_Mode_Slave ),这两个模式的最大区别为 SPI 的 SCK 信号线的时序, SCK 的时序是由通讯中的主机产生的。若被配置为从机模式, STM32 的 SPI 外设将接受外来的 SCK 信号。

SPI_DataSize:用于设置SPI通信的数据帧长度,可以选择8位(SPI_DataSize_8b)或者 16 位(SPI_DataSize_16b)。

SPI_CPOL:用于设置时钟极性,可设置为高电平(SPI_CPOL_High)或低电平(SPI_CPOL_Low )。

SPI_CPHA:用于设置时钟相位,也就是选择在串行同步时钟的第几个跳变沿(上升或下降)数据被采样,可以为 SPI_CPHA_1Edge(在 SCK 的奇数边沿采集数据) 或SPI_CPHA_2Edge (在 SCK 的偶数边沿采集数据) 。

SPI_NSS:用于设置NSS引脚的使用模式,可以选择为硬件模式(SPI_NSS_Hard )与软件模式(SPI_NSS_Soft ),在硬件模式中的 NSS信号由 SPI 硬件自动产生,而软件模式则需要我们使用相应的 GPIO 端口来控制。

SPI_BaudRatePrescaler:用于设置波特率分频因子,分频后的时钟即为 SPI 的 SCK 信号线的时钟频率。可设置为 fpclk 的 2、 4、 6、 8、 16、 32、 64、 128、 256 分频。

SPI_FirstBit:用于设置数据传输顺序是 MSB 位在前还是 LSB 位在前。

SPI_CRCPolynomial:用于设置 CRC 校验多项式,提高通信可靠性。

举例

SPI_InitTypeDef  SPI_InitStructure;

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工

SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构

SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为高电平

SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定义波特率预分频的值:波特率预分频值为256

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始

SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式

SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

(3)使能(开启)SPI

void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);

(4)SPI数据传输

void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);

uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);

(5)查看SPI传输状态

FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);

使用较多的是发送完成标志(SPI_I2S_FLAG_TXE)和接收完成标志(SPI_I2S_FLAG_RXNE)

SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE);

  1. EN25QXX介绍

EN25QXX 是大容量 SPI FLASH 产品,EN25Q64的容量是64Mb(8M字节),EN25Q128 的容量为 128Mb(16M字节),该系列还有EN25Q08/16/32/64 等。我们开发板上使用的是EN25Q16,学习这个芯片可以参考华邦公司的W25Q128芯片,因为它们是完全兼容的。所以我们以W25Q128进行介绍。

W25Q128 将 16M 的容量分为 256 个块( Block),每个块大小为 64K 字节,每个块又分为16 个扇区( Sector),每个扇区 4K 个字节。 W25Q128 的最小擦除单位为一个扇区,也就是每次必须擦除 4K 个字节。这样我们需要给 W25Q128 开辟一个至少 4K 的缓存区,这样对 SRAM 要求比较高,要求芯片必须有 4K 以上 SRAM 才能很好的操作。

W25Q128 的擦写周期多达 10W 次,具有 20 年的数据保存期限,支持电压为 2.7~3.6V,W25Q128 支持标准的 SPI,还支持双输出/四输出的 SPI,最大 SPI 时钟可以到 80Mhz(双输出时相当于 160Mhz,四输出时相当于 320M)

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/59521.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言 - 结构体、结构体数组、结构体指针和结构体嵌套

结构体的意义 问题:学籍管理需要每个学生的下列数据:学号、姓名、性别、年龄、分数,请用 C 语言程序存储并处理一组学生的学籍。 单个学生学籍的数据结构: 学号(num): int 型姓名(…

2.Redis 通用命令

Redis 中最核心的两个命令: set 作用:设置 key 对应的 value 值并存储进去。若key已包含一个值,则无论其类型如何,都会覆盖该值。在SET操作成功时,将丢弃与密钥相关联的任何先前生存时间。 对于上述这里的 key和val…

五、Kafka消费者

目录 5.1 Kafka的消费方式5.2 Kafka 消费者工作流程1、总体流程2、消费者组原理3、消费者组初始化流程4、消费者组详细消费流程 5.3 消费者API1 独立消费者案例(订阅主题)2 独立消费者案例(订阅分区)3 消费者组案例 5.4 生产经验—…

Linux内核学习(十二)—— 页高速缓存和页回写(基于Linux 2.6内核)

目录 一、缓存手段 二、Linux 页高速缓存 三、flusher 线程 Linux 内核实现了一个被叫做页高速缓存(page cache)的磁盘缓存,它主要用来减少对磁盘的 I/O 操作。它是通过把磁盘中的数据缓存到内存中,把对磁盘的访问变为对物理内…

聚类分析 | MATLAB实现基于AHC聚类算法可视化

聚类分析 | MATLAB实现基于AHC聚类算法可视化 目录 聚类分析 | MATLAB实现基于AHC聚类算法可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 AHC聚类算法,聚类结果可视化,MATLAB程序。 Agglomerative Hierarchical Clustering(自底…

JVM ZGC垃圾收集器

ZGC垃圾收集器 ZGC(“Z”并非什么专业名词的缩写,这款收集器的名字就叫作Z Garbage Collector)是一款在JDK 11中新加入的具有实验性质[1]的低延迟垃圾收集器,是由Oracle公司研发的。 ZGC收集器是一款基于Region内存布局的&#…

为什么深度网络(vgg,resnet)最后都不使用softmax(概率归一)函数,而是直接加fc层?

这个问题很简单,并不是没有使用softmax,而是没有显式使用softmax。 随着深度学习框架的发展,为了更好的性能,部分框架选择了在使用交叉熵损失函数时默认加上softmax,这样无论你的输出层是什么,只要用了nn.…

Linux 打开U盘硬盘等报错 file type exfat not configured in kernel

目录 原因: 查看系统文件系统和当前系统版本 回归正题,如何解决报错 在centons 7中打开U盘,报错file type exfat not configured in kernel。 原因: 这是因为Linux采用的文件系统和我U盘的文件系统不一致引起。如下图&#xf…

2023蓝帽杯初赛ctf部分题目

Web LovePHP 打开网站环境,发现显示出源码 来可以看到php版本是7.4.33 简单分析了下,主要是道反序列化的题其中发现get传入的参数里有_号是非法字符,如果直接传值传入my_secret.flag,会被php处理掉 绕过 _ 的方法 对于__可以…

C++哈希(散列)与unordered关联式容器封装(Map、Set)

一、unordered系列关联式容器 在C98中,STL提供了以红黑树为底层数据结构的关联式容器(map、set等),查询时的效率可以达到,最差情况下需要比较红黑树的高度次。因此在C11中,STL提供了四个unordered系列关联式容器&…

Star History 月度开源精选|Llama 2 及周边生态特辑

7 月 18 日,Meta 发布了 Llama,大语言模型 Llama 1 的进阶版,可以自由免费用于研究和商业,支持私有化部署。 所以本期 Star History 的主题是:帮助你快速把 Llama 2 在自己机器上跑起来的开源工具,无论你的…

LeetCode 面试题 02.04. 分割链表

文章目录 一、题目二、C# 题解 一、题目 给你一个链表的头节点 head 和一个特定值 x,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你不需要 保留 每个分区中各节点的初始相对位置。 点击此处跳转题目。 示例 1&#…

【JS案例】JS实现手风琴效果

JS案例手风琴 🌟效果展示 🌟HTML结构 🌟CSS样式 🌟实现思路 🌟具体实现 1.绑定事件 2.自定义元素属性 3.切换菜单 🌟完整JS代码 🌟写在最后 🌟效果展示 🌟HTML…

【⑬MySQL | 数据类型(一)】简介 | 整数 | 浮点 | 定点 | 时间/日期类型

前言 ✨欢迎来到小K的MySQL专栏,本节将为大家带来MySQL数据类型简介 | 整数 | 浮点 | 定点 | 时间/日期类型的分享✨ 目录 前言0.数据类型简介1 整数类型2 浮点类型3 定点类型4 日期/时间类型总结 0.数据类型简介 数据类型(data_type)是指系…

链表(详解)

一、链表 1.1、什么是链表 1、链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,有一系列结点(地址)组成,结点可动态的生成。 2、结点包括两个部分:&#x…

经典问题解析四

关于动态内存分配 new 和 malloc 的区别是什么? delete 和 free 的区别是什么? new 关键字与 malloc 函数的区别 new 关键字是 C 的一部分 malloc 是由 C 库函数提供的函数 new 是以具体类型为单位进行内存分配 malloc 以字节为单位进行内存分配 …

【1267. 统计参与通信的服务器】

来源:力扣(LeetCode) 描述: 这里有一幅服务器分布图,服务器的位置标识在 m * n 的整数矩阵网格 grid 中,1 表示单元格上有服务器,0 表示没有。 如果两台服务器位于同一行或者同一列&#xff…

【Terraform学习】使用 Terraform 从 EC2 实例访问 S3 存储桶(Terraform-AWS最佳实战学习)

使用 Terraform 从 EC2 实例访问 S3 存储桶 实验步骤 前提条件 安装 Terraform: 地址 下载仓库代码模版 本实验代码位于 task_ec2_s3connet 文件夹中。 变量文件 variables.tf 在上面的代码中,您将声明,aws_access_key,aws_…

百亿数据查询秒级响应,观测体系之日志中心该如何玩转?

日志是处理生产故障、性能优化、业务分析的重要参考依据,是系统稳定运行不可或缺的一部分。随着业务系统规模急剧膨胀增大,尤其是是微服务架构逐渐普及,一个系统可能涉及多个应用模块与服务实例,传统模式下运维人员去定位问题显得…

一文速学-让神经网络不再神秘,一天速学神经网络基础-输出层(四)

前言 思索了很久到底要不要出深度学习内容,毕竟在数学建模专栏里边的机器学习内容还有一大半算法没有更新,很多坑都没有填满,而且现在深度学习的文章和学习课程都十分的多,我考虑了很久决定还是得出神经网络系列文章,不…