initial commit

This commit is contained in:
Mikkeli Matlock
2026-02-15 02:48:59 +09:00
commit 19db125619
258 changed files with 345581 additions and 0 deletions

View File

@@ -0,0 +1,378 @@
#include "codec_board.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h"
#include "tca9554.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/spi_common.h"
#include "esp_idf_version.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
#include "esp_lcd_panel_dev.h"
#include "esp_lcd_panel_st7789.h"
#else
#include "esp_lcd_panel_vendor.h"
#endif
#if CONFIG_IDF_TARGET_ESP32P4
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_mipi_dsi.h"
#include "esp_lcd_ili9881c.h"
#include "esp_ldo_regulator.h"
#include "soc/mipi_dsi_bridge_struct.h"
#include "esp_lcd_ek79007.h"
#endif
#include "freertos/FreeRTOS.h"
#define TAG "LCD_INIT"
#define RETURN_ON_ERR(ret) if (ret != 0) { \
ESP_LOGE(TAG, "Fail to run on %d ret %d", __LINE__, ret); \
return ret; \
}
typedef struct {
int (*init)(lcd_cfg_t *cfg);
int (*set_dir)(int16_t gpio, bool output);
int (*set_gpio)(int16_t gpio, bool high);
} extend_io_ops_t;
static extend_io_ops_t extend_io_ops;
static esp_lcd_panel_handle_t panel_handle = NULL;
static int tca9554_io_init(lcd_cfg_t *cfg)
{
return tca9554_init(cfg->io_i2c_port);
}
static int tca9554_io_set_dir(int16_t gpio, bool output)
{
gpio = (1 << gpio);
tca9554_set_io_config(gpio, output ? TCA9554_IO_OUTPUT : TCA9554_IO_INPUT);
return 0;
}
static int tca9554_io_set(int16_t gpio, bool high)
{
gpio = (1 << gpio);
return tca9554_set_output_state(gpio, high ? TCA9554_IO_HIGH : TCA9554_IO_LOW);
}
static void register_tca9554(void)
{
extend_io_ops.init = tca9554_io_init;
extend_io_ops.set_dir = tca9554_io_set_dir;
extend_io_ops.set_gpio = tca9554_io_set;
}
static int init_extend_io(lcd_cfg_t *cfg)
{
if (cfg->io_type == EXTENT_IO_TYPE_NONE) {
return 0;
}
switch (cfg->io_type) {
case EXTENT_IO_TYPE_TCA9554:
register_tca9554();
break;
default:
return -1;
}
return extend_io_ops.init(cfg);
}
static int set_pin_dir(int16_t pin, bool output)
{
if (pin & BOARD_EXTEND_IO_START) {
pin &= ~BOARD_EXTEND_IO_START;
extend_io_ops.set_dir(pin, output);
} else {
gpio_config_t bk_gpio_config = {
.mode = output ? GPIO_MODE_OUTPUT : GPIO_MODE_INPUT,
.pin_bit_mask = pin > 0 ? 1ULL << pin : 0ULL,
};
gpio_config(&bk_gpio_config);
}
return 0;
}
static int set_pin_state(int16_t pin, bool high)
{
if (pin & BOARD_EXTEND_IO_START) {
extend_io_ops.set_gpio(pin, high);
} else {
gpio_set_level(pin, true);
}
return 0;
}
static int16_t get_hw_gpio(int16_t pin)
{
if (pin == -1) {
return pin;
}
if (pin & BOARD_EXTEND_IO_START) {
return -1;
}
return pin;
}
static void sleep_ms(int ms)
{
vTaskDelay(ms / portTICK_PERIOD_MS);
}
static int _lcd_rest(lcd_cfg_t *cfg)
{
if (cfg->reset_pin >= 0) {
set_pin_state(cfg->reset_pin, false);
sleep_ms(100);
set_pin_state(cfg->reset_pin, true);
}
return 0;
}
static int _init_spi_lcd(lcd_cfg_t *cfg)
{
int ret = 0;
if (cfg->spi_cfg.cs & BOARD_EXTEND_IO_START) {
set_pin_dir(cfg->spi_cfg.cs, true);
sleep_ms(10);
set_pin_dir(cfg->spi_cfg.cs, false);
sleep_ms(10);
}
spi_bus_config_t buscfg = {
.sclk_io_num = cfg->spi_cfg.clk,
.mosi_io_num = cfg->spi_cfg.mosi,
.miso_io_num = -1,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = cfg->width * cfg->height * 2,
};
#if SOC_SPI_SUPPORT_OCT
if (cfg->spi_cfg.d[6] >= 0) {
buscfg.data1_io_num = cfg->spi_cfg.d[0];
buscfg.data2_io_num = cfg->spi_cfg.d[1];
;
buscfg.data3_io_num = cfg->spi_cfg.d[2];
;
buscfg.data4_io_num = cfg->spi_cfg.d[3];
;
buscfg.data5_io_num = cfg->spi_cfg.d[4];
;
buscfg.data6_io_num = cfg->spi_cfg.d[5];
;
buscfg.data7_io_num = cfg->spi_cfg.d[6];
;
buscfg.flags = SPICOMMON_BUSFLAG_OCTAL;
}
#endif
int bus_id = SPI1_HOST + (cfg->spi_cfg.spi_bus - 1);
ret = spi_bus_initialize(bus_id, &buscfg, SPI_DMA_CH_AUTO);
ESP_LOGI(TAG, "CLK %d MOSI %d CS:%d DC: %d Bus:%d",
cfg->spi_cfg.clk, cfg->spi_cfg.mosi,
get_hw_gpio(cfg->spi_cfg.cs), cfg->spi_cfg.dc,
bus_id);
RETURN_ON_ERR(ret);
esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = cfg->spi_cfg.dc,
.cs_gpio_num = get_hw_gpio(cfg->spi_cfg.cs),
.pclk_hz = cfg->spi_cfg.pclk_clk ? cfg->spi_cfg.pclk_clk : 60 * 1000 * 1000,
.spi_mode = 0,
.trans_queue_depth = 10,
.lcd_cmd_bits = cfg->spi_cfg.cmd_bits ? cfg->spi_cfg.cmd_bits : 8,
.lcd_param_bits = cfg->spi_cfg.param_bits ? cfg->spi_cfg.param_bits : 8,
.on_color_trans_done = NULL,
.user_ctx = NULL,
};
#if SOC_SPI_SUPPORT_OCT
if (cfg->spi_cfg.d[6] >= 0) {
io_config.flags.octal_mode = 1;
io_config.spi_mode = 3;
}
#endif
esp_lcd_panel_io_handle_t io_handle;
ret = esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)bus_id, &io_config, &io_handle);
RETURN_ON_ERR(ret);
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = get_hw_gpio(cfg->reset_pin),
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
.rgb_ele_order = ESP_LCD_COLOR_SPACE_BGR,
#else
.rgb_endian = LCD_RGB_ENDIAN_BGR,
#endif
.bits_per_pixel = 16,
};
switch (cfg->controller) {
default:
return -1;
case LCD_CONTROLLER_TYPE_ST7789:
ret = esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle);
RETURN_ON_ERR(ret);
ESP_LOGI(TAG, "Init driver ST7789 finished");
break;
}
return ret;
}
#if CONFIG_IDF_TARGET_ESP32P4
static int power_on_dsi(lcd_mipi_cfg_t *mipi_cfg)
{
esp_ldo_channel_handle_t ldo_mipi_phy = NULL;
esp_ldo_channel_config_t ldo_mipi_phy_config = {
.chan_id = mipi_cfg->ldo_chan,
.voltage_mv = mipi_cfg->ldo_voltage,
};
return esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy);
}
static int _init_mipi_lcd(lcd_cfg_t *cfg)
{
int ret = 0;
lcd_mipi_cfg_t *mipi_cfg = &cfg->mipi_cfg;
power_on_dsi(mipi_cfg);
// create MIPI DSI bus first, it will initialize the DSI PHY as well
esp_lcd_dsi_bus_handle_t mipi_dsi_bus;
esp_lcd_dsi_bus_config_t bus_config = {
.bus_id = 0,
.num_data_lanes = mipi_cfg->lane_num,
.phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT,
.lane_bit_rate_mbps = mipi_cfg->lane_bitrate,
};
ret = esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus);
RETURN_ON_ERR(ret);
ESP_LOGI(TAG, "Install MIPI DSI LCD control panel");
esp_lcd_panel_io_handle_t mipi_dbi_io;
// we use DBI interface to send LCD commands and parameters
esp_lcd_dbi_io_config_t dbi_config = {
.virtual_channel = 0,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
ret = esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &mipi_dbi_io);
RETURN_ON_ERR(ret);
esp_lcd_dpi_panel_config_t dpi_config = {
.num_fbs = mipi_cfg->fb_num,
.virtual_channel = 0,
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
.dpi_clock_freq_mhz = mipi_cfg->dpi_clk,
.pixel_format = mipi_cfg->bit_depth == 24 ? LCD_COLOR_PIXEL_FORMAT_RGB888 : LCD_COLOR_PIXEL_FORMAT_RGB565,
.video_timing = {
.h_size = cfg->width,
.v_size = cfg->height,
.hsync_back_porch = mipi_cfg->dsi_hbp,
.hsync_pulse_width = mipi_cfg->dsi_hsync,
.hsync_front_porch = mipi_cfg->dsi_hfp,
.vsync_back_porch = mipi_cfg->dsi_vbp,
.vsync_pulse_width = mipi_cfg->dsi_vsync,
.vsync_front_porch = mipi_cfg->dsi_vfp,
},
.flags.use_dma2d = true,
};
esp_lcd_panel_dev_config_t panel_config = {
.bits_per_pixel = mipi_cfg->bit_depth,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.reset_gpio_num = cfg->reset_pin,
};
if (cfg->width == 1024 && cfg->height == 600) {
ESP_LOGI(TAG, "Install EK79007 LCD control panel");
esp_lcd_dpi_panel_config_t dpi_config = EK79007_1024_600_PANEL_60HZ_CONFIG(LCD_COLOR_PIXEL_FORMAT_RGB565);
ek79007_vendor_config_t vendor_config = {
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
},
};
panel_config.vendor_config = &vendor_config;
ret = esp_lcd_new_panel_ek79007(mipi_dbi_io, &panel_config, &panel_handle);
RETURN_ON_ERR(ret);
} else {
ili9881c_vendor_config_t vendor_config = {
.mipi_config = {
.dsi_bus = mipi_dsi_bus,
.dpi_config = &dpi_config,
.lane_num = mipi_cfg->lane_num,
},
};
panel_config.vendor_config = &vendor_config;
ret = esp_lcd_new_panel_ili9881c(mipi_dbi_io, &panel_config, &panel_handle);
}
RETURN_ON_ERR(ret);
esp_lcd_panel_reset(panel_handle);
ESP_LOGI(TAG, "Install MIPI DSI LCD data panel");
return ret;
}
#else
static int _init_mipi_lcd(lcd_cfg_t *cfg)
{
return -1;
}
#endif
static int _init_lcd(lcd_cfg_t *cfg)
{
int ret = 0;
if (cfg->io_type != EXTENT_IO_TYPE_NONE) {
ret = init_extend_io(cfg);
if (ret != 0) {
return ret;
}
}
// Config reset and ctrl gpio dir
if (cfg->reset_pin >= 0) {
set_pin_dir(cfg->reset_pin, true);
}
if (cfg->ctrl_pin >= 0) {
set_pin_dir(cfg->ctrl_pin, true);
}
if (cfg->bus_type == LCD_BUS_TYPE_SPI) {
if (cfg->spi_cfg.cs >= 0) {
set_pin_dir(cfg->spi_cfg.cs, true);
}
}
_lcd_rest(cfg);
if (cfg->ctrl_pin >= 0) {
set_pin_dir(cfg->ctrl_pin, true);
}
if (cfg->bus_type == LCD_BUS_TYPE_SPI) {
ret = _init_spi_lcd(cfg);
} else if (cfg->bus_type == LCD_BUS_TYPE_MIPI) {
ret = _init_mipi_lcd(cfg);
}
if (panel_handle) {
ret = esp_lcd_panel_init(panel_handle);
RETURN_ON_ERR(ret);
if (cfg->color_inv) {
ret = esp_lcd_panel_invert_color(panel_handle, cfg->color_inv);
}
// ret = esp_lcd_panel_set_gap(panel_handle, 0, 0);
if (cfg->swap_xy) {
ret = esp_lcd_panel_swap_xy(panel_handle, cfg->swap_xy);
}
if (cfg->mirror_x || cfg->mirror_y) {
ret = esp_lcd_panel_mirror(panel_handle, cfg->mirror_x, cfg->mirror_y);
}
ret = esp_lcd_panel_disp_on_off(panel_handle, true);
}
return ret;
}
int board_lcd_init(void)
{
lcd_cfg_t cfg = { 0 };
int ret = get_lcd_cfg(&cfg);
if (ret != 0) {
return ret;
}
return _init_lcd(&cfg);
}
void *board_get_lcd_handle(void)
{
if (panel_handle) {
return panel_handle;
}
return NULL;
}