【复旦微FM33 MCU 外设开发指南】外设篇3——SPI

前言

本系列基于复旦微FM33系列单片机的DataSheet编写,旨在提供一些开发指南。

本文章及本系列其他文章将持续更新,本系列其它文章请跳转【复旦微FM33 MCU 外设开发指南】总集篇

本文章最后更新日期:2024/08/31

文章目录

  • 前言
  • GPIO配置
  • SPI配置
    • [1. SPI的寄存器](#1. SPI的寄存器)
    • [2. SPI的时钟](#2. SPI的时钟)
    • [3. SPI的工作模式](#3. SPI的工作模式)
      • [3.1 主机和从机](#3.1 主机和从机)
      • [3.2 单发送模式和单接收模式](#3.2 单发送模式和单接收模式)
      • [3.3 工作模式](#3.3 工作模式)
      • [3.4 片选控制](#3.4 片选控制)
    • [4. SPI的时序控制](#4. SPI的时序控制)
      • [4.1 时钟极性和时钟相位](#4.1 时钟极性和时钟相位)
      • [4.2 MISO的时序](#4.2 MISO的时序)
      • [4.3 SPI两帧之间的时间间隔](#4.3 SPI两帧之间的时间间隔)
      • [4.4 SPI帧格式](#4.4 SPI帧格式)
    • [5. SPI的复位](#5. SPI的复位)
  • SPI发送&接收
    • [1. SPI的状态标志位](#1. SPI的状态标志位)
    • [2. 等待标志位发送或接收](#2. 等待标志位发送或接收)
    • [3. 使用中断发送或接收](#3. 使用中断发送或接收)
    • [4. 通过DMA发送或接收](#4. 通过DMA发送或接收)
  • 注意事项
    • [1. SPI单接收模式通过DMA接收数据,多产生两个时钟周期](#1. SPI单接收模式通过DMA接收数据,多产生两个时钟周期)

GPIO配置

要使用SPI功能,需要将使用的引脚配置为数字功能(写GPIO寄存器时要注意打开GPIO时钟)。

(有的引脚需要配置额外数字功能寄存器DFS,详见GPIO章节【复旦微FM33 MCU 外设开发指南】外设篇1------GPIO

通常,我们会将MISO、MOSI和CLK引脚配置为数字功能,而将CS引脚配置为GPIO输出功能,以实现软件片选。

可以在SPIx->CR1寄存器中交换MOSI和MISO引脚。

SPI配置

1. SPI的寄存器

SPIx->CR1:控制寄存器1,用于选择SPI主机/从机、SPI时钟、信号时序
SPIx->CR2:控制寄存器2,用于控制SPI使能、数据字长配置、片选配置
SPIx->CR3:控制寄存器3,用于清空发送缓冲区、清空接收缓冲区、清除错误标志
SPIx->IER:中断使能寄存器,用于发送中断、接收中断、错误中断的使能和关闭
SPIx->ISR:中断标志寄存器,用于SPI BUSY标志、接收缓冲区满标志、发送缓冲区满标志、错误标志等的读取
SPIx->TXBUF:发送缓冲区,用于单次发送数据时写入(通过DMA传输的话会自动写入)
SPIx->RXBUF:接收缓冲区,用于单次读取数据时写入(通过DMA传输的话会自动读取)

2. SPI的时钟

要使用SPI,要在RCC->PCLKCR3寄存器中开启SPI外设的时钟使能。

SPI外设挂载在APB总线上,因此要调整SPI外设的工作时钟,可以通过对APBCLK预分频,也可以调整SPI的预分频。

(有关时钟的配置详见【复旦微FM33 MCU 外设开发指南】系统篇------时钟

FM33LC0 SPI外设的预分频在SPIx->CR1寄存器中配置,最高为APBCLK的二分频

3. SPI的工作模式

3.1 主机和从机

SPI的时序由主机产生。FM33LC0 SPI外设的主机从机模式选择在SPIx->CR1寄存器中配置

3.2 单发送模式和单接收模式

SPI是全双工通讯,因此在读取数据的时候,也必须发送数据,以产生时钟信号。

但我们使用的过程中一般是异步的。比如从一块SRAM中读取数据,只需发送一个命令帧告诉SRAM要从哪里读,读多长就可以了,之后SRAM返回其中保存的数据,这种时候主机每一帧发送的数据是无效的。单发送和单接收就可以应用在类似的场景中。


可以在SPIx->CR2寄存器中使能或关闭单发送模式/单接收模式。

3.3 工作模式

可以在SPIx->CR2寄存器中控制SPI的工作模式。

SPI有很多种工作模式,常用四线全双工模式

除此之外有四线半双工(一个MISO/MOSI引脚用于区分命令帧和数据帧)和三线半双工(删除一个MISO/MOSI引脚)等

四线半双工常见的应用就是SPI显示屏

3.4 片选控制

可以在SPIx->CR2寄存器中控制片选。


当然我日常喜欢使用软件片选,而且不通过寄存器去改变片选状态,而是将引脚配置为GPIO输出模式,写GPIOx->DO寄存器来改变其引脚状态。

4. SPI的时序控制

4.1 时钟极性和时钟相位

SPI时序控制最基本的即为时钟极性和时钟相位,SPI的主机和从机应配置为相同的时钟极性和时钟相位。

一般MCU作为SPI的主机使用,从机的时钟极性和时钟相位一般是固定死的,根据从机的DataSheet要求配置即可。

FM33LC0 SPI外设的时钟极性和时钟相位在SPIx->CR1寄存器中配置

4.2 MISO的时序

除了时钟极性和时钟相位,还可以在SPIx->CR1寄存器中调整MISO的时序

4.3 SPI两帧之间的时间间隔

SPI传输时,接上示波器,可以观察两个时钟周期之间有时间间隔。

1.如果是多次的单次传输(直接向TXBUF中写入数据然后启动SPI传输),那么这个时间间隔主要是软件等待标志位产生的

2.如果是通过DMA的连续传输,那么这个时间间隔会变得很短。

我们用SPI来和显示屏通讯,会发现使用DMA的刷屏速率会比不用DMA快很多,主要是省下了大量的两帧之间的时间间隔。

可以在SPIx->CR1寄存器中调整SPI的两帧数据之间的等待时间。

(但我认为这个只对DMA传输影响显著,因为多次的单次传输,SPI两帧的时间间隔实在是太久了)

4.4 SPI帧格式

可以在SPIx->CR2寄存器中调整SPI单帧的传输字长。


可以在SPIx->CR1寄存器中调整SPI的帧格式为大端或者小端。

5. SPI的复位

SPI2的复位在RCC->AHBRSTCR1寄存器中。

SPI1的复位在RCC->AHBRSTCR2寄存器中。

注意,这里的复位不是说写1就复位了,复位好了之后要写0取消复位。

SPI发送&接收

1. SPI的状态标志位

SPI的状态标志位在SPIx->ISR寄存器中查询。

虽说这个寄存器叫中断状态标志位,但没开启中断的时候,这个标志位也会置位,只是不响应中断罢了。

SPIx->ISR寄存器中常用的三个标志位:

RXBFTXBE 标志位对应SPIx->IER寄存器中可以开启的接收完成中断发送完成中断 ,即开启中断后,如果TXBE和RXBF置位,就会进入中断服务函数,在中断服务函数中可以判断中断来源。

RXBFTXBE 什么时候置位?根据描述来看,是接收缓存满 或者发送缓冲区空 的时候。
但必须注意接收缓存满不代表接收完成,发送缓冲区空也不代表发送完成。

通过文首结构框图,可以看到不仅有发送/接收缓冲区,也有发送/接收移位寄存器。

在写入SPIx->TXBUF后,数据会从SPIx->TXBUF传入发送移位寄存器中,这时SPIx->TXBUF空,并置位TXBE标志,进入中断服务函数。

但这时发送移位寄存器的值还没有发送出去。

BUSY标志位才能代表当前是否有数据传输,只有在移位寄存器空,才会清零BUSY标志位,代表SPI当前没有数据传输

如果没有意识到这点,在写软件的时候会经常遇到一些错误,比如接收数组里没有最后一帧。

2. 等待标志位发送或接收

在发送时,向SPIx->TXBUF寄存器写入,然后等待BUSY 标志

在接收时,向SPIx->TXBUF寄存器写入任意数据(因为SPI是全双工),然后等待BUSY 标志,读取SPIx->RXBUF

多字节的发送/接收就是重复这个过程。

这种方式最简单,缺点是效率很低,而且软件死等的方式在软件开发中很危险,如果等不到标志程序就死在那里了,除非看门狗复位。

3. 使用中断发送或接收

在发送时,使能发送中断,向SPIx->TXBUF寄存器写入,在中断服务函数中等待BUSY 标志为0,即为发送完成

如果还要继续写入数据,在中断服务函数中可以不等待BUSY 标志为0,直接向SPIx->TXBUF写入,以实现连续的发送。

当然,进入中断之后要判断产生中断的原因,是发送完成中断、接受完成中断还是错误中断。

4. 通过DMA发送或接收

这里DataSheet上写的很好,不做过多阐述。



注意事项

1. SPI单接收模式通过DMA接收数据,多产生两个时钟周期

应用场景: 主机使用单发送模式向从机发送命令字节,随后开启单接收模式,通过DMA接收从机回发数据
问题描述: 用示波器看波形,会发现多了两个时钟周期,配置spi字长为8bit,就会多出两个8bit时钟;配置spi字长为16bit,就会多出两个16bit时钟
调试记录:

1.收到的数据无误

2.使能SPI后时钟线立刻产生了两个时钟周期,因此和DMA无关,可能是SPI单接收模式的问题

3.如SPI不使用单接收模式而使用全双工接收数据,相同情况下时钟线不会产生两个时钟周期。确认是单接收模式的问题
推测原因:

在分析原因之前,重复一下SPI外设的特性:

  • SPI是全双工通信,主机即使只接收数据也要向TX缓冲区写数据,时钟产生并开启传输。即使将SPI配置为单接收模式,也是SPI外设自动向TX缓冲区填写数据,时钟产生并开启传输
  • SPI外设有缓冲区和移位寄存器,从机返回的数据将先进入移位寄存器,再进入接收缓冲区。在接收缓冲区非空的时候,移位寄存器的数据是无法进入接收缓冲区的。因此如果主机接收缓冲区读的不及时,接收缓冲区非空,移位寄存器无法写入接收缓冲区,则SPI传输中止(时序由主机提供)

根据以上特性,可以分析出原因:

  • 当读取完一组数据后,SPI还在单接收模式中,继续往TX缓冲区填写数据,因此继续产生时钟,有时钟就有接收到的数据(如果从机不响应,则接收到的就是全0)
  • 但是SPI主机没有继续读取RX缓冲区的数据(因为已经收到了设定长度的数据),导致RX缓冲区满,进而导致移位寄存器无法写入接收缓冲区。
  • 因此,多出的第一个时钟周期的数据在接收缓冲区中,第二个时钟周期的数据在移位寄存器中
  • 最终因为移位寄存器满而停止传输

解决办法:

在DMA传输下,不使用单接收模式,使用全双工模式。

这是因为DMA接收时会自动写TXBUF,不需要再配置单接收模式。

相关推荐
无人装备硬件开发爱好者4 小时前
STM32G474 + 1.32 寸 OLED(128×96)俄罗斯方块游戏实现指南
stm32·嵌入式硬件·游戏
三佛科技-134163842124 小时前
SM2850P无电感离线稳压器 5V输出 典型应用电路分析(管脚、关键设计要点)
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
dqsh065 小时前
关于STM32G474芯片有规律的自动重启的问题
stm32·单片机·嵌入式硬件·系统重启·原因解析
时空自由民.6 小时前
BLDC无刷直流电机作为发电机的波形图
单片机
yong99906 小时前
基于 STM32 的 4×4 矩阵键盘源码
stm32·矩阵·计算机外设
JSMSEMI116 小时前
JSM63006 5A 28V三相无刷电机驱动电路
单片机·嵌入式硬件
国产芯片设计6 小时前
【LCD驱动实战】单颗YL1621脚位不足?双芯片联动驱动方案详解
stm32·单片机·mcu·51单片机·硬件工程
bubiyoushang8889 小时前
基于 Freescale S12 单片机的 Bootloader 开发
单片机·嵌入式硬件·mongodb
笨笨小乌龟119 小时前
单片机的半主机模式与 MicroLib 机制(Keil UseMicroLIB)
stm32·单片机·嵌入式硬件
旧梦吟13 小时前
5.9 电工考试-易错题
stm32·嵌入式硬件