Bodmer / TFT_eSPI

Arduino and PlatformIO IDE compatible TFT library optimised for the Raspberry Pi Pico (RP2040), STM32, ESP8266 and ESP32 that supports different driver chips
Other
3.54k stars 1.02k forks source link

DMA stops writing after the first frame #3367

Open JordanKlaers opened 3 weeks ago

JordanKlaers commented 3 weeks ago

Only raise issues for problems with the library and/or provided examples. Post questions, comments and useful tips etc in the "Discussions" section.

To minimise effort to resolve issues the following should be provided as a minimum:

  1. A description of the problem and the conditions that cause it to occur: I am using an esp32-s3 with platformio. I have had DMA writing working before but now it just stops writing after the first frame. I have tested all of the demos for DMA as well as the previous code of mine that used DMA, all stop writing after the first frame.
  2. IDE (e.g. Arduino or PlatformIO): PlatformIO
  3. TFT_eSPI library version (try the latest, the problem may have been resolved!) from the Manage Libraries... menu: version=2.5.43
  4. Board package version (e.g. 2.0.3) available from the Boards Manager... menu: Im using platformIO so im not sure which things this is asking for
  5. Procesor, e.g RP2040, ESP32 S3 etc: ESP32-S3
  6. TFT driver (e.g. ILI9341), a link to the vendors product web page is useful too.: lcd screen
  7. Interface type (SPI or parallel): SPI

Plus further information as appropriate to the problem:

  1. TFT to processor connections used: In the Adafruit_GFX library, I have enforced hardware spi with my custom pins because esp32-s3 can use any pins for spi, so I needed to force/set the hardware pins manaually hwspi._spi->begin(4, -1, 5, 15);
  2. A zip file containing your setup file (just drag and drop in message window - do not paste in long files!): Im sorry which file would this be?
  3. A zip file containing a simple and complete example sketch that demonstrates the problem but needs no special hardware sensors or libraries. All the DMA demos/examples have this issue (not writing after the first frame)
  4. Screen shot pictures showing the problem (just drag and drop in message window) dma

I see its using void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer) from the "processors/TFT_eSPI_ESP32_S3.c file. Ive added some Serial.print's in there but it doesnt get caught up.

Im not sure how to debug this one, or why it stop writing after the first frame. Please let me know what additional information I need to provide or how I can look into this more myself

mjocean commented 3 weeks ago

I'm unfortunately having the same issues (and I posted about this in a Discussion thread yesterday) I am using an ESP32-S3 "Zero" (this is a waveshare "mini" form factor of an ESP32-S3FH4R2) and the very same GC9A01 1.28" circular LCDs, from the same vendor.

Everything works fine without DMA (e.g., pushPixels()), but the standard DMA examples stop updating the display after the initial frame, while the code continues to run, logging looks correct, and functions take time. I do not have this issue on the RP2040, only on this ESP32S3.

I have adjusted my pin connections to match the HSPI description of standard pins found in several repos: https://github.com/hideakitai/ESP32DMASPI?tab=readme-ov-file, https://github.com/espressif/arduino-esp32/blob/e1f14331f173a00a9062f616bc9a62c358b9076f/variants/esp32s3/pins_arduino.h so that relevant bits of my setup now read like this:

#define GC9A01_DRIVER

#define TFT_WIDTH 240
#define TFT_HEIGHT 240

#define TFT_MOSI 11 // "SDA" 
#define TFT_MISO 13 // No input, but standard pin nums
#define TFT_SCLK 12
#define TFT_CS   10 // Chip select control pin
#define TFT_DC    8  // Data Command control pin
#define TFT_RST   9  // Reset pin 
#define TFT_BL 40 // not connected
#define TFT_BACKLIGHT_ON HIGH

#define SPI_FREQUENCY  80000000  // working non-DMA with direct connection to headers
#define USE_HSPI_PORT

In my own code, I've tried any number of things include allocating buffer memory specifically for DMA usage (heap_caps_calloc(n_bytes, sizeof(uint16_t), MALLOC_CAP_DMA)) to no avail. And the standard DMA examples aren't working. I'm at a loss. Any advice would be greatly appreciated.

JordanKlaers commented 3 weeks ago

you said you are also setting specifically which pins are used for hspi?

mjocean commented 3 weeks ago

Yes. I adjusted my SPI pins to match the table found here: https://github.com/hideakitai/ESP32DMASPI?tab=readme-ov-file#spi-buses-and-spi-pins as shown in the excerpt of my Setup above.

JordanKlaers commented 3 weeks ago

I read that any pin could be used for spi so I updated the library for spi (since it was saying there were no defaults for hspi) to use the pins I wanted. The weird part is that DMA write was working about a month ago and now it isnt. I have no idea what could have changed, specially since its able to write the first frame, hopefully someone can provide some insight

mjocean commented 3 weeks ago

I had read the same about HSPI pin number flexibility, but since DMA was not working and there was specific information given about using specific pins, I thought the specific pins may matter after all.

Interesting that it had been working for you a month ago. I just got my esp32s3, so I haven't tried it before this past week.

I just tried rolling back the tft_espi library to the 2.5.34 release but there was no improvement. Leaving tft_espi at 2.5.34, I also tried rolling back esp32 board definitions back down to 3.0.0 and 2.0.17 but neither resolved the issue.

JordanKlaers commented 3 weeks ago

A slight change to the "pushImageDMA" function

ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY);
    if (ret != ESP_OK) {
        Serial.println("Failed to queue SPI transaction");
    }

    // Wait for the transaction to complete
    spi_transaction_t* rtrans;
    ret = spi_device_get_trans_result(dmaHAL, &rtrans, portMAX_DELAY);
    if (ret != ESP_OK) {
        Serial.println("Failed to get SPI transaction result");
    }
    free(buffer);
This causes the screen to update BUT its very slow and has a significant phase of all black between screen updates. Not a viable solution but maybe this gives a clue for someone with more experience. Also the Serial.print's are not called which seems to be an indication that those functions miiiight not be the exact issues
mjocean commented 2 weeks ago

At the risk of stating the obvious: your modification there inserts (essentially) the ESP32_S3 definition of tft.dmaWait() after the call to enqueue the DMA transaction. Since all of the push*DMA() methods are incrementing spiBusyCheck, then immediately calling dmaWait() after a pushImageDMA() call should have the same effect, but I tried it here, but I still see a frozen first frame.

JordanKlaers commented 2 weeks ago

You are right, I didnt notice that. I think more specifically though what made a difference was the free() call. I need to look into it more to see if I can get more information/a better fix

Enchiridion commented 1 week ago

I'm having the same issue, no updates after the first frame with DMA enabled, but everything works fine using pushSprite(). I believe I'm using the HSPI port (pins 13-15). My code and serial output still work fine and I'm seeing a 5fps increase with DMA enabled.

I'm using an ESP32-S3-DevKitC-1 (not official) with platformio with a round LCD using GC9A01 (not the waveshare version).

If I set the MISO pin to the same as CS, which I saw as a suggestion in a discussion about this issue, then some corrupted updates are continuously made to the upper portion of the screen. Varying the SPI frequency causes different kinds of corruption, but only with DMA enabled.

Platform espressif32@6.6.0 Board esp32-s3-devkitm-1 Library bodmer/TFT_eSPI@^2.5.43

Screenshot 2024-06-24 220402

JordanKlaers commented 1 week ago

You said with DMA, no updates after the first frame, but then also 5 fps increase with DMA, but partial corruption?

Enchiridion commented 1 week ago

@JordanKlaers Yes. I was only able to know there was a 5 fps increase using DMA because I was sending the fps over serial.

Enchiridion commented 1 week ago

Small update after more troubleshooting, turns out it wasn't actually drawing the first frame at all, just the random corruption as seen at the top. What I was seeing was the last contents of the graphics ram persistent between builds. When I power cycle the display then try again, it shows colored snow with the corruption at the top.