Skip to content

Hardware SPI in arduino-esp32 not work on ESP32-P4 #11398

Open
@linghuye

Description

@linghuye

Board

DNESP32P4

Device Description

DNESP32P4 mini-board with esp32 p4 chip

Hardware Configuration

16M flash 32M param

Version

v3.2.0

IDE Name

VS Code platformIO
SDK v5.4.1-1-g2f7dcd862a-dirty

Operating System

Windows 11

Flash frequency

80MHZ

PSRAM enabled

yes

Upload speed

115200

Description

Hi, I tried to use a ST7789 SPI 320*240 lcd screen on ESP32-P4 with Arduino TFT_eSPI and Adafruit ST7735 and ST7789 Library,
and found they both don't work on ESP32-P4.
After some testing, I found the software SPI mode in Adafruit T7789 Library works good on ESP32-P4 but with very slow speed,
and it also works good with ESP32-IDF framwork's esp_lcd component with hardware SPI.
It just doesn't work with the Arduino's hardware SPI on ESP32-P4.

The Arduino core that I used is lastest 3.2.0.

Finally I found that, the same simple code below lights up the ST7789 LCD with messy colors on ESP32-S3/ESP32-C3, but not work on ESP32-P4 with only a black backlighted screen.

// Works on ESP32 S3/C3 with hardware SPI
    pinMode(TFT_CS, OUTPUT);
    pinMode(TFT_DC, OUTPUT);
    pinMode(TFT_RST, OUTPUT);
    digitalWrite(TFT_CS, HIGH); // Chip select high (Inactive)
    digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode
    digitalWrite(TFT_RST, HIGH);// NO Reset

    SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1);

    digitalWrite(TFT_CS, HIGH); // Chip select high (inactive)
    digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode
    digitalWrite(TFT_RST, HIGH);
    delay(200);
    digitalWrite(TFT_RST, LOW);
    delay(20);
    digitalWrite(TFT_RST, HIGH);
    delay(200);
    
    // Sleep out
    GPIO.out_w1tc.val = (1 << TFT_CS);
    GPIO.out1_w1tc.val = (1 << (TFT_DC - 32));
    
    *_spi_mosi_dlen = 7;               
    *_spi_w = ST7789_SLPOUT;            
    *_spi_cmd = SPI_UPDATE;
    while(*_spi_cmd & SPI_UPDATE);        
    *_spi_cmd = SPI_USR;
    while(*_spi_cmd & SPI_USR);

    GPIO.out1_w1ts.val = (1 << (TFT_DC - 32));
    GPIO.out_w1ts.val = (1 << TFT_CS);
    delay(120);

    // Display on
    GPIO.out_w1tc.val = (1 << TFT_CS);
    GPIO.out1_w1tc.val = (1 << (TFT_DC - 32));

    *_spi_mosi_dlen = 7;               
    *_spi_w = ST7789_DISPON;            
    *_spi_cmd = SPI_UPDATE;
    while(*_spi_cmd & SPI_UPDATE);        
    *_spi_cmd = SPI_USR;
    while(*_spi_cmd & SPI_USR);

    GPIO.out1_w1ts.val = (1 << (TFT_DC - 32));
    GPIO.out_w1ts.val = (1 << TFT_CS);
    delay(120); 

    pinMode(TFT_BL, OUTPUT);
    digitalWrite(TFT_BL, HIGH); 

My pin Settings on ESP32-P4
It works good with esp_lcd component in IDF framework but not work with Arduino framework.

#define TFT_MOSI   29                
#define TFT_SCLK   30            
#define TFT_CS     28               
#define TFT_DC     49               
#define TFT_BL     23              
#define TFT_RST    50         
#define TFT_MISO   -1  

#define ST7789_DRIVER     
#define TFT_RGB_ORDER TFT_BGR 
#define TFT_WIDTH  240      
#define TFT_HEIGHT 320   

Any suggestion will be appreciated, I just want to use TFT_eSPI library for LCD on ESP32 C3/S3/C6/P4 with the same code.

Sketch

// Works on ESP32 S3/C3 with hardware SPI
    pinMode(TFT_CS, OUTPUT);
    pinMode(TFT_DC, OUTPUT);
    pinMode(TFT_RST, OUTPUT);
    digitalWrite(TFT_CS, HIGH); // Chip select high (Inactive)
    digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode
    digitalWrite(TFT_RST, HIGH);// NO Reset

    SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1);

    digitalWrite(TFT_CS, HIGH); // Chip select high (inactive)
    digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode
    digitalWrite(TFT_RST, HIGH);
    delay(200);
    digitalWrite(TFT_RST, LOW);
    delay(20);
    digitalWrite(TFT_RST, HIGH);
    delay(200);
    
    // Sleep out
    GPIO.out_w1tc.val = (1 << TFT_CS);
    GPIO.out1_w1tc.val = (1 << (TFT_DC - 32));
    
    *_spi_mosi_dlen = 7;               
    *_spi_w = ST7789_SLPOUT;            
    *_spi_cmd = SPI_UPDATE;
    while(*_spi_cmd & SPI_UPDATE);        
    *_spi_cmd = SPI_USR;
    while(*_spi_cmd & SPI_USR);

    GPIO.out1_w1ts.val = (1 << (TFT_DC - 32));
    GPIO.out_w1ts.val = (1 << TFT_CS);
    delay(120);

    // Display on
    GPIO.out_w1tc.val = (1 << TFT_CS);
    GPIO.out1_w1tc.val = (1 << (TFT_DC - 32));

    *_spi_mosi_dlen = 7;               
    *_spi_w = ST7789_DISPON;            
    *_spi_cmd = SPI_UPDATE;
    while(*_spi_cmd & SPI_UPDATE);        
    *_spi_cmd = SPI_USR;
    while(*_spi_cmd & SPI_USR);

    GPIO.out1_w1ts.val = (1 << (TFT_DC - 32));
    GPIO.out_w1ts.val = (1 << TFT_CS);
    delay(120); 

    pinMode(TFT_BL, OUTPUT);
    digitalWrite(TFT_BL, HIGH); 



#define TFT_MOSI   29                
#define TFT_SCLK   30            
#define TFT_CS     28               
#define TFT_DC     49               
#define TFT_BL     23              
#define TFT_RST    50         
#define TFT_MISO   -1  

#define ST7789_DRIVER     
#define TFT_RGB_ORDER TFT_BGR 
#define TFT_WIDTH  240      
#define TFT_HEIGHT 320

Debug Message

No error, no warning, lcd just not light up, loop() still works.

Other Steps to Reproduce

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <Arduino.h>
#include <SPI.h>

// 7789 320*240
// For the breakout board, you can use any 2 or 3 pins.
// These pins will also work for the 1.8" TFT shield.
#define TFT_MOSI   29              
#define TFT_SCLK   30            
#define TFT_DC 49
#define TFT_CS 28
#define TFT_BL 23                
#define TFT_RST 50 // Or set to -1 and connect to Arduino RESET pin

// OPTION 1 (recommended) is to use the HARDWARE SPI pins, which are unique
// to each board and not reassignable. 
// This is the fastest mode of operation and is required if
// using the breakout board's microSD card.

// For 1.44" and 1.8" TFT with ST7735 use:
// Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

// For 1.14", 1.3", 1.54", 1.69", and 2.0" TFT with ST7789:
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

// OPTION 2 lets you interface the display using ANY TWO or THREE PINS,
// tradeoff being that performance is not as fast as hardware SPI above.

// For ST7735-based displays, we will use this call
// Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

// OR for the ST7789-based displays, we will use this call
// Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);

void testLines(uint16_t color)
{
    tft.fillScreen(ST77XX_BLACK);
    for(int16_t x = 0; x < tft.width(); x += 6)
    {
        tft.drawLine(0, 0, x, tft.height() - 1, color);
        delay(0);
    }
    for(int16_t y = 0; y < tft.height(); y += 6)
    {
        tft.drawLine(0, 0, tft.width() - 1, y, color);
        delay(0);
    }

    tft.fillScreen(ST77XX_BLACK);
    for(int16_t x = 0; x < tft.width(); x += 6)
    {
        tft.drawLine(tft.width() - 1, 0, x, tft.height() - 1, color);
        delay(0);
    }
    for(int16_t y = 0; y < tft.height(); y += 6)
    {
        tft.drawLine(tft.width() - 1, 0, 0, y, color);
        delay(0);
    }

    tft.fillScreen(ST77XX_BLACK);
    for(int16_t x = 0; x < tft.width(); x += 6)
    {
        tft.drawLine(0, tft.height() - 1, x, 0, color);
        delay(0);
    }
    for(int16_t y = 0; y < tft.height(); y += 6)
    {
        tft.drawLine(0, tft.height() - 1, tft.width() - 1, y, color);
        delay(0);
    }

    tft.fillScreen(ST77XX_BLACK);
    for(int16_t x = 0; x < tft.width(); x += 6)
    {
        tft.drawLine(tft.width() - 1, tft.height() - 1, x, 0, color);
        delay(0);
    }
    for(int16_t y = 0; y < tft.height(); y += 6)
    {
        tft.drawLine(tft.width() - 1, tft.height() - 1, 0, y, color);
        delay(0);
    }
}

void testDrawText(const char* text, uint16_t color)
{
    tft.setCursor(0, 0);
    tft.setTextColor(color);
    tft.setTextWrap(true);
    tft.print(text);
}

void testFastLines(uint16_t color1, uint16_t color2)
{
    tft.fillScreen(ST77XX_BLACK);
    for(int16_t y = 0; y < tft.height(); y += 5)
    {
        tft.drawFastHLine(0, y, tft.width(), color1);
    }
    for(int16_t x = 0; x < tft.width(); x += 5)
    {
        tft.drawFastVLine(x, 0, tft.height(), color2);
    }
}

void testDrawRects(uint16_t color)
{
    tft.fillScreen(ST77XX_BLACK);
    for(int16_t x = 0; x < tft.width(); x += 6)
    {
        tft.drawRect(tft.width() / 2 - x / 2, tft.height() / 2 - x / 2, x, x, color);
    }
}

void testFillRects(uint16_t color1, uint16_t color2)
{
    tft.fillScreen(ST77XX_BLACK);
    for(int16_t x = tft.width() - 1; x > 6; x -= 6)
    {
        tft.fillRect(tft.width() / 2 - x / 2, tft.height() / 2 - x / 2, x, x, color1);
        tft.drawRect(tft.width() / 2 - x / 2, tft.height() / 2 - x / 2, x, x, color2);
    }
}

void testFillCircles(uint8_t radius, uint16_t color)
{
    for(int16_t x = radius; x < tft.width(); x += radius * 2)
    {
        for(int16_t y = radius; y < tft.height(); y += radius * 2)
        {
            tft.fillCircle(x, y, radius, color);
        }
    }
}

void testDrawCircles(uint8_t radius, uint16_t color)
{
    for(int16_t x = 0; x < tft.width() + radius; x += radius * 2)
    {
        for(int16_t y = 0; y < tft.height() + radius; y += radius * 2)
        {
            tft.drawCircle(x, y, radius, color);
        }
    }
}

void testTriangles()
{
    tft.fillScreen(ST77XX_BLACK);
    uint16_t color = 0xF800;
    int t;
    int w = tft.width() / 2;
    int x = tft.height() - 1;
    int y = 0;
    int z = tft.width();
    for(t = 0; t <= 15; t++)
    {
        tft.drawTriangle(w, y, y, x, z, x, color);
        x -= 4;
        y += 4;
        z -= 4;
        color += 100;
    }
}

void testRoundRects()
{
    tft.fillScreen(ST77XX_BLACK);
    uint16_t color = 100;
    int i;
    int t;
    for(t = 0; t <= 4; t += 1)
    {
        int x = 0;
        int y = 0;
        int w = tft.width() - 2;
        int h = tft.height() - 2;
        for(i = 0; i <= 16; i += 1)
        {
            tft.drawRoundRect(x, y, w, h, 5, color);
            x += 2;
            y += 3;
            w -= 4;
            h -= 6;
            color += 1100;
        }
        color += 100;
    }
}

void tftPrintTest()
{
    tft.setTextWrap(false);
    tft.fillScreen(ST77XX_BLACK);
    tft.setCursor(0, 30);
    tft.setTextColor(ST77XX_RED);
    tft.setTextSize(1);
    tft.println("Hello World!");
    tft.setTextColor(ST77XX_YELLOW);
    tft.setTextSize(2);
    tft.println("Hello World!");
    tft.setTextColor(ST77XX_GREEN);
    tft.setTextSize(3);
    tft.println("Hello World!");
    tft.setTextColor(ST77XX_BLUE);
    tft.setTextSize(4);
    tft.print(1234.567);
    delay(1500);
    tft.setCursor(0, 0);
    tft.fillScreen(ST77XX_BLACK);
    tft.setTextColor(ST77XX_WHITE);
    tft.setTextSize(0);
    tft.println("Hello World!");
    tft.setTextSize(1);
    tft.setTextColor(ST77XX_GREEN);
    tft.print(3.1415926f, 6);
    tft.println(" Want pi?");
    tft.println(" ");
    tft.print(8675309, HEX); // print 8,675,309 out in HEX!
    tft.println(" Print HEX!");
    tft.println(" ");
    tft.setTextColor(ST77XX_WHITE);
    tft.println("Sketch has been");
    tft.println("running for: ");
    tft.setTextColor(ST77XX_MAGENTA);
    tft.print(millis() / 1000);
    tft.setTextColor(ST77XX_WHITE);
    tft.print(" seconds.");
}

void testMediaButtons()
{
    // play
    tft.fillScreen(ST77XX_BLACK);
    tft.fillRoundRect(25, 10, 78, 60, 8, ST77XX_WHITE);
    tft.fillTriangle(42, 20, 42, 60, 90, 40, ST77XX_RED);
    delay(500);
    // pause
    tft.fillRoundRect(25, 90, 78, 60, 8, ST77XX_WHITE);
    tft.fillRoundRect(39, 98, 20, 45, 5, ST77XX_GREEN);
    tft.fillRoundRect(69, 98, 20, 45, 5, ST77XX_GREEN);
    delay(500);
    // play color
    tft.fillTriangle(42, 20, 42, 60, 90, 40, ST77XX_BLUE);
    delay(50);
    // pause color
    tft.fillRoundRect(39, 98, 20, 45, 5, ST77XX_RED);
    tft.fillRoundRect(69, 98, 20, 45, 5, ST77XX_RED);
    // play color
    tft.fillTriangle(42, 20, 42, 60, 90, 40, ST77XX_GREEN);
}

void setup(void)
{
    delay(1200);
    Serial.begin(115200);
    Serial.print("Hello! ST7789 TFT Test\n");

    // Use this initializer if using a 1.8" TFT screen:
    // tft.initR(INITR_BLACKTAB); // Init ST7735S chip, black tab

    // OR use this initializer if using a 1.8" TFT screen with offset such as
    // WaveShare: tft.initR(INITR_GREENTAB);      // Init ST7735S chip, green
    // tab

    // OR use this initializer if using a 1.44" TFT:
    // tft.initR(INITR_144GREENTAB); // Init ST7735R chip, green tab

    // OR use this initializer if using a 0.96" 160x80 TFT:
    // tft.initR(INITR_MINI160x80);  // Init ST7735S mini display
    // OR use this initializer if using a 0.96" 160x80 TFT with
    // plug-in FPC (if you see the display is inverted!)
    // tft.initR(INITR_MINI160x80_PLUGIN);  // Init ST7735S mini display

    // OR use this initializer if using a 1.3" or 1.54" 240x240 TFT:
    // tft.init(240, 240);           // Init ST7789 240x240

    // OR use this initializer if using a 1.69" 280x240 TFT:
    // tft.init(240, 280);           // Init ST7789 280x240

    // OR use this initializer if using a 2.0" 320x240 TFT:
    tft.setSPISpeed(40 * 1000 * 1000);
    tft.init(240, 320); // Init ST7789 320x240

    pinMode(TFT_BL, OUTPUT);
    digitalWrite(TFT_BL, HIGH);

    // OR use this initializer if using a 1.14" 240x135 TFT:
    // tft.init(135, 240);           // Init ST7789 240x135

    // OR use this initializer if using a 1.47" 172x320 TFT:
    // tft.init(172, 320);           // Init ST7789 172x320
    
    // SPI speed defaults to SPI_DEFAULT_FREQ defined in the library, you can
    // override it here. Note that speed allowable depends on chip and quality of
    // wiring, if you go too fast, you may end up with a black screen some
    // times, or all the time. tft.setSPISpeed(40000000);

    Serial.println(F("Initialized"));

    uint16_t time = millis();
    tft.fillScreen(ST77XX_BLACK);
    time = millis() - time;

    Serial.println(time, DEC);
    delay(500);

    // large block of text
    tft.fillScreen(ST77XX_BLACK);
    testDrawText(
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur "
        "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, "
        "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor "
        "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet "
        "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a "
        "tortor imperdiet posuere. ",
        ST77XX_WHITE);
    delay(1000);

    // tft print function!
    tftPrintTest();
    delay(3000);

    // a single pixel
    tft.drawPixel(tft.width() / 2, tft.height() / 2, ST77XX_GREEN);
    delay(500);

    // line draw test
    testLines(ST77XX_YELLOW);
    delay(500);

    // optimized lines
    testFastLines(ST77XX_RED, ST77XX_BLUE);
    delay(500);

    testDrawRects(ST77XX_GREEN);
    delay(500);

    testFillRects(ST77XX_YELLOW, ST77XX_MAGENTA);
    delay(500);

    tft.fillScreen(ST77XX_BLACK);
    testFillCircles(10, ST77XX_BLUE);
    testDrawCircles(10, ST77XX_WHITE);
    delay(500);

    testRoundRects();
    delay(500);

    testTriangles();
    delay(500);

    testMediaButtons();
    delay(500);

    Serial.println("done");
    delay(1000);
}

void loop()
{
    tft.invertDisplay(true);
    delay(500);
    tft.invertDisplay(false);
    delay(500);
}

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.0 migrationissue relates to migration from 2.X to 3.X version

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions