GD32F470入门教程(八)SPI/I2S

8.5k 词

SPI/I2S

简介

SPI/I2S 模块可以通过 SPI 协议或 I2S 音频协议与外部设备进行通信。
串行外设接口(Serial Peripheral Interface,缩写为 SPI)提供了基于 SPI 协议的数据发送和接收功能,可以工作于主机或从机模式。SPI 接口支持具有硬件 CRC 计算和校验的全双工和单工模式。SPI5 还支持 SPI 四线主机模式。
片上音频接口(Inter-IC Sound,缩写为 I2S)支持四种音频标准,分别是 I2S 飞利浦标准, MSB 对齐标准,LSB 对齐标准和 PCM
标准。它可以在四种模式下运行,包括主机发送模式,主机接收模式,从机发送模式和从机接收模式。通过使用附加的 I2S 模块:I2S1_ADD 和 I2S2_ADD,SPI1 和 SPI2 支持 I2S 全双工模式。

主要特性

image-20260227204026903

SPI 信号线描述

image-20260227204357090

image-20260227204507994

SPI运行模式

表 21-5. SPI 运行模式

模式 描述 寄存器配置 使用的数据引脚
MFD 全双工主机模式 MSTMOD = 1RO = 0BDEN = 0BDOEN:不要求 MOSI:发送MISO:接收
MTU 单向线连接主机发送模式 MSTMOD = 1RO = 0BDEN = 0BDOEN:不要求 MOSI:发送MISO:不使用
MRU 单向线连接主机接收模式 MSTMOD = 1RO = 1BDEN = 0BDOEN:不要求 MOSI:不使用MISO:接收
MTB 双向线连接主机发送模式 MSTMOD = 1RO = 0BDEN = 1BDOEN = 1 MOSI:发送MISO:不使用
MRB 双向线连接主机接收模式 MSTMOD = 1RO = 0BDEN = 1BDOEN = 0 MOSI:接收MISO:不使用
SFD 全双工从机模式 MSTMOD = 0RO = 0BDEN = 0BDOEN:不要求 MOSI:接收MISO:发送
STU 单向线连接从机发送模式 MSTMOD = 0RO = 0BDEN = 0BDOEN:不要求 MOSI:不使用MISO:发送
SRU 单向线连接从机接收模式 MSTMOD = 0RO = 1BDEN = 0BDOEN:不要求 MOSI:接收MISO:不使用
STB 双向线连接从机发送模式 MSTMOD = 0RO = 0BDEN = 1BDOEN = 1 MOSI:不使用MISO:发送
SRB 双向线连接从机接收模式 MSTMOD = 0RO = 0BDEN = 1BDOEN = 0 MOSI:不使用MISO:接收

image-20260227205058573

image-20260227205110719

使用实例

这里以 SPI0 为例,使用 PB3 (SPI0_SCK), PB4 (SPI0_MISO), PB5 (SPI0_MOSI) 进行说明。(注意:具体的引脚映射请参考芯片的数据手册)

1. SPI初始化配置

配置SPI之前,需要先开启GPIO和SPI的时钟,并配置GPIO为复用推挽输出模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "gd32f4xx.h"

void spi_config(void)
{
spi_parameter_struct spi_init_struct;

/* 1. 开启时钟:GPIOB和SPI0 */
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_SPI0);

/* 2. 配置GPIO引脚 (PB3: SCK, PB4: MISO, PB5: MOSI) */
/* 根据具体情况,SPI引脚通常配置为复用模式 */
gpio_af_set(GPIOB, GPIO_AF_5, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);

/* 3. SPI参数配置 */
/* 复位SPI0 */
spi_i2s_deinit(SPI0);

/* 配置SPI参数 */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; // 全双工模式
spi_init_struct.device_mode = SPI_MASTER; // 主机模式
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT; // 8位数据帧
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE; // 时钟极性低,第一沿采样
spi_init_struct.nss = SPI_NSS_SOFT; // 软件NSS控制
spi_init_struct.prescale = SPI_PSC_8; // 预分频系数
spi_init_struct.endian = SPI_ENDIAN_MSB; // 高位先行
spi_init(SPI0, &spi_init_struct);

/* 4. 使能SPI */
spi_enable(SPI0);
}

2. SPI发送/接收一字节函数

在全双工模式下,发送数据的同时也会接收数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*!
\brief 通过SPI发送并接收一个字节
\param[in] data: 要发送的数据
\param[out] none
\retval 接收到的数据
*/
uint8_t spi_read_write_byte(uint8_t data)
{
/* 等待发送缓冲区为空 (TBE标志置位) */
while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE));

/* 发送数据 */
spi_i2s_data_transmit(SPI0, data);

/* 等待接收缓冲区非空 (RBNE标志置位) */
while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE));

/* 返回接收到的数据 */
return spi_i2s_data_receive(SPI0);
}

3. 应用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int main(void)
{
uint8_t rx_data;

// 系统时钟配置等...

// 初始化SPI
spi_config();

while(1) {
// 选中从机(拉低CS引脚,需额外配置一个GPIO作为CS)
// gpio_bit_reset(GPIOB, GPIO_PIN_6);

// 发送 0xAA 并接收从机返回的数据
rx_data = spi_read_write_byte(0xAA);

// 释放从机
// gpio_bit_set(GPIOB, GPIO_PIN_6);

// 处理接收到的数据
}
}

FLASH示例可查看二十六、 SPI FLASH 应用 | 立创开发板技术文档中心

SPI/I2S库函数

image-20260227211828718

image-20260227211854914

一、SPI/I2S固件库函数总表

函数分类 函数名 核心功能
初始化与复位 spi_i2s_deinit 复位SPI/I2S外设
初始化与复位 spi_struct_para_init 初始化SPI结构体参数为默认值
初始化与复位 spi_init 初始化SPI外设
初始化与复位 i2s_init 初始化I2S外设
初始化与复位 i2s_psc_config 配置I2S预分频器
外设使能/禁用 spi_enable 使能SPI外设
外设使能/禁用 spi_disable 禁用SPI外设
外设使能/禁用 i2s_enable 使能I2S外设
外设使能/禁用 i2s_disable 禁用I2S外设
NSS引脚控制 spi_nss_output_enable 使能SPI NSS引脚输出
NSS引脚控制 spi_nss_output_disable 禁用SPI NSS引脚输出
NSS引脚控制 spi_nss_internal_high 软件模式下SPI NSS引脚拉高
NSS引脚控制 spi_nss_internal_low 软件模式下SPI NSS引脚拉低
DMA功能控制 spi_dma_enable 使能SPI DMA功能
DMA功能控制 spi_dma_disable 禁用SPI DMA功能
数据收发 spi_i2s_data_transmit 发送SPI/I2S数据
数据收发 spi_i2s_data_receive 接收SPI/I2S数据
标志位查询 spi_i2s_flag_get 获取SPI/I2S状态标志位
标志位清除 spi_i2s_flag_clear 清除SPI/I2S状态标志位
中断控制 spi_i2s_interrupt_enable 使能SPI/I2S中断
中断控制 spi_i2s_interrupt_disable 禁用SPI/I2S中断
中断标志查询 spi_i2s_interrupt_flag_get 获取SPI/I2S中断标志位
中断标志清除 spi_i2s_interrupt_flag_clear 清除SPI/I2S中断标志位

二、函数逐行详细解析

1. 初始化与复位类函数

(1)spi_i2s_deinit
  • 函数原型:void spi_i2s_deinit(uint32_t spi_periph);
  • 功能解释:将指定的SPI/I2S外设寄存器恢复为默认复位值,完成外设的硬件复位。
  • 传入参数:
    • spi_periph:SPI/I2S外设基地址(如SPI0、SPI1、I2S0等,对应芯片手册的外设地址宏)。
  • 传出参数:无。
(2)spi_struct_para_init
  • 函数原型:void spi_struct_para_init(spi_parameter_struct* spi_struct);
  • 功能解释:将SPI初始化结构体(spi_parameter_struct)的所有成员变量赋值为默认值,避免未初始化导致的配置错误。
  • 传入参数:
    • spi_struct:指向SPI参数结构体的指针(结构体包含模式、波特率、数据位宽、极性相位等配置项)。
  • 传出参数:无(直接修改传入的结构体内容)。
(3)spi_init
  • 函数原型:void spi_init(uint32_t spi_periph, spi_parameter_struct* spi_struct);
  • 功能解释:根据传入的SPI参数结构体,配置SPI外设的工作模式、数据格式、时钟等核心参数,完成SPI初始化。
  • 传入参数:
    • spi_periph:SPI外设基地址(如SPI0);
    • spi_struct:指向已配置好的SPI参数结构体的指针。
  • 传出参数:无。
(4)i2s_init
  • 函数原型:void i2s_init(uint32_t i2s_periph, i2s_mode_enum i2s_mode, uint32_t i2s_standard, i2s_ckpl_enum i2s_ckpl);
  • 功能解释:初始化I2S外设的工作模式、通信标准、时钟极性等核心参数。
  • 传入参数:
    • i2s_periph:I2S外设基地址(如I2S0);
    • i2s_mode:I2S工作模式枚举(如主发送、从接收、主接收等);
    • i2s_standard:I2S通信标准(如I2S_PHILLIPS、I2S_MSB、I2S_LSB等);
    • i2s_ckpl:I2S时钟极性枚举(时钟空闲电平高/低)。
  • 传出参数:无。
(5)i2s_psc_config
  • 函数原型:void i2s_psc_config(uint32_t i2s_periph, i2s_audio_sample_enum i2s_audio_sample, uint32_t i2s_mckout_en);
  • 功能解释:配置I2S的预分频器,确定音频采样率对应的时钟频率,可选是否使能主时钟输出(MCK)。
  • 传入参数:
    • i2s_periph:I2S外设基地址;
    • i2s_audio_sample:音频采样率枚举(如8kHz、16kHz、44.1kHz等);
    • i2s_mckout_en:主时钟输出使能(ENABLE/DISABLE)。
  • 传出参数:无。

2. 外设使能/禁用类函数

(1)spi_enable
  • 函数原型:void spi_enable(uint32_t spi_periph);
  • 功能解释:置位SPI外设的使能位,启动SPI外设工作。
  • 传入参数:
    • spi_periph:SPI外设基地址。
  • 传出参数:无。
(2)spi_disable
  • 函数原型:void spi_disable(uint32_t spi_periph);
  • 功能解释:清零SPI外设的使能位,停止SPI外设工作。
  • 传入参数:
    • spi_periph:SPI外设基地址。
  • 传出参数:无。
(3)i2s_enable
  • 函数原型:void i2s_enable(uint32_t i2s_periph);
  • 功能解释:置位I2S外设的使能位,启动I2S外设工作。
  • 传入参数:
    • i2s_periph:I2S外设基地址。
  • 传出参数:无。
(4)i2s_disable
  • 函数原型:void i2s_disable(uint32_t i2s_periph);
  • 功能解释:清零I2S外设的使能位,停止I2S外设工作。
  • 传入参数:
    • i2s_periph:I2S外设基地址。
  • 传出参数:无。

3. NSS引脚控制类函数

(1)spi_nss_output_enable
  • 函数原型:void spi_nss_output_enable(uint32_t spi_periph);
  • 功能解释:使能SPI的NSS引脚输出功能(仅主模式下有效),用于硬件片选控制。
  • 传入参数:
    • spi_periph:SPI外设基地址。
  • 传出参数:无。
(2)spi_nss_output_disable
  • 函数原型:void spi_nss_output_disable(uint32_t spi_periph);
  • 功能解释:禁用SPI的NSS引脚输出功能,切换为软件片选模式。
  • 传入参数:
    • spi_periph:SPI外设基地址。
  • 传出参数:无。
(3)spi_nss_internal_high
  • 函数原型:void spi_nss_internal_high(uint32_t spi_periph);
  • 功能解释:软件片选模式下,将SPI的NSS内部信号拉高(取消片选)。
  • 传入参数:
    • spi_periph:SPI外设基地址。
  • 传出参数:无。
(4)spi_nss_internal_low
  • 函数原型:void spi_nss_internal_low(uint32_t spi_periph);
  • 功能解释:软件片选模式下,将SPI的NSS内部信号拉低(选中从设备)。
  • 传入参数:
    • spi_periph:SPI外设基地址。
  • 传出参数:无。

4. DMA功能控制类函数

(1)spi_dma_enable
  • 函数原型:void spi_dma_enable(uint32_t spi_periph, uint8_t dma);
  • 功能解释:使能SPI的DMA收发功能,支持批量数据的无CPU干预传输。
  • 传入参数:
    • spi_periph:SPI外设基地址;
    • dma:DMA功能类型(如SPI_DMA_TX:发送DMA;SPI_DMA_RX:接收DMA)。
  • 传出参数:无。
(2)spi_dma_disable
  • 函数原型:void spi_dma_disable(uint32_t spi_periph, uint8_t dma);
  • 功能解释:禁用SPI指定的DMA功能。
  • 传入参数:
    • spi_periph:SPI外设基地址;
    • dma:DMA功能类型(SPI_DMA_TX/SPI_DMA_RX)。
  • 传出参数:无。

5. 数据收发类函数

(1)spi_i2s_data_transmit
  • 函数原型:void spi_i2s_data_transmit(uint32_t spi_periph, uint16_t data);
  • 功能解释:向SPI/I2S的数据寄存器写入待发送的数据,触发一次数据传输。
  • 传入参数:
    • spi_periph:SPI/I2S外设基地址;
    • data:待发送的16位数据(SPI可根据配置自动截断为8/16位)。
  • 传出参数:无。
(2)spi_i2s_data_receive
  • 函数原型:uint16_t spi_i2s_data_receive(uint32_t spi_periph);
  • 功能解释:从SPI/I2S的数据寄存器读取接收到的数据。
  • 传入参数:
    • spi_periph:SPI/I2S外设基地址。
  • 传出参数:
    • 返回值:接收到的16位数据(SPI可根据配置截取8/16位有效位)。

6. 标志位查询类函数

(1)spi_i2s_flag_get
  • 函数原型:FlagStatus spi_i2s_flag_get(uint32_t spi_periph, uint32_t flag);
  • 功能解释:查询SPI/I2S的指定状态标志位是否置位(如发送空、接收满、忙标志等)。
  • 传入参数:
    • spi_periph:SPI/I2S外设基地址;
    • flag:状态标志位(如SPI_FLAG_TXE:发送空;SPI_FLAG_RXNE:接收满;SPI_FLAG_BSY:忙标志)。
  • 传出参数:
    • 返回值:FlagStatus枚举(SET:标志位置位;RESET:标志位清零)。

7. 标志位清除类函数

(1)spi_i2s_flag_clear
  • 函数原型:void spi_i2s_flag_clear(uint32_t spi_periph, uint32_t flag);
  • 功能解释:清除SPI/I2S的指定状态标志位(仅支持可清除的标志位,如溢出标志)。
  • 传入参数:
    • spi_periph:SPI/I2S外设基地址;
    • flag:待清除的状态标志位(如SPI_FLAG_OVR:溢出标志)。
  • 传出参数:无。

8. 中断控制类函数

(1)spi_i2s_interrupt_enable
  • 函数原型:void spi_i2s_interrupt_enable(uint32_t spi_periph, uint32_t interrupt);
  • 功能解释:使能SPI/I2S的指定中断(如发送空中断、接收满中断、溢出中断等)。
  • 传入参数:
    • spi_periph:SPI/I2S外设基地址;
    • interrupt:中断类型(如SPI_INT_TXE:发送空中断;SPI_INT_RXNE:接收满中断)。
  • 传出参数:无。
(2)spi_i2s_interrupt_disable
  • 函数原型:void spi_i2s_interrupt_disable(uint32_t spi_periph, uint32_t interrupt);
  • 功能解释:禁用SPI/I2S的指定中断。
  • 传入参数:
    • spi_periph:SPI/I2S外设基地址;
    • interrupt:中断类型(SPI_INT_TXE/SPI_INT_RXNE等)。
  • 传出参数:无。

9. 中断标志查询/清除类函数

(1)spi_i2s_interrupt_flag_get
  • 函数原型:FlagStatus spi_i2s_interrupt_flag_get(uint32_t spi_periph, uint32_t int_flag);
  • 功能解释:查询SPI/I2S的指定中断标志位是否置位(触发中断的依据)。
  • 传入参数:
    • spi_periph:SPI/I2S外设基地址;
    • int_flag:中断标志位(如SPI_INT_FLAG_TXE:发送空中断标志;SPI_INT_FLAG_RXNE:接收满中断标志)。
  • 传出参数:
    • 返回值:FlagStatus枚举(SET:中断标志置位;RESET:中断标志清零)。
(2)spi_i2s_interrupt_flag_clear
  • 函数原型:void spi_i2s_interrupt_flag_clear(uint32_t spi_periph, uint32_t int_flag);
  • 功能解释:清除SPI/I2S的指定中断标志位(中断处理完成后需手动清除)。
  • 传入参数:
    • spi_periph:SPI/I2S外设基地址;
    • int_flag:待清除的中断标志位(如SPI_INT_FLAG_OVR:溢出中断标志)。
  • 传出参数:无。

留言