0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

【GD32 MCU 入门教程】GD32 MCU 常见外设介绍(8)SPI 模块介绍

聚沃科技 2024-08-17 09:36 次阅读

串行外设接口(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”的电平来实现的。

CKPL=0 时,SCK 引脚在空闲状态保持低电平;

CKPL=1 时,SCK 引脚在空闲状态保持高电平;

CKPH=0 时,SCK 时钟的第一个边沿进行采样;

CKPH =1 时,SCK 时钟的第二个边沿进行采样。

四种模式如下图SPI通讯模式所示:

输入图片说明

SPI 数据传输流程

前面我们了解了SPI协议的物理连接方式和SPI的具体协议和SPI的四种工作模式,下面我们从整体上分析一下SPI通信的流程。通过前面的内容可知,在一个SCK周期内,SPI会完成如下操作:

主机通过MOSI线发送1位数据,从机通过该线读取这1位数据。

从机通过MISO线发送1位数据,主机通过该线读取这1位数据。

这是通过移位寄存器来实现的。如下图所示,主机和从机各有一个移位寄存器,且二者连接成环。随着时钟脉冲,数据按照从高位到低位的方式依次移出主机寄存器和从机寄存器,并且依次移入从机寄存器和主机寄存器。当寄存器中的内容全部移出时,相当于完成了两个寄存器内容的交换。通信流程如图所示:

输入图片说明

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先行收发数据来分析一下通讯流程:

控制NSS信号线进入低电平,选中从器件发出通信开始信号;

检查“发送缓冲区”是否为空(SPI_STAT的TBE是否为1),如果为空,将所需要发送的数据写入“发送缓冲区”;

“发送缓冲区”里的数据一次性写入“移位寄存器”,一旦“发送缓冲区”里的数据写入“移位寄存器”SPI通信正式开始;

“移位寄存器”通过MOSI信号线从高位一位一位的发送到接收方,由于SPI的通信时全双工的,所以MOSI每发出一位MISO就接收一位存入移位寄存器;

直到一个数据单元发完(数据单元大小8位/16位可配置)。“移位寄存器”里接收回来的数据将一次性写入“接收缓冲区”,这时SPI_STAT的RBNE位将置1。也就是说“接收缓冲区”已有数 据。这时就可以读取数据了。

如果要发多组数据或者收多组数据,只需重复第2,3,4,5步。注意如果只收不发时,只需发送0xFF即可;

当所有数据都通信完成控制NSS信号进入高电平,通信正式结束。

各系列 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时钟。

void rcu_config(void) { #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_SPI0); #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X rcu_periph_clock_enable(RCU_AF); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X #endif #endif }

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片选信号拉高。

void gpio_config(void) { #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X /* SPI0 GPIO config:SCK/PA5, MISO/PA6, MOSI/PA7 */ gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7); gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6); /* PA3 as NSS */ gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X #if defined GD32F1X0 || GD32F3X0 || GD32E23X /* SPI0 GPIO config: SCK/PA5, MISO/PA6, MOSI/PA7 */ gpio_af_set(GPIOA, GPIO_AF_0, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7); #elif defined GD32F4XX gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7); #endif gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7); gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7); gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3); gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3); #endif SET_SPI0_NSS_HIGH }

SPI 外设配置

SPI外设配置如代码清单SPI例程SPI外设配置所示。GD32全系列MCU中SPI外设配置基本相同,在本例程中,SPI0作为主机全双工模式,GD32标准库提供了SPI初始化结构体及初始化函数来配置SPI外设,其初始化结构体说明如表 0-13 SPI初始化结构体说明列表所示,SPI初始化结构体填充完成后,调用spi_init函数进行SPI外设配置,配置完成后,调用spi_enable使能SPI外设。

void spi_config(void) { #if defined GD32F10X_HD|| GD32F30X_HD || GD32F1X0 || GD32F20X_CL || GD32F4XX || GD32F3X0 || GD32E10X || GD32E23X spi_parameter_struct spi_init_struct; /* SPI0 parameter config */ spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; spi_init_struct.device_mode = SPI_MASTER; spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT; spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE; spi_init_struct.nss = SPI_NSS_SOFT; spi_init_struct.prescale = SPI_PSC_256; spi_init_struct.endian = SPI_ENDIAN_MSB; spi_init(SPI0, &spi_init_struct); spi_enable(SPI0); #endif }

SPI 初始化结构体说明列表

输入图片说明

主函数说明

主函数如代码清单SPI例程主函数所示,该主函数主要分成四部分,RCU时钟配置、 GPIO 配置、SPI外设配置和while(1)主函数,前三部分已在前三小节介绍,在while(1)主循环中采用查询的方法循环发送SPI数据,单次循环数据填充完成后,查询RBNE和TRANS标志位判断数据发送 完成,然后拉高CS片选,完成单次循环发送。

int main(void) { /* peripheral clock enable */ rcu_config(); /* GPIO config */ gpio_config(); /* SPI config */ spi_config(); while(1) { SET_SPI0_NSS_LOW /* wait for transmit complete */ while(send_n < arraysize){ while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE)); spi_i2s_data_transmit(SPI0, spi0_send_array[send_n++]); } while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE)); while(RESET != spi_i2s_flag_get(SPI0, SPI_FLAG_TRANS)) {} SET_SPI0_NSS_HIGH send_n = 0; } }

运行结果

将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方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6019

    文章

    44339

    浏览量

    627886
  • mcu
    mcu
    +关注

    关注

    146

    文章

    16634

    浏览量

    347408
  • SPI
    SPI
    +关注

    关注

    17

    文章

    1661

    浏览量

    90625
收藏 人收藏

    评论

    相关推荐

    GD32 MCU 入门教程GD32 MCU 常见外设介绍(12)FMC 模块介绍

    闪存控制器(FMC),提供了片上闪存需要的所有功能。FMC 也提供了页擦除,整片擦除,以及32 位整字或 16 位半字编程闪存等操作。 GD32 MCU 支持不同类型编程的具体说明如下表 GD32
    的头像 发表于 08-21 09:56 627次阅读
    <b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>入门教程</b>】<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>常见外设</b><b class='flag-5'>介绍</b>(12)FMC <b class='flag-5'>模块</b><b class='flag-5'>介绍</b>

    GD32MCU介绍

    其实兆芯的MCU为了兼容ST,外设的寄存器设计与ST保持一致了。比如GD32VF103或者GD32E103系列的USBFS这个外设,基本等同
    发表于 11-01 06:03

    GD32 MCU原理及固件库开发指南》 + 初读感悟

    GD32 MCU原理固件库开发指南这本书内容丰富,囊括了GD32中的所有外设,书中首先介绍了如何使用MDK或IAR软件搭建
    发表于 03-31 22:11

    GD32 MCU原理及固件库开发指南》+读后感

    ,包括ADC和DAC。 第7章介绍GD32 MCU的基础通信外设,包括USART、I2C和SPI。 第8
    发表于 06-06 21:52

    GD32 MCU Dfu驱动64位Win8

    GD32 MCU Dfu驱动64位Win8
    发表于 10-08 14:55 0次下载

    兆易创新GD32 MCU选型手册,适用于GD32全系列MCU

    兆易创新GD32MCU选型手册,适用于GD32全系列MCUGD32MCU选型手册,适用于GD32全系列MCU
    发表于 10-19 17:26 48次下载

    你了解GD32 MCU的命名规则吗

    下面为大家介绍GD32 MCU的通用命名规则,以GD32F303ZGT6为例,其中,GD32代表GD32
    的头像 发表于 01-13 09:38 2997次阅读
    你了解<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b>的命名规则吗

    GD32 MCU的选项字节是什么?

    GD32 MCU的选项字节是什么,有什么功能呢?选项字节被误篡改如何回复?
    的头像 发表于 01-17 09:42 1008次阅读
    <b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b>的选项字节是什么?

    不同型号的GD32 MCU如何区分?

    大家是否碰到过以下应用场景:同一套软件代码希望跑在不同型号的GD32 MCU中,但有些地方需要根据MCU型号进行调整?或者上位机或其他MCUGD3
    的头像 发表于 01-27 09:32 778次阅读
    不同型号的<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b>如何区分?

    GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(1)使用Keil开发GD32

    GD32系列为通用型MCU,所以开发环境也可以使用通用型的IDE,目前使用较多的是KEIL、IAR、 GCC和Embedded Builder,客户可以根据个人喜好来选择相应的开发环境。
    的头像 发表于 08-08 15:01 472次阅读
    【<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>入门教程</b>】一、<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> 开发环境搭建(1)使用Keil开发<b class='flag-5'>GD32</b>

    GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(2)使用 IAR 开发 GD32

    GD32系列为通用型MCU,所以开发环境也可以使用通用型的IDE,目前使用较多的是KEIL、IAR、 GCC和Embedded Builder,客户可以根据个人喜好来选择相应的开发环境。
    的头像 发表于 08-08 15:40 320次阅读
    【<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>入门教程</b>】一、<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> 开发环境搭建(2)使用 IAR 开发 <b class='flag-5'>GD32</b>

    GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(3)使用 Embedded Builder 开发 GD32

    GD32系列为通用型MCU,所以开发环境也可以使用通用型的IDE,目前使用较多的是KEIL、IAR、 GCC和Embedded Builder,客户可以根据个人喜好来选择相应的开发环境。
    的头像 发表于 08-08 16:03 443次阅读
    【<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>入门教程</b>】一、<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> 开发环境搭建(3)使用 Embedded Builder 开发 <b class='flag-5'>GD32</b>

    GD32 MCU 入门教程GD32 MCU 常见外设介绍(14)RTC 模块介绍

    GD32 MCU内部提供了一个RTC(实时时钟)模块,通过RTC可以实现日历时钟、闹钟等功能。RTC也可以用于深度睡眠或待机模式的低功耗唤醒。不同系列的GD32
    的头像 发表于 08-23 09:18 181次阅读
    【<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>入门教程</b>】<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>常见外设</b><b class='flag-5'>介绍</b>(14)RTC <b class='flag-5'>模块</b><b class='flag-5'>介绍</b>

    GD32 MCU 入门教程GD32 MCU FPU 使用方法

    GD32 MCU FPU 使用方法
    的头像 发表于 08-25 09:24 175次阅读
    【<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>入门教程</b>】<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> FPU 使用方法

    GD32 MCU入门教程GD32 MCU GPIO 结构与使用注意事项

    本文是专门为基于GD32 MCU开发的工程设计人员提供,主要介绍了GPIO的功能配置、内部结构以及在不同场景使用时的注意事项,旨在帮助GD32 MC
    的头像 发表于 09-07 10:34 141次阅读
    【<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b><b class='flag-5'>入门教程</b>】<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> GPIO 结构与使用注意事项