TFT_eSPI icon indicating copy to clipboard operation
TFT_eSPI copied to clipboard

ESP32-C3 SPI Display Issue: TFT_eSPI Library Fails While Direct Hardware SPI Works

Open Heartestrella opened this issue 6 months ago • 13 comments

Environment

  • Board: ESP32-C3 (e.g., ESP32-C3-DevKitM-1)
  • Arduino Core: [email protected]
  • TFT_eSPI Version: 2.5.43
  • Display: ILI9486 (320x480, SPI)

Symptoms

  • Direct SPI (Working)

    • Manual SPIClass initialization succeeds.
    • Display responds perfectly at 27MHz (Mode 0).
  • TFT_eSPI (Failing)

    • Backlight turns on but no pixel activity.

Configuration

User_Setup.h

#define ILI9486_DRIVER
#define TFT_MOSI 6  // GPIO6 (ESP32-C3 SPI2)
#define TFT_SCLK 4  // GPIO4 (ESP32-C3 SPI2)
#define TFT_CS   7  // GPIO7
#define TFT_DC   3  // GPIO3
#define TFT_RST  10 // GPIO10
#define SPI_FREQUENCY 27000000
#define TFT_SPI_MODE SPI_MODE0

SPI Direct Code:

#include <SPI.h>
// 引脚定义
#define TFT_SCLK 4   // SPI时钟
#define TFT_MOSI 6   // SPI数据输出
#define TFT_RST  10  // 复位引脚
#define TFT_DC   3   // 数据/命令选择
#define TFT_CS   7   // 片选引脚

// 屏幕分辨率(根据实际屏幕修改)
#define TFT_WIDTH  320
#define TFT_HEIGHT 480

SPIClass mySPI(FSPI); // 使用FSPI(ESP32-C3的SPI2)

void tft_send_cmd(uint8_t cmd) {
  digitalWrite(TFT_DC, LOW);  // 命令模式
  digitalWrite(TFT_CS, LOW);
  mySPI.transfer(cmd);
  digitalWrite(TFT_CS, HIGH);
}

void tft_send_data(uint8_t data) {
  digitalWrite(TFT_DC, HIGH); // 数据模式
  digitalWrite(TFT_CS, LOW);
  mySPI.transfer(data);
  digitalWrite(TFT_CS, HIGH);
}

void tft_init() {
  // 初始化GPIO
  pinMode(TFT_DC, OUTPUT);
  pinMode(TFT_RST, OUTPUT);
  pinMode(TFT_CS, OUTPUT);
  
  // 复位序列
  digitalWrite(TFT_RST, LOW);
  delay(100);
  digitalWrite(TFT_RST, HIGH);
  delay(120);

  // 初始化SPI
  mySPI.begin(TFT_SCLK, -1, TFT_MOSI, TFT_CS); // MISO未使用设为-1
  mySPI.setFrequency(40000000); // 40MHz

  // 基础初始化命令(适用于大多数SPI TFT)
  tft_send_cmd(0x01);  // 软件复位
  delay(150);
  tft_send_cmd(0x11);  // 退出睡眠模式
  delay(120);
  tft_send_cmd(0x3A);  // 像素格式设置
  tft_send_data(0x55); // 16位像素(RGB565)
  delay(10);
  tft_send_cmd(0x29);  // 开启显示
  delay(20);
}

void tft_fill_screen(uint16_t color) {
  // 设置写入区域为全屏
  tft_send_cmd(0x2A);  // 列地址设置
  tft_send_data(0x00); tft_send_data(0x00);
  tft_send_data((TFT_WIDTH >> 8) & 0xFF); 
  tft_send_data(TFT_WIDTH & 0xFF);
  
  tft_send_cmd(0x2B);  // 行地址设置
  tft_send_data(0x00); tft_send_data(0x00);
  tft_send_data((TFT_HEIGHT >> 8) & 0xFF);
  tft_send_data(TFT_HEIGHT & 0xFF);
  
  tft_send_cmd(0x2C);  // 内存写入命令

  // 快速填充颜色
  uint8_t hi = color >> 8, lo = color & 0xFF;
  digitalWrite(TFT_DC, HIGH);
  digitalWrite(TFT_CS, LOW);
  for(uint32_t i = 0; i < TFT_WIDTH * TFT_HEIGHT; i++) {
    mySPI.transfer(hi);
    mySPI.transfer(lo);
  }
  digitalWrite(TFT_CS, HIGH);
}

void setup() {
  Serial.begin(115200);
  Serial.println("Starting TFT init...");
  
  tft_init();
  Serial.println("TFT initialized");
  
  tft_fill_screen(0x0000); // RGB565黑色
  Serial.println("Screen filled black");
}

void loop() {
  // 保持显示
}

ESPI Code:

#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();  // 初始化库

void setup() {
  // 初始化屏幕
  pinMode(TFT_RST, OUTPUT);
  digitalWrite(TFT_RST, LOW);   // 复位屏幕
  delay(50);
  digitalWrite(TFT_RST, HIGH);  // 解除复位
  delay(50);

  tft.init();
  tft.setRotation(3);          // 根据屏幕方向调整(0~3)
  tft.fillScreen(TFT_BLACK);   // 全屏填充黑色
}

void loop() {
  // 无操作,保持黑屏
}

Circuit Diagram

Image

Image

Image

The development board is ESP32-C3 Supermini

Heartestrella avatar Jul 06 '25 04:07 Heartestrella

I have a similar issue with my ESP32C3: When building the project with ESP-IDF, I can see a kernel panic at TFT_eSPI::fillScreen(unsigned int), and its inlined function, TFT_eSPI::begin_tft_write(). Reading the objdump, TFT_eSPI tries to write to RAM using a pointer, which is set to 0x10, causing the equivalent of a segmentation fault.

libewa avatar Jul 11 '25 10:07 libewa

related to #3743

libewa avatar Jul 11 '25 10:07 libewa

I figure out this bug in v3.X.X, you must set pin TFT_MISO to a nonzero pin. If not, in v3.X.X esp32 core, this will cause the spi register (*_spi_cmd) never to refresh. (https://github.com/Bodmer/TFT_eSPI/blob/5793878d24161c1ed23ccb136f8564f332506d53/Processors/TFT_eSPI_ESP32_C3.h#L541-L546) And if you don't define TFT_MISO or TFT_MISO == -1, this code will set it to TFT_MOSI. https://github.com/Bodmer/TFT_eSPI/blob/5793878d24161c1ed23ccb136f8564f332506d53/Processors/TFT_eSPI_ESP32_C3.h#L316-L321

niu541412 avatar Aug 01 '25 19:08 niu541412

@libewa It is a library error. https://github.com/Bodmer/TFT_eSPI/blob/5793878d24161c1ed23ccb136f8564f332506d53/Processors/TFT_eSPI_ESP32_C3.h#L71 You should change from #define SPI_PORT SPI2_HOST to #define SPI_PORT 2 Based by discussion

alexmorshu avatar Aug 19 '25 08:08 alexmorshu

Having the same issue, but your code solved it? Somehow it is working Great. Thank you

Reyansh-Niranjan avatar Oct 29 '25 12:10 Reyansh-Niranjan

Tôi đã tìm ra lỗi này trong v3.XX, bạn phải đặt chân TFT_MISO thành một chân khác 0. Nếu không, trong lõi esp32 v3.XX, điều này sẽ khiến thanh ghi spi (*_spi_cmd) không bao giờ được làm mới. (

TFT_eSPI/Bộ xử lý/TFT_eSPI_ESP32_C3.h

Dòng 541 đến 546 trong 5793878

#define TFT_WRITE_BITS ( D , B ) *_spi_mosi_dlen = B-1;
*_spi_w = D;
_spi_cmd = SPI_UPDATE;
trong khi (
_spi_cmd & SPI_UPDATE);
_spi_cmd = SPI_USR;
trong khi (
_spi_cmd & SPI_USR); ) Và nếu bạn không định nghĩa TFT_MISO hoặc TFT_MISO == -1, đoạn mã này sẽ đặt nó thành TFT_MOSI. TFT_eSPI/Bộ xử lý/TFT_eSPI_ESP32_C3.h

Dòng 316 đến 321 trong 5793878

#nếu đã xác định( CONFIG_IDF_TARGET_ESP32C3 ) || đã xác định( CONFIG_IDF_TARGET_ESP32S2 ) #nếu ( TFT_MISO == -1 ) #undef TFT_MISO #define TFT_MISO TFT_MOSI #kết thúc nếu #kết thúc nếu

I also didn't define MISO, but why does esp32 work and c3 doesn't?

ghost avatar Nov 21 '25 08:11 ghost

With C3, you must define TFT_MISO to a pin that is neither 0 nor -1. In the 3.0 core, if TFT_MISO and TFT_MOSI have the same pin, it will cause the register stucking.

niu541412 avatar Nov 21 '25 08:11 niu541412

Với C3, bạn phải định nghĩa TFT_MISO cho một chân không phải là 0 hoặc -1. Trong lõi 3.0, nếu TFT_MISO và TFT_MOSI có cùng chân, thanh ghi sẽ bị kẹt.

Only C3, any other board? esp32 is working without define MISO

ghost avatar Nov 21 '25 09:11 ghost

With C3, you must define TFT_MISO to a pin that is neither 0 nor -1. In the 3.0 core, if TFT_MISO and TFT_MOSI have the same pin, it will cause the register stucking.

I tried and the screen is still blank. #define USER_SETUP_INFO "User_Setup" #define ST7789_DRIVER // Full configuration option, define additional parameters below for this display

#define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320 #define TFT_HEIGHT 280

#define CGRAM_OFFSET

#define TFT_MISO 5 // Automatically assigned with ESP8266 if not defined #define TFT_MOSI 6 // Automatically assigned with ESP8266 if not defined #define TFT_SCLK 4 // Automatically assigned with ESP8266 if not defined

#define TFT_CS 7 // Chip select control pin D8 #define TFT_DC 8 // Data Command control pin #define TFT_RST 9 // Reset pin (could connect to NodeMCU RST, see next line)

#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH #define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters #define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters #define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm #define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-. #define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. #define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts #define SMOOTH_FONT

#define SPI_FREQUENCY 40000000 #define SPI_READ_FREQUENCY 20000000

ghost avatar Nov 21 '25 10:11 ghost

Working just put miso to number other than 0 Just in case I put it according to software SPI rather than Hardware SPI. https://github.com/Bodmer/TFT_eSPI/blob/5793878d24161c1ed23ccb136f8564f332506d53/Processors/TFT_eSPI_ESP32_C3.h#L71 there is lib issue #define SPI_PORT SPI2_HOST to #define SPI_PORT 2 Then try

Reyansh-Niranjan avatar Nov 22 '25 17:11 Reyansh-Niranjan

@libewa It is a library error.

TFT_eSPI/Processors/TFT_eSPI_ESP32_C3.h

Line 71 in 5793878

#define SPI_PORT SPI2_HOST

You should change from #define SPI_PORT SPI2_HOST to #define SPI_PORT 2 Based by discussion

I can confirm that this change fixed the library for me on my ESP32-C3 Supermini.

Setting TFT_MISO to a value greater than 0 did nothing.

kartchnb avatar Nov 23 '25 02:11 kartchnb

See my comment in another issue. I've attached a tarball with minimal modification to codes with esp32c3. There is also an arduino example in it.

niu541412 avatar Nov 23 '25 11:11 niu541412

Xem bình luận của tôi ở một bài viết khác. Tôi đã đính kèm một tệp tarball với một số sửa đổi nhỏ cho mã lệnh esp32c3. Ngoài ra còn có một ví dụ về Arduino trong đó.

Ok, my screen working with esp32c3 2 issues:

  • Edit SPI2_HOST to 2 or FSPI
  • Define MISO different 0 or -1 Hope Bodmer fixes this.

ghost avatar Nov 23 '25 23:11 ghost