GD32 SPI 查询方式和DMA方式在全双模式下效率区别

news/2025/3/31 10:39:30/

最近在使用SPI的时候,遇到了一些数据传输效率问题,在此记录自己学习过程。SPI的基础知识这里就不在讲述了,直接分析SPI查询方式和DMA方式的效率问题。这里使用的芯片是GD32F303CC。

SPI以查询方式进行全双工通信

1.查询手册,SPI0挂载在APB2总线下,最高频率120MHZ。

2.接下来对SPI0进行配置

以下只是简化的配置内容,可以看出SPI0的CLK速率是3.75MHZ,还有一个注意的点MISO配置的是输入模式,而不是输出。

// SPI0 主机模式 使用软件SPI片选信号
/* SPI0 GPIO config:NSS/PA3, 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); // MOSI 浮空输入
/* PA3 as NSS */
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);/* 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_32;  //120M/32 = 3.75M
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI0, &spi_init_struct);
3.使用API函数进行数据的发送和接收,最后通过逻辑分析仪抓取时序图

发现SPI传输数据的过程中,SCK的时钟频率为3.703M符合我们设置的CLK频率,但是我们发现两个SPI的字节之间有一段SCK是空闲的,从逻辑分析仪上看时间高达1.95us,比SPI传输一个自字节的时间还长,在极大的影响了SPI的传输速率。其实这个空闲时间正是MCU在搬运SPI的数据。

到底是不是这么回事呢,我们提升SPI的SCK速率,来继续观察。

 这里我们把SPI的CLK速率提升到15Mhz,发现空闲状态的时间已经是传输数据的时间的好几倍了,且空闲状态的时间为1.87us(逻辑分析仪采样率不足导致),与1.95us接近。如果传输大量数据的话,使用查询的方式效率还是太低。

SPI以DMA进行全双工通信

1.查询SPI0的DMA相关信息 

DMA 功能在传输过程中将应用程序从数据读写过程中释放出来, 从而提高了系统效率。根据查询手册我们知道,SPI0的RX和TX分别挂载在DMA0的通道1和通道2下面。

2.接下来对SPI0进行配置

其他SPI的配置都和前面一致,只是新增了SPI DMA相关的配置。这里简短的贴上一部分代码:

void spi_dma_config(void)
{dma_parameter_struct dma_init_struct;/* SPI0 transmit dma config:DMA0-DMA_CH2  */dma_deinit(DMA0, DMA_CH2);dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI0);dma_init_struct.memory_addr = (uint32_t)spi0_send_array;dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;dma_init_struct.priority = DMA_PRIORITY_LOW;dma_init_struct.number = arraysize;dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;dma_init(DMA0, DMA_CH2, &dma_init_struct);/* configure DMA mode */dma_circulation_disable(DMA0, DMA_CH2);dma_memory_to_memory_disable(DMA0, DMA_CH2);/* SPI0 receive dma config:DMA0-DMA_CH1  */dma_deinit(DMA0, DMA_CH1);dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI0);dma_init_struct.memory_addr = (uint32_t)spi0_receive_array;dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;dma_init_struct.priority = DMA_PRIORITY_HIGH;dma_init(DMA0, DMA_CH1, &dma_init_struct);/* configure DMA mode */dma_circulation_disable(DMA0, DMA_CH1);dma_memory_to_memory_disable(DMA0, DMA_CH1);/* SPI1 transmit dma config:DMA0,DMA_CH4  */dma_deinit(DMA0, DMA_CH4);dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI1);dma_init_struct.memory_addr = (uint32_t)spi1_send_array;dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;dma_init_struct.priority = DMA_PRIORITY_MEDIUM;dma_init(DMA0, DMA_CH4, &dma_init_struct);/* configure DMA mode */dma_circulation_disable(DMA0, DMA_CH4);dma_memory_to_memory_disable(DMA0, DMA_CH4);/* SPI1 receive dma config:DMA0,DMA_CH3  */dma_deinit(DMA0, DMA_CH3);dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI1);dma_init_struct.memory_addr = (uint32_t)spi1_receive_array;dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;dma_init(DMA0, DMA_CH3, &dma_init_struct);/* configure DMA mode */dma_circulation_disable(DMA0, DMA_CH3);dma_memory_to_memory_disable(DMA0, DMA_CH3);
}
3.使用API函数进行数据的发送和接收,最后通过逻辑分析仪抓取时序图

从逻辑分析仪上可以看出,SPI使用DMA发送不会再出现两个字节之间CLK空余时间,极大的提升了SPI的传输速率。

防伪记录:文章原创于yl浪迹天涯。

总结

对于一般数据几个字节的传输,还是建议使用查询式(阻塞式)SPI,因为传输更加容易,DMA方式适合于高频次大容量数据传输的场景。比如在使用SPI 读取W25Q128芯片ID或者一般的操作指令的时候,就没有必要使用DMA方式了,但是在一次读取几个页的数据的时候,建议还是使用DMA方式。

附带源码

参考源码来源于GD32官网的GD32F30x_Firmware_Library_Vx.x.x库里面的Examples,具体代码直接去GD32官网下载即可。


http://www.ppmy.cn/news/555594.html

相关文章

模型评估 (Model Assessment)

1.模型评估 (Model Assessment) 笔记来源于《白话机器学习的数学》 我们训练好模型后,要对知道这个模型到底好不好,定量描述这个模型好坏就是模型评估 把获取的全部训练数据分成两份:一份用于测试,一份用于训练。然后用前者来评估…

UE4/5动画系列(2.怎么套模板)

目录 大象套模板 动画同步(这个在模板里面开同步): 速度限制: 穿墙问题: 在之前我们已经做了一个基础的模板了: UE4/5动画蓝图模板制作和套模板(1.模板制作)_多方通行8的博客-C…

如何给服务器重装系统时,安装Raid驱动

文章目录 **问题描述:****问题分析****解决办法** 问题描述: 前段时间给一台浪潮服务器重装windows server 2008R2系统时,发现一个问题——直接使用ISO安装系统时,在安装windows界面时会提示找不到驱动器 但是在PE里面又可以正常…

winpe加载raid_WinPE添加RAID驱动的步骤

如何为WinPE添加RAID卡的驱动?下面教你几招搞定。 1、先找到WinPE.IS_文件,直接将其改成WinPE.CAB,然后用WinRAR解压缩,会发现其实就是一个ISO,如:WINPE.ISO。 2、找到你的RAID卡的驱动,一般来说…

xpraid安装_在Win2003/XP安装光盘中集成RAID驱动 不用软驱装RAID/SATA/SAS驱动

――本文详尽,彻底,准确,可用!此项技术,本文足矣!请细致阅读。 ――本文以Windows 2003 SP2集成Intel S5000PSLSAS主板SAS RAID驱动为例讲解,但同样适合Windows XP等操作系统及其他RAID/SATA/SA…

RAID | 更新驱动

RAID | 更新驱动 背景 联想SR650服务器采用的RAID卡 Ubuntu16不支持且PXE装机环境也不支持,导致PXE无法自动装机,即使ISO挂载方式装Ubuntu16,也导致Ubuntu16无法开机挂载磁盘。 需要做如下2步: 先搞定PXE装机环境驱动,…

HP DL380 G5安装CentOS7找不到RAID驱动器问题解决方法

今天给机房的老服务器HP DL380 G5安装CentOS7.5的时候,进到安装界面后死活找不到RAID驱动器,Google查了一下,解决办法其实很简单:在安装程序启动前的引导菜单选择Install CentOS7后按tab键修改引导参数,在最后增加参数…

部分AMD RAID驱动程序需及时升级

微软在 Windows 10 Version 1903 正式版里已经为某些类别的驱动程序增加新的设备输入和设备输出要求。 这意味着硬件开发商必须更新这类驱动程序才能良好的兼容,而对于不兼容驱动程序微软也会自动阻止升级。 例如 AMD RAID V9.2.0.105 版及之前版本的驱动程序就无法…