SPI读写SD卡速度有多快?

SD卡是一个嵌入式中非常常用的外设,可以用于存储一些大容量的数据。但用单片机读写SD卡速度一般都有限(对于高速SD卡,主要是受限于单片机本身的接口速度),在高速、实时数据存储时可能会有影响。但具体速度可以达到多少呢,今天就来实际测试一下。

SD卡一般有两种常用的接口SPI和SDIO,SDIO又有1线和4线之分。很多单片机没有SDIO接口,但SPI接口就比较常用,今天主要来测试一下SPI接口读写SD卡的速度,主要是写入速度。

测试条件:

单片机:STM32L433CCT6

编译环境:MDK 5.30+HAL库

SD卡:32Gbit SDNAND,型号:米客方德MKDV32GCL-STH

文件系统:FatFS R0.12c

1.单纯SPI接口测试(非DMA)

我们知道,想SD卡之类的Flash存储器,一般都是按扇区擦除整块数据。因此每次写入字节数是扇区整数倍时,效率会比较高。同时,每次写入数据时,都需要先发送一些SD卡的指令,所以单次写入数据量越大,平均速度也就越快。了解了这些,我们就知道如何进行测试了。

首先,SD卡底层驱动使用的是HAL库函数,单字节读写,没有任何改动和优化:

uint8_tSPI_ReadWriteByte(uint8_t TxData)
{ 
    uint8_t RxData = 0;
    HAL_SPI_TransmitReceive(&hspi3,&TxData,&RxData,1,100);
    return RxData;
}

接下来,我们先确定SPI和时钟频率多少合适,经过测试,发现20MHz的时钟频率比较合适,10MHz时读写速度会降低,再高的时钟频率对速度的提升也很小。因此我们这里用20MHz的时钟。

然后我们分别测试单次写入4KB、8KB、16KB时的速度为多少,测试结果如下:

可以看到,单次写入数据量越大,平均速度就越快。当单次写入数据达到32KB时,速度提升不明显。而且一般单片机内部RAM缓存也有限,单次写入16KB是一个比较合适的选择。

看到这个不到100KB/S速度,我还是有的不敢相信的,毕竟20MHz的时钟,理论上速度可以达到2MB/S左右,考虑到一些文件系统等协议的消耗,能到1/3差不多,那也得600多KB,现在的速度差距有点大。

当然,这个使用的HAL库函数有关,HAL_SPI_TransmitReceive函数效率比较低,内部做了大量的判断等操作,而且单字节传输也严重影响效率。如果自己优化一下,相信效率会有很大的提升。有兴趣的小伙伴可以试试。我们这次其实主要是测试SPI+DMA的速度,所以就不在这里纠结了。

2.SPI+DMA接口测试

DMA可以在外设和内存之间搬运数据,而不需要CPU的参与。其优势在于大量数据传输时,比如SD卡读写、SPI接口的液晶屏刷屏等。如果只是读写几个字节的数据,比如一些SPI接口的AD、DA等,DMA的优势就不明显。

因为SPI接口的设备一般都不是纯数据传输,都要配合一些指令等。所以即使使用DMA,也是要等待DMA传输完成再进行其它操作。当然这期间CPU可以通过中断方式去处理一些其它事情。

SPI+DMA写数据函数如下,使用的也是HAL库,没有进行优化。


int8_t SD_WriteBuffer_DMA(const uint8_t *TxData, uint16_t Size)
{
  uint32_t i = 0;          // 循环变量

  SPI3_DMA_Flag = 0;
  SPI_TransmitReceive_DMA(&HSPI_TF, (uint8_t*)TxData, txrxdata, Size); 

  /* 等待DMA传输完成 */
  while (1)
  {
    if(SPI3_DMA_Flag == 1)
      break;
    i++;
    if (i > 0xFFFFFF)
    {
      return 1;  /* 超时退出 */
    }
  }
  return 0;
}

以向SD卡写数据为例,需要改为DMA的地方有2处:写命令和写扇区数据,因为这两处发送的字节数比较多。一些SD卡的起始、结束、应答等单字节的数据传输使用的还是非DMA方式传输。下面是部分程序:

我们进行了两种测试:只使能DMA写扇区数据,以及使能DMA写扇区数据和发送指令。都是按照单次写入16KB进行测试,测试结果如下:

可以看到,速度提升非常明显。数据和指令都用DMA传输时,速度最快。如果再进行一些底层函数的优化,速度还会有提升。

最后我们对读取速度也进行了测试,使用DMA方式,使能DMA读扇区数据和发送指令,测试结果如下,读取速度可以达到1.1MB~1.2MB/S。

3.总结

SPI+DMA的方式读写SD卡速度优势明显,推荐使用。当然,这跟非DMA方式的底层函数效率低下有很大的关系。

但DMA的另一个更重要的优势在于,读写数据时可以大部分释放CPU资源。比如我之前的一个应用,需要以1KHz的频率在外部中断中去读取一些数据,每次大约需要几十uS。如果使用非DMA方式,频繁的中断,且几十uS时间也不短,会导致SD卡写入出错。而使用DMA方式则不会有这个问题。

驱动程序:

https://download.csdn.net/download/zhang062061/87554323

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue2+高德地图web端开发使用

创建vue2项目我们创建一个vue2项目,创建vue2项目就不用再多说了吧,使用“vue create 项目名 ”创建即可注册高德地图高德地图官网地址:https://lbs.amap.com/如果是第一次使用,点击注册然后进入我们的控制台注册完之后进入控制台&…

<Linux>计算机体系结构和操作系统

计算机体系结构(冯 • 诺依曼体系)和操作系统(Operator System) 文章目录计算机体系结构(冯 • 诺依曼体系)和操作系统(Operator System)一、冯 • 诺依曼体系结构1.存储器(内存)2.运算器和控制器&#xff…

系统重装漏洞

zzcms系统重装漏洞 一、配置zzcms环境 1. 使用小皮搭建zzcms框架 2. 安装zzcms 按照下面的操作进行,傻瓜式操作即可 3. 打开网站 二、漏洞利用 在访问install目录的默认文件后,会出现zzcms安装向导 http://www.zzcms.com/install/index.php 但是会显示 “安装向导…

HTTPS,SSL(对称加密和非对称加密详解)

上一篇博客(HTTP详解_徐憨憨!的博客-CSDN博客)详细讲解了关于HTTP的知识,了解到HTTP协议下的数据传输是一种明文传输,既然是明文传输,可能导致在传输过程中出现一些被篡改的情况,此时就需要对所…

MATLAB | 给热图整点花哨操作(三角,树状图,分组图)

前段时间写的特殊热图绘制函数迎来大更新,基础使用教程可以看看这一篇: https://slandarer.blog.csdn.net/article/details/129292679 原本的绘图代码几乎完全不变,主要是增添了很多新的功能!!! 工具函数完…

【链表OJ题(六)】链表分割

​ ​📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:数据结构 🎯长路漫漫浩浩,万事皆有期待 文章目录链表OJ题(六)1. 链表…

燕山大学-面向对象程序设计实验-实验三 类和对象—构造函数与析构函数-实验报告

CSDN的各位友友们你们好,今天千泽为大家带来的是燕山大学-面向对象程序设计实验-实验三 类和对象—构造函数与析构函数,接下来让我们一起进入c的神奇小世界吧,相信看完你也能写出自己的 实验报告!如果对您有帮助的话希望能够得到您的支持和帮助,我会持续更新的!🚀3.…

硬刚ChatGPT!文心一言能否为百度止颓?

引言:近年来,人工智能领域的发展突飞猛进,尤其是在自然语言处理(NLP)方面。OpenAI的ChatGPT无疑是这个领域的佼佼者[1]。那么,面对这样一款高度智能的AI模型,国内市场上是否有相应的产品能与之抗…

你是真的“C”——指针进阶知识分享【上篇】

你是真的“C”——指针进阶知识分享【上篇】😎前言🙌指针初阶必备小知识~😊一. 字符指针😊二. 指针数组😊三、数组指针😊数组指针的定义😘四、 &数组名VS数组名😊总结撒花&#…

【K8S系列】从零开始学习 k8s:入门指南(二)

目录 序言 前情提要: 4.K8S架构 4.1 声明式系统VS命令式系统 4.2 k8s-声明式系统 4.2.1 声明方式-yaml 4.3 Kubernetes的基本概念 1.集群 2.节点 3.容器 4.Pod 5.Service 6.Deployment 问题: 4.4 K8S核心组件 4.4.1 kube-apiserver 4.4…

【Linux学习】进程间通信——system V(共享内存 | 消息队列 | 信号量)

🐱作者:一只大喵咪1201 🐱专栏:《Linux学习》 🔥格言:你只管努力,剩下的交给时间! 进程间通信——共享内存 | 消息队列 | 信号量🏀共享内存⚽系统调用shmgetkey值⚽系统…

提升Python代码性能的六个技巧

文章目录前言为什么要写本文?1、代码性能检测1.1、使用 timeit 库1.2、使用 memory_profiler 库1.3、使用 line_profiler 库2、使用内置函数和库3、使用内插字符串 f-string4、使用列表推导式5、使用 lru_cache 装饰器缓存数据6、针对循环结构的优化7、选择合适算法…

【WEB前端进阶之路】 HTML 全路线学习知识点梳理(下)

前言 本文是HTML零基础小白学习系列的第三篇文章,点此阅读 上一篇文章 文章目录前言十五.HTML布局1.使用div元素添加网页布局2.使用table元素添加网页布局十六.HTML表单和输入1.文本域2.密码字段3.单选按钮4.复选框5.提交按钮十七.HTML框架1.iframe语法2.iframe设置…

Windows电脑密码忘记解决方法

目录 背景 方法一 方法二 方法三 方法四 方法五 背景 个人电脑忘记了密码,无法登录用户界面。 方法一 1. 开机时常按 F11,如果是Win10一下系统,就常按 F8,知道出现一下图状 2. 选择疑难解答,再选择高级选项 3.…

Tomcat前端页面部署

一,Tomcat的安装1.Tomcat是什么Tomcat是一个HTTP服务器,HTTP协议是HTTP客户端和HTTP服务器之间交换数据的格式,我们可以通过ajax和Java Socket分别构造HTTP客户端,同时HTTP服务器也可以通过Java Socket来实现,而Tomcat…

React项目规范:目录结构、根目录别名、CSS重置、路由、redux、二次封装axios

React项目(一)一、创建项目二、目录结构三、craco配置别名并安装less1.craco安装2.配置别名3.安装less四、CSS样式重置五、配置路由六、配置Redux1.创建大仓库2.创建小仓库(1)方式1:RTK(2)方式2…

toString()、equals()是什么,为啥需要重写,多种方法来重写

https://m.runoob.com/java/java-object-class.html toString() 1.为什么会有toString 子类继承父类就可以使用父类所有非私有的属性的方法。 在Java中所有类都直接或者间接继承Object类,可以说只要是Object类里面定义的非私有的属性和方法,任何类都可…

Linux上如何使用Stable Diffusion WebUI

在我把所有的坑都踩了一遍之后,决定记录一下linux上的Stable Diffusion webui是怎么搞的。 前提条件 已安装CUDA 已安装git 已安装Anaconda 直接安装Anaconda不要指望Linux自带的Python。虽然Linux自带的Python,但是缺胳膊少腿,所以还是直接…

IntelliJ IDEA创建Servlet

目录 ——————————————————————————————— 一、创建Java项目 1、创建java项目 2、选择java 3、next 4、给项目命名 5、新创建完java项目的目录结构 二、变java为servlet项目 1、变servlet项目 2、选择Web Application 3、更新完成后的目录…

尚融宝04-mybatis-plus插件和条件构造器

目录 一、分页插件 1、添加配置类 2、添加分页插件 3、测试分页 二、XML自定义分页 1、UserMapper中定义接口方法 2、定义XML 3、测试 三、乐观锁 1、场景 2、乐观锁方案 3、乐观锁实现流程 4、优化流程 四、wapper介绍 1、Wrapper家族 2、创建测试类 五、Qu…