SPI通信协议学习-基于STM32HAL库

目录

前言

        本文摘抄于野火开发指南,仅用于学习过程的记录,如有侵权请联系删除。

1.SPI简介

        SPI 是英语 Serial Peripheral interface 的缩写,顾名思义就是串行外围设备接口。是 Motorola 首先在其 MC68HCXX 系列处理器上定义的。SPI 接口主要应用在 EEPROMFLASH,实时时 钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。SPI 是一种高速的,全双工,同 步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上 节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协 议,STM32F1 也有 SPI 接口。

        SPI 接口一般使用 4 条线通信:
        MISO 主设备数据输入,从设备数据输出。
        MOSI 主设备数据输出,从设备数据输入。
        SCLK 时钟信号,由主设备产生。
        CS 从设备片选信号,由主设备控制。
        SPI 主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可
编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。
        SPI 总线四种工作方式 SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串
行同步时钟极性和相位可以进行配置,时钟极性( CPOL )对传输协议没有重大的影响。如果
CPOL=0 ,串行同步时钟的空闲状态为低电平;如果 CPOL=1 ,串行同步时钟的空闲状态为高电
平。时钟相位( CPHA )能够配置用于选择两种不同的传输协议之一进行数据传输。如 CPHA=0
在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果 CPHA=1 ,在串行同步时钟
的第二个跳变沿(上升或下降)数据被采样。 SPI 主模块和与之通信的外设备时钟相位和极性
应该一致。
不同时钟相位下的总线数据传输时序如图   所示:
SPI 通讯设备之间的常用连接方式见

2.SPI协议

        与 I2C 的类似, SPI 协议定义了通讯的 起始和停止信号、数据有效性、时钟同步等环节

      2.1 SPI基本通讯过程

        先看看 SPI 通讯的通讯时序,见 图 

这是一个主机的通讯时序。 NSS SCK MOSI 信号都由主机控制产生,而 MISO 的信号由从机
产生,主机通过该信号线读取从机的数据。 MOSI MISO 的信号只在 NSS 为低电平的时候才有
效,在 SCK 的每个时钟周期 MOSI MISO 传输一位数据。
以上通讯流程中包含的各个信号分解如下:

2.2通讯的起始信号和停止信号

        在图   中的标号处, NSS 信号线由高变低,是 SPI 通讯的起始信号。 NSS 是每个从机各自独
占的信号线,当从机在自己的 NSS 线检测到起始信号后,就知道自己被主机选中了,开始准备
与主机通讯。在图中的标号处, NSS 信号由低变高,是 SPI 通讯的停止信号,表示本次通讯结束, 从机的选中状态被取消。

2.3数据有效性

        SPI 使用 MOSI MISO 信号线来传输数据,使用 SCK 信号线进行数据同步。 MOSI MISO 数 据线在 SCK 的每个时钟周期传输一位数据,且数据输入输出是同时进行的。数据传输时, MSB 先行或 LSB 先行并没有作硬性规定,但要保证两个 SPI 通讯设备之间使用同样的协定,一般都会采用图 中的 MSB 先行模式。 观察图中的标号处,MOSI MISO 的数据在 SCK 的上升沿期间变化输出,在 SCK 的下降沿时 被采样。即在 SCK 的下降沿时刻, MOSI MISO 的数据有效,高电平时表示数据“ 1 ”,为低电 平时表示数据“0 ”。在其它时刻,数据无效, MOSI MISO 为下一次表示数据做准备。 SPI 每次数据传输可以 8 位或 16 位为单位,每次传输的单位数不受限制。

2.4 CPOL/CPHA及通讯模式

        上面讲述的图  中的时序只是 SPI 中的其中一种通讯模式, SPI 一共有四种通讯模式,它们的 主要区别是总线空闲时 SCK 的时钟状态以及数据采样时刻。为方便说明,在此引入“时钟极性 CPOL”和“时钟相位 CPHA ”的概念。
        时钟极性 CPOL 是指 SPI 通讯设备处于空闲状态时, SCK 信号线电平信号 ( SPI 通讯开始前、 NSS 线为高电平时 SCK 的状态 ) CPOL=0 时, SCK 在空闲状态时为低电平, CPOL=1 时,则相反。
        时钟相位 CPHA 是指数据的采样的时刻,当 CPHA=0 时, MOSI MISO 数据线上的信号将会在 SCK 时钟线的“奇数边沿”被采样。当 CPHA=1 时,数据线在 SCK 的“偶数边沿”采样。见 图:
        

                                                         CPHA=0 时的 SPI 通讯模式

CPHA=1 时,不受 CPOL 的影响,数据信号在 SCK 的偶数边沿被采样

                                                                 CPHA=1 时的 SPI 通讯模式

CPOL CPHA 的不同状态, SPI 分成了四种模式,见表 ,主机与从机需要工作在相同的
模式下才可以正常通讯,实际中采用较多的是“模式 0 ”与“模式 3

 SPI 的四种模式:

3.STM32的SPI特性及架构

3.1STM32的SPI外设简介

        STM32 的 SPI 外设可用作通讯的主机及从机,支持最高的 SCK 时钟频率为 f pclk /2 (STM32F103 型 号的芯片默认 f:sub: pclk1 36MHz f pclk2 72MHz) ,完全支持 SPI 协议的 4 种模式,数据帧长 度可设置为 8 位或 16 位,可设置数据 MSB 先行或 LSB 先行。它还支持双线全双工 ( 前面小节说 明的都是这种模式) 、双线单向以及单线模式。其中双线单向模式可以同时使用 MOSI MISO 数 据线向一个方向传输数据,可以加快一倍的传输速度。而单线模式则可以减少硬件接线,当然这样速率会受到影响。

3.2STM的SPI架构剖析 

3.3通讯引脚

        SPI 的所有硬件架构都从图 24‑5 中左侧 MOSI MISO SCK NSS 线展开的。 STM32 芯片有多 个 SPI 外设,它们的 SPI 通讯信号引出到不同的 GPIO 引脚上,使用时必须配置到这些指定的引 脚,见表 。关于 GPIO 引脚的复用功能,可查阅《 STM32F10x 规格书》,以它为准

        其中 SPI1 APB2 上的设备,最高通信速率达 36Mbtis/s SPI2 SPI3 APB1 上的设备,最高 通信速率为 18Mbits/s 。除了通讯速率,在其它功能上没有差异。其中 SPI3 用到了下载接口的引 脚,这几个引脚默认功能是下载,第二功能才是 IO 口,如果想使用 SPI3 接口,则程序上必须先 禁用掉这几个 IO 口的下载功能。一般在资源不是十分紧张的情况下,这几个 IO 口是专门用于下 载和调试程序,不会复用为 SPI3

3.4时钟控制逻辑

        SCK 线的时钟信号,由波特率发生器根据“ 控制寄存器 CR1 ”中的 BR[0:2] 控制,该位是对 f pclk 时钟的分频因子,对 f pclk 的分频结果就是 SCK 引脚的输出时钟频率,计算方法见表

 其中的 fpclk 频率是指 SPI 所在的 APB 总线频率,APB1 fpclk1APB2 fpckl2

通过配置“控制寄存器 CR ”的“ CPOL 位”及“ CPHA ”位可以把 SPI 设置成前面分析的  4 SPI 模式

3.5数据控制逻辑

        SPI 的 MOSI MISO 都连接到数据移位寄存器上,数据移位寄存器的数据来源及目标接收、发 送缓冲区以及 MISO MOSI 线。当向外发送数据的时候,数据移位寄存器以“发送缓冲区”为数 据源,把数据一位一位地通过数据线发送出去;当从外部接收数据的时候,数据移位寄存器把数 据线采样到的数据一位一位地存储到“接收缓冲区”中。通过写 SPI 的“数据寄存器 DR ”把数 据填充到发送缓冲区中,通讯读“数据寄存器 DR ”,可以获取接收缓冲区中的内容。其中数据帧 长度可以通过“控制寄存器 CR1 ”的“ DFF 位”配置成 8 位及 16 位模式;配置“ LSBFIRST 位” 可选择 MSB 先行还是 LSB 先行。

3.6整体控制逻辑

        整体控制逻辑负责协调整个 SPI 外设,控制逻辑的工作模式根据我们配置的“控制寄存器(CR1/CR2)”的参数而改变,基本的控制参数包括前面提到的 SPI 模式、波特率、 LSB 先行、主 从模式、单双向模式等等。在外设工作时,控制逻辑会根据外设的工作状态修改“状态寄存器 (SR)”,我们只要读取状态寄存器相关的寄存器位,就可以了解 SPI 的工作状态了。除此之外,控 制逻辑还根据要求,负责控制产生 SPI 中断信号、 DMA 请求及控制 NSS 信号线。
        实际应用中,我们一般不使用 STM32 SPI 外设的标准 NSS 信号线,而是更简单地使用普通的 GPIO,软件控制它的电平输出,从而产生通讯起始和停止信号。

3.7通讯过程

        STM32 使用 SPI 外设通讯时,在通讯的不同阶段它会对“状态寄存器 SR ”的不同数据位写入参 数,我们通过读取这些寄存器标志来了解通讯状态。

        中的是“主模式”流程,即 STM32 作为 SPI 通讯的主机端时的数据收发过程。

图中  主发送器通讯过程
主模式收发流程及事件说明如下:
        (1) 控制 NSS 信号线,产生起始信号 ( 图中没有画出 )
        (2) 把要发送的数据写入到“数据寄存器 DR ”中,该数据会被存储到发送缓冲区;
        (3) 通讯开始, SCK 时钟开始运行。 MOSI 把发送缓冲区中的数据一位一位地传输出去; MISO 则把数据一位一位地存储进接收缓冲区中;
        (4) 当发送完一帧数据的时候,“状态寄存器 SR ”中的“ TXE 标志位”会被置 1 ,表示传输完一
帧,发送缓冲区已空;类似地,当接收完一帧数据的时候,“ RXNE 标志位”会被置 1 ,表示传输
完一帧,接收缓冲区非空;
        (5) 等待到“ TXE 标志位”为 1 时,若还要继续发送数据,则再次往“数据寄存器 DR ”写入数据即可;等待到“RXNE 标志位”为 1 时,通过读取“数据寄存器 DR ”可以获取接收缓冲区中的 内容。
        假如我们使能了 TXE RXNE 中断, TXE RXNE 1 时会产生 SPI 中断信号,进入同一个中 断服务函数,到 SPI 中断服务程序后,可通过检查寄存器位来了解是哪一个事件,再分别进行处 理。也可以使用 DMA 方式来收发“数据寄存器 DR ”中的数据。

4.SPI初始化结构体详解

typedef struct {
        uint32_t Mode;
        /* 设置 SPI 的主 / 从机端模式 */
        uint32_t Direction; /* 设置 SPI 的单双向模式 */
        uint32_t DataSize;
        /* 设置 SPI 的数据帧长度,可选 8/16 */
        uint32_t CLKPolarity; /* 设置时钟极性 CPOL ,可选高 / 低电平 */
        uint32_t CLKPhase; /* 设置时钟相位,可选奇 / 偶数边沿采样 */
        uint32_t NSS;
        /* 设置 NSS 引脚由 SPI 硬件控制还是软件控制 */
        uint32_t BaudRatePrescaler; /* 设置时钟分频因子, fpclk/ 分频数 =fSCK */
        uint32_t FirstBit; /* 设置 MSB/LSB 先行 */
        uint32_t TIMode;
        /* 指定是否启用 TI 模式 */
        uint32_t CRCCalculation; /* 指定是否启用 CRC 计算 */
        uint32_t CRCPolynomial;
        /* 设置 CRC 校验的表达式 */
} SPI_InitTypeDef;
这些结构体成员说明如下,其中括号内的文字是对应参数在 STM32 标准库中定义的宏:
        (1) Mode 本成员设置 SPI 工作在 主机模式 (SPI_MODE_MASTER) 从机模式 (SPI_MODE _SLAVE ),这两个模式的最大区别为 SPI 的 SCK 信号线的时序, SCK 的时序是由通讯中的主机产生的。若被配置为从机模式,STM32 的 SPI 外设将接受外来的 SCK 信号。
        (2) Direction :本成员设置 SPI 的通讯方向,可设置为双线全 (SPI_DIRECTION_2LINES) ,双 线只接收 (SPI_DIRECTION_2LINES_RXONLY) ,单线 SPI_DIRECTION_1LINE
        (3) DataSize 本成员可以选择 SPI 通讯的数据帧大小是为 8 (SPI_DATASIZE_8BIT) 还是 16 位 (SPI_DATASIZE_16BIT)
        (4) CLKPolarity 和 CLKPhase :这两个成员配置 SPI 的时钟极性 CLKPolarity 和时钟相位 CLKPhase ,这两个配置影响到 SPI 的通讯模式,关于 CLKPolarity CLKPhase 的说明参考前
面“ 通讯模式 ”小节。时钟极性 CLKPolarity 成员,可设置为高电平 (SPI_POLARITY_HIGH) 或低电平 (SPI_POLARITY_LOW) 。时钟相位 CPHA 则可以设置为 SPI_PHASE_1EDGE( 在 SCK 的奇数边沿采集数据 ) SPI_P HASE_2EDGE( SCK 的偶数边沿采集数据 )
        (5) NSS 本成员配置 NSS 引脚的使用模式,可以选择为 硬件模式 (SPI_NSS_HARD ) 软件模 式 ( SPI_NSS_SOFT ) ,在硬件模式中的 SPI 片选信号由 SPI 硬件自动产生,而软件模式则需 要我们亲自把相应的 GPIO 端口拉高或置低产生非片选和片选信号。实际中软件模式应用
比较多。
        (6) BaudRatePrescaler 本成员设置波特率分频因子,分频后的时钟即为 SPI SCK 信号线的时 钟频率。这个成员参数可设置为 fpclk 2 4 6 8 16 32 64 128 256 分频。
        (7) FirstBit 所有串行的通讯协议都会有 MSB 先行 ( 高位数据在前 ) 还是 LSB 先行 ( 低位数据在 前) 的问题,而 STM32 SPI 模块可以通过这个结构体成员,对这个特性编程控制。
        (8) TIMode :指定是否启用 TI 模式。可选择为使能 ( SPI_TIMO DE_ENABLE ) 与不是能 ( SPI_TIMODE_DISABLE )
        (9) CRCCalculation :指定是否启用 CRC 计算
        (10) SPI_CRCPolynomial 这是 SPI CRC 校验中的多项式 ,若我们使用 CRC 校验时,就使用这 个成员的参数 ( 多项式 ) ,来计算 CRC 的值。
        配置完这些结构体成员后,我们要调用 HAL_SPI_Init 函数把这些参数写入到寄存器中,实现 SPI 的初始化,然后调用 __HAL_SPI_ENABLE 来使能 SPI 外设。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以帮你解答关于STM32HAL库SPI通信问题。SPI通信是一种同步的串行通信协议,它使用4根线实现通信,分别是时钟线(SCLK)、主设备输出线(MOSI)、主设备输入线(MISO)和片选线(CS)。下面是一份使用STM32HAL库进行SPI通信的示例代码,你可以参考一下: ```c #include "stm32f4xx_hal.h" // 定义SPI句柄 SPI_HandleTypeDef hspi1; // 定义数据缓冲区 uint8_t tx_buf[10]; uint8_t rx_buf[10]; int main(void) { // 初始化HAL库 HAL_Init(); // 初始化SPI口 hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; // 主机模式 hspi1.Init.Direction = SPI_DIRECTION_2LINES; // 双线全双工 hspi1.Init.DataSize = SPI_DATASIZE_8BIT; // 8位数据位 hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // 时钟极性为低电平 hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // 时钟相位为第一边沿 hspi1.Init.NSS = SPI_NSS_SOFT; // 软件控制片选信号 hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; // 波特率预分频 hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; // MSB优先 hspi1.Init.TIMode = SPI_TIMODE_DISABLE; // 禁用TI模式 hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // 禁用CRC校验 HAL_SPI_Init(&hspi1); // 发送数据 HAL_SPI_Transmit(&hspi1, tx_buf, 10, 100); // 接收数据 HAL_SPI_Receive(&hspi1, rx_buf, 10, 100); // 同时发送和接收数据 HAL_SPI_TransmitReceive(&hspi1, tx_buf, rx_buf, 10, 100); while (1) { } } ``` 在使用HAL库进行SPI通信时,需要先初始化SPI口并定义一个SPI句柄。然后可以使用HAL_SPI_Transmit、HAL_SPI_Receive和HAL_SPI_TransmitReceive函数分别进行发送、接收和同时发送和接收数据。参数说明如下: - 第一个参数:SPI句柄 - 第二个参数:待发送数据的缓冲区指针 - 第三个参数:待发送/接收数据的长度 - 第四个参数:超时时间(单位为ms) 希望这些信息可以帮助你解决问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值