Help with ESP32-C3 code for Waveshare 7.5" E-paper using GxEPD2

Hi,
I am having some difficulty getting GxEPD2 working on a Seeed XIAO ESP32-C3 development board. I have an Espressif S3 dev board that the same sketch works on. Here is the sketch that works on the S3 but not on the C3.

#define MAX_DISPLAY_BUFFER_SIZE 65536ul
#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8))
GxEPD2_BW<GxEPD2_750_T7, MAX_HEIGHT(GxEPD2_750_T7)> display(GxEPD2_750_T7(...));
SPIClass hspi(HSPI);

void fill_black() {
  display.setFullWindow();
  display.firstPage();
  do
  {
    display.fillScreen(GxEPD_BLACK);
  }
  while (display.nextPage());

}

void display_init() {
  hspi.setHwCs(false);
  hspi.begin(...); 
  display.epd2.selectSPI(hspi, SPISettings(4000000, MSBFIRST, SPI_MODE0));
  display.init(115200);
  display.setRotation(1); // portrait
  Serial.println("display initialized");
}
void setup() {
  Serial.begin(9600);
  while(!Serial) {};
  delay(3000);
  display_init();
  fill_black();
}

For the S3 development board, the sketch works properly with the following display constructor and SPI initialization call:

GxEPD2_BW<GxEPD2_750_T7, MAX_HEIGHT(GxEPD2_750_T7)> display(GxEPD2_750_T7(15, 1, 26, 4));
hspi.begin(13, 12, 14, 15); 

For the XIAO C3 board, I've tried a few different things. I've tried to read the code for GxEPD2 very thoroughly to figure out what is going on at each step, but I must be missing something important. The current constructor I am using for the C3 is:

GxEPD2_BW<GxEPD2_750_T7, MAX_HEIGHT(GxEPD2_750_T7)> display(GxEPD2_750_T7(/* CS */ D7, /* DC */ D4, /* RST */ D5, /* BUSY */ D6));

D7 corresponds to GPIO 20, which is the hardware SPI chip/slave select. This is confirmed by following the define to Pins_Arduino.h, where both D7 == 20 and SS = 20 The other pin choices are pins that are not mapped to hardware SPI as far as I can tell (however, some of them are mapped to hardware I2C).

For the SPI initializer, I have tried the following to no success:

hspi.begin(13, 12, 14, 15); 
hspi.begin(SCK, MISO, MOSI, SS); 
hspi.begin(-1, -1, -1, -1); 
hspi.begin(D8, D9, D10, D7); 

My reasoning for the -1, -1, -1, -1 constructor was that in hspi.begin(), if all four pin arguments are -1, the function defaults to this branch:

  #elif CONFIG_IDF_TARGET_ESP32C3
        _sck = SCK;
        _miso = MISO;
        _mosi = MOSI;
        _ss = SS;

Otherwise, it does this:

    } else {
        _sck = sck;
        _miso = miso;
        _mosi = mosi;
        _ss = ss;
    }

The two lines below should be equivalent.

hspi.begin(SCK, MISO, MOSI, SS); 
hspi.begin(D8, D9, D10, D7); 

I am at a loss at how to get this working on this board. If anyone has any other ideas, or if there is some other problem with the code, please let me know. I can't figure out what the different SPI_MODEs mean (there are no comments in source), and I am almost wondering if there is a byte ordering issue since the C3 is RISC-V and the S3 is Xtensa. Thanks in advance.

Some additional notes: These are the power requirements for the display listed on Waveshare's wiki:

image

I feel as though the board should be able to supply this no problem, even without looking at the datasheet.

Another note: It looks like some of the SPI pins are used in the startup sequence:

I don't have a logic analyzer with me at the moment, but I put an LED on the SPI MOSI pin to see if there's any activity on it. It looks like that pin has something going on during startup as well as during the setup() call.

Hi,
to get an answer from the Author of GxEPD2, you could post your question in
ZinggJM/GxEPD2 · Discussions · GitHub.
In general, you should not need to remap HW SPI pins for boards that can be selected to compile for, such as XIAO_ESP32C3. The SPIClass uses the pins defined in pins_arduino.h.
You can use any free pin for CS (and DC, RST, BUSY), just adapt the parameter. Try to avoid strapping pins.

I understand that calling hspi.begin() with no arguments will use the pins defined in Pins_Arduino.h, but looking through the implementation, it does seem like you can override these pins by passing parameters. Either way, it doesn't seem like the display is working with this board whether I override the pins or not. Unfortunately, it looks like the SPI pins are also used as strapping pins, although I don't really know what that means.

Number of SPI channels on ESP32C3 is inconsistent · Issue #7596 · espressif/arduino-esp32

Thanks, this is frustrating but enlightening. I'll give this a try and see how that goes. Is FSPI (Flash SPI?) just using normal GPIO? Are the pins arbitrary, like in this reply? Number of SPI channels on ESP32C3 is inconsistent · Issue #7596 · espressif/arduino-esp32 · GitHub

Why don't you just let GxEPD2 use the default global HW SPI class with the defined pins for your board? I told you no re-map should be needed. Don't expect more from me.

To clarify, I have also tried that. Here is a sketch doing just that, which doesn't work:

/* From GxEPD2 example code*/
#define MAX_DISPLAY_BUFFER_SIZE 65536ul
#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8))
GxEPD2_BW<GxEPD2_750_T7, MAX_HEIGHT(GxEPD2_750_T7)> display(GxEPD2_750_T7(/* CS */ SS, /* DC */ D4, /* RST */ D5, /* BUSY */ D6));

SPIClass hspi(HSPI);
void setup() {
  Serial.begin(9600);
  while(!Serial) {};
  delay(3000);
  display_init();
  delay(1000);
  fill_black();
}

void display_init() {
  display.init(115200);
  display.setRotation(1); // portrait
  Serial.println("display initialized");
}

void fill_black() {
  display.setFullWindow();
  display.firstPage();
  do
  {
    display.fillScreen(GxEPD_BLACK);
  }
  while (display.nextPage());
}

If I understand correctly, this will initialize the SPI peripheral using the following pins listed in Pins_Arduino.h, because at some point SPIClass::begin or an equivalent constructor is either called with no parameters or with these parameters:

static const uint8_t SS    = 20;
static const uint8_t MOSI  = 10;
static const uint8_t MISO  = 9;
static const uint8_t SCK   = 8;

I have my display hooked up with the following:

D20 (SS/CS) -> CS
D10 (MOSI) -> DIN
D8 (SCK/CLK) -> CLK
D4 -> DC
D5 -> RST
D6 -> BUSY

According to the datasheet, GPIO8/D8 and GPIO9/D9 are both strapping pins, so if I want to use SPI at all, it seems impossible to avoid using them while using the pin definitions in Pins_Arduino.h. As additional clarification, I was able to get the sketch working no problem on the S3 development board, even with a) manual pin remapping and b) using SPIClass::begin. However, the sketch I'm attempting to get running now adheres to all of your suggestions, except for the usage of SPIClass spi(FSPI) that is suggested in the GitHub issue that you linked.

Just want to send a quick update. I opened a discussion on GitHub concerning this topic here: Trouble using Seeed XIAO ESP32-C3 with 7.5" BW display · ZinggJM/GxEPD2 · Discussion #80 · GitHub

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.