ESP32S2 Problem With More SPI Devices [SOLVED]

1. The Problem

The problem appears when there is more than one device connected to the SPI bus. As it is known, SPI interface uses several wires to achieve fast data rates [1]. It requires one data-in wire, one data-out wire, one clock wire, a ground reference and one chip-select (CS) wire.

The last one is the problem.

ESP32 allows remapping the default SPI pins for almost any other available pin [2]. This allows a certain level of flexibility in a design.

Each of the new devices connected to the same SPI bus requires one additional chip-select wire dedicated to this device. Since there is a default CS pin, there is a problem with changing it.

It yields the issue that only one device can be accessed, since the CS pin points to only one device.

2. My Setup

I encountered this problem with ESP32-S2 (board: LOLIN S2 mini) while having GMG12864 display with u8g2 graphic Arduino library and a generic SD card reader connected to the same SPI bus.

The SD card reader initialized fine and read the file that was meant for logging. Then, when the initialization of a display comes, it overwrites the previous configuration and it stays that way. When the time to log data to the SD card comes, it can not open the file for writing, since ESP still tries to communicate with the display.

My pins:

1
2
const uint8_t SD_SPI_CS = 12;
const uint8_t SCREEN_SPI_CS = 38;

I defined different SPI classes for each device with SPIClass spiSD = SPIClass(HSPI); and spiSD.begin(7, 9, 11, SD_SPI_CS); (same for screen), but it did not help.

Even with spiSD.end() before another device SPI class is started.

Manually setting each CS pin for low and high did not help either.

It is probably the issue of libraries used to drive both devices.

3. Solution

For my specific case, to use these two devices was to leave SD card as is and initiate display every time any update is to be made.

To do so, the u8g2.begin(); can be called before making any changes to the displayed content. Normally, it has to be called only once - in a setup function. Unfortunately, this creates a negative side effect of the screen blinking every time this is called. Initially, it does not matter, but when on the screen only some data is to be refreshed, and the entire screen refreshes - it is not pleasing to see. It can be disturbing.

To solve this, the source code of u8g2 can be investigated:

1
2
3
4
5
6
7
8
9
10
11
bool begin(void) {
/* note: call to u8x8_utf8_init is not required here, this is done in the setup procedures before */
#ifndef U8G2_USE_DYNAMIC_ALLOC
initDisplay();
clearDisplay();
setPowerSave(0);
return 1;
#else
return 0;
#endif
}

The lines that are causing problems are clearDisplay(); and setPowerSave(0);. These can be omitted and u8g2.begin(); can be replaced with u8g2.initDisplay();. Unfortunately it may not work as expected in certain situations - I did not come with a clear explanation.

I managed to debug the problem and finally replaced u8g2.begin(); with two lines below:

1
2
u8g2.initInterface();
u8g2.setPowerSave(0);

These are called every time new changes are to be sent to display.

For the SD card, logging in my case functionality, the code looks like this:

1
2
3
4
5
6
7
8
spiSD.begin(7, 9, 11, SD_SPI_CS); //!!!!
SD.begin(SD_SPI_CS, spiSD, SDSPEED); //!!!!
String SDlog = "Some logging message";
char char_ming_message[SDlog.length()];
SDlog.toCharArray(char_ming_message, SDlog.length());
sd_append_success = appendFile(SD, FILE_NAME, char_ming_message);
SD.end(); //!!!!
spiSD.end(); //!!!!

I am not sure if the SD and spiSD .begin() and .end() are required to be called every single time, but it works like that. I tried minimizing the code by removing certain parts, but with very mixed results, so I left them. Since ESP32-S2 is 240MHz it can handle a few extra .begin's.

Few extra sites for the topic: [4], [5].

4. Sources

[1] https://www.ti.com/lit/ug/sprugp2a/sprugp2a.pdf

[2] https://randomnerdtutorials.com/esp32-spi-communication-arduino/

[3] https://aleksmola.github.io/2023/10/25/how-to-connect-gmg12864-display/

[4] https://www.esp32.com/viewtopic.php?t=13697

[5] https://github.com/espressif/arduino-esp32/issues/1219