IT评测·应用市场-qidao123.com

标题: 四、GD32 MCU 常见外设介绍(8)SPI 模块介绍 [打印本页]

作者: 勿忘初心做自己    时间: 2024-7-29 20:14
标题: 四、GD32 MCU 常见外设介绍(8)SPI 模块介绍
串行外设接口(Serial Peripheral Interface,缩写为 SPI) 提供了基于SPI 协议的数据发送和接收功能, 可以工作于主机或从机模式。 SPI 接口支持具有硬件 CRC 盘算和校验的全双工和单工模式。
8.1.SPI 底子知识

SPI 物理层

SPI接口接纳主从模式(Master Slave)架构;支持一主一从模式和一主多从模式,但不支持多主模式。它是一种同步高速全双工的通信总线,总体布局如下图常见的SPI通讯体系所示。

一个主机连接四个从机,此中一个SPI总线一样平常有四个信号分为:
SCLK:时钟信号,由主机产生并控制。
MOSI:主机数据输出,从机数据输入。
MISO:主机数据输入,从机数据输出。
SS/NSS:从机片选使能信号,由主机控制。在一主对多从的模式下,每一个从机都需要独占一个SS,也就是说有多少个从机就有多少个片选信号。
SPI 协议层

SPI的协议界说了通信的起始信号、克制信号、数据有效性、时钟同步等环节。下面我们分析一下两个设备通过SPI总线通信的过程,SPI通信时序图如下图通讯时序所示:
SPI 通讯时序

这个是一个主机的通信时序,信号线 NSS、SCK、MOSI 都是由主机控制,MISO 是由从机举行控制。此中 MOSI 和 MISO 上的数据仅在 NSS 为低时才有效,而且每个SCK 时钟周期只互换一位数据。
起始信号和克制信号:如_SPI通讯时序图_中①和⑥分别表现通信的起始和结束,这些信号的产生是通过主机将片选信号(NSS)置低和置高实现的。NSS 除了是开始和结束信号的产生者,它也是主机和从机通信的选择者,当一个主机对多个从机通信时,主机通过置低从机的 NSS 信号线来选择与哪个从机举行通信。
时钟同步:SPI 总线是一个同步全双工的通信总线,以是 SPI 的数据传输是需要 SCK 时钟信号严酷同步的,每一个 SCK 周期只传输一位数据,这一个周期里要完成数据的准备和采样,且数据的输入和输出是同时举行的。MSB 先行或 LSB先行协议中是没有硬性规定,只需通信两边保持统一即可。SPI 每次数据传输可以是 8 位或 16 位为单元,每次传输的单元数不受限制。
数据有效性:SPI 在 SCK 时钟的同步下举行数据的准备和采样,过程如图 1-2 的②③④⑤所示。在 NSS 为低的环境时,在 SCK 的上升沿时 MISO 和 MOSI 举行数据准备,SCK 的下降沿时读取 MISO 和 MOSI 上的数据。在 NSS 为高时,MISO 和MOSI 上的数据无效。
SPI 工作模式:如_SPI通讯时序图_只是 SPI 的一种工作模式,SPI 一共有四种工作模式。他们的区别是总线空闲时 SCK 的电平状态和数据采样时候。这四种模式的配置是通过配置“时钟极 性 CKPL”和“时钟相位 CKPH”的电平来实现的。
四种模式如下图SPI通讯模式所示:

SPI 数据传输流程

前面我们相识了SPI协议的物理连接方式和SPI的详细协议和SPI的四种工作模式,下面我们从整体上分析一下SPI通信的流程。通过前面的内容可知,在一个SCK周期内,SPI会完成如下操作:
这是通过移位寄存器来实现的。如下图所示,主机和从机各有一个移位寄存器,且二者连接成环。随着时钟脉冲,数据按照从高位到低位的方式依次移出主机寄存器和从机寄存器,而且依次移入从机寄存器和主机寄存器。当寄存器中的内容全部移出时,相当于完成了两个寄存器内容的互换。通信流程如图所示:
 

8.2.GD32 SPI 外设原理简介

因篇幅有限,本文无法详细介绍GD32全部系列SPI外设接口,下面以GD32F30x为列,着重介绍下GD32F30x的SPI外设简介和布局框图,后介绍下各个系列的差异。
GD32 SPI 主要特性
◼ 具有全双工和单工模式的主从操作;
◼ 16位宽度,独立的发送和接收缓冲区;
◼ 8位或16位数据帧格式;
◼ 低位在前或高位在前的数据位次序;
◼ 软件和硬件NSS管理;
◼ 硬件CRC盘算、发送和校验;
◼ 发送和接收支持DMA模式;
◼ 支持SPI TI模式;
◼ 支持SPI NSS脉冲模式;
◼ 支持SPI四线功能的主机模式(仅在SPI0中)。
GD32的SPI外设还支持I2S功能,I2S功能是一种音频串行通讯协议,如果需要学习请参考各个系列的User_Manual,本文不做过多的介绍。
SPI 布局框图介绍

SPI 通讯模式
 

通讯引脚:如_SPI通讯模式图_的①所示,GD32硬件接口SCK、NSS、MOSI、MISO为尺度的SPI协议的四条信号线;IO2、IO3为GD32的SPI四线模式利用到的引脚,分别为:发送或接收数据2线和3线(在GD32F30x中仅SPI0支持四线主机模式)。各个系列的SPI个数不同,SPI接口和芯片I/O口的对应关系,可查阅各个系列的Datasheet。
时钟天生器:如_SPI通讯模式图_的②所示,SCK线的时钟信号,是由波特率发生器根据“控制寄存器0(SPI_CTL0)”中的PSC[2:0]位控制的。详细分频选择如下
000:PCLK/2 100:PCLK/32
001:PCLK/4 101:PCLK/64
010:PCLK/8 110:PCLK/128
011:PCLK/16 111:PCLK/256
当利用SPI0时,PCLK=PCLK2,当利用SPI1和SPI2时,PCLK=PCLK1。
数据通讯单元:如_SPI通讯模式图_的③所示,SPI的MOSI及MISO都连接到数据移位寄存器上,数据移位寄存器的数据泉源及目标接收、发送缓冲区以及MISO、MOSI线。当向外发送数据的时候,数据移位寄存器以“发送缓冲区”为数据源,把数据一位一位地通过数据线发送出去;当从外部接收数据的时候,数据移位寄存器把数据线采样到的数据一位一位地存储到“接收缓冲区”中。
通过写SPI的“数据寄存器(SPI_DATA)”把数据填充到发送缓冲区中,通讯读“数据寄存器(SPI_DATA)”,可以获取接收缓冲区中的内容。此中数据帧长度可以通过“控制寄存器0(SPI_CTL0)”的“FF16位”配置成8位及16位模式;配置“LF位”可选择MSB先行还是LSB先行。
下面以SPI作为主机MSB先行收发数据来分析一下通讯流程:
各系列 SPI 功能差异
GD32系列MCU有关SPI外设各系列功能差异如下表所示

8.3.硬件连接说明

SPI 串行 Flash 硬件连接图

如图所示,为典范的SPI外设硬件连接图:GD25Q40是一种利用 SPI通讯协议的NOR FLASH存储器,它的CS/SCLK/SI/SO引脚分别连接到了GD32对应的SPI引脚NSS/SCK/MOSI/MISO上,此中GD32的NSS引脚是一个平凡的GPIO,不是SPI的专用NSS引脚,以是程序中我们要利用软件控制的方式。若硬件计划中为SPI_NSS可以程序里可以配置为硬件控制方式。
读者可以根据典范硬件连接图和相应系列的Datasheet计划出自己的硬件连接方式。
8.4.软件配置说明

本末节讲解SPI_Example进程中SPI模块的配置说明,主要包括外设时钟配置、GPIO引脚配置、SPI外设配置、主函数介绍以及运行效果。本例程主要介绍GD32 MCU各系列SPI0模块的数据发送,有关SPI其他功能例程可参考各系列固件库例程。
外设时钟配置

外设时钟配置如代码清单例程时钟配置所示,在GD32全系列MCU中需打开GPIOA和SPI0的时钟,由于利用到PA3/PA5/PA7引脚以及SPI0模块,另外,在GD32F10X、GD32F20X、GD32F30X、GD32E10X中需要打开AF时钟。
  1. void rcu_config(void)
  2. {
  3. #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F4XX || GD32F3X0 ||
  4. GD32E23X
  5. rcu_periph_clock_enable(RCU_GPIOA);
  6. rcu_periph_clock_enable(RCU_SPI0);
  7. #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X
  8. rcu_periph_clock_enable(RCU_AF);
  9. #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X
  10. #endif
  11. #endif
  12. }
复制代码
GPIO 引脚配置

GPIO引脚配置如代码清单SPI例程GPIO引脚配置所示,GD32F10X、GD32F30X、GD32F20X、GD32E10X系列GPIO配置雷同,PA5、PA7需配置为复用推挽输出、PA6需配置为浮空输入、PA3作为片选控制引脚配置为推挽输出模式;GD32F1X0、GD32F4XX、GD32F3X0、 GD32E23X系列GPIO配置基本雷同,不同在于PA5/PA6/PA7引脚的AF复用功能配置不同,在GD32F1X0、GD32F3X0和GD32E23X上,需要配置为AF0模式,在GD32F4XX上需要配置为AF5模式。GPIO配置完成后,例程中将CS片选信号拉高。
  1. void gpio_config(void)
  2. {
  3. #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X
  4. /* SPI0 GPIO config:SCK/PA5, MISO/PA6, MOSI/PA7 */
  5. gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
  6. gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
  7. /* PA3 as NSS */
  8. gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
  9. #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X
  10. #if defined GD32F1X0 || GD32F3X0 || GD32E23X
  11. /* SPI0 GPIO config: SCK/PA5, MISO/PA6, MOSI/PA7 */
  12. gpio_af_set(GPIOA, GPIO_AF_0, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
  13. #elif defined GD32F4XX
  14. gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
  15. #endif
  16. gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
  17. gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
  18. gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
  19. gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
  20. #endif
  21. SET_SPI0_NSS_HIGH
  22. }
复制代码
SPI 外设配置

SPI外设配置如代码清单SPI例程SPI外设配置所示。GD32全系列MCU中SPI外设配置基本雷同,在本例程中,SPI0作为主机全双工模式,GD32尺度库提供了SPI初始化布局体及初始化函数来配置SPI外设,其初始化布局体说明如表 0-13 SPI初始化布局体说明列表所示,SPI初始化布局体填充完成后,调用spi_init函数举行SPI外设配置,配置完成后,调用spi_enable使能SPI外设。
  1. void spi_config(void)
  2. {
  3. #if defined GD32F10X_HD|| GD32F30X_HD || GD32F1X0 || GD32F20X_CL || GD32F4XX || GD32F3X0 || GD32E10X ||
  4. GD32E23X
  5. spi_parameter_struct spi_init_struct;
  6. /* SPI0 parameter config */
  7. spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
  8. spi_init_struct.device_mode = SPI_MASTER;
  9. spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
  10. spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
  11. spi_init_struct.nss = SPI_NSS_SOFT;
  12. spi_init_struct.prescale = SPI_PSC_256;
  13. spi_init_struct.endian = SPI_ENDIAN_MSB;
  14. spi_init(SPI0, &spi_init_struct);
  15. spi_enable(SPI0);
  16. #endif
  17. }
复制代码
SPI 初始化布局体说明列表

主函数说明 

主函数如代码清单SPI例程主函数所示,该主函数主要分成四部门,RCU时钟配置、 GPIO 配置、SPI外设配置和while(1)主函数,前三部门已在前三末节介绍,在while(1)主循环中接纳查询的方法循环发送SPI数据,单次循环数据填充完成后,查询RBNE和TRANS标记位判定命据发送 完成,然后拉高CS片选,完成单次循环发送。 
  1. int main(void)
  2. {
  3. /* peripheral clock enable */
  4. rcu_config();
  5. /* GPIO config */
  6. gpio_config();
  7. /* SPI config */
  8. spi_config();
  9. while(1)
  10. {
  11. SET_SPI0_NSS_LOW
  12. /* wait for transmit complete */
  13. while(send_n < arraysize){
  14. while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE));
  15. spi_i2s_data_transmit(SPI0, spi0_send_array[send_n++]);
  16. }
  17. while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE));
  18. while(RESET != spi_i2s_flag_get(SPI0, SPI_FLAG_TRANS))
  19. {}
  20. SET_SPI0_NSS_HIGH
  21. send_n = 0;
  22. }
  23. }
复制代码
运行效果

将SPI_Example例程按照对应的芯片工程编译完成后,下载到对应芯片中,接纳示波器或者逻辑分析仪查看SPI_CS、SPI_CLK、SPI_MOSI引脚波形,如下图SPI发送逻辑分析仪抓取波形图所示,通过协议解析后,SPI数据发送正确。

8.5.SPI 利用注意事项

(1) 在切换SPI时钟前要关闭SPI,切换完成后再使能SPI。
(2) 在接纳SPI发送数据时,发送buf空标记TBE置位,并不代表数据发送完成,仅代表数据从发送数据寄存器移到发送移位寄存器中,如果通过查询TBE标记来拉高CS片选,由于GD32系列MCU代码执行服从较高,当发送速率较低时可能会出现当TBE置位时,拉高CS片选,此时数据还未完成发送,造成从机接受数据堕落。可以通过查询接收数据寄存器非空RBNE和TRANS标记位来判定命据发送完成,然后再拉高CS片选。
(3) SPI的MISO管脚需配置为浮空输入模式,否则有可能数据接收异常。

本章内容逐日连续更新,如有爱好,请关注收藏
更多GD32 MCU相干咨询:https://www.gd32bbs.com/ 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4