ESP32 how to select between HW SPI peripherals

Thread Starter

zazas321

Joined Nov 29, 2015
917
Hello I am running accelerometer LIS3DH code for my ESP32 device. I am using Adafruit LIS3DH library Full code is here:
Code:
// Basic demo for accelerometer readings from Adafruit LIS3DH

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_LIS3DH.h>
#include <Adafruit_Sensor.h>

// Used for software SPI
//#define LIS3DH_CLK 14
//#define LIS3DH_MISO 12
//#define LIS3DH_MOSI 13
// Used for hardware & software SPI
#define LIS3DH_CS 15

// software SPI
//Adafruit_LIS3DH lis = Adafruit_LIS3DH(LIS3DH_CS, LIS3DH_MOSI, LIS3DH_MISO, LIS3DH_CLK);
// hardware SPI
Adafruit_LIS3DH lis = Adafruit_LIS3DH(LIS3DH_CS);
// I2C
//Adafruit_LIS3DH lis = Adafruit_LIS3DH();

void setup(void) {
  Serial.begin(115200);
  while (!Serial) delay(10);     // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("LIS3DH test!");

  if (! lis.begin(0x18)) {   // change this to 0x19 for alternative i2c address
    Serial.println("Couldnt start");
    while (1) yield();
  }
  Serial.println("LIS3DH found!");

  // lis.setRange(LIS3DH_RANGE_4_G);   // 2, 4, 8 or 16 G!

  Serial.print("Range = "); Serial.print(2 << lis.getRange());
  Serial.println("G");

  // lis.setDataRate(LIS3DH_DATARATE_50_HZ);
  Serial.print("Data rate set to: ");
  switch (lis.getDataRate()) {
    case LIS3DH_DATARATE_1_HZ: Serial.println("1 Hz"); break;
    case LIS3DH_DATARATE_10_HZ: Serial.println("10 Hz"); break;
    case LIS3DH_DATARATE_25_HZ: Serial.println("25 Hz"); break;
    case LIS3DH_DATARATE_50_HZ: Serial.println("50 Hz"); break;
    case LIS3DH_DATARATE_100_HZ: Serial.println("100 Hz"); break;
    case LIS3DH_DATARATE_200_HZ: Serial.println("200 Hz"); break;
    case LIS3DH_DATARATE_400_HZ: Serial.println("400 Hz"); break;

    case LIS3DH_DATARATE_POWERDOWN: Serial.println("Powered Down"); break;
    case LIS3DH_DATARATE_LOWPOWER_5KHZ: Serial.println("5 Khz Low Power"); break;
    case LIS3DH_DATARATE_LOWPOWER_1K6HZ: Serial.println("16 Khz Low Power"); break;
  }
}

void loop() {
  lis.read();      // get X Y and Z data at once
  // Then print out the raw data
  Serial.print("X:  "); Serial.print(lis.x);
  Serial.print("  \tY:  "); Serial.print(lis.y);
  Serial.print("  \tZ:  "); Serial.print(lis.z);

  /* Or....get a new sensor event, normalized */
  sensors_event_t event;
  lis.getEvent(&event);

  /* Display the results (acceleration is measured in m/s^2) */
  Serial.print("\t\tX: "); Serial.print(event.acceleration.x);
  Serial.print(" \tY: "); Serial.print(event.acceleration.y);
  Serial.print(" \tZ: "); Serial.print(event.acceleration.z);
  Serial.println(" m/s^2 ");

  Serial.println();

  delay(200);
}
The lis3dh object is created with the following method:
Code:
Adafruit_LIS3DH lis = Adafruit_LIS3DH(LIS3DH_CS);
Since I do not pass any parameters except CS, it automatically defaults to the HW spi pins of the ESP32.

My question:



How does it know which SPI peripheral to choose since ESP32 has multiple SPI peripherals?

1630485868241.png
SPI1:
VSPI MOSI (GPIO23)
VSPI MISO (GPIO19)
VSPI SCLK (GPIO18)

SPI2:
HSPI MOSI (GPIO13)
HSPI MISO (GPIO 12)
HSPI SCLK (GPIO 14)

For example, in my custom board I have selected to use SPI2 and use VSPI pins for something else. When I call the default HW spi method to initialise my LIS3DH object, it does not work. I have to use the software SPI method instead:

Code:
#define LIS3DH_CLK 14
#define LIS3DH_MISO 12
#define LIS3DH_MOSI 13
// Used for hardware & software SPI
#define LIS3DH_CS 15

// software SPI
Adafruit_LIS3DH lis = Adafruit_LIS3DH(LIS3DH_CS, LIS3DH_MOSI, LIS3DH_MISO, LIS3DH_CLK);

But I think it is not correct to use software SPI when I can use HW spi instead
 

Thread Starter

zazas321

Joined Nov 29, 2015
917
I have solved the problem. I have went into the Adafruit_LIS3DH library code and noticed what is the deal.
Code:
 *   @brief  Instantiates a new LIS3DH class using hardware SPI
 *   @param  cspin
 *           number of CSPIN (Chip Select)
 *   @param  *theSPI
 *           optional parameter contains spi object
 */
Adafruit_LIS3DH::Adafruit_LIS3DH(int8_t cspin, SPIClass *theSPI) {
  _cs = cspin;
  _mosi = -1;
  _miso = -1;
  _sck = -1;
  _sensorID = -1;
  SPIinterface = theSPI;
}
As you can see, there is an optional parameter that I can pass and that is exactly what controls which SPI peripheral to choose.

Code:
#define LIS3DH_CS 15
SPIClass spi_acceleromter(HSPI);
// software SPI
//Adafruit_LIS3DH lis = Adafruit_LIS3DH(LIS3DH_CS, LIS3DH_MOSI, LIS3DH_MISO, LIS3DH_CLK);
// hardware SPI
Adafruit_LIS3DH lis = Adafruit_LIS3DH(LIS3DH_CS,&spi_acceleromter);
working as expected
 
Top