Open SFNFIH opened 5 months ago
I'm not sure what the exact problem might be here, but I'm guessing the data buffers are not being properly accounted for when you press the rotate button on your display. What code executes when that button is pressed? Does it simply update the lv_disp_drv.rotated = LV_DISP_ROT_NONE;
value or does it also call the driver to indicate the display is also rotated (via ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(lcd_handle, false));
)
`static lv_obj_t meter; static lv_obj_t btn; static lv_disp_rot_t rotation = LV_DISP_ROT_NONE;
static void set_value(void *indic, int32_t v) { lv_meter_set_indicator_end_value(meter, indic, v); }
static void btn_cb(lv_event_t e) { lv_disp_t disp = lv_event_get_user_data(e); rotation++; if (rotation > LV_DISP_ROT_270) { rotation = LV_DISP_ROT_NONE; } lv_disp_set_rotation(disp, rotation); }
void example_lvgl_demo_ui() { lv_obj_t *scr = lv_scr_act(); meter = lv_meter_create(scr); lv_obj_center(meter); lv_obj_set_size(meter, 200, 200);
/*Add a scale first*/
lv_meter_scale_t *scale = lv_meter_add_scale(meter);
lv_meter_set_scale_ticks(meter, scale, 41, 2, 10, lv_palette_main(LV_PALETTE_GREY));
lv_meter_set_scale_major_ticks(meter, scale, 8, 4, 15, lv_color_black(), 10);
lv_meter_indicator_t *indic;
/*Add a blue arc to the start*/
indic = lv_meter_add_arc(meter, scale, 3, lv_palette_main(LV_PALETTE_BLUE), 0);
lv_meter_set_indicator_start_value(meter, indic, 0);
lv_meter_set_indicator_end_value(meter, indic, 20);
/*Make the tick lines blue at the start of the scale*/
indic = lv_meter_add_scale_lines(meter, scale, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_BLUE), false, 0);
lv_meter_set_indicator_start_value(meter, indic, 0);
lv_meter_set_indicator_end_value(meter, indic, 20);
/*Add a red arc to the end*/
indic = lv_meter_add_arc(meter, scale, 3, lv_palette_main(LV_PALETTE_RED), 0);
lv_meter_set_indicator_start_value(meter, indic, 80);
lv_meter_set_indicator_end_value(meter, indic, 100);
/*Make the tick lines red at the end of the scale*/
indic = lv_meter_add_scale_lines(meter, scale, lv_palette_main(LV_PALETTE_RED), lv_palette_main(LV_PALETTE_RED), false, 0);
lv_meter_set_indicator_start_value(meter, indic, 80);
lv_meter_set_indicator_end_value(meter, indic, 100);
/*Add a needle line indicator*/
indic = lv_meter_add_needle_line(meter, scale, 4, lv_palette_main(LV_PALETTE_GREY), -10);
btn = lv_btn_create(scr);
lv_obj_t * lbl = lv_label_create(btn);
lv_label_set_text_static(lbl, LV_SYMBOL_REFRESH" ROTATE");
lv_obj_align(btn, LV_ALIGN_BOTTOM_LEFT, 30, -30);
/*Button event*/
lv_obj_add_event_cb(btn, btn_cb, LV_EVENT_CLICKED, NULL);
/*Create an animation to set the value*/
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_exec_cb(&a, set_value);
lv_anim_set_var(&a, indic);
lv_anim_set_values(&a, 0, 100);
lv_anim_set_time(&a, 2000);
lv_anim_set_repeat_delay(&a, 100);
lv_anim_set_playback_time(&a, 500);
lv_anim_set_playback_delay(&a, 100);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_start(&a);
}` I just called the UI case provided by espressif. Normally, the screen will rotate normally without any distortion.
It seems that there is a problem with the screen's hardware rotation driver code. The software rotation is normal, but the refresh speed is very slow, and it is visible to the naked eye that the lines are refreshed one by one.
Thanks for the additional code, based on what you have provided LVGL would be preparing it's rendered image to match the initial state of the hardware and sending it over to the display as-is (a few lines at a time). If you increase the size of the buffer it may help. You might also test with 16-bit mode rather than 18-bit mode. The 18-bit mode requires processing of the pixel data before it can be sent over to the display, this may also add a small delay.
I'd also suggest using esp_lvgl_port if you aren't already.
You are the second person to remind me to use it. I will accept it. Thank you.
`static esp_err_t app_lcd_init(void) { esp_err_t ret = ESP_OK;
/* LCD backlight */
gpio_config_t bk_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << EXAMPLE_LCD_GPIO_BL
};
ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
/* LCD initialization */
ESP_LOGD(TAG, "Initialize SPI bus");
const spi_bus_config_t buscfg = {
.sclk_io_num = EXAMPLE_LCD_GPIO_SCLK,
.mosi_io_num = EXAMPLE_LCD_GPIO_MOSI,
.miso_io_num = GPIO_NUM_NC,
.quadwp_io_num = GPIO_NUM_NC,
.quadhd_io_num = GPIO_NUM_NC,
.max_transfer_sz = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT * sizeof(uint16_t),
};
ESP_RETURN_ON_ERROR(spi_bus_initialize(EXAMPLE_LCD_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed");
ESP_LOGD(TAG, "Install panel IO");
const esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = EXAMPLE_LCD_GPIO_DC,
.cs_gpio_num = EXAMPLE_LCD_GPIO_CS,
.pclk_hz = EXAMPLE_LCD_PIXEL_CLK_HZ,
.lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
.lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
.spi_mode = 0,
.trans_queue_depth = 10,
};
ESP_GOTO_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)EXAMPLE_LCD_SPI_NUM, &io_config, &lcd_io), err, TAG, "New panel IO failed");
ESP_LOGD(TAG, "Install LCD driver");
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = EXAMPLE_LCD_GPIO_RST,
.color_space = EXAMPLE_LCD_COLOR_SPACE,
.bits_per_pixel = EXAMPLE_LCD_BITS_PER_PIXEL,
};
ESP_GOTO_ON_ERROR(esp_lcd_new_panel_ili9488(lcd_io, &panel_config, LV_BUFFER_SIZE, &lcd_panel), err, TAG, "New panel failed");
esp_lcd_panel_reset(lcd_panel);
esp_lcd_panel_init(lcd_panel);
esp_lcd_panel_mirror(lcd_panel, true, true);
esp_lcd_panel_disp_on_off(lcd_panel, true);
/* LCD backlight on */
ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_LCD_GPIO_BL, EXAMPLE_LCD_BL_ON_LEVEL));
return ret;
err: if (lcd_panel) { esp_lcd_panel_del(lcd_panel); } if (lcd_io) { esp_lcd_panel_io_del(lcd_io); } spi_bus_free(EXAMPLE_LCD_SPI_NUM); return ret; }
static esp_err_t app_lvgl_init(void) { / Initialize LVGL / const lvgl_port_cfg_t lvgl_cfg = { .task_priority = 4, / LVGL task priority / .task_stack = 4096, / LVGL task stack size / .task_affinity = -1, / LVGL task pinned to core (-1 is no affinity) / .task_max_sleep_ms = 500, / Maximum sleep in LVGL task / .timer_period_ms = 5 / LVGL timer tick period in ms / }; ESP_RETURN_ON_ERROR(lvgl_port_init(&lvgl_cfg), TAG, "LVGL port initialization failed");
/* Add LCD screen */
ESP_LOGD(TAG, "Add LCD screen");
const lvgl_port_display_cfg_t disp_cfg = {
.io_handle = lcd_io,
.panel_handle = lcd_panel,
.buffer_size = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_DRAW_BUFF_HEIGHT,
.double_buffer = EXAMPLE_LCD_DRAW_BUFF_DOUBLE,
.hres = EXAMPLE_LCD_H_RES,
.vres = EXAMPLE_LCD_V_RES,
.monochrome = false,
.rotation = {
.swap_xy = false,
.mirror_x = true,
.mirror_y = true,
},
.flags = {
.buff_dma = true,
}
};
lvgl_disp = lvgl_port_add_disp(&disp_cfg);
return ESP_OK;
}
void app_main(void) { ESP_ERROR_CHECK(app_lcd_init()); ESP_ERROR_CHECK(app_lvgl_init()); lvgl_demo_ui();
ESP_LOGI(TAG, "Display LVGL Meter Widget");
while(1)
{
vTaskDelay(1000);
}
} ` I'm still a newbie, why is the screen black?
I'm not sure off hand why it would be blank, I'd suggest reviewing one of their samples as the only change to their example would be calling to create the display as ili9488.
You can try to compare it to this code which is working. LVGL9.1 though and I am using indev drivers which you can simply remove.
header:
#pragma once
#include "wholeinclude.h"
#include "ui.h"
#include "esp_lcd_touch_gt911.h"
#include "esp_lcd_ili9488.h"
#include "touch.h"
#include "helper_functions.h"
#include "driver/i2c_master.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////// Please update the following configuration according to your LCD spec //////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The pixel number in horizontal and vertical
// #define EXAMPLE_LCD_H_RES 320
// #define EXAMPLE_LCD_V_RES 480
#define EXAMPLE_LCD_H_RES 480
#define EXAMPLE_LCD_V_RES 320
// Bit number used to represent command and parameter
#define EXAMPLE_LCD_CMD_BITS 8
#define EXAMPLE_LCD_PARAM_BITS 8
#define EXAMPLE_LVGL_TICK_PERIOD_MS 10
#define BUFFER_SIZE EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES / 30
extern void ui_init(lv_obj_t *scr);
// static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)
// static lv_disp_drv_t disp_drv; // contains callback functions
static lv_display_t *disp;
// static lv_color16_t *buf1, *buf2;
static esp_lcd_touch_handle_t tp; // LCD touch handle
static bool notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
lv_display_t *disp_driver = (lv_display_t *)user_ctx;
lv_disp_flush_ready(disp_driver);
return false;
}
static void lvgl_flush_cb(lv_display_t *drv, const lv_area_t *area, uint8_t *color_map)
{
esp_lcd_panel_draw_bitmap((esp_lcd_panel_handle_t)lv_display_get_user_data(drv), area->x1, area->y1, area->x2 + 1, area->y2 + 1, color_map);
lv_disp_flush_ready(drv);
}
static void lvgl_tick_increment_cb(void *arg)
{
lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS);
}
void tft_init(void);
cpp:
#include "tft.h"
// static SemaphoreHandle_t lvgl_mux; // LVGL mutex
#define TAG "LCD"
#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (10 * 1000 * 1000)
#define EXAMPLE_LCD_I80_BUS_WIDTH 8
#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 1
#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL
#define EXAMPLE_PIN_NUM_DATA0 ((gpio_num_t)18)
#define EXAMPLE_PIN_NUM_DATA1 ((gpio_num_t)5)
#define EXAMPLE_PIN_NUM_DATA2 ((gpio_num_t)26)
#define EXAMPLE_PIN_NUM_DATA3 ((gpio_num_t)25)
#define EXAMPLE_PIN_NUM_DATA4 ((gpio_num_t)17)
#define EXAMPLE_PIN_NUM_DATA5 ((gpio_num_t)16)
#define EXAMPLE_PIN_NUM_DATA6 ((gpio_num_t)27)
#define EXAMPLE_PIN_NUM_DATA7 ((gpio_num_t)14)
#define EXAMPLE_PIN_NUM_PCLK ((gpio_num_t)4) // WR
#define EXAMPLE_PIN_NUM_CS ((gpio_num_t)33)
#define EXAMPLE_PIN_NUM_DC ((gpio_num_t)15)
#define EXAMPLE_PIN_NUM_RST ((gpio_num_t)32)
#define EXAMPLE_PIN_NUM_BK_LIGHT ((gpio_num_t)13)
#define EXAMPLE_PIN_NUM_SDA ((gpio_num_t)21)
#define EXAMPLE_PIN_NUM_SCL ((gpio_num_t)22)
#define EXAMPLE_PIN_NUM_INT ((gpio_num_t)19)
#define EXAMPLE_PIN_NUM_CRST ((gpio_num_t)23)
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_TIMEOUT_MS 1000
void tft_init(void)
{
ESP_LOGI(TAG, "Turn off LCD backlight");
gpio_config_t bk_gpio_config = {
.pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT,
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE};
ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL);
ESP_LOGI(TAG, "Initialize Intel 8080 bus");
esp_lcd_i80_bus_handle_t i80_bus = NULL;
esp_lcd_i80_bus_config_t bus_config = {
.dc_gpio_num = EXAMPLE_PIN_NUM_DC,
.wr_gpio_num = EXAMPLE_PIN_NUM_PCLK,
.clk_src = LCD_CLK_SRC_DEFAULT,
.data_gpio_nums = {
EXAMPLE_PIN_NUM_DATA0,
EXAMPLE_PIN_NUM_DATA1,
EXAMPLE_PIN_NUM_DATA2,
EXAMPLE_PIN_NUM_DATA3,
EXAMPLE_PIN_NUM_DATA4,
EXAMPLE_PIN_NUM_DATA5,
EXAMPLE_PIN_NUM_DATA6,
EXAMPLE_PIN_NUM_DATA7},
.bus_width = EXAMPLE_LCD_I80_BUS_WIDTH,
.max_transfer_bytes = BUFFER_SIZE * sizeof(lv_color16_t),
.psram_trans_align = 64};
ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_io_i80_config_t io_config = {
.cs_gpio_num = EXAMPLE_PIN_NUM_CS,
.pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
.trans_queue_depth = 20,
// .on_color_trans_done = notify_lvgl_flush_ready,
.user_ctx = disp, // this
.lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
.lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
.dc_levels = {
.dc_idle_level = 1,
.dc_cmd_level = 0,
.dc_dummy_level = 0,
.dc_data_level = 1},
.flags = {.cs_active_high = 0, .reverse_color_bits = 0, .swap_color_bytes = 1, .pclk_active_neg = 0, .pclk_idle_low = 0}};
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
ESP_LOGI(TAG, "Install LCD driver of ili9488");
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = EXAMPLE_PIN_NUM_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,
.bits_per_pixel = 16};
ESP_ERROR_CHECK(esp_lcd_new_panel_ili9488(io_handle, &panel_config, BUFFER_SIZE, &panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle, 0, 0));
//These are here to rotate the screen to landscape mode, dont forget to alter the EXAMPLE_LCD_H_RES and EXAMPLE_LCD_V_RES to your new POV
ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, true));
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, false, true));
ESP_LOGI(TAG, "Turn on LCD backlight");
ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL));
helper_functions::delay(200);
////////////////////////////////////////////////////
// I2C INIT
ESP_LOGI(TAG, "INIT i2c");
i2c_master_bus_handle_t i2c_bus = NULL;
i2c_master_bus_config_t i2c_bus_config = {
.i2c_port = 0,
.sda_io_num = EXAMPLE_PIN_NUM_SDA,
.scl_io_num = EXAMPLE_PIN_NUM_SCL,
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.flags{.enable_internal_pullup = true},
};
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, &i2c_bus));
////////////////////////////////////////////////////////////////////////
helper_functions::delay(200);
ESP_LOGI(TAG, "Initialize LVGL library");
lv_init();
static lv_color16_t *buf1 = (lv_color16_t *)heap_caps_malloc(BUFFER_SIZE * sizeof(lv_color16_t), MALLOC_CAP_DMA);
static lv_color16_t *buf2 = (lv_color16_t *)heap_caps_malloc(BUFFER_SIZE * sizeof(lv_color16_t), MALLOC_CAP_DMA);
ESP_LOGI(TAG, "Buffers initialized");
disp = lv_display_create(EXAMPLE_LCD_H_RES, EXAMPLE_LCD_V_RES);
ESP_LOGI(TAG, "Display initialized");
lv_display_set_buffers(disp, &buf1[0], &buf2[0], BUFFER_SIZE * sizeof(lv_color16_t), LV_DISPLAY_RENDER_MODE_PARTIAL);
ESP_LOGI(TAG, "buffers set");
lv_display_set_flush_cb(disp, lvgl_flush_cb);
lv_display_set_user_data(disp, panel_handle);
lv_display_set_driver_data(disp, panel_handle);
lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565);
helper_functions::delay(100);
////////////////////////////////////////////////////
// INIT TOUCH
ESP_LOGI(TAG, "INIT TOUCH");
static lv_indev_t *indev_drv_tp = lv_indev_create();
const esp_lcd_touch_config_t tp_cfg = {
.x_max = EXAMPLE_LCD_H_RES,
.y_max = EXAMPLE_LCD_V_RES,
.rst_gpio_num = GPIO_NUM_NC,
.int_gpio_num = EXAMPLE_PIN_NUM_INT,
.levels = {
.reset = 0,
.interrupt = 0,
},
.flags = {
//if altering these values do not lead to the expected results,
// try to alter the values read in your touchpad_read() function
//(e.g. subtract the hor_max from the x value and multiply by -1)
.swap_xy = 1,
.mirror_x = 0,
.mirror_y = 0,
},
};
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
tp_io_config.scl_speed_hz = 400000;
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c_v2(i2c_bus, &tp_io_config, &tp_io_handle));
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp));
assert(tp);
/* Register a touchpad input device */
lv_indev_set_type(indev_drv_tp, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev_drv_tp, touchpad_read);
lv_indev_set_user_data(indev_drv_tp, tp);
lv_indev_set_display(indev_drv_tp, disp);
////////////////////////////////////////////////////
ESP_LOGI(TAG, "Install LVGL tick timer");
const esp_timer_create_args_t lvgl_tick_timer_args = {
.callback = &lvgl_tick_increment_cb,
.arg = NULL,
.dispatch_method = ESP_TIMER_TASK,
.name = "lvgl_tick",
.skip_unhandled_events = false};
esp_timer_handle_t lvgl_tick_timer = NULL;
ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));
ESP_LOGI(TAG, "Display LVGL animation");
lv_obj_t *scr = lv_disp_get_scr_act(disp);
ui_init(scr);
}
Hello, your driver successfully drives my LCD screen, but I encountered some problems. The screen will be distorted when switching to landscape mode.The MCU I use is ESP32S3, and the lvgl version is 8.3.
The above is my driver code, which is basically written according to your example。