espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.79k stars 7.31k forks source link

ESP32S3 uses QSPI to send large data, resulting in only a small part of the information sent (IDFGH-8462) #9924

Open mmMicky opened 2 years ago

mmMicky commented 2 years ago

Board

ESP32-S3-WROOM-1U

Device Description

The pins are connected via board jumpers.

Hardware Configuration

define PIN_LCD_TE 11

define PIN_LCD_CS 6

define PIN_LCD_CLK 7

define PIN_LCD_D0 8

define PIN_LCD_D1 18

define PIN_LCD_D2 17

define PIN_LCD_D3 16

define PIN_LCD_RES 15

Version

v2.0.5

IDE Name

PlatformIO

Operating System

windows 10

Flash frequency

80

PSRAM enabled

yes

Upload speed

115200

Description

Use ESP32-S3 to drive SH1106 chip in QSPI mode. SH1106 is mostly the same as ST7789, but needs to use QSPI to drive. When I send data, I need to set the size of the form and then send the pixel data. Problem: Works fine when I send an image size of 150x109. The waveform I captured is shown below. h109

When I send the image size is 150x110. The waveform is as shown below. The ESP32-S3 only sent a small amount of data. It looks like there is only one line on the screen. h110

I have set max_transfer_sz to 3,862,536 (longer than the image data length) at initialization.

Sketch

static void lcd_gpio_init() {
  pinMode(_lcd_setting->cs_gpio_num, OUTPUT);
  pinMode(_lcd_setting->res_gpio_num, OUTPUT);

  digitalWrite(_lcd_setting->cs_gpio_num, HIGH);
  digitalWrite(_lcd_setting->res_gpio_num, HIGH);
}

static void lcd_send_cmd(uint32_t cmd, uint8_t *dat, uint32_t len) {
  spi_transaction_t t;
  memset(&t, 0, sizeof(t));
  t.flags = (SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR);
  t.cmd = 0x02;
  t.addr = cmd;
  t.length = 8 * len;
  if (len != 0) {
    t.tx_buffer = dat;
  } else {
    t.tx_buffer = NULL;
  }
  spi_device_polling_transmit(spi, &t);
}

void lcd_address_set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
  lcd_cmd_t t[3] = {
      {0x2a00, {x1 >> 8, x1, x2 >> 8, x2}, 0x04},
      {0x2b00, {y1 >> 8, y1, y2 >> 8, y2}, 0x04},
      {0x2c00, {0x00}, 0x00},
  };
  for (uint32_t i = 0; i < 3; i++) {
    lcd_send_cmd(t[i].addr, t[i].param, t[i].len);
  }
}

void lcd_push_colors(uint16_t x, uint16_t y, uint16_t width, uint16_t hight,
                     uint16_t *data) {

  size_t len = width * hight * 2;
  lcd_address_set(x, y, x + width - 1, y + hight - 1);

  /***********4 line***********/
  Serial.println("len : " + String(len));
  spi_transaction_t t;
  memset(&t, 0, sizeof(t));
  t.flags = (SPI_TRANS_MODE_QIO /* | SPI_TRANS_MODE_DIOQIO_ADDR */);
  t.cmd = 0x32;
  t.addr = 0x002C00;
  t.tx_buffer = (uint8_t *)data;
  t.length = 16 * len;
  Serial.println("t.length : " + String(t.length));
  ESP_ERROR_CHECK(spi_device_queue_trans(spi, &t , portMAX_DELAY));
}

void lcd_init(lcd_settings_t *config) {
  _lcd_setting = config;
  lcd_gpio_init();
  esp_err_t ret;
  horizontal = 0;

  spi_bus_config_t buscfg = {
      .data0_io_num = config->d0_gpio_num,
      .data1_io_num = config->d1_gpio_num,
      .sclk_io_num = config->clk_gpio_num,
      .data2_io_num = config->d2_gpio_num,
      .data3_io_num = config->d3_gpio_num,
      .max_transfer_sz = (LCD_WIDTH * LCD_HEIGHT * 32 * 2) + 8,
      // .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_QUAD |
      //          SPICOMMON_BUSFLAG_GPIO_PINS,
      .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_GPIO_PINS,
  };

  spi_device_interface_config_t devcfg = {
      .command_bits = 8,
      .address_bits = 24,
      // .dummy_bits=1,
      .mode = TFT_SPI_MODE,
      .clock_speed_hz = SPI_MASTER_FREQ_8M,
      .spics_io_num = config->cs_gpio_num,
      .flags = SPI_DEVICE_HALFDUPLEX,
      .queue_size = 3,

      // .pre_cb=lcd_spi_pre_transfer_callback,  //Specify pre-transfer callback
      // to handle D/C line
  };
  ret = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
  ESP_ERROR_CHECK(ret);
  ret = spi_bus_add_device(SPI2_HOST, &devcfg, &spi);
  ESP_ERROR_CHECK(ret);

  LCD_RES_Clr(); // reset
  delay(200);
  LCD_RES_Set();
  delay(200);

  lcd_cmd_t *t = sh8501_cmd;
  for (uint32_t i = 0; i < (sizeof(sh8501_cmd) / sizeof(lcd_cmd_t)); i++) {
    lcd_send_cmd(t[i].addr, t[i].param, t[i].len & 0x7f);
    if (t[i].len & 0x80) {
      delay(120);
    }
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("1.47 AMOLED Demo");
  Serial.println(String(ESP.getPsramSize() / 1024) + " KB");
  // lcd module :SH1106
  lcd_settings_t lcd_config = {.clk_gpio_num = PIN_LCD_CLK,
                               .d0_gpio_num = PIN_LCD_D0,
                               .d1_gpio_num = PIN_LCD_D1,
                               .d2_gpio_num = PIN_LCD_D2,
                               .d3_gpio_num = PIN_LCD_D3,
                               .cs_gpio_num = PIN_LCD_CS,
                               .res_gpio_num = PIN_LCD_RES,
                               .frequency = 5000000};

  lcd_init(&lcd_config);
  delay(1);
  lcd_push_colors(10, 10, 150, 109, (uint16_t *)gImage_image_logo);
  //lcd_push_colors(10, 10, 150, 110, (uint16_t *)gImage_image_logo);
}

Debug Message

The program just doesn't display properly, no error message appears.

Other Steps to Reproduce

LCD.zip

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

me-no-dev commented 2 years ago

Arduino v2.0.5 uses ESP-IDF v4.4.2. sdkconfig can be found here

mmMicky commented 2 years ago

It seems normal that it sends a small amount of data. In the example, the length is 194 x 110 x 2 x 16=682,880(bit). Only a small number of messages are sent.

Maksons commented 2 years ago

Looks like some 16KiB transaction limitation ? 150109 = 16350 (< 16384) 150110 = 16500 (> 16384) , 116 bytes over , maybe only those got sent ? From ESP-IDF SPI Master: "Maximum transfer size, in bytes. Defaults to 4092 if 0 when DMA enabled..." maybe it got *4 because of QSPI type of transaction

Forairaaaaa commented 1 year ago

Hi, I meet the same issue, when my data is more than 32,000 bytes like 34,000 big, it'll only send 2,000 byte. But it's normal when I send 34,000 bytes one by one

dj140 commented 4 months ago

I get the same issue too but it seems to behave a little differently, when I transfer a large amount of data, the QSPI bus will stall every 32768 byte and an error will occur when the transmitted data is greater than 32768 * 8 bytes.

E (1627) lcd_panel.io.spi: panel_io_spi_tx_color(387): spi transmit (queue) color failed

is esp32s3 max dma transfer size 32768 bytes?