SPI

示例列表

本章介绍 SPI 示例的详细信息。RTL87x2G 为 SPI 外设提供以下示例。

功能概述

串行外设接口(SPI)允许与外部设备进行半/全双工、同步、串行通信。 该接口可以配置为两种操作模式之一:作为串行主设备或串行从设备。在主模式下,它为外部从设备提供通信时钟(SCK)。 对于RTL87x2G,SPI0 可以配置为主设备或从设备,SPI1 是主设备。

特性列表

SPI 主设备特性列表:

  • 支持 4 种时钟模式。(CPOL, CPHA)

    • Mode 0 (CPOL=0, CPHA=0).

    • Mode 1 (CPOL=0, CPHA=1).

    • Mode 2 (CPOL=1, CPHA=0).

    • Mode 3 (CPOL=1, CPHA=1).

  • 最大 SPI0 SCK 50MHz;最大 SPI1 SCK 20MHz。

  • SCK frequency= SPI source clock/N; N 是介于 2 和 65534 之间的任何偶数。

  • 支持 4 到 32 位数据帧格式。

  • TX FIFO 深度 32。

  • RX FIFO 深度 32。

  • 支持 GDMA

SPI 从设备特性列表:

  • 支持 4 种时钟模式。(CPOL, CPHA)

  • 最大输入 SCK 为 20MHz。

  • 支持 4/8/16 位数据帧格式。

  • TX FIFO 宽度 16 位,深度 64。

  • RX FIFO 宽度 16 位,深度 64。

  • 支持 GDMA

系统框图

SPI 的系统框图如下图所示。通过调用 MCU Firmware 固件实现 SPI TX/RX 等功能,硬件通过 MOSI 与 MISO 实现数据交互,实现与外部设备的通信。

../../../../../_images/spi_block_diagram.png

SPI 系统框图

传输模式

SPI 支持四种传输模式:

通信时序图

SPI 支持 4 种时钟模式,分别对应 CPOL 和 CPHA 为 0 和 1 的四种情况。

  • 时钟极性(CPOL)位设置时钟信号在空闲状态下的极性。0 表示低电平,1 表示高电平。

  • 时钟相位(CPHA)位设置捕获数据的边沿:0 表示第一边沿,1 表示第二边沿。

下图分别为四种模式下的 SPI 通信时序图。

../../../../../_images/SPI_Communication_Sequence_Diagram_SCPH_0.jpg

SPI 通信时序图 (CPHA is 0)

../../../../../_images/SPI_Communication_Sequence_Diagram_SCPH_1.jpg

SPI 通信时序图 (CPHA is 1)

SPI 从机

当初始化选择外设为 SPI0_SLAVE 时,会将 SPI 配置为从设备模式。当 SPI 被配置为从设备时,所有串行传输均由串行总线主设备启动和控制。

SPI 从机使用时需要注意以下几点:

  1. CPHA 和 CPOL 必须与主设备设置相同。

  2. 如果 SPI 从设备向主设备传输数据,必须确保在串行主设备发起传输之前,TX FIFO 中存在数据。如果在从设备 TX FIFO 中没有数据的情况下主设备向 SPI 从设备发起传输,则 SPI 状态位 SPI_FLAG_TXE 会被置起。

  3. 在从设备发送最后一个数据帧后,TX FIFO 变为空,此时,SPI 主设备不应再发送时钟请求从设备的数据,因为从设备没有数据可以传输。如果此时主设备继续发送时钟,则会产生 TX FIFO 下溢,触发 SPI_INT_TUF 中断。从设备会反复向主设备返回低电平。

  4. 在设备以高速状态下运行时,建议使用 GDMA 传输。

SPI 高速模式

SPI0 支持高速模式。在 SPI 传输速率高于 20MHz 时,推荐使用 SPI0 的高速模式,同时推荐搭配 GDMA 进行使用。高速模式下,需要选择外设的基地址为 SPI0_HS。

在开启 SPI 高速模式下,推荐和专属 PAD 配套使用。部分 PAD 可以支持被配置为指定外设的高速模式,在使用专属 PAD 时,PAD 被固定分配为指定功能,无法进行更改。SPI0 的专属 PAD 如下:

SPI0 Dedicated PAD

PAD

Function

P4_0

SPI0_CLK

P4_1

SPI0_MISO

P4_2

SPI0_MOSI

P4_3

SPI0_CSN

在使用 SPI0 高速模式时,需要进行如下配置:

  1. 调用 Pad_Dedicated_Config(),开启指定 PAD 的专属模式。

  2. 调用 Pinmux_HS_Config(),开启 SPI0 高速模式。

  3. 需要额外配置 0x40002310 地址下寄存器的 BIT15 为 1,才可以正常使用高速模式。

  4. 在使用专属 PAD 时,无需执行 Pad_Config()Pinmux_Config()。如果需要手动控制 CS 线,Pad_Dedicated_Config() 函数可以不配置 CS 相关引脚,执行 Pad_Config() 即可。

    Pad_Dedicated_Config(SPI_SCK_PIN, ENABLE);
    Pad_Dedicated_Config(SPI_MOSI_PIN, ENABLE);
    Pad_Dedicated_Config(SPI_MISO_PIN, ENABLE);
    Pad_Dedicated_Config(SPI_CS_PIN, ENABLE);
    
    Pinmux_HS_Config(SPI0_HS_MUX);
    
    *((volatile uint32_t *)0x40002310) |= BIT15;
    
  5. 外设需要使用基地址为 SPI0_HS,其中 RCC_PeriphClockCmd() 与 GDMA Handshake 仍使用 SPI0 相关配置。

    RCC_PeriphClockCmd(APBPeriph_SPI0, APBPeriph_SPI0_CLOCK, ENABLE);
    ...
    SPI_Init(SPI0_HS, &SPI_InitStructure);
    ...
    GDMA_InitStruct.GDMA_DestinationAddr     = (uint32_t)SPI0_HS->SPI_DR;
    GDMA_InitStruct.GDMA_DestHandshake       = GDMA_Handshake_SPI0_TX;
    ...
    SPI_Cmd(SPI0_HS, ENABLE);
    

由于 SPI 的时钟源默认为 40M,且 SPI 最小分频系数为 2,因此默认情况下 SPI 最高支持 20M 通信速率。如果 SPI0 想要使用超过 20M 速率,需要修改 SPI 的时钟源为 PLL 时钟源。有关 PLL 时钟源的具体介绍,可参考 极速PLL时钟

修改 SPI0 时钟源的配置如下:

  1. 调用 pm_spi0_master_freq_set(),修改时钟源为指定的某个 PLL 时钟源,并指定输出频率。返回值若为 0,代表时钟源配置成功。

  2. 调用 SPI_ClkConfig(),指定 SPI 的时钟源与分频系数。

  3. 若想要配置 SPI0 输出频率为 50MHz,可以指定时钟源为 PLL1 100MHz,采用 1 分频,并配置 SPI_InitTypeDef::SPI_BaudRatePrescaler 为 2,即可得到 50MHz SPI 输出频率。

  4. 若想要配置 SPI0 输出频率为 40MHz,可以指定时钟源为 PLL2 160MHz,采用 2 分频,并配置 SPI_InitTypeDef::SPI_BaudRatePrescaler 为 2,即可得到 40MHz SPI 输出频率。

    // Set SPI0 Clock Output Frequency to 50MHz.
    int32_t flag = pm_spi0_master_freq_set(CLK_PLL1_SRC, 100, 100);
    SPI_ClkConfig(SPI0, SPI_CLOCK_SRC_PLL1, SPI_CLOCK_DIVIDER_1);
    ...
    SPI_InitStructure.SPI_BaudRatePrescaler = 2;
    ...
    
    // Set SPI0 Clock Output Frequency to 40MHz.
    int32_t flag = pm_spi0_master_freq_set(CLK_PLL2_SRC, 160, 80);
    SPI_ClkConfig(SPI0, SPI_CLOCK_SRC_PLL2, SPI_CLOCK_DIVIDER_2);
    ...
    SPI_InitStructure.SPI_BaudRatePrescaler = 2;
    ...
    

SPI GDMA

SPI GDMA TX

在 SPI 串行传输过程中,当 TX FIFO 内数据的数量小于或等于初始化中设置的 SPI_InitTypeDef::SPI_TxWaterlevel 值时,会触发一次 GDMA burst 搬运。 GDMA 一次 burst 会将 GDMA_InitTypeDef::GDMA_DestinationMsize 个数据写入 SPI TX FIFO 中。

SPI GDMA TX 时,推荐设置 SPI_InitTypeDef::SPI_TxWaterlevel 的值为 SPI_TX_FIFO_SIZE - MSize

Here should be spi tx dma diagram

SPI GDMA TX 示意图

SPI GDMA RX

在 SPI 串行传输过程中,当 RX FIFO 内数据的数量大于等于初始化中设置的 SPI_InitTypeDef::SPI_RxWaterlevel + 1 时,会触发一次 GDMA burst 搬运。 GDMA 一次 burst 会从 SPI RX FIFO 中获取 GDMA_InitTypeDef::GDMA_SourceMsize 个数据。

SPI GDMA RX 时,推荐设置 SPI_InitTypeDef::SPI_RxWaterlevel 的值为 MSize - 1

Here should be spi rx dma diagram

SPI GDMA RX 示意图