四、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”的电平来实现的。

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

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

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

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

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

SPI 数据传输流程

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

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

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

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

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

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

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

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

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

  7. 当所有数据都通信完成控制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 || 
GD32E23Xrcu_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 GD32F4XXgpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
#endifgpio_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 || 
GD32E23Xspi_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_HIGHsend_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相关咨询:https://www.gd32bbs.com/ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3266535.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【Three.js基础学习】17.imported-models

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 课程回顾&#xff1a; 如何在three.js 中引入不同的模型&#xff1f; 1. 格式 &#xff08;不同的格式&#xff09; https://en.wikipedia.org/wiki/List_of_file_form…

UART编程框架详解

1. UART介绍 UART&#xff1a;通用异步收发传输器&#xff08;Universal Asynchronous Receiver/Transmitter)&#xff0c;简称串口。 调试&#xff1a;移植u-boot、内核时&#xff0c;主要使用串口查看打印信息 外接各种模块 1.1 硬件知识_UART硬件介绍 UART的全称是Unive…

Unity UGUI 之 事件接口

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 本文在发布时间选用unity 2022.3.8稳定版本&#xff0c;请注意分别 1.什么是事件接口&…

找实习,三本计算机 > 985文科 ?

2018年3月&#xff0c;大三下学期。 写了一段时间博客以后&#xff0c;竟有人说要内推我。 我说我大三&#xff0c;还没毕业&#xff0c;准备暑假去找实习。 网上认识的朋友建议我去春招实习试试&#xff0c;还有些厂在走流程中&#xff0c;还有机会。 我婉拒了&#xff0c…

Centos 8 配置网络源

备份当前的软件源配置文件&#xff1a; sudo cp -a /etc/yum.repos.d /etc/yum.repos.d.bak 清理原有的 yum 仓库配置信息&#xff1a; sudo rm -f /etc/yum.repos.d/*.repo 获取阿里云的 CentOS 8 源配置&#xff1a; sudo curl -o /etc/yum.repos.d/CentOS-Base.repo ht…

Shell编程之正则表达式与文本处理器2--sed

目录 一、sed 工具 1. 概述 2. sed 原理 3、常用操作选项 3.1 常用选项 3.2 操作命令 4. sed 的使用 5. 具体操作 5.1 打印输出 p 5.1.1 显示范围、单行、指定行输出、指定往后加几行输出 5.1.2 显示奇偶行 5.1.3 将指定内容的行打印出来 5.1.4 只输出行号…

《python程序语言设计》第6章12题 显示字符,使用下面的函数头,编写一个打印字符的函数

def printChars(ch1, ch2, numberPerLine):a ord(ch1)b ord(ch2)count 0for i in range(a, b 1):count 1print(chr(i), end" ")if count % numberPerLine 0:print()printChars("1", "Z", 10)

UDP/TCP协议解析

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

FTTransformer,一个很能打的模型

FTTransformer&#xff0c;是一个BERT模型架构在结构化数据集上的迁移变体。和BERT一样&#xff0c;它非常能打。 它可能是少数能够在大多数结构化数据集上取得超过或者匹配LightGBM结果的深度模型。 本范例我们将应用它在来对Covertype植被覆盖数据集进行一个多分类任务。 我们…

k8s通过应用修改yaml文件修改容器时区

通过挂载&#xff0c;把本地的/etc/localtime挂载到容器中&#xff1a; apiVersion: apps/v1 kind: Deployment metadata:name: seb-algorithmsnamespace: jiaoda spec:replicas: 1selector:matchLabels:app: seb-algorithmstemplate:metadata:labels:app: seb-algorithmsspec…

虚幻引擎(Unreal Engine)深入探索与应用实践

目录 引言 虚幻引擎基础 引擎概述 核心组件 安装与配置 准备工作 安装步骤 常见问题 应用实践 游戏开发 影视特效 数字孪生 虚幻引擎中的C示例 如何在虚幻引擎中使用C代码 引言 虚幻引擎&#xff08;Unreal Engine&#xff0c;简称UE&#xff09;作为目前游戏开…

Ruoyi-WMS部署

所需软件 1、JDK&#xff1a;8 安装包&#xff1a;https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.htmlopen in new window 安装文档&#xff1a;https://cloud.tencent.com/developer/article/1698454open in new window 2、Redis 3.0 安装包&a…

ZStack Cloud 5.1.8正式发布——GPU运维、物理机硬件监控、克隆云主机网络配置三大亮点简析

云轴科技ZStack Cloud云平台是遵循“简单、弹性、健壮、智能”的“4S”特性的私有云和无缝混合云产品。ZStack Cloud 5.1.8版本正式发布&#xff0c;从用户业务场景和实际需求出发&#xff0c;丰富和完善平台功能&#xff0c;推出一系列重要功能和多项改进&#xff0c;覆盖云主…

Oracle集群RAC磁盘管理命令asmcmd的使用

文章目录 ASM磁盘共享简介ASM磁盘共享的优势ASM磁盘组成ASM磁盘共享的应用场景Asmcmd简介Asmcmd的功能Asmcmd的命令Asmcmd的使用注意事项Asmcmd运行模式交互模式运行非交互模式运行ASMCMD命令分类实例管理命令:文件管理命令:磁盘组管理命令:模板管理命令:文件访问管理命令:…

产线工控安全新纪元:主机加固与防勒索病毒双剑合璧

在这个数字时代&#xff0c;企业面临的最大挑战之一就是如何确保数据的安全。随着勒索病毒等恶意软件的不断进化&#xff0c;传统的安全措施已经难以应对这些新型威胁。深信达公司的MCK主机加固系统&#xff0c;以其独特的内核级签名校验技术和深度学习驱动的业务场景白名单策略…

SpringMVC中的常用注解

目录 SpringMVC的定义 SpringMVC的常用注解 获取Cookie和Session SpringMVC的定义 Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc)&#xff0c;但它…

[k8s源码]5.自己写一个informer控制器

k8s的informer控制器有一个informer&#xff0c;有一个indexer&#xff0c;还需要一个队列来存储从kubernetes API获取的信息。 初始化自己的informer的结构 type Controller struct {indexer cache.Indexerinformer cache.Controllerqueue workqueue.RateLimitingInterf…

C#基础——类

类 类是一个数据类型的蓝图。构成类的方法和变量称为类的成员&#xff0c;对象是类的实例。类的定义规定了类的对象由什么组成及在这个对象上可执行什么操作。 class 类名 { (访问属性) 成员变量; (访问属性) 成员函数; } 访问属性&#xff1a;public&#xff08;公有的&…

Python的mouse库防止计算机进入睡眠状态或锁定屏幕

目录 引言 安装 mouse 库 实现步骤 代码解析 注意事项 引言 在工作或娱乐过程中,我们有时会遇到计算机进入睡眠状态或锁定屏幕的情况,这会打断我们的任务.通过编写一个小程序,可以自动移动鼠标,从而防止计算机进入睡眠状态或锁定屏幕.本文将介绍如何使用 Python 的 mouse…

ElasticSearch(四)— 数据检索与查询

一、基本查询语法 所有的 REST 搜索请求使用_search 接口&#xff0c;既可以是 GET 请求&#xff0c;也可以是 POST请求&#xff0c;也可以通过在搜索 URL 中指定索引来限制范围。 _search 接口有两种请求方法&#xff0c;一种是基于 URI 的请求方式&#xff0c;另一种是基于…