首页 > 其他分享 >ESP32的SPI外设(SPI HSPI VSPI)

ESP32的SPI外设(SPI HSPI VSPI)

时间:2023-12-14 12:12:04浏览次数:45  
标签:VSPI 引脚 ESP32 spi SPI num HSPI

ESP32的SPI外设(SPI HSPI VSPI)

ESP32 SPI简介

参考文档:ESP32技术参考手册

ESP32的SPI一共有4个,分别为SPI0、SPI1、SPI2、SPI3。如下图所示:

imag1

其中SPI0SPI1通过一个仲裁器共用一组信号总线,这组信号总线前缀带有SPI,主要用于访问外部存储单元和DMA操作。所以SPI信号总线不是提供给用户使用的。

SPI2SPI3分别使用带HSPI前缀和带VSPI前缀的信号总线。这两个控制器可以供用户使用。这两组SPI控制器器既可作为主机使用又可作为从机使用。当SPI控制器作为主机时,每个控制器都有CS0、CS1、CS2 3个片选信号,可以连接多个SPI从机。

下图分别为SPI、HSPI、VSPI的信号总线名称:
imag2

在Arduino中使用SPI

在Arduino中,可以使用SPI.h库来使用SPI外设。

SPI.cpp源文件的最后面定义了SPIClass对象SPI

#if CONFIG_IDF_TARGET_ESP32
SPIClass SPI(VSPI);
#else
SPIClass SPI(FSPI);
#endif

sdkconfig.h头文件中可以查看到已经定义了#define CONFIG_IDF_TARGET_ESP32 1,所以是使用VSPI定义了SPI对象。

esp32-hal-spi.h文件中可以找到如下代码,这里定义了FSPI、HSPI、VSPI的宏定义,分别为1、2、3。

#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
#define FSPI  0
#define HSPI  1
#else
#define FSPI  1 //SPI bus attached to the flash (can use the same data lines but different SS)
#define HSPI  2 //SPI bus normally mapped to pins 12 - 15, but can be matrixed to any pins
#if CONFIG_IDF_TARGET_ESP32
#define VSPI  3 //SPI bus normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins
#endif
#endif

SPI.cpp文件中定义了SPIClass类,在创建SPI对象时,传入了VSPI(3),也就是说将该类中的成员变量_spi_num赋值为了3。
然后,初始化SPI需要调用begin函数,在该函数中,使用了spiStartBus函数创建了_spi结构体,意味着_spi使用的是VSPI的控制器。

SPIClass::SPIClass(uint8_t spi_bus)
    :_spi_num(spi_bus)
    ,_spi(NULL)
    ,_use_hw_ss(false)
    ,_sck(-1)
    ,_miso(-1)
    ,_mosi(-1)
    ,_ss(-1)
    ,_div(0)
    ,_freq(1000000)
    ,_inTransaction(false)

......

void SPIClass::begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
{
    if(_spi) {
        return;
    }

    if(!_div) {
        _div = spiFrequencyToClockDiv(_freq);
    }

    _spi = spiStartBus(_spi_num, _div, SPI_MODE0, SPI_MSBFIRST);
    if(!_spi) {
        return;
    }

    if(sck == -1 && miso == -1 && mosi == -1 && ss == -1) {
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
        _sck = (_spi_num == FSPI) ? SCK : -1;
        _miso = (_spi_num == FSPI) ? MISO : -1;
        _mosi = (_spi_num == FSPI) ? MOSI : -1;
        _ss = (_spi_num == FSPI) ? SS : -1;
#elif CONFIG_IDF_TARGET_ESP32C3
        _sck = SCK;
        _miso = MISO;
        _mosi = MOSI;
        _ss = SS;
#else
        _sck = (_spi_num == VSPI) ? SCK : 14;
        _miso = (_spi_num == VSPI) ? MISO : 12;
        _mosi = (_spi_num == VSPI) ? MOSI : 13;
        _ss = (_spi_num == VSPI) ? SS : 15;
#endif
    } else {
        _sck = sck;
        _miso = miso;
        _mosi = mosi;
        _ss = ss;
    }

    spiAttachSCK(_spi, _sck);
    spiAttachMISO(_spi, _miso);
    spiAttachMOSI(_spi, _mosi);

}

begin函数中可以指定SPI所使用的引脚sck、miso、mosi、ss(在ESP32中,大部分外设可以指定在任意IO引脚上)。如果没有指定,默认为-1,代表着使用默认引脚。

可以看到,如果_spi_num为VSPI(3),则默认引脚使用SCK、MISO、MOSI、SS,这些引脚在pin_arduino.h头文件中定义为了如下所示的IO引脚。

static const uint8_t SS    = 5;
static const uint8_t MOSI  = 23;
static const uint8_t MISO  = 19;
static const uint8_t SCK   = 18;

而如果_spi_num为HSPI(2),则默认引脚使用SCK(14)、MISO(12)、MOSI(13)、SS(15)。

如果指定了引脚,则会将SPI的总线映射在所指定的引脚上。

以上介绍的都是如何使用已经定义好的SPI。如果用户自定义了另外一个SPIClass对象,而且没有指定spi_bus,则默认会使用HSPI。相关代码在SPI.h中,如下所示:

SPIClass(uint8_t spi_bus=HSPI);

示例

下面介绍一下如何在Arduino中完整的使用自定义SPI:

#define MY_CS   32
#define MY_SCK  14
#define MY_MOSI 13
#define MY_MISO 12 //自定义spi引脚
SPIClass my_spi(HSPI);  //创建SPIClass对象my_spi

my_spi.begin(MY_SCK, MY_MISO, MY_MOSI, MY_CS);  //初始化,并绑定引脚
spiAttachSS(my_spi.bus(), 0, MY_CS);            //绑定cs引脚
my_spi.setFrequency(18000000);                  //设置频率,18MHz
my_spi.setBitOrder(SPI_MSBFIRST);               //设置高位bit先传输
my_spi.setDataMode(SPI_MODE1);                  //设置spi模式

标签:VSPI,引脚,ESP32,spi,SPI,num,HSPI
From: https://www.cnblogs.com/haostudio/p/17900928.html

相关文章

  • Unity升级到2022版本后,打开Spine会卡住
    1)Unity升级到2022版本后,打开Spine会卡住2)iPhone在同时播放多个音效的时候会压低某些音源的音量3)在Y77手机上出现IMGSRV:GetMainShaderConstantBufferBaseAddress:Unsupported4)UE4打包后在部分安卓机型出现“花屏”这是第364篇UWA技术知识分享的推送,精选了UWA社区的热门话题,涵盖......
  • C++ Qt开发:SpinBox数值微调框组件
    Qt是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QSpinBox精度数值组件的常用方法及灵活运用。QSpinBox是Qt框架中的一个部件(Widget),用于提供一个方......
  • SPI通信协议总结
    我们将讨论最常见协议的基础:串行外设接口(SerialPeripheralInterface,SPI)SPI,I2C和UART比USB,以太网,蓝牙和WiFi等协议要慢很多,但它们更简单,使用的硬件和系统资源也更少。SPI,I2C和UART非常适用于微控制器之间以及不需要传输大量高速数据的微控制器与传感器之间的通信。串行通信 ......
  • 快速入门:使用 .NET Aspire 组件实现缓存
    前言云原生应用程序通常需要各种类型的可扩展缓存解决方案来提高性能。.NETAspire组件简化了连接到流行的缓存服务(例如Redis)的过程,今天小编就为大家简单介绍一下如何使用.NETAspire组件实现缓存。本文的内容概要:创建一个设置为使用.NETAspire的基本ASP.NETCore应......
  • 如何实现SPI机制
     一.定义SPI(ServiceProviderInterface)是一种面向接口编程的技术,它可以让一个程序根据接口约定规范自动发现和加载对应的实现类。它是一种Java种的接口编程规范,它定义了接口和服务提供者之间的约定规范,使得在运行时动态加载实现该接口的类。SPI机制是通过在服务提供者接口......
  • 在Arduino环境下对ESP32进行寄存器操作和区别比较
    在Arduino环境下对ESP32进行寄存器操作和区别比较前言这篇文章主要是对在Arduino环境下如何对ESP32进行寄存器操作进行了相关的说明。并且比较了在不同编程方式下GPIO口的电平翻转速度,这可以更加直观的不同编程方式下的代码运行效率。(平台是VScode,使用Platformio下的Arduino固......
  • 普冉PY32系列(十三) SPI驱动WS2812全彩LED
    目录普冉PY32系列(一)PY32F0系列32位CortexM0+MCU简介普冉PY32系列(二)UbuntuGCCToolchain和VSCode开发环境普冉PY32系列(三)PY32F002A资源实测-这个型号不简单普冉PY32系列(四)PY32F002A/003/030的时钟设置普冉PY32系列(五)使用JLinkRTT代替串口输出日志普冉P......
  • 6、spi模块
    串行外设接口SPI模块spi分为主从两种模式,一个spi通讯系统要包含一个主设备和一个或多个从设备。提供时钟的是主设备。spi的读写操作都是从主设备发起的。SPI信号线SPI接口一般使用四条信号线通信:SDI(数据输入),SDO(数据输出),SCK(时钟),CS(片选)MISO:主设备输入/从设备输出引脚。该引......
  • Java ClassLoader、ContextClassLoader与SPI实现详解
    (目录)JavaClassLoaderClassLoader做什么的?​ 众所周知,Java或者其他运行在JVM(java虚拟机)上面的程序都需要最终便以为字节码,然后被JVM加载运行,那么这个加载到虚拟机的过程就是classloader类加载器所干的事情.直白一点,就是通过一个类的全限定类名称来获取描述此类......
  • vue+spirngboot前后端数据加解密(基于AES+RSA实现)
    案例说明案例只针对post请求这里使用’Content-Type’:‘application/x-www-form-urlencoded;charset=UTF-8’;为键值对的形式(非json)AES加密数据,RAS加密AES的key实现思路前台首先请求非加密接口获取后台的公钥前台在请求前生成自己的公钥和私钥,以及AES对称加密的key使用前台......