Hello there,
I have been doing a lot of tinkering for my understanding of C, ESP-IDF and LVGL for the last days. I tried things I found in this forum, on github, tried different LLMs like chatGPT or perplexity and still I cannot get the necessary understanding of what I am doing wrong or need to change.
Therefore I am reaching out to you and I am asking for advise. I am pretty novice in working with such low level (for my understanding/skill) programming.
I have an ESP32C6 from seeedstudio (link) MCU.
I am using VSCode, ESP-IDF v5.4.3 and LVGL 9.4. Additional components added thru the ESP-IDF plugin (Component Manager) in VSCode are espresssif/esp_lvgl_port 2.6.2 and espressif/esp_lcd_gc9a01 2.0.4
Problem: I cannot get the colors right and the font sharp.
I tried LV_COLOR_16_SWAP in lv_conf.h both 1 and 0 but I cannot see any difference. I did full clean and rebuild after changing from 1 to 0 and 0 to 1.
I have LV_COLOR_DEPTH 16 in my lv_conf.h
Only if I use esp_lcd_panel_invert_color(panel_handle, true) the screen’s background is white and the font black (if set it to false lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0xFFFFFF), LV_PART_MAIN); will give me a black background on the screen)
edit: I just realised that the colors are actually wrong since lv_color_hex is 0xRRGGBB and I thought when using .rgb_endian = LCD_RGB_ENDIAN_BGR, in the panel_config it’s also BBGGRR).
I attach a picture of the screen drawn with the code below.
The 3 buttons left to right shown are:
left: BLUE & should be lv_color_hex(0xFF0000) (for BGR colors thats fine)
middle: RED & should be lv_color_hex(0x00FF00) (for BGR colors thats swapped with green)
right: GREEN & should be lv_color_hex(0x0000FF) (for BGR colors thats swapped with red)
If I use
lv_palette_main(LV_PALETTE_BLUE)
lv_palette_main(LV_PALETTE_GREEN)
lv_palette_main(LV_PALETTE_RED)
the colors are as in this image:
I have also been running a ESP32 (WROOM32) with lv_micropython and there I could get everything up and running. I compiled the firmware with these flags make BOARD=GENERIC LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1" and selected invert = False & colormode = ..BGR so that’s what I tried first using C but no luck so far.
Here is a picture of the same display driven with a WROOM32 using lv_micropython:
That’s my code below in hope you can help me and tell me what I am doing wrong and why/how to fix it. I have the feeling that both the color swap and fuzzy font are related but cannot find the solution on my own.
Thanks a lot in advance!
#include <stdio.h>
#include "include/time.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_gc9a01.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "driver/ledc.h"
#include "lv_conf.h"
#include "lvgl.h"
static const char *ESP_LOG_TAG = "RIoT4ESP";
// GC9A01 display
#define DISP_MOSI GPIO_NUM_18
#define DISP_CLK GPIO_NUM_19
#define DISP_RES GPIO_NUM_21
#define DISP_DC GPIO_NUM_2
#define DISP_CS GPIO_NUM_1
#define DISP_BLK GPIO_NUM_0
#define DISP_FREQ 10000000 // 10 MHz
#define DISP_CMD_BITS 8
#define DISP_CMD_PARAM_BITS 8
#define DISP_HRES 240
#define DISP_VRES 240
#define DISP_SPI_HOST SPI2_HOST
static uint8_t disp_buf1[DISP_HRES * DISP_VRES * 2]; // 2 bytes per pixel for RGB565 & maybe multiply with 1/10 for partial render mode
static uint8_t disp_buf2[DISP_HRES * DISP_VRES * 2]; // 2 bytes per pixel for RGB565 & maybe multiply with 1/10 for partial render mode
static lv_display_t *lv_disp = NULL;
static esp_lcd_panel_handle_t panel_handle = NULL;
// lvgl needs a callback which provides the (run)time in milliseconds
uint32_t lvgl_get_milliseconds_cb(void)
{
return esp_timer_get_time() / 1000;
}
// green and blue are swapped with my GC9A01 display so I need to do that in the flus function
static void lvgl_flush_cb(lv_display_t *display, const lv_area_t *area, uint8_t *color_map)
{
esp_lcd_panel_draw_bitmap(panel_handle, area->x1, area->y1, area->x2 + 1, area->y2 + 1, color_map);
lv_display_flush_ready(display);
}
void app_main(void)
{
ESP_LOGI(ESP_LOG_TAG, "Hello, starting up!");
lv_init();
lv_tick_set_cb(lvgl_get_milliseconds_cb);
// config SPI bus according to https://github.com/espressif/esp-bsp/blob/master/components/lcd/esp_lcd_gc9a01/README.md
const spi_bus_config_t bus_config = GC9A01_PANEL_BUS_SPI_CONFIG(DISP_CLK, DISP_MOSI,
DISP_HRES * 80 * sizeof(uint16_t));
ESP_ERROR_CHECK(spi_bus_initialize(DISP_SPI_HOST, &bus_config, SPI_DMA_CH_AUTO));
// config io handle and io config according to https://github.com/espressif/esp-bsp/blob/master/components/lcd/esp_lcd_gc9a01/README.md
esp_lcd_panel_io_handle_t io_handle = NULL;
const esp_lcd_panel_io_spi_config_t io_config = GC9A01_PANEL_IO_SPI_CONFIG(DISP_CS, DISP_DC,
NULL, NULL);
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)DISP_SPI_HOST, &io_config, &io_handle));
ESP_LOGI(ESP_LOG_TAG, "Install GC9A01 panel driver");
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = DISP_RES,
//.rgb_endian = LCD_RGB_ENDIAN_RGB, LCD_RGB_ENDIAN_BGR
//.rgb_ele_order = LCD_RGB_ENDIAN_RGB,
.rgb_endian = LCD_RGB_ENDIAN_BGR,
.bits_per_pixel = 16,
};
ESP_ERROR_CHECK(esp_lcd_new_panel_gc9a01(io_handle, &panel_config, &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_invert_color(panel_handle, true));
ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, false));
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false));
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
lv_disp = lv_display_create(DISP_HRES, DISP_VRES);
lv_display_set_flush_cb(lv_disp, lvgl_flush_cb);
lv_display_set_buffers(lv_disp, disp_buf1, disp_buf2, sizeof(disp_buf1) + sizeof(disp_buf2), LV_DISPLAY_RENDER_MODE_DIRECT);
lv_obj_t *b1 = lv_button_create(lv_screen_active());
lv_obj_set_size(b1, 50, 50);
lv_obj_set_style_bg_color(b1, lv_color_hex(0xFF0000), LV_PART_MAIN);
// rgb_endian = LCD_RGB_ENDIAN_BGR: yellow, esp_lcd_panel_invert_color false
// rgb_endian = LCD_RGB_ENDIAN_RGB: teal, esp_lcd_panel_invert_color false
// rgb_endian = LCD_RGB_ENDIAN_BGR: blue, esp_lcd_panel_invert_color true
// rgb_endian = LCD_RGB_ENDIAN_RGB: red, esp_lcd_panel_invert_color true
lv_obj_align(b1, LV_ALIGN_CENTER, -75, 0);
lv_obj_t *b2 = lv_button_create(lv_screen_active());
lv_obj_set_size(b2, 50, 50);
lv_obj_set_style_bg_color(b2, lv_color_hex(0x00FF00), LV_PART_MAIN);
// rgb_endian = LCD_RGB_ENDIAN_BGR: teal, esp_lcd_panel_invert_color false
// rgb_endian = LCD_RGB_ENDIAN_RGB: yellow, esp_lcd_panel_invert_color false
// rgb_endian = LCD_RGB_ENDIAN_BGR: red, esp_lcd_panel_invert_color true
// rgb_endian = LCD_RGB_ENDIAN_RGB: blue, esp_lcd_panel_invert_color true
lv_obj_align(b2, LV_ALIGN_CENTER, 0, 0);
lv_obj_t *b3 = lv_button_create(lv_screen_active());
lv_obj_set_size(b3, 50, 50);
lv_obj_set_style_bg_color(b3, lv_color_hex(0x0000FF), LV_PART_MAIN);
// rgb_endian = LCD_RGB_ENDIAN_BGR: purple, esp_lcd_panel_invert_color false
// rgb_endian = LCD_RGB_ENDIAN_RGB: purple, esp_lcd_panel_invert_color false
// rgb_endian = LCD_RGB_ENDIAN_BGR: green, esp_lcd_panel_invert_color true
// rgb_endian = LCD_RGB_ENDIAN_RGB: green, esp_lcd_panel_invert_color true
lv_obj_align(b3, LV_ALIGN_CENTER, 75, 0);
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0xFFFFFF), LV_PART_MAIN);
lv_obj_t *label = lv_label_create(lv_screen_active());
lv_obj_set_style_text_color(lv_screen_active(), lv_color_hex(0x000000), LV_PART_MAIN);
lv_obj_align(label, LV_ALIGN_CENTER, 0, 75);
lv_label_set_text(label, "Example\nText\nfuzzy & blurry");
while (true)
{
lv_timer_handler();
sleep_ms(100);
}
}


