LV16-20-SPI-01-基础知识

本文主要是STM32开发——SPI通信基础知识的一些相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows windows11
Ubuntu Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
SecureCRT Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日
开发板 正点原子 i.MX6ULL Linux阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
STM32开发板 正点原子战舰V3(STM32F103ZET6)
点击查看本文参考资料
  • 通用
分类 网址说明
官方网站https://www.arm.com/ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档
https://www.st.com/content/st_com/zh.htmlST官方网站,在这里我们可以找到STM32的相关文档
https://www.stmcu.com.cn/意法半导体ST中文官方网站,在这里我们可以找到STM32的相关中文参考文档
http://elm-chan.org/fsw/ff/00index_e.htmlFatFs文件系统官网
教程书籍《ARM Cortex-M3权威指南》ARM公司专家Joseph Yiu(姚文祥)的力作,中文翻译是NXP的宋岩
《ARM Cortex-M0权威指南》
《ARM Cortex-M3与Cortex-M4权威指南》
开发论坛http://47.111.11.73/forum.php开源电子网,正点原子的资料下载及问题讨论论坛
https://www.firebbs.cn/forum.php国内Kinetis开发板-野火/秉火(刘火良)主持的论坛,现也做STM32和i.MX RT
https://www.amobbs.com/index.php阿莫(莫进明)主持的论坛,号称国内最早最火的电子论坛,以交流Atmel AVR系列单片机起家,现已拓展到嵌入式全平台,其STM32系列帖子有70W+。
http://download.100ask.net/index.html韦东山嵌入式资料中心,有些STM32和linux的相关资料也可以来这里找。
博客参考http://www.openedv.com/开源网-原子哥个人博客
http://blog.chinaaet.com/jihceng0622博主是原Freescale现NXP的现场应用工程师
cortex-m-resources这其实并不算是一个博客,这是ARM公司专家Joseph Yiu收集整理的所有对开发者有用的官方Cortex-M资料链接(也包含极少数外部资源链接)
  • STM32
STM32STM32 HAL库开发实战指南——基于F103系列开发板野火STM32开发教程在线文档
STM32库开发实战指南——基于野火霸道开发板野火STM32开发教程在线文档
  • SD卡
SD Association提供了SD存储卡和SDIO卡系统规范
点击查看相关文件下载
STM32F103xx英文数据手册STM32F103xC/D/E系列的英文数据手册
STM32F103xx中文数据手册STM32F103xC/D/E系列的中文数据手册
STM32F10xxx英文参考手册(RM0008)STM32F10xxx系列的英文参考手册
STM32F10xxx中文参考手册(RM0008)STM32F10xxx系列的中文参考手册
Arm Cortex-M3 处理器技术参考手册-英文版Cortex-M3技术参考手册-英文版
STM32F10xxx Cortex-M3编程手册-英文版(PM0056)STM32F10xxx/20xxx/21xxx/L1xxxx系列Cortex-M3编程手册-英文版
SD卡相关资料——最新版本有关SD卡的一些资料可以从这里下载
SD卡相关资料——历史版本有关SD卡的一些历史版本资料可以从这里下载,比如后边看的SD卡2.0协议
SD 2.0 协议标准完整版这是一篇关于SD卡2.0协议的中文文档,还是比较有参考价值的,可以一看

一、SPI简介

这一部分可以查看笔记《通信协议-04-SPI通信》。

二、STM32的SPI外设

1. 简介

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

2. 框图

关于STM32的SPI外设的框图,我们可以看 [STM32中文参考手册](https://www.stmcu.com.cn/Designresource/detail/localization_document /710001)的23.3 SPI功能描述一节:

image-20230507162113905

2.1 ①通讯引脚

SPI 的所有硬件架构都从图 24‑5 中左侧 MOSI、 MISO、 SCK 及 NSS 线展开的。 STM32 芯片有多个 SPI 外设,它们的 SPI 通讯信号引出到不同的 GPIO 引脚上,使用时必须配置到这些指定的引脚,见下表。关于 GPIO 引脚的复用功能,还是要查看STM32参考手册。

引脚 SPI1 SPI2 SPI3
NSS PA4 PB12 PA15 下载口的 TDI
CLK PA5 PB13 PB3 下载口的 TDO
MISO PA6 PB14 PB4 下载口的 NTRST
MOSI PA7 PB15 PB5

其中 SPI1 是 APB2 上的设备,最高通信速率达 36Mbtis/s, SPI2、 SPI3 是 APB1 上的设备,最高通信速率为 18Mbits/s。除了通讯速率,在其它功能上没有差异。其中 SPI3 用到了下载接口的引脚,这几个引脚默认功能是下载,第二功能才是 IO 口,如果想使用 SPI3 接口,则程序上必须先禁用掉这几个 IO 口的下载功能。一般在资源不是十分紧张的情况下,这几个 IO 口是专门用于下载和调试程序,不会复用为 SPI3。 当用到SPI3的时候,需要注意我们下载的时候要按着reset复位按键,然后再下载,当芯片处于复位状态时,才能正常下载。

实际应用中,我们一般不使用 STM32 SPI 外设的标准 NSS 信号线,而是更简单地使用普通的GPIO,软件控制它的电平输出,从而产生通讯起始和停止信号。NSS引脚通过配置寄存器,配置成通过软件来控制的形式,这样只要在需要启动SPI的时候将NSS拉低就可以了,不一定非要接在PA4。

对于GPIO的复用模式,我们可以看[STM32中文参考手册](https://www.stmcu.com.cn/Designresource/detail/localization_document /710001)8.11小节:

image-20230507163950643

2.2 ②时钟控制逻辑

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

BR[0:2] 分频结果 (SCK 频率) BR[0:2] 分频结果 (SCK 频率)
000 fpclk/2 100 fpclk/32
001 fpclk/4 101 fpclk/64
010 fpclk/8 110 fpclk/128
011 fpclk/16 111 fpclk/256

其中的 fpclk 频率是指 SPI 所在的 APB 总线频率, APB1 为 fpclk1, APB2 为 fpckl2。通过配置“控制寄存器 CR”的“CPOL 位”及“CPHA”位可以把 SPI 设置成 4 种 SPI模式中的一种。

2.3 ③数据控制逻辑

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

2.4 ④整体控制逻辑

整体控制逻辑负责协调整个 SPI 外设,控制逻辑的工作模式根据我们配置的“控制寄存器(CR1/CR2)”的参数而改变,基本的控制参数包括前面提到的 SPI 模式、波特率、 LSB 先行、主从模式、单双向模式等等。在外设工作时,控制逻辑会根据外设的工作状态修改“状态寄存器(SR)”,我们只要读取状态寄存器相关的寄存器位,就可以了解 SPI 的工作状态了。除此之外,控制逻辑还根据要求,负责控制产生 SPI 中断信号、 DMA 请求及控制 NSS 信号线。

3. 通讯过程

STM32 使用 SPI 外设通讯时,在通讯的不同阶段它会对“状态寄存器 SR”的不同数据位写入参数,我们通过读取这些寄存器标志来了解通讯状态。 我们可以查看 [STM32中文参考手册](https://www.stmcu.com.cn/Designresource/detail/localization_document /710001)的 23.3.5 数据发送与接收过程部分。

image-20230507163558609

主模式收发流程及事件说明如下:

(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”中的数据。

【注意】:发送和接收是同时进行的,当我们只想接收数据的时候也还是需要向发送缓冲区写数据,这样才能触发SPI产生时钟驱动数据的传输,当然我们写入的数据可以是任意的,只要有数据写进去就可以。

4. SPI在那个总线?

这个我们可以看一下系统框图:

image-20230507211722423

会发现,这里SPI1挂载在APB1总线,最高时钟就是36MHz,剩下两个挂载在APB2总线,最高时钟源为72MHz,根据这些信息来控制SPI的时钟。

三、相关寄存器

这一部分我们可以查看 [STM32中文参考手册](https://www.stmcu.com.cn/Designresource/detail/localization_document /710001)的23.5 SPI和I2S寄存器描述。我们可以用半字(16位)或字(32位)的方式操作这些外设寄存器。

1. 控制寄存器 1(SPI_CR1)

image-20230507164540173

2. 控制寄存器 2(SPI_CR2)

image-20230507164525551

3. 状态寄存器(SPI_SR)

image-20230507164511621

4. 数据寄存器(SPI_DR)

image-20230507164438277

5. 配置寄存器(SPI_I2S_CFGR)

image-20230507164417711

6. 预分频寄存器(SPI_I2SPR)

image-20230507164353928

四、HAL库函数

1. SPI_InitTypeDef

1
2
3
4
5
6
7
8
9
10
11
12
13
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;

(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 的值。

2. 数据传输

1
2
3
4
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size,
uint32_t Timeout);