Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for ESP BSP 3 / IDF 5 and double buffering #394

Open
ladyada opened this issue Dec 3, 2023 · 17 comments
Open

support for ESP BSP 3 / IDF 5 and double buffering #394

ladyada opened this issue Dec 3, 2023 · 17 comments

Comments

@ladyada
Copy link
Contributor

ladyada commented Dec 3, 2023

hiya @moononournation - we were looking to see if this library could support the latest ESP board support package (right now its 3.0.0 alpha) since there's many changes in IDF5. also we think that it would be great to enable double-buffer support for the RGB TTL interface to avoid the tearing effect
https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/lcd.html#double-frame-buffer-in-psram

i don't have time to submit a PR...can we sponsor you to add one or both? if so please email limor@adafruit.com !

thanks :)

@moononournation
Copy link
Owner

any sponsor is welcome ;)

@ladyada
Copy link
Contributor Author

ladyada commented Dec 4, 2023

OK i sponsored! hopefully it will help :)

@ThorAsgardDev
Copy link

ThorAsgardDev commented Dec 5, 2023

Hello,

I have the Adafruit Qualia ESP32-S3 for TTL RGB-666 Displays (https://www.adafruit.com/product/5800) with the Round RGB TTL TFT Display - 4" 720x720 - NV3052C (https://www.adafruit.com/product/5793)
I'm not an LCD expert but I have prototyped a double buffered test app using ESP-IDF 5.1 (under platformio).
It's not perfect (I still got some timing issues) but it can save your time when using the new esp_lcd API (it's not very well documented specially about double buffering).

Hope this will help you.

Here is my code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "hal/gpio_types.h"
#include "rom/cache.h"

#include "esp_err.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_rgb.h"
#include "freertos/semphr.h"
#include "esp_timer.h"


#include "MyWire.h"
#include "MyPCA9554.h"
#include "MyUtils.h"


#define PCA_TFT_BACKLIGHT 4
#define PCA_BUTTON_DOWN 6
#define PCA_BUTTON_UP 5

#define TFT_DE 2
#define TFT_VSYNC 42
#define TFT_HSYNC 41
#define TFT_PCLK 1
#define TFT_R1 11
#define TFT_R2 10
#define TFT_R3 9
#define TFT_R4 46
#define TFT_R5 3
#define TFT_G0 48
#define TFT_G1 47
#define TFT_G2 21
#define TFT_G3 14
#define TFT_G4 13
#define TFT_G5 12
#define TFT_B1 40
#define TFT_B2 39
#define TFT_B3 38
#define TFT_B4 0
#define TFT_B5 45

#define WIDTH 720
#define HEIGHT 720

#define RGB565(r, g, b) ((((r)&0xF8) << 8) | (((g)&0xFC) << 3) | ((b) >> 3))

#define SQUARE_COUNT 20

typedef struct {
    int x;
    int y;
    int size;
    int dx;
    int dy;
    uint16_t color;
} SQUARE;


void fill_rect(uint16_t *frame_buffer, int32_t x, int32_t y, int32_t w, int32_t h, uint16_t color) {
    uint16_t *p = frame_buffer + WIDTH * y + x;
    uint16_t *first_line = p;

    uint32_t iw = w;

    if (h--) {
        while (iw--) *p++ = color;
    }
    
    p = first_line;
    while (h--) {
        p += WIDTH;
        memcpy(p, first_line, w << 1);
    }
}

int clamp(int v, int low, int high) {
    if (v < low) {
        v = low;
    }
    if (v >= high) {
        v = high;
    }
    return v;
}

void init_square(SQUARE *p) {
    p->size = 20 + (rand() % 30);
    p->x = clamp(rand() % WIDTH, 0, WIDTH - p->size - 1);
    p->y = clamp(rand() % HEIGHT, 0, HEIGHT - p->size - 1);
    p->dx = (3 + (rand() % 6)) * ((rand() % 2) == 1 ? 1 : -1);
    p->dy = (3 + (rand() % 6)) * ((rand() % 2) == 1 ? 1 : -1);
    p->color = RGB565(rand() % 255, rand() % 255, rand() % 255);
}

void draw_square(uint16_t *frame_buffer, SQUARE *p) {
    fill_rect(frame_buffer, p->x, p->y, p->size, p->size, p->color);
}

void update_square(SQUARE *p) {
    p->x += p->dx;
    if (p->x >= WIDTH - p->size - 1) {
        p->x = WIDTH - p->size - 1;
        p->dx = -p->dx;
    } else if (p->x <= 0) {
        p->x = 0;
        p->dx = -p->dx;
    }

    p->y += p->dy;
    if (p->y >= HEIGHT - p->size - 1) {
        p->y = HEIGHT - p->size - 1;
        p->dy = -p->dy;
    } else if (p->y <= 0) {
        p->y = 0;
        p->dy = -p->dy;
    }
}

static const uint8_t hd40015c40_init_operations[] = {
    BEGIN_WRITE,
    WRITE_C8_D8, 0xFF, 0x30,
    WRITE_C8_D8, 0xFF, 0x52,
    WRITE_C8_D8, 0xFF, 0x01,
    WRITE_C8_D8, 0xE3, 0x00,
    WRITE_C8_D8, 0x0A, 0x11,
    WRITE_C8_D8, 0x23, 0xA0,
    WRITE_C8_D8, 0x24, 0x32,
    WRITE_C8_D8, 0x25, 0x12,
    WRITE_C8_D8, 0x26, 0x2E,
    WRITE_C8_D8, 0x27, 0x2E,
    WRITE_C8_D8, 0x29, 0x02,
    WRITE_C8_D8, 0x2A, 0xCF,
    WRITE_C8_D8, 0x32, 0x34,
    WRITE_C8_D8, 0x38, 0x9C,
    WRITE_C8_D8, 0x39, 0xA7,
    WRITE_C8_D8, 0x3A, 0x27,
    WRITE_C8_D8, 0x3B, 0x94,
    WRITE_C8_D8, 0x42, 0x6D,
    WRITE_C8_D8, 0x43, 0x83,
    WRITE_C8_D8, 0x81, 0x00,
    WRITE_C8_D8, 0x91, 0x67,
    WRITE_C8_D8, 0x92, 0x67,
    WRITE_C8_D8, 0xA0, 0x52,
    WRITE_C8_D8, 0xA1, 0x50,
    WRITE_C8_D8, 0xA4, 0x9C,
    WRITE_C8_D8, 0xA7, 0x02,
    WRITE_C8_D8, 0xA8, 0x02,
    WRITE_C8_D8, 0xA9, 0x02,
    WRITE_C8_D8, 0xAA, 0xA8,
    WRITE_C8_D8, 0xAB, 0x28,
    WRITE_C8_D8, 0xAE, 0xD2,
    WRITE_C8_D8, 0xAF, 0x02,
    WRITE_C8_D8, 0xB0, 0xD2,
    WRITE_C8_D8, 0xB2, 0x26,
    WRITE_C8_D8, 0xB3, 0x26,

    WRITE_C8_D8, 0xFF, 0x30,
    WRITE_C8_D8, 0xFF, 0x52,
    WRITE_C8_D8, 0xFF, 0x02,
    WRITE_C8_D8, 0xB1, 0x0A,
    WRITE_C8_D8, 0xD1, 0x0E,
    WRITE_C8_D8, 0xB4, 0x2F,
    WRITE_C8_D8, 0xD4, 0x2D,
    WRITE_C8_D8, 0xB2, 0x0C,
    WRITE_C8_D8, 0xD2, 0x0C,
    WRITE_C8_D8, 0xB3, 0x30,
    WRITE_C8_D8, 0xD3, 0x2A,
    WRITE_C8_D8, 0xB6, 0x1E,
    WRITE_C8_D8, 0xD6, 0x16,
    WRITE_C8_D8, 0xB7, 0x3B,
    WRITE_C8_D8, 0xD7, 0x35,
    WRITE_C8_D8, 0xC1, 0x08,
    WRITE_C8_D8, 0xE1, 0x08,
    WRITE_C8_D8, 0xB8, 0x0D,
    WRITE_C8_D8, 0xD8, 0x0D,
    WRITE_C8_D8, 0xB9, 0x05,
    WRITE_C8_D8, 0xD9, 0x05,
    WRITE_C8_D8, 0xBD, 0x15,
    WRITE_C8_D8, 0xDD, 0x15,
    WRITE_C8_D8, 0xBC, 0x13,
    WRITE_C8_D8, 0xDC, 0x13,
    WRITE_C8_D8, 0xBB, 0x12,
    WRITE_C8_D8, 0xDB, 0x10,
    WRITE_C8_D8, 0xBA, 0x11,
    WRITE_C8_D8, 0xDA, 0x11,
    WRITE_C8_D8, 0xBE, 0x17,
    WRITE_C8_D8, 0xDE, 0x17,
    WRITE_C8_D8, 0xBF, 0x0F,
    WRITE_C8_D8, 0xDF, 0x0F,
    WRITE_C8_D8, 0xC0, 0x16,
    WRITE_C8_D8, 0xE0, 0x16,
    WRITE_C8_D8, 0xB5, 0x2E,
    WRITE_C8_D8, 0xD5, 0x3F,
    WRITE_C8_D8, 0xB0, 0x03,
    WRITE_C8_D8, 0xD0, 0x02,

    WRITE_C8_D8, 0xFF, 0x30,
    WRITE_C8_D8, 0xFF, 0x52,
    WRITE_C8_D8, 0xFF, 0x03,
    WRITE_C8_D8, 0x08, 0x09,
    WRITE_C8_D8, 0x09, 0x0A,
    WRITE_C8_D8, 0x0A, 0x0B,
    WRITE_C8_D8, 0x0B, 0x0C,
    WRITE_C8_D8, 0x28, 0x22,
    WRITE_C8_D8, 0x2A, 0xE9,
    WRITE_C8_D8, 0x2B, 0xE9,
    WRITE_C8_D8, 0x34, 0x51,
    WRITE_C8_D8, 0x35, 0x01,
    WRITE_C8_D8, 0x36, 0x26,
    WRITE_C8_D8, 0x37, 0x13,
    WRITE_C8_D8, 0x40, 0x07,
    WRITE_C8_D8, 0x41, 0x08,
    WRITE_C8_D8, 0x42, 0x09,
    WRITE_C8_D8, 0x43, 0x0A,
    WRITE_C8_D8, 0x44, 0x22,
    WRITE_C8_D8, 0x45, 0xDB,
    WRITE_C8_D8, 0x46, 0xdC,
    WRITE_C8_D8, 0x47, 0x22,
    WRITE_C8_D8, 0x48, 0xDD,
    WRITE_C8_D8, 0x49, 0xDE,
    WRITE_C8_D8, 0x50, 0x0B,
    WRITE_C8_D8, 0x51, 0x0C,
    WRITE_C8_D8, 0x52, 0x0D,
    WRITE_C8_D8, 0x53, 0x0E,
    WRITE_C8_D8, 0x54, 0x22,
    WRITE_C8_D8, 0x55, 0xDF,
    WRITE_C8_D8, 0x56, 0xE0,
    WRITE_C8_D8, 0x57, 0x22,
    WRITE_C8_D8, 0x58, 0xE1,
    WRITE_C8_D8, 0x59, 0xE2,
    WRITE_C8_D8, 0x80, 0x1E,
    WRITE_C8_D8, 0x81, 0x1E,
    WRITE_C8_D8, 0x82, 0x1F,
    WRITE_C8_D8, 0x83, 0x1F,
    WRITE_C8_D8, 0x84, 0x05,
    WRITE_C8_D8, 0x85, 0x0A,
    WRITE_C8_D8, 0x86, 0x0A,
    WRITE_C8_D8, 0x87, 0x0C,
    WRITE_C8_D8, 0x88, 0x0C,
    WRITE_C8_D8, 0x89, 0x0E,
    WRITE_C8_D8, 0x8A, 0x0E,
    WRITE_C8_D8, 0x8B, 0x10,
    WRITE_C8_D8, 0x8C, 0x10,
    WRITE_C8_D8, 0x8D, 0x00,
    WRITE_C8_D8, 0x8E, 0x00,
    WRITE_C8_D8, 0x8F, 0x1F,
    WRITE_C8_D8, 0x90, 0x1F,
    WRITE_C8_D8, 0x91, 0x1E,
    WRITE_C8_D8, 0x92, 0x1E,
    WRITE_C8_D8, 0x93, 0x02,
    WRITE_C8_D8, 0x94, 0x04,
    WRITE_C8_D8, 0x96, 0x1E,
    WRITE_C8_D8, 0x97, 0x1E,
    WRITE_C8_D8, 0x98, 0x1F,
    WRITE_C8_D8, 0x99, 0x1F,
    WRITE_C8_D8, 0x9A, 0x05,
    WRITE_C8_D8, 0x9B, 0x09,
    WRITE_C8_D8, 0x9C, 0x09,
    WRITE_C8_D8, 0x9D, 0x0B,
    WRITE_C8_D8, 0x9E, 0x0B,
    WRITE_C8_D8, 0x9F, 0x0D,
    WRITE_C8_D8, 0xA0, 0x0D,
    WRITE_C8_D8, 0xA1, 0x0F,
    WRITE_C8_D8, 0xA2, 0x0F,
    WRITE_C8_D8, 0xA3, 0x00,
    WRITE_C8_D8, 0xA4, 0x00,
    WRITE_C8_D8, 0xA5, 0x1F,
    WRITE_C8_D8, 0xA6, 0x1F,
    WRITE_C8_D8, 0xA7, 0x1E,
    WRITE_C8_D8, 0xA8, 0x1E,
    WRITE_C8_D8, 0xA9, 0x01,
    WRITE_C8_D8, 0xAA, 0x03,

    WRITE_C8_D8, 0xFF, 0x30,
    WRITE_C8_D8, 0xFF, 0x52,
    WRITE_C8_D8, 0xFF, 0x00,
    WRITE_C8_D8, 0x36, 0x0A,

    WRITE_COMMAND_8, 0x11, // Sleep Out
    END_WRITE,

    DELAY, 100,

    BEGIN_WRITE,
    WRITE_COMMAND_8, 0x29, // Display On
    END_WRITE,

    DELAY, 50
};

// Semaphore used to synchronize frame buffers swap
SemaphoreHandle_t sem_vsync_end;
SemaphoreHandle_t sem_frame_buffer_ready;

uint16_t *frame_buffers[2];
int current_frame_buffer_idx = 0;


bool on_vsync(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *data, void *user_ctx) {
    BaseType_t high_task_awoken0 = pdFALSE;
    xSemaphoreGiveFromISR(sem_vsync_end, &high_task_awoken0);

    BaseType_t high_task_awoken1 = pdFALSE;
    xSemaphoreTakeFromISR(sem_frame_buffer_ready, &high_task_awoken1);

    return (high_task_awoken0 == pdTRUE) || (high_task_awoken1 == pdTRUE);
}

void wait_vsync_and_show_frame_buffer(esp_lcd_panel_handle_t panel, uint16_t *frame_buffer) {

    xSemaphoreTake(sem_vsync_end, portMAX_DELAY);

    // If the last esp_lcd_panel_draw_bitmap arg is a frame buffer allocated in PSRAM,
    // then esp_lcd_panel_draw_bitmap does not make a copy but switches to this frame buffer
    esp_lcd_panel_draw_bitmap(panel, 0, 0, WIDTH, HEIGHT, frame_buffer);

    xSemaphoreGive(sem_frame_buffer_ready);
}

void create_lcd_panel(esp_lcd_panel_handle_t *panel_handle) {
    esp_lcd_rgb_panel_config_t panel_config;

    memset(&panel_config, 0, sizeof(esp_lcd_rgb_panel_config_t));

    panel_config.data_width = 16; // RGB565 in parallel mode, thus 16bit in width
    panel_config.psram_trans_align = 64;
    panel_config.clk_src = LCD_CLK_SRC_PLL160M;
    panel_config.disp_gpio_num = GPIO_NUM_NC;
    panel_config.pclk_gpio_num = TFT_PCLK;
    panel_config.vsync_gpio_num = TFT_VSYNC;
    panel_config.hsync_gpio_num = TFT_HSYNC;
    panel_config.de_gpio_num = TFT_DE;
    panel_config.data_gpio_nums[0] = TFT_B1;
    panel_config.data_gpio_nums[1] = TFT_B2;
    panel_config.data_gpio_nums[2] = TFT_B3;
    panel_config.data_gpio_nums[3] = TFT_B4;
    panel_config.data_gpio_nums[4] = TFT_B5;
    panel_config.data_gpio_nums[5] = TFT_G0;
    panel_config.data_gpio_nums[6] = TFT_G1;
    panel_config.data_gpio_nums[7] = TFT_G2;
    panel_config.data_gpio_nums[8] = TFT_G3;
    panel_config.data_gpio_nums[9] = TFT_G4;
    panel_config.data_gpio_nums[10] = TFT_G5;
    panel_config.data_gpio_nums[11] = TFT_R1;
    panel_config.data_gpio_nums[12] = TFT_R2;
    panel_config.data_gpio_nums[13] = TFT_R3;
    panel_config.data_gpio_nums[14] = TFT_R4;
    panel_config.data_gpio_nums[15] = TFT_R5;

    panel_config.timings.pclk_hz = 16000000;
    panel_config.timings.h_res = WIDTH;
    panel_config.timings.v_res = HEIGHT;
    panel_config.timings.hsync_back_porch = 44;
    panel_config.timings.hsync_front_porch = 46;
    panel_config.timings.hsync_pulse_width = 2;
    panel_config.timings.vsync_back_porch = 16;
    panel_config.timings.vsync_front_porch = 50;
    panel_config.timings.vsync_pulse_width = 16;
    panel_config.timings.flags.pclk_active_neg = 0;

    panel_config.timings.flags.vsync_idle_low = 1;

    // Request 2 frame buffers in PSRAM
    panel_config.num_fbs = 2;
    panel_config.flags.fb_in_psram = true;

    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, panel_handle));

    esp_lcd_rgb_panel_event_callbacks_t callbacks;
    memset(&callbacks, 0, sizeof(esp_lcd_rgb_panel_event_callbacks_t));
    callbacks.on_vsync = on_vsync;
    ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(*panel_handle, &callbacks, NULL));

    ESP_ERROR_CHECK(esp_lcd_panel_reset(*panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_init(*panel_handle));

    // Retrieve allocated frame buffers
    ESP_ERROR_CHECK(esp_lcd_rgb_panel_get_frame_buffer(*panel_handle, 2, (void **)&frame_buffers[0], (void **)&frame_buffers[1]));
}

void app_main(void) {
    printf("Hello world!\n");

    sem_vsync_end = xSemaphoreCreateBinary();
    assert(sem_vsync_end);
    sem_frame_buffer_ready = xSemaphoreCreateBinary();
    assert(sem_frame_buffer_ready);

    my_wire_create();
    MY_PCA9554_HANDLE handle;
    my_PCA9554_create(&handle);

    my_PCA9554_send_command(&handle, 0x01);
    my_delay(120);
    my_PCA9554_batch(&handle, hd40015c40_init_operations, sizeof(hd40015c40_init_operations));

    esp_lcd_panel_handle_t panel_handle = NULL;
    create_lcd_panel(&panel_handle);

    my_PCA9554_pin_mode(&handle, PCA_TFT_BACKLIGHT, OUTPUT);
    my_PCA9554_digital_write(&handle, PCA_TFT_BACKLIGHT, HIGH);

    SQUARE squares[SQUARE_COUNT];
    for (int i = 0; i < SQUARE_COUNT; i++) {
        init_square(&squares[i]);
    }

    int fps_counter = 0;
    unsigned long fps_time = my_millis();

    while (true) {

        uint16_t *frame_buffer;
        frame_buffer = frame_buffers[current_frame_buffer_idx];
        
        // Clear frame buffer and draw squares
        fill_rect(frame_buffer, 0, 0, WIDTH, HEIGHT, RGB565(0, 0, 255));
        for (int i = 0; i < SQUARE_COUNT; i++) {
            draw_square(frame_buffer, &squares[i]);
        }

        wait_vsync_and_show_frame_buffer(panel_handle, frame_buffer);
        current_frame_buffer_idx = 1 - current_frame_buffer_idx;

        // Update squares positions
        for (int i = 0; i < SQUARE_COUNT; i++) {
            update_square(&squares[i]);
        }

        // Update FPS counter and print FPS
        fps_counter++;
        unsigned long t = my_millis();
        if (t - fps_time >= 1000) {
            printf("FPS: %d\n", fps_counter);
            fps_counter = 0;
            fps_time = t;
        }
    }

    my_PCA9554_delete(&handle);
    my_wire_delete();
}

@moononournation
Copy link
Owner

Just trying 3.0.0-ALPHA3, seems this version not yet enable SOC_LCD_RGB_SUPPORTED. Still a long way to go.

moononournation added a commit that referenced this issue Dec 9, 2023
moononournation added a commit that referenced this issue Dec 9, 2023
@emre2blue
Copy link

Hello,

I have the Adafruit Qualia ESP32-S3 for TTL RGB-666 Displays (https://www.adafruit.com/product/5800) with the Round RGB TTL TFT Display - 4" 720x720 - NV3052C (https://www.adafruit.com/product/5793) I'm not an LCD expert but I have prototyped a double buffered test app using ESP-IDF 5.1 (under platformio). It's not perfect (I still got some timing issues) but it can save your time when using the new esp_lcd API (it's not very well documented specially about double buffering).

Hope this will help you.

Here is my code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "hal/gpio_types.h"
#include "rom/cache.h"

#include "esp_err.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_rgb.h"
#include "freertos/semphr.h"
#include "esp_timer.h"


#include "MyWire.h"
#include "MyPCA9554.h"
#include "MyUtils.h"


#define PCA_TFT_BACKLIGHT 4
#define PCA_BUTTON_DOWN 6
#define PCA_BUTTON_UP 5

#define TFT_DE 2
#define TFT_VSYNC 42
#define TFT_HSYNC 41
#define TFT_PCLK 1
#define TFT_R1 11
#define TFT_R2 10
#define TFT_R3 9
#define TFT_R4 46
#define TFT_R5 3
#define TFT_G0 48
#define TFT_G1 47
#define TFT_G2 21
#define TFT_G3 14
#define TFT_G4 13
#define TFT_G5 12
#define TFT_B1 40
#define TFT_B2 39
#define TFT_B3 38
#define TFT_B4 0
#define TFT_B5 45

#define WIDTH 720
#define HEIGHT 720

#define RGB565(r, g, b) ((((r)&0xF8) << 8) | (((g)&0xFC) << 3) | ((b) >> 3))

#define SQUARE_COUNT 20

typedef struct {
    int x;
    int y;
    int size;
    int dx;
    int dy;
    uint16_t color;
} SQUARE;


void fill_rect(uint16_t *frame_buffer, int32_t x, int32_t y, int32_t w, int32_t h, uint16_t color) {
    uint16_t *p = frame_buffer + WIDTH * y + x;
    uint16_t *first_line = p;

    uint32_t iw = w;

    if (h--) {
        while (iw--) *p++ = color;
    }
    
    p = first_line;
    while (h--) {
        p += WIDTH;
        memcpy(p, first_line, w << 1);
    }
}

int clamp(int v, int low, int high) {
    if (v < low) {
        v = low;
    }
    if (v >= high) {
        v = high;
    }
    return v;
}

void init_square(SQUARE *p) {
    p->size = 20 + (rand() % 30);
    p->x = clamp(rand() % WIDTH, 0, WIDTH - p->size - 1);
    p->y = clamp(rand() % HEIGHT, 0, HEIGHT - p->size - 1);
    p->dx = (3 + (rand() % 6)) * ((rand() % 2) == 1 ? 1 : -1);
    p->dy = (3 + (rand() % 6)) * ((rand() % 2) == 1 ? 1 : -1);
    p->color = RGB565(rand() % 255, rand() % 255, rand() % 255);
}

void draw_square(uint16_t *frame_buffer, SQUARE *p) {
    fill_rect(frame_buffer, p->x, p->y, p->size, p->size, p->color);
}

void update_square(SQUARE *p) {
    p->x += p->dx;
    if (p->x >= WIDTH - p->size - 1) {
        p->x = WIDTH - p->size - 1;
        p->dx = -p->dx;
    } else if (p->x <= 0) {
        p->x = 0;
        p->dx = -p->dx;
    }

    p->y += p->dy;
    if (p->y >= HEIGHT - p->size - 1) {
        p->y = HEIGHT - p->size - 1;
        p->dy = -p->dy;
    } else if (p->y <= 0) {
        p->y = 0;
        p->dy = -p->dy;
    }
}

static const uint8_t hd40015c40_init_operations[] = {
    BEGIN_WRITE,
    WRITE_C8_D8, 0xFF, 0x30,
    WRITE_C8_D8, 0xFF, 0x52,
    WRITE_C8_D8, 0xFF, 0x01,
    WRITE_C8_D8, 0xE3, 0x00,
    WRITE_C8_D8, 0x0A, 0x11,
    WRITE_C8_D8, 0x23, 0xA0,
    WRITE_C8_D8, 0x24, 0x32,
    WRITE_C8_D8, 0x25, 0x12,
    WRITE_C8_D8, 0x26, 0x2E,
    WRITE_C8_D8, 0x27, 0x2E,
    WRITE_C8_D8, 0x29, 0x02,
    WRITE_C8_D8, 0x2A, 0xCF,
    WRITE_C8_D8, 0x32, 0x34,
    WRITE_C8_D8, 0x38, 0x9C,
    WRITE_C8_D8, 0x39, 0xA7,
    WRITE_C8_D8, 0x3A, 0x27,
    WRITE_C8_D8, 0x3B, 0x94,
    WRITE_C8_D8, 0x42, 0x6D,
    WRITE_C8_D8, 0x43, 0x83,
    WRITE_C8_D8, 0x81, 0x00,
    WRITE_C8_D8, 0x91, 0x67,
    WRITE_C8_D8, 0x92, 0x67,
    WRITE_C8_D8, 0xA0, 0x52,
    WRITE_C8_D8, 0xA1, 0x50,
    WRITE_C8_D8, 0xA4, 0x9C,
    WRITE_C8_D8, 0xA7, 0x02,
    WRITE_C8_D8, 0xA8, 0x02,
    WRITE_C8_D8, 0xA9, 0x02,
    WRITE_C8_D8, 0xAA, 0xA8,
    WRITE_C8_D8, 0xAB, 0x28,
    WRITE_C8_D8, 0xAE, 0xD2,
    WRITE_C8_D8, 0xAF, 0x02,
    WRITE_C8_D8, 0xB0, 0xD2,
    WRITE_C8_D8, 0xB2, 0x26,
    WRITE_C8_D8, 0xB3, 0x26,

    WRITE_C8_D8, 0xFF, 0x30,
    WRITE_C8_D8, 0xFF, 0x52,
    WRITE_C8_D8, 0xFF, 0x02,
    WRITE_C8_D8, 0xB1, 0x0A,
    WRITE_C8_D8, 0xD1, 0x0E,
    WRITE_C8_D8, 0xB4, 0x2F,
    WRITE_C8_D8, 0xD4, 0x2D,
    WRITE_C8_D8, 0xB2, 0x0C,
    WRITE_C8_D8, 0xD2, 0x0C,
    WRITE_C8_D8, 0xB3, 0x30,
    WRITE_C8_D8, 0xD3, 0x2A,
    WRITE_C8_D8, 0xB6, 0x1E,
    WRITE_C8_D8, 0xD6, 0x16,
    WRITE_C8_D8, 0xB7, 0x3B,
    WRITE_C8_D8, 0xD7, 0x35,
    WRITE_C8_D8, 0xC1, 0x08,
    WRITE_C8_D8, 0xE1, 0x08,
    WRITE_C8_D8, 0xB8, 0x0D,
    WRITE_C8_D8, 0xD8, 0x0D,
    WRITE_C8_D8, 0xB9, 0x05,
    WRITE_C8_D8, 0xD9, 0x05,
    WRITE_C8_D8, 0xBD, 0x15,
    WRITE_C8_D8, 0xDD, 0x15,
    WRITE_C8_D8, 0xBC, 0x13,
    WRITE_C8_D8, 0xDC, 0x13,
    WRITE_C8_D8, 0xBB, 0x12,
    WRITE_C8_D8, 0xDB, 0x10,
    WRITE_C8_D8, 0xBA, 0x11,
    WRITE_C8_D8, 0xDA, 0x11,
    WRITE_C8_D8, 0xBE, 0x17,
    WRITE_C8_D8, 0xDE, 0x17,
    WRITE_C8_D8, 0xBF, 0x0F,
    WRITE_C8_D8, 0xDF, 0x0F,
    WRITE_C8_D8, 0xC0, 0x16,
    WRITE_C8_D8, 0xE0, 0x16,
    WRITE_C8_D8, 0xB5, 0x2E,
    WRITE_C8_D8, 0xD5, 0x3F,
    WRITE_C8_D8, 0xB0, 0x03,
    WRITE_C8_D8, 0xD0, 0x02,

    WRITE_C8_D8, 0xFF, 0x30,
    WRITE_C8_D8, 0xFF, 0x52,
    WRITE_C8_D8, 0xFF, 0x03,
    WRITE_C8_D8, 0x08, 0x09,
    WRITE_C8_D8, 0x09, 0x0A,
    WRITE_C8_D8, 0x0A, 0x0B,
    WRITE_C8_D8, 0x0B, 0x0C,
    WRITE_C8_D8, 0x28, 0x22,
    WRITE_C8_D8, 0x2A, 0xE9,
    WRITE_C8_D8, 0x2B, 0xE9,
    WRITE_C8_D8, 0x34, 0x51,
    WRITE_C8_D8, 0x35, 0x01,
    WRITE_C8_D8, 0x36, 0x26,
    WRITE_C8_D8, 0x37, 0x13,
    WRITE_C8_D8, 0x40, 0x07,
    WRITE_C8_D8, 0x41, 0x08,
    WRITE_C8_D8, 0x42, 0x09,
    WRITE_C8_D8, 0x43, 0x0A,
    WRITE_C8_D8, 0x44, 0x22,
    WRITE_C8_D8, 0x45, 0xDB,
    WRITE_C8_D8, 0x46, 0xdC,
    WRITE_C8_D8, 0x47, 0x22,
    WRITE_C8_D8, 0x48, 0xDD,
    WRITE_C8_D8, 0x49, 0xDE,
    WRITE_C8_D8, 0x50, 0x0B,
    WRITE_C8_D8, 0x51, 0x0C,
    WRITE_C8_D8, 0x52, 0x0D,
    WRITE_C8_D8, 0x53, 0x0E,
    WRITE_C8_D8, 0x54, 0x22,
    WRITE_C8_D8, 0x55, 0xDF,
    WRITE_C8_D8, 0x56, 0xE0,
    WRITE_C8_D8, 0x57, 0x22,
    WRITE_C8_D8, 0x58, 0xE1,
    WRITE_C8_D8, 0x59, 0xE2,
    WRITE_C8_D8, 0x80, 0x1E,
    WRITE_C8_D8, 0x81, 0x1E,
    WRITE_C8_D8, 0x82, 0x1F,
    WRITE_C8_D8, 0x83, 0x1F,
    WRITE_C8_D8, 0x84, 0x05,
    WRITE_C8_D8, 0x85, 0x0A,
    WRITE_C8_D8, 0x86, 0x0A,
    WRITE_C8_D8, 0x87, 0x0C,
    WRITE_C8_D8, 0x88, 0x0C,
    WRITE_C8_D8, 0x89, 0x0E,
    WRITE_C8_D8, 0x8A, 0x0E,
    WRITE_C8_D8, 0x8B, 0x10,
    WRITE_C8_D8, 0x8C, 0x10,
    WRITE_C8_D8, 0x8D, 0x00,
    WRITE_C8_D8, 0x8E, 0x00,
    WRITE_C8_D8, 0x8F, 0x1F,
    WRITE_C8_D8, 0x90, 0x1F,
    WRITE_C8_D8, 0x91, 0x1E,
    WRITE_C8_D8, 0x92, 0x1E,
    WRITE_C8_D8, 0x93, 0x02,
    WRITE_C8_D8, 0x94, 0x04,
    WRITE_C8_D8, 0x96, 0x1E,
    WRITE_C8_D8, 0x97, 0x1E,
    WRITE_C8_D8, 0x98, 0x1F,
    WRITE_C8_D8, 0x99, 0x1F,
    WRITE_C8_D8, 0x9A, 0x05,
    WRITE_C8_D8, 0x9B, 0x09,
    WRITE_C8_D8, 0x9C, 0x09,
    WRITE_C8_D8, 0x9D, 0x0B,
    WRITE_C8_D8, 0x9E, 0x0B,
    WRITE_C8_D8, 0x9F, 0x0D,
    WRITE_C8_D8, 0xA0, 0x0D,
    WRITE_C8_D8, 0xA1, 0x0F,
    WRITE_C8_D8, 0xA2, 0x0F,
    WRITE_C8_D8, 0xA3, 0x00,
    WRITE_C8_D8, 0xA4, 0x00,
    WRITE_C8_D8, 0xA5, 0x1F,
    WRITE_C8_D8, 0xA6, 0x1F,
    WRITE_C8_D8, 0xA7, 0x1E,
    WRITE_C8_D8, 0xA8, 0x1E,
    WRITE_C8_D8, 0xA9, 0x01,
    WRITE_C8_D8, 0xAA, 0x03,

    WRITE_C8_D8, 0xFF, 0x30,
    WRITE_C8_D8, 0xFF, 0x52,
    WRITE_C8_D8, 0xFF, 0x00,
    WRITE_C8_D8, 0x36, 0x0A,

    WRITE_COMMAND_8, 0x11, // Sleep Out
    END_WRITE,

    DELAY, 100,

    BEGIN_WRITE,
    WRITE_COMMAND_8, 0x29, // Display On
    END_WRITE,

    DELAY, 50
};

// Semaphore used to synchronize frame buffers swap
SemaphoreHandle_t sem_vsync_end;
SemaphoreHandle_t sem_frame_buffer_ready;

uint16_t *frame_buffers[2];
int current_frame_buffer_idx = 0;


bool on_vsync(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *data, void *user_ctx) {
    BaseType_t high_task_awoken0 = pdFALSE;
    xSemaphoreGiveFromISR(sem_vsync_end, &high_task_awoken0);

    BaseType_t high_task_awoken1 = pdFALSE;
    xSemaphoreTakeFromISR(sem_frame_buffer_ready, &high_task_awoken1);

    return (high_task_awoken0 == pdTRUE) || (high_task_awoken1 == pdTRUE);
}

void wait_vsync_and_show_frame_buffer(esp_lcd_panel_handle_t panel, uint16_t *frame_buffer) {

    xSemaphoreTake(sem_vsync_end, portMAX_DELAY);

    // If the last esp_lcd_panel_draw_bitmap arg is a frame buffer allocated in PSRAM,
    // then esp_lcd_panel_draw_bitmap does not make a copy but switches to this frame buffer
    esp_lcd_panel_draw_bitmap(panel, 0, 0, WIDTH, HEIGHT, frame_buffer);

    xSemaphoreGive(sem_frame_buffer_ready);
}

void create_lcd_panel(esp_lcd_panel_handle_t *panel_handle) {
    esp_lcd_rgb_panel_config_t panel_config;

    memset(&panel_config, 0, sizeof(esp_lcd_rgb_panel_config_t));

    panel_config.data_width = 16; // RGB565 in parallel mode, thus 16bit in width
    panel_config.psram_trans_align = 64;
    panel_config.clk_src = LCD_CLK_SRC_PLL160M;
    panel_config.disp_gpio_num = GPIO_NUM_NC;
    panel_config.pclk_gpio_num = TFT_PCLK;
    panel_config.vsync_gpio_num = TFT_VSYNC;
    panel_config.hsync_gpio_num = TFT_HSYNC;
    panel_config.de_gpio_num = TFT_DE;
    panel_config.data_gpio_nums[0] = TFT_B1;
    panel_config.data_gpio_nums[1] = TFT_B2;
    panel_config.data_gpio_nums[2] = TFT_B3;
    panel_config.data_gpio_nums[3] = TFT_B4;
    panel_config.data_gpio_nums[4] = TFT_B5;
    panel_config.data_gpio_nums[5] = TFT_G0;
    panel_config.data_gpio_nums[6] = TFT_G1;
    panel_config.data_gpio_nums[7] = TFT_G2;
    panel_config.data_gpio_nums[8] = TFT_G3;
    panel_config.data_gpio_nums[9] = TFT_G4;
    panel_config.data_gpio_nums[10] = TFT_G5;
    panel_config.data_gpio_nums[11] = TFT_R1;
    panel_config.data_gpio_nums[12] = TFT_R2;
    panel_config.data_gpio_nums[13] = TFT_R3;
    panel_config.data_gpio_nums[14] = TFT_R4;
    panel_config.data_gpio_nums[15] = TFT_R5;

    panel_config.timings.pclk_hz = 16000000;
    panel_config.timings.h_res = WIDTH;
    panel_config.timings.v_res = HEIGHT;
    panel_config.timings.hsync_back_porch = 44;
    panel_config.timings.hsync_front_porch = 46;
    panel_config.timings.hsync_pulse_width = 2;
    panel_config.timings.vsync_back_porch = 16;
    panel_config.timings.vsync_front_porch = 50;
    panel_config.timings.vsync_pulse_width = 16;
    panel_config.timings.flags.pclk_active_neg = 0;

    panel_config.timings.flags.vsync_idle_low = 1;

    // Request 2 frame buffers in PSRAM
    panel_config.num_fbs = 2;
    panel_config.flags.fb_in_psram = true;

    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, panel_handle));

    esp_lcd_rgb_panel_event_callbacks_t callbacks;
    memset(&callbacks, 0, sizeof(esp_lcd_rgb_panel_event_callbacks_t));
    callbacks.on_vsync = on_vsync;
    ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(*panel_handle, &callbacks, NULL));

    ESP_ERROR_CHECK(esp_lcd_panel_reset(*panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_init(*panel_handle));

    // Retrieve allocated frame buffers
    ESP_ERROR_CHECK(esp_lcd_rgb_panel_get_frame_buffer(*panel_handle, 2, (void **)&frame_buffers[0], (void **)&frame_buffers[1]));
}

void app_main(void) {
    printf("Hello world!\n");

    sem_vsync_end = xSemaphoreCreateBinary();
    assert(sem_vsync_end);
    sem_frame_buffer_ready = xSemaphoreCreateBinary();
    assert(sem_frame_buffer_ready);

    my_wire_create();
    MY_PCA9554_HANDLE handle;
    my_PCA9554_create(&handle);

    my_PCA9554_send_command(&handle, 0x01);
    my_delay(120);
    my_PCA9554_batch(&handle, hd40015c40_init_operations, sizeof(hd40015c40_init_operations));

    esp_lcd_panel_handle_t panel_handle = NULL;
    create_lcd_panel(&panel_handle);

    my_PCA9554_pin_mode(&handle, PCA_TFT_BACKLIGHT, OUTPUT);
    my_PCA9554_digital_write(&handle, PCA_TFT_BACKLIGHT, HIGH);

    SQUARE squares[SQUARE_COUNT];
    for (int i = 0; i < SQUARE_COUNT; i++) {
        init_square(&squares[i]);
    }

    int fps_counter = 0;
    unsigned long fps_time = my_millis();

    while (true) {

        uint16_t *frame_buffer;
        frame_buffer = frame_buffers[current_frame_buffer_idx];
        
        // Clear frame buffer and draw squares
        fill_rect(frame_buffer, 0, 0, WIDTH, HEIGHT, RGB565(0, 0, 255));
        for (int i = 0; i < SQUARE_COUNT; i++) {
            draw_square(frame_buffer, &squares[i]);
        }

        wait_vsync_and_show_frame_buffer(panel_handle, frame_buffer);
        current_frame_buffer_idx = 1 - current_frame_buffer_idx;

        // Update squares positions
        for (int i = 0; i < SQUARE_COUNT; i++) {
            update_square(&squares[i]);
        }

        // Update FPS counter and print FPS
        fps_counter++;
        unsigned long t = my_millis();
        if (t - fps_time >= 1000) {
            printf("FPS: %d\n", fps_counter);
            fps_counter = 0;
            fps_time = t;
        }
    }

    my_PCA9554_delete(&handle);
    my_wire_delete();
}

I wish you could upload it to us the way we can test the code in arduino. Can you give us a little bit information how to compile it and test it on our dafruit Qualia ESP32-S3 boards?

@MCUdude
Copy link

MCUdude commented Dec 19, 2023

@moononournation I have a Makerfabs 4.0" 480x480 ESP32S3 based board that suffers badly from screen tearing when using LVGL. When the picture is still, I get about 33 FPS, but when large portions of the screen are changing, it drops down to about 4 FPS, and it tears really bad. Will the double buffer work with this screen as well (RGB565+SPI). If yes, that would be a game changer for all the Makerfabs ESP32-based touch screens.

@ThorAsgardDev
Copy link

Hello,
I have the Adafruit Qualia ESP32-S3 for TTL RGB-666 Displays (https://www.adafruit.com/product/5800) with the Round RGB TTL TFT Display - 4" 720x720 - NV3052C (https://www.adafruit.com/product/5793) I'm not an LCD expert but I have prototyped a double buffered test app using ESP-IDF 5.1 (under platformio). It's not perfect (I still got some timing issues) but it can save your time when using the new esp_lcd API (it's not very well documented specially about double buffering).
Hope this will help you.
Here is my code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

I wish you could upload it to us the way we can test the code in arduino. Can you give us a little bit information how to compile it and test it on our dafruit Qualia ESP32-S3 boards?

The problem is that this code can be compiled only using ESP IDF 5.X. The arduino environment is currently using ESP IDF 4.X.
So currently it's not possible to compile this code "in arduino".

@moononournation
Copy link
Owner

yes, still need to wait next dev version.

@MCUdude
Copy link

MCUdude commented Dec 19, 2023

How about PlatformIO? That's what I'm currently using. I'm using the Arduino-ESP32 framework, but as far as I know, it uses IDF 5.x.

@moononournation
Copy link
Owner

try it

@MCUdude
Copy link

MCUdude commented Dec 19, 2023

yes, still need to wait next dev version.

They have already released development versions of their next arduino-esp32 package:
https://github.com/espressif/arduino-esp32/releases

It should be possible to use with Arduino IDE if one install the development version:
https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html

@emre2blue
Copy link

Hello,
I have the Adafruit Qualia ESP32-S3 for TTL RGB-666 Displays (https://www.adafruit.com/product/5800) with the Round RGB TTL TFT Display - 4" 720x720 - NV3052C (https://www.adafruit.com/product/5793) I'm not an LCD expert but I have prototyped a double buffered test app using ESP-IDF 5.1 (under platformio). It's not perfect (I still got some timing issues) but it can save your time when using the new esp_lcd API (it's not very well documented specially about double buffering).
Hope this will help you.
Here is my code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

I wish you could upload it to us the way we can test the code in arduino. Can you give us a little bit information how to compile it and test it on our dafruit Qualia ESP32-S3 boards?

The problem is that this code can be compiled only using ESP IDF 5.X. The arduino environment is currently using ESP IDF 4.X. So currently it's not possible to compile this code "in arduino".

hi, I've get rid of Arduino IDE and installed VSCode yesterday night. I can build and upload ESP32-S3 programs to it and it runs.
I think you are using VSCode too.

Only Problem is we don't have

#include "MyWire.h"
#include "MyPCA9554.h"
#include "MyUtils.h"

those files and related to them. So I could not compile and test the code. Arduino IDE is irrelevant to me to run the LCD now. If those files are in a library can you share the name of them so I could download and check them ?

@ThorAsgardDev
Copy link

ThorAsgardDev commented Dec 19, 2023

Hello,
I have the Adafruit Qualia ESP32-S3 for TTL RGB-666 Displays (https://www.adafruit.com/product/5800) with the Round RGB TTL TFT Display - 4" 720x720 - NV3052C (https://www.adafruit.com/product/5793) I'm not an LCD expert but I have prototyped a double buffered test app using ESP-IDF 5.1 (under platformio). It's not perfect (I still got some timing issues) but it can save your time when using the new esp_lcd API (it's not very well documented specially about double buffering).
Hope this will help you.
Here is my code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

I wish you could upload it to us the way we can test the code in arduino. Can you give us a little bit information how to compile it and test it on our dafruit Qualia ESP32-S3 boards?

The problem is that this code can be compiled only using ESP IDF 5.X. The arduino environment is currently using ESP IDF 4.X. So currently it's not possible to compile this code "in arduino".

hi, I've get rid of Arduino IDE and installed VSCode yesterday night. I can build and upload ESP32-S3 programs to it and it runs. I think you are using VSCode too.

Only Problem is we don't have

#include "MyWire.h" #include "MyPCA9554.h" #include "MyUtils.h"

those files and related to them. So I could not compile and test the code. Arduino IDE is irrelevant to me to run the LCD now. If those files are in a library can you share the name of them so I could download and check them ?

It's a very basic reimplementation of minimum required functions to use the Qualia 666
Here are the sources:

lib.zip

Unzip this in the lib directory of your platformio project.

@emre2blue
Copy link

emre2blue commented Jan 2, 2024

Hello,
I have the Adafruit Qualia ESP32-S3 for TTL RGB-666 Displays (https://www.adafruit.com/product/5800) with the Round RGB TTL TFT Display - 4" 720x720 - NV3052C (https://www.adafruit.com/product/5793) I'm not an LCD expert but I have prototyped a double buffered test app using ESP-IDF 5.1 (under platformio). It's not perfect (I still got some timing issues) but it can save your time when using the new esp_lcd API (it's not very well documented specially about double buffering).
Hope this will help you.
Here is my code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

I wish you could upload it to us the way we can test the code in arduino. Can you give us a little bit information how to compile it and test it on our dafruit Qualia ESP32-S3 boards?

The problem is that this code can be compiled only using ESP IDF 5.X. The arduino environment is currently using ESP IDF 4.X. So currently it's not possible to compile this code "in arduino".

hi, I've get rid of Arduino IDE and installed VSCode yesterday night. I can build and upload ESP32-S3 programs to it and it runs. I think you are using VSCode too.
Only Problem is we don't have
#include "MyWire.h" #include "MyPCA9554.h" #include "MyUtils.h"
those files and related to them. So I could not compile and test the code. Arduino IDE is irrelevant to me to run the LCD now. If those files are in a library can you share the name of them so I could download and check them ?

It's a very basic reimplementation of minimum required functions to use the Qualia 666 Here are the sources:

lib.zip

Unzip this in the lib directory of your platformio project.

Hello, It's me again. Happy new year :D I'm sorry to bother you. I could not have time to test it. But today I've done it. with only one error

/esp/esp-idf/components/freertos/app_startup.c:206: undefined reference to `app_main'

I think this is a major error, because there seems no solution for it. Could you help me a little what did I do wrong ?

EDIT: I've found the problem. I alwasy pressed "ESP-IDF build" button. There is another button called "PlatformIO Build". And I could build it and upload it to RGB666 board. But There are some warnings

like :
Processing adafruit_qualia_s3_rgb666 (platform: espressif32; board: adafruit_qualia_s3_rgb666; framework: espidf)

Verbose mode can be enabled via -v, --verbose option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/adafruit_qualia_s3_rgb666.html
PLATFORM: Espressif 32 (6.5.0) > Adafruit Qualia ESP32-S3 RGB666
HARDWARE: ESP32S3 240MHz, 320KB RAM, 16MB Flash
DEBUG: Current (cmsis-dap) External (cmsis-dap, esp-bridge, esp-builtin, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES:

  • framework-espidf @ 3.50102.0 (5.1.2)
  • tool-cmake @ 3.16.4
  • tool-esptoolpy @ 1.40501.0 (4.5.1)
  • tool-idf @ 1.0.1
  • tool-mconf @ 1.4060000.20190628 (406.0.0)
  • tool-mkfatfs @ 2.0.1
  • tool-mklittlefs @ 1.203.210628 (2.3)
  • tool-mkspiffs @ 2.230.0 (2.30)
  • tool-ninja @ 1.9.0
  • tool-riscv32-esp-elf-gdb @ 11.2.0+20220823
  • tool-xtensa-esp-elf-gdb @ 11.2.0+20230208
  • toolchain-esp32ulp @ 1.23500.220830 (2.35.0)
  • toolchain-riscv32-esp @ 12.2.0+20230208
  • toolchain-xtensa-esp32s3 @ 12.2.0+20230208
    Reading CMake configuration...
    Warning! Flash memory size mismatch detected. Expected 16MB, found 2MB!
    Please select a proper value in your sdkconfig.defaults or via the menuconfig target!
    LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
    LDF Modes: Finder ~ chain, Compatibility ~ soft
    Found 3 compatible libraries
    Scanning dependencies...
    Dependency Graph
    |-- MyPCA9554
    |-- MyUtils
    |-- MyWire
    Building in release mode
    Retrieving maximum program size .pio\build\adafruit_qualia_s3_rgb666\firmware.elf
    Checking size .pio\build\adafruit_qualia_s3_rgb666\firmware.elf
    Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
    RAM: [ ] 4.0% (used 13136 bytes from 327680 bytes)
    Flash: [== ] 23.4% (used 245373 bytes from 1048576 bytes)
    Configuring upload protocol...

Warning! Flash memory size mismatch detected. Expected 16MB, found 2MB!

Did you ever get that type of warning ? And when I upload the code to Board. I check the Serial port for debug. Calloc for Frame buffer fails.

@emre2blue
Copy link

I have this message from Serial Port of Qualia S3 RGB666 board. Did you ever get such an error ?? Would you please help me ?
I've fixed the 16MB Flash problem with menuconfig. But I'm not sure it worked correctly

"lcd_rgb_panel_alloc_frame_buffers(156): no mem for frame buffer"

Rebooting...
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x3 (RTC_SW_SYS_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x4037734b
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3818,len:0x1750
load:0x403c9700,len:0x4
load:0x403c9704,len:0xc00
load:0x403cc700,len:0x2e04
entry 0x403c9908
�[0;32mI (26) boot: ESP-IDF 5.1.2 2nd stage bootloader�[0m
�[0;32mI (27) boot: compile time Jan 4 2024 15:09:45�[0m
�[0;32mI (27) boot: Multicore bootloader�[0m
�[0;32mI (30) boot: chip revision: v0.2�[0m
�[0;32mI (33) boot.esp32s3: Boot SPI Speed : 80MHz�[0m
�[0;32mI (38) boot.esp32s3: SPI Mode : DIO�[0m
�[0;32mI (43) boot.esp32s3: SPI Flash Size : 16MB�[0m
�[0;32mI (48) boot: Enabling RNG early entropy source...�[0m
�[0;32mI (53) boot: Partition Table:�[0m
�[0;32mI (57) boot: ## Label Usage Type ST Offset Length�[0m
�[0;32mI (64) boot: 0 nvs WiFi data 01 02 00009000 00006000�[0m
�[0;32mI (71) boot: 1 phy_init RF data 01 01 0000f000 00001000�[0m
�[0;32mI (79) boot: 2 factory factory app 00 00 00010000 00100000�[0m
�[0;32mI (86) boot: End of partition table�[0m
�[0;32mI (91) esp_image: segment 0: paddr=00010020 vaddr=3c020020 size=0c278h ( 49784) map�[0m
�[0;32mI (108) esp_image: segment 1: paddr=0001c2a0 vaddr=3fc93a00 size=02ac8h ( 10952) load�[0m
�[0;32mI (111) esp_image: segment 2: paddr=0001ed70 vaddr=40374000 size=012a8h ( 4776) load�[0m
�[0;32mI (117) esp_image: segment 3: paddr=00020020 vaddr=42000020 size=1d910h (121104) map�[0m
�[0;32mI (146) esp_image: segment 4: paddr=0003d938 vaddr=403752a8 size=0e688h ( 59016) load�[0m
�[0;32mI (166) boot: Loaded app from partition at offset 0x10000�[0m
�[0;32mI (166) boot: Disabling RNG early entropy source...�[0m
�[0;32mI (178) cpu_start: Multicore app�[0m
�[0;32mI (178) cpu_start: Pro cpu up.�[0m
�[0;32mI (178) cpu_start: Starting app cpu, entry point is 0x403761d8�[0m
�[0;32mI (0) cpu_start: App cpu up.�[0m
�[0;32mI (196) cpu_start: Pro cpu start user code�[0m
�[0;32mI (196) cpu_start: cpu freq: 160000000 Hz�[0m
�[0;32mI (196) cpu_start: Application information:�[0m
�[0;32mI (199) cpu_start: Project name: RainBow�[0m
�[0;32mI (204) cpu_start: App version: 1�[0m
�[0;32mI (209) cpu_start: Compile time: Jan 4 2024 15:09:33�[0m
�[0;32mI (215) cpu_start: ELF file SHA256: 1ab96ed1b3ec3a5e...�[0m
�[0;32mI (221) cpu_start: ESP-IDF: 5.1.2�[0m
�[0;32mI (225) cpu_start: Min chip rev: v0.0�[0m
�[0;32mI (230) cpu_start: Max chip rev: v0.99 �[0m
�[0;32mI (235) cpu_start: Chip rev: v0.2�[0m
�[0;32mI (240) heap_init: Initializing. RAM available for dynamic allocation:�[0m
�[0;32mI (247) heap_init: At 3FC96D50 len 000529C0 (330 KiB): DRAM�[0m
�[0;32mI (253) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM�[0m
�[0;32mI (260) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM�[0m
�[0;32mI (266) heap_init: At 600FE010 len 00001FD8 (7 KiB): RTCRAM�[0m
�[0;32mI (273) spi_flash: detected chip: gd�[0m
�[0;32mI (276) spi_flash: flash io: dio�[0m
�[0;32mI (281) sleep: Configure to isolate all GPIO pins in sleep state�[0m
�[0;32mI (287) sleep: Enable automatic switching of GPIO sleep configuration�[0m
�[0;32mI (295) app_start: Starting scheduler on CPU0�[0m
�[0;32mI (299) app_start: Starting scheduler on CPU1�[0m
�[0;32mI (299) main_task: Started on CPU0�[0m
�[0;32mI (309) main_task: Calling app_main()�[0m

my_wire_create
Initialising I2C Master: sda=8 scl=18 freq=1000000
MyWire ready!
PCA9554 found
�[0;31mE (1069) lcd_panel.rgb: lcd_rgb_panel_alloc_frame_buffers(156): no mem for frame buffer�[0m
�[0;31mE (1069) lcd_panel.rgb: esp_lcd_new_rgb_panel(285): alloc frame buffers failed�[0m
Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.

Core 0 register dump:
PC : 0x420034c1 PS : 0x00060730 A0 : 0x82003aca A1 : 0x3fc9a560
A2 : 0x3fc9bdc8 A3 : 0x3c0205ac A4 : 0x3c020adc A5 : 0x0000042d
A6 : 0x3c0205ac A7 : 0x3c020d8c A8 : 0x00000000 A9 : 0x3fc9a500
A10 : 0x42012284 A11 : 0x3c0205ac A12 : 0x3c020adc A13 : 0x3fc9a560
A14 : 0x3fc9a540 A15 : 0x0000000c SAR : 0x00000004 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000 LBEG : 0x400556d5 LEND : 0x400556e5 LCOUNT : 0xfffffffa

Backtrace: 0x420034be:0x3fc9a560 0x42003ac7:0x3fc9a580 0x4200187b:0x3fc9a5c0 0x42001997:0x3fc9a690 0x4037de10:0x3fc9a8a0 0x4037da09:0x3fc9a8d0

ELF file SHA256: 1ab96ed1b3ec3a5e

@mikegoettling
Copy link

Hello I tested your program on platformio with IDF 5.2.1 and it works. your LCD setup is spot on and the timing issue is not that but your updating the buffers too fast and its causing what looks to be vertical row. if you add vTaskDelay and play with delay it works. also found that the log command is also slowing it down to show frame buffers. its not 100% but it works. To emre2blue you do not have PSram turned on so its not seeing the Psram flash. have to configure that in menuconfig

fill_rect(frame_buffer, 0, 0, WIDTH, HEIGHT, RGB565(0, 0, 255));
for (int i = 0; i < SQUARE_COUNT; i++) {
vTaskDelay(109);
draw_square(frame_buffer, &squares[i]);
}

    wait_vsync_and_show_frame_buffer(panel_handle, frame_buffer);
    current_frame_buffer_idx = 1 - current_frame_buffer_idx;

    // Update squares positions
   for (int i = 0; i < SQUARE_COUNT; i++) {
   update_square(&squares[i]);
    }

@jhzzzz
Copy link
Sponsor

jhzzzz commented May 27, 2024

Arduino-ESP32 3.0 now supports IDF5. eagerly hope that gfx will support it soon. just sponsored, thank you :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants