So I just tried to get closer to making it work with the libs provided by Espressif. It’s call compiling and the backlight turns on but nothing is getting displayed.
tuner_lcd.h
#if !defined(TUNER_LCD)
#define TUNER_LCD
#include "esp_err.h"
#include "esp_io_expander.h"
#include "esp_lcd_panel_io.h"
#define LCD_IO_SPI_CS_EXPANDER (IO_EXPANDER_PIN_NUM_1)
/********************* LCD *********************/
#define LCD_MOSI 1
#define LCD_SCLK 2
#define LCD_CS -1 // Using EXIO
// The pixel number in horizontal and vertical
#define LCD_V_RES 640
#define LCD_H_RES 480
#define LCD_DATA_WIDTH 16
#define LCD_BIT_PER_PIXEL (18)
// #define LCD_BUF_LINES 32
// #define LCD_DRAWBUF_SIZE (LCD_H_RES * LCD_BUF_LINES) // works with both DMA and SPIRAM but slower in SPIRAM
// #define LCD_DRAWBUF_SIZE (LCD_H_RES * LCD_V_RES * LCD_DATA_WIDTH / 10) // crashes when using
#define LCD_DRAWBUF_SIZE (LCD_H_RES * LCD_V_RES / 10) // works in DMA and SPIRAM but slower in SPIRAM by 1-2 fps
#define LCD_PIXEL_CLOCK_HZ (30 * 1000 * 1000) // original as defined by Waveshare
#define LCD_BK_LIGHT_ON_LEVEL 1
#define LCD_BK_LIGHT_OFF_LEVEL !LCD_BK_LIGHT_ON_LEVEL
#define PIN_NUM_BK_LIGHT 6
#define PIN_NUM_HSYNC 38
#define PIN_NUM_VSYNC 39
#define PIN_NUM_DE 40
#define PIN_NUM_PCLK 41
#define PIN_NUM_DATA0 5 // B0
#define PIN_NUM_DATA1 45 // B1
#define PIN_NUM_DATA2 48 // B2
#define PIN_NUM_DATA3 47 // B3
#define PIN_NUM_DATA4 21 // B4
#define PIN_NUM_DATA5 14 // G0
#define PIN_NUM_DATA6 13 // G1
#define PIN_NUM_DATA7 12 // G2
#define PIN_NUM_DATA8 11 // G3
#define PIN_NUM_DATA9 10 // G4
#define PIN_NUM_DATA10 9 // G5
#define PIN_NUM_DATA11 46 // R0
#define PIN_NUM_DATA12 3 // R1
#define PIN_NUM_DATA13 8 // R2
#define PIN_NUM_DATA14 18 // R3
#define PIN_NUM_DATA15 17 // R4
#define PIN_NUM_DISP_EN -1
#define LCD_NUM_OF_FRAME_BUFFERS 2
#define LEDC_TIMER LEDC_TIMER_0
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_OUTPUT_IO PIN_NUM_BK_LIGHT // Define the output GPIO
#define LEDC_CHANNEL LEDC_CHANNEL_0
#define LEDC_DUTY_RES LEDC_TIMER_10_BIT // Set duty resolution to 10 bits
#define LEDC_DUTY (512) // Set duty to 50%. (2^10) * 50% = 512
#define LEDC_FREQUENCY (30000) // Frequency in Hertz. Set frequency at 30 kHz to keep it out of the audible range.
#define Backlight_MAX 100
esp_err_t init_tuner_lcd(esp_lcd_panel_io_handle_t *io_handle, esp_lcd_panel_handle_t *panel_handle);
esp_err_t lcd_display_brightness_set(uint8_t brightness);
#endif // TUNER_LCD
tuner_lcd_c
#include "tuner_lcd.h"
// #include "freertos/task.h"
// // #include "soc/soc.h"
#include <driver/gpio.h>
#include <driver/spi_master.h>
#include "esp_system.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_io_expander_tca9554.h"
#include "esp_lcd_panel_io_additions.h"
#include "esp_lcd_st7701.h"
#include "driver/ledc.h"
static const char *TAG = "LCD";
extern i2c_master_bus_handle_t i2c_bus_handle;
static esp_io_expander_handle_t io_expander;
esp_err_t init_tuner_lcd(esp_lcd_panel_io_handle_t *io_handle, esp_lcd_panel_handle_t *panel_handle) {
// Create TCA9554 IO Expander
ESP_ERROR_CHECK(esp_io_expander_new_i2c_tca9554(i2c_bus_handle, ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_000, &io_expander));
ESP_LOGI(TAG, "Install 3-wire SPI panel IO");
spi_line_config_t line_config = {
.cs_io_type = IO_TYPE_EXPANDER,
.cs_gpio_num = LCD_IO_SPI_CS_EXPANDER,
.scl_io_type = IO_TYPE_GPIO,
.scl_gpio_num = LCD_SCLK,
.sda_io_type = IO_TYPE_GPIO,
.sda_gpio_num = LCD_MOSI,
.io_expander = io_expander,
};
esp_lcd_panel_io_3wire_spi_config_t io_config = ST7701_PANEL_IO_3WIRE_SPI_CONFIG(line_config, 0);
ESP_ERROR_CHECK(esp_lcd_new_panel_io_3wire_spi(&io_config, io_handle));
ESP_LOGI(TAG, "Install ST7701 panel driver");
esp_lcd_rgb_panel_config_t rgb_config = {
.data_width = LCD_DATA_WIDTH,
.psram_trans_align = 64,
.num_fbs = LCD_NUM_OF_FRAME_BUFFERS,
// .bounce_buffer_size_px = 10,
.clk_src = LCD_CLK_SRC_DEFAULT,
.disp_gpio_num = PIN_NUM_DISP_EN,
.pclk_gpio_num = PIN_NUM_PCLK,
.vsync_gpio_num = PIN_NUM_VSYNC,
.hsync_gpio_num = PIN_NUM_HSYNC,
.de_gpio_num = PIN_NUM_DE,
.data_gpio_nums = {
PIN_NUM_DATA0,
PIN_NUM_DATA1,
PIN_NUM_DATA2,
PIN_NUM_DATA3,
PIN_NUM_DATA4,
PIN_NUM_DATA5,
PIN_NUM_DATA6,
PIN_NUM_DATA7,
PIN_NUM_DATA8,
PIN_NUM_DATA9,
PIN_NUM_DATA10,
PIN_NUM_DATA11,
PIN_NUM_DATA12,
PIN_NUM_DATA13,
PIN_NUM_DATA14,
PIN_NUM_DATA15,
},
.timings = {
.pclk_hz = LCD_PIXEL_CLOCK_HZ,
.h_res = LCD_H_RES,
.v_res = LCD_V_RES,
.hsync_back_porch = 10,
.hsync_front_porch = 50,
.hsync_pulse_width = 8,
.vsync_back_porch = 18,
.vsync_front_porch = 8,
.vsync_pulse_width = 2,
.flags.pclk_active_neg = false,
},
.flags.fb_in_psram = true, // allocate frame buffer in PSRAM
};
st7701_vendor_config_t vendor_config = {
.rgb_config = &rgb_config,
.flags.enable_io_multiplex = true, // TODO: not sure what this should be
};
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = GPIO_NUM_NC,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,
.bits_per_pixel = LCD_BIT_PER_PIXEL,
.vendor_config = &vendor_config,
};
esp_err_t e = esp_lcd_new_panel_st7701(*io_handle, &panel_config, panel_handle);
ESP_LOGI(TAG, "esp_lcd_new_panel_st7701() returned %s", esp_err_to_name(e));
e = esp_lcd_panel_reset(*panel_handle);
ESP_LOGI(TAG, "esp_lcd_panel_reset() returned %s", esp_err_to_name(e));
e = esp_lcd_panel_init(*panel_handle);
ESP_LOGI(TAG, "esp_lcd_panel_init() returned %s", esp_err_to_name(e));
/********************* BackLight *********************/
// Prepare and then apply the LEDC PWM timer configuration
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_MODE,
.timer_num = LEDC_TIMER,
.duty_resolution = LEDC_DUTY_RES,
.freq_hz = LEDC_FREQUENCY, // Set output frequency at 30 kHz
.clk_cfg = LEDC_AUTO_CLK
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
// Prepare and then apply the LEDC PWM channel configuration
ledc_channel_config_t ledc_channel = {
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = LEDC_OUTPUT_IO,
.duty = 0, // Set duty to 0%
.hpoint = 0
};
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
lcd_display_brightness_set(100);
return ESP_OK;
}
esp_err_t lcd_display_brightness_set(uint8_t brightness) {
if (brightness > Backlight_MAX || brightness < 0) {
ESP_LOGI(TAG, "Set Backlight parameters in the range of 0 to 100 ");
} else {
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, brightness*(1024/100))); // Set duty
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); // Update duty to apply the new value
}
return ESP_OK;
}
init code:
static esp_lcd_panel_io_handle_t lcd_io;
static esp_lcd_panel_handle_t lcd_panel;
static void *buf1 = NULL;
static void *buf2 = NULL;
void lvgl_port_flush_cb(lv_display_t *display, const lv_area_t *area, uint8_t *px_map) {
esp_lcd_panel_draw_bitmap(lcd_panel, area->x1, area->y1, area->x2 + 1, area->y2 + 1, px_map);
lv_display_flush_ready(display);
}
// NOT USED YET
bool spi_trans_done_cb(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) {
if (!user_ctx) {
return false;
}
lv_display_flush_ready((lv_display_t *)user_ctx);
return false; // return true if a higher priority task needs a reschedule
}
static void tick_timer_cb(void *arg)
{
/* Tell LVGL how many milliseconds has elapsed */
lv_tick_inc(5);
}
esp_err_t lvgl_init() {
lv_init();
const esp_timer_create_args_t tick_timer_args = {
.callback = &tick_timer_cb,
.name = "tick_timer"
};
esp_timer_handle_t tick_timer = NULL;
ESP_ERROR_CHECK(esp_timer_create(&tick_timer_args, &tick_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(tick_timer, 5 * 1000)); // every 5 milliseconds
lvgl_display = lv_display_create(LCD_H_RES, LCD_V_RES);
lv_display_set_flush_cb(lvgl_display, lvgl_port_flush_cb);
// Allocate and set the display buffers
buf1 = heap_caps_malloc(LCD_DRAWBUF_SIZE, MALLOC_CAP_SPIRAM);
assert(buf1);
buf2 = heap_caps_malloc(LCD_DRAWBUF_SIZE, MALLOC_CAP_SPIRAM);
assert(buf2);
lv_display_set_buffers(lvgl_display, buf1, buf2, LCD_DRAWBUF_SIZE, LV_DISPLAY_RENDER_MODE_PARTIAL);
return ESP_OK;
}
void tuner_gui_task(void *pvParameter) {
ESP_ERROR_CHECK(init_tuner_lcd(&lcd_io, &lcd_panel));
ESP_ERROR_CHECK(lvgl_init());
// Draw initial LVGL objects here
...
while(1) {
// draw and manipulate lvgl objects
lv_timer_handler();
vTaskDelay(pdMS_TO_TICKS(33));
}
}