I recently migrated to the ESP32 3.x update, and still tracking down issues. Posting this in case it helps others, and also maybe you have suggestions how I can implement this better?
I have multiple SPI devices on the VSPI (FSPI) bus on the ESP32 S3 FN8 (custom PCB).
On version 2.x, I simply created a unique SPIClass for each device, pointing to the same VSPI bus. In the code snippet below I'll use the barometer and imu for example:
//uninitialised pointers to SPI objects
SPIClass * baro_vspi = NULL;
SPIClass * imu_vspi = NULL;
void setup() {
delay(1000);
Serial.begin(115200);
delay(1000);
Serial.println("Starting Setup");
baro_vspi = new SPIClass(VSPI);
baro_vspi->begin(SPI_CLK, SPI_MISO, SPI_MOSI, SPI_SS_BARO);
pinMode(baro_vspi->pinSS(), OUTPUT);
digitalWrite(baro_vspi->pinSS(), HIGH);
imu_vspi = new SPIClass(VSPI);
imu_vspi->begin(SPI_CLK, SPI_MISO, SPI_MOSI, SPI_SS_IMU);
pinMode(imu_vspi->pinSS(), OUTPUT);
digitalWrite(imu_vspi->pinSS(), HIGH);
}
This worked fine on version 2.x, but now on version 3.0 the code hangs when we eventually do an spi->transfer(). I traced this down to the specific SPIClass->begin() instruction. It seems like on v3.0 you can't call that twice (once for each device) if they're pointing to the same bus?
Full code is below. If you comment out the second begin line (imu_vspi->begin(...)), then it "works". But of course with that line commented out, you no longer have the SPI object set up properly and can't reference the different chip select pin (SPI_SS_IMU).
Is there a better way to handle multiple SPI devices on the same bus? I realize I can create my own helper functions and handle the chip select pins manually. But I don't see the point of the SPIClass configuring a unique SS pin if you can't create multiple classes to handle multiple devices.
Any tips? Thanks!
#include <SPI.h>
#define SPI_SS_IMU 10
#define SPI_MOSI 11
#define SPI_CLK 12
#define SPI_MISO 13
#define SPI_SS_BARO 18
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#define VSPI FSPI
#endif
static const int spiClk = 1000000; // 1 MHz
//uninitialised pointers to SPI objects
SPIClass * baro_vspi = NULL;
SPIClass * imu_vspi = NULL;
void setup() {
delay(1000);
Serial.begin(115200);
delay(1000);
Serial.println("Starting Setup");
baro_vspi = new SPIClass(VSPI);
baro_vspi->begin(SPI_CLK, SPI_MISO, SPI_MOSI, SPI_SS_BARO);
pinMode(baro_vspi->pinSS(), OUTPUT);
digitalWrite(baro_vspi->pinSS(), HIGH);
imu_vspi = new SPIClass(VSPI);
imu_vspi->begin(SPI_CLK, SPI_MISO, SPI_MOSI, SPI_SS_IMU); // comment this line out to make it "work"
pinMode(imu_vspi->pinSS(), OUTPUT);
digitalWrite(imu_vspi->pinSS(), HIGH);
}
void loop() {
spi_Command(baro_vspi, 0b01010101); // junk data to illustrate usage
delay(100);
spi_Command(imu_vspi, 0b01010101); // junk data to illustrate usage
delay(100);
}
void spi_Command(SPIClass *spi, byte data) {
spi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
Serial.print("Began tx. ");
digitalWrite(spi->pinSS(), LOW);
Serial.print("SS low. ");
spi->transfer(data);
Serial.print("sent data. ");
digitalWrite(spi->pinSS(), HIGH);
Serial.print("SS high. ");
spi->endTransaction();
Serial.println("end tx. ");
}
PS: for completeness, when you comment out the second ->begin, you get proper repeating serial prints:
Began tx. SS low. sent data. SS high. end tx.
Began tx. SS low. sent data. SS high. end tx.
..etc
when you leave that second ->begin line in place, you get:
Began tx. SS low. <hang>