四、GD32 MCU 常见外设介绍(8)SPI 模块介绍

news2024/9/28 5:26:51

串行外设接口(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 || 
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相关咨询:https://www.gd32bbs.com/ 

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

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

相关文章

Pytorch使用教学7-张量的广播

PyTorch中的张量具有和NumPy相同的广播特性&#xff0c;允许不同形状的张量之间进行计算。 广播的实质特性&#xff0c;其实是低维向量映射到高维之后&#xff0c;相同位置再进行相加。我们重点要学会的就是低维向量如何向高维向量进行映射。 相同形状的张量计算 虽然我们觉…

自动驾驶(八十八)---------通讯之SOMEIP

1. 什么是SOME/IP 服务导向架构&#xff08;SOA&#xff0c;Service-Oriented Architecture&#xff09;是一种设计软件系统的方法&#xff0c;强调通过可重用的服务来实现系统的松散耦合。每个服务是独立的功能单元&#xff0c;可以被不同的应用程序使用。这些服务通过标准化的…

新版海螺影视主题模板M3.1全解密版本多功能苹果CMSv10后台自适应主题

苹果CMS2022新版海螺影视主题M3.1版本&#xff0c;这个主题我挺喜欢的&#xff0c;之前也有朋友给我提供过原版主题&#xff0c;一直想要破解但是后来找了几个SG11解密的大哥都表示解密需要大几百大洋&#xff0c;所以一直被搁置了。这个版本是完全解密的&#xff0c;无需SG11加…

ADG901介绍

目录 一、特性二、增强产品特性三、应用四、一般描述五、极低功耗六、引脚描述七、尺寸参数八、电路连接 一、特性 宽带开关&#xff1a;-3 dB 在 4.5 GHz吸收型开关高关断隔离度&#xff1a;在 1 GHz 时为 38 dB低插入损耗&#xff1a;在 1 GHz 时为 0.8 dB单一 1.65 V 至 2.…

QT5:嵌入式linux开发板调用键盘

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录​​​​​​​ 前言 一、Buildroot构建QT环境 1.1 构建环境 1.2 检查qtvirtualkeyboard库 二、测试过程 2.1 直接调用qtvirtualkeyboard 1.测试代码 2.测试效果 2.2 运行…

【Unity国产化信创平台】麒麟银河V10系统虚拟机创建

目录 一、麒麟V10系统镜像下载 二、虚拟机创建流程 三、麒麟银河系统安装流程 一、麒麟V10系统镜像下载 https://www.kylinos.cn/# 官方访问还是会有问题&#xff0c;如果有需要麒麟银河Kylin系统V10的镜像文件&#xff0c;可以留下邮箱或者私信博主获取。 二、虚拟机创…

时间序列分析方法之 -- 移动平均(Moving Average)

目录 原理 适用情况 Python 示例代码 结论 原理 移动平均&#xff08;Moving Average, MA&#xff09;是一种常用的时间序列分析和数据平滑方法。其基本思想是通过取时间序列中某个时间窗口内数据的平均值来消除短期波动&#xff0c;从而更好地揭示数据的长期趋势。根据取平…

【Tomcat】Mac M3 Pro安装Tomcat7

文章目录 下载配置环境变量修改权限启动和关闭 下载 官网&#xff1a;https://tomcat.apache.org/ cd ~/Library tar -zxvf /Users/用户名/Downloads/apache-tomcat-7.0.99.tar.gz mv apache-tomcat-7.0.99 ~/Library/tomcat配置环境变量 vi ~/.bash_profileexport TOMCAT…

UWA Gears正式上线,助力移动平台性能优化

亲爱的开发者朋友们&#xff0c; 我们非常激动地向大家宣布&#xff0c;UWA最新的无SDK性能分析工具 - UWA Gears&#xff0c;现已正式发布&#xff01;无论您使用的是哪种开发引擎&#xff0c;这款工具都能轻松应对&#xff0c;为您的项目保驾护航。更令人心动的是&#xff0c…

vue3【实战】可编辑的脱敏信息

<script lang"ts" setup> import { ref, onMounted } from "vue"; let real_name ref("朝阳");let name ref("");onMounted(() > {name.value des_name(real_name.value); });function focusing() {name.value real_name…

spring —— 事务管理器

事务管理主要针对数据源进行操作&#xff1a;在数据库方面&#xff0c;通过 TransactionManager 事务管理器进行管理&#xff0c;表明一旦出现错误&#xff0c;该数据源的所有数据全部复原。那么数据库如何判断是否发生了错误呢&#xff1f;这就需要在代码方面&#xff0c;通过…

FPGA开发——实现流水灯的设计

一、概述 众所周知&#xff0c;在我们学习任何一款硬件&#xff0c;不管是单片机MCU&#xff0c;DSP以及其他的一系列硬件在内的最开始接触的都是LED流水灯的实现&#xff0c;这就和我们在学习编程时的输出“Hello World”一样&#xff0c;我们在学习FPGA的过程当中也是要从LE…

Webshell管理工具:AntSword(中国蚁剑)

中国蚁剑是一款开源的跨平台网站管理工具&#xff0c;它主要面向于合法授权的渗透测试安全人员以及进行常规操作的网站管理员。 通俗的讲&#xff1a;中国蚁剑是 一 款比菜刀还牛的shell控制端软件。 一、中国蚁剑下载 1. 下载 AntSword-Loader https://github.com/AntSwordP…

MySQL窗口函数详解

MySQL窗口函数详解 MySQL从8.0版本开始引入了窗口函数&#xff0c;这是一个强大的特性&#xff0c;可以大大简化复杂的数据分析任务。本文将详细介绍MySQL窗口函数的概念、语法和常见用法&#xff0c;并结合实际应用场景进行说明。 什么是窗口函数? 窗口函数是一种能够对结…

单元测试的最佳实践

整体架构 合适的架构可以提升可测试性。比如菱形对称架构的模块化和解耦特性使得系统各个部分可以独立进行单元测试。这不仅提高了测试的效率&#xff0c;还能够减少测试的依赖性&#xff0c;提高测试准确性。 代码设计 代码设计和可测试性有密切关联。强烈建议一个方法的代码行…

Java面试八股之什么是spring boot starter

什么是spring boot starter Spring Boot Starter是Spring Boot项目中的一个重要概念。它是一种依赖管理机制&#xff0c;用于简化Maven或Gradle配置文件中的依赖项声明。Spring Boot Starter提供了一组预定义的依赖关系&#xff0c;这些依赖关系被封装在一个单一的包中&#x…

CC-Link转Profinet协议网关功能与配置详解

怎么样才能把CC-Link和Profinet网络连接起来呢?这几天有几个朋友问到了这个问题&#xff0c;作者在这里统一为大家详细说明一下。其实有一个设备可以很轻松地解决这个问题&#xff0c;名为JM-PN-CCLK&#xff0c;下面是详细介绍。 一&#xff0c;产品主要功能 1、捷米特JM-P…

go语言学习文档精简版

Go语言是一门开源的编程语言&#xff0c;目的在于降低构建简单、可靠、高效软件的门槛。Go平衡了底层系统语言的能力&#xff0c;以及在现代语言中所见到的高级特性。 你好&#xff0c;Go package main // 程序组织成包import "fmt" // fmt包用于格式化输出数据// …

【C++_list】理解链表!实现链表!成为链表!!

List 1. list的介绍及使用2. list的模拟1&#xff09;大致了解List框架2&#xff09;模拟实现List操作3&#xff09;关于const迭代器的问题&#xff08;重点&#xff09;4&#xff09;关于链表拷贝的问题 1. list的介绍及使用 下面会给出list的文档介绍官网&#xff0c;也是本博…

Vue常用指令及其生命周期

作者&#xff1a;CSDN-PleaSure乐事 欢迎大家阅读我的博客 希望大家喜欢 目录 1.常用指令 1.1 v-bind 1.2 v-model 注意事项 1.3 v-on 注意事项 1.4 v-if / v-else-if / v-else 1.5 v-show 1.6 v-for 无索引 有索引 生命周期 定义 流程 1.常用指令 Vue当中的指令…