Unable to get valid IO Expander handle for ESP32-S3 and LCD using TCA9554 IO Expander
Posted: Tue Oct 08, 2024 9:20 pm
Setup: Driving LCD (without touchscreen) with an Adafruit Qualia ESP32-S3 board which uses a TCA9554 I/O expander. LCD screen uses ST7701 panel driver. Attached schematics show connection between ESP32-S3, I/O expander and LCD screen.
Trying to run the rgb_avoid_tearing example from ESP-IOT-SOLUTION with this setup. For some reason, I'm unable to get a valid io_handle for the I/O expander.
Code as follows:
This is what my output looks like after successfully flashing the code to ESP32-S3. It goes into panic abort mode.
Functions in the esp_io_expander managed component seem to not register a valid I/O expander handle. The error is being thrown by the function i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, TickType_t ticks_to_wait) in component driver/i2c.c. The following line of code: throws the i2c driver not installed error. Array p_i2c_obj has a length of 8.
I'm lost on how to address the issue and would appreciate some help.
Trying to run the rgb_avoid_tearing example from ESP-IOT-SOLUTION with this setup. For some reason, I'm unable to get a valid io_handle for the I/O expander.
Code as follows:
Code: Select all
#define CONFIG_EXAMPLE_LCD_RGB_BOUNCE_BUFFER_HEIGHT 10
#define ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_NEW 0x3F
#define EXAMPLE_LCD_H_RES 480
#define EXAMPLE_LCD_V_RES 480
#define EXAMPLE_LCD_BIT_PER_PIXEL (16)
#define EXAMPLE_RGB_BIT_PER_PIXEL (16)
#define EXAMPLE_RGB_DATA_WIDTH (16)
#define EXAMPLE_RGB_BOUNCE_BUFFER_SIZE (EXAMPLE_LCD_H_RES * CONFIG_EXAMPLE_LCD_RGB_BOUNCE_BUFFER_HEIGHT)
#define EXAMPLE_LCD_IO_RGB_DISP (-1) // -1 if not used
#define EXAMPLE_LCD_IO_RGB_VSYNC 42
#define EXAMPLE_LCD_IO_RGB_HSYNC 41
#define EXAMPLE_LCD_IO_RGB_DE 2
#define EXAMPLE_LCD_IO_RGB_PCLK 1
#define EXAMPLE_LCD_IO_RGB_DATA0 40
#define EXAMPLE_LCD_IO_RGB_DATA1 39
#define EXAMPLE_LCD_IO_RGB_DATA2 38
#define EXAMPLE_LCD_IO_RGB_DATA3 0
#define EXAMPLE_LCD_IO_RGB_DATA4 45
#define EXAMPLE_LCD_IO_RGB_DATA5 48
#define EXAMPLE_LCD_IO_RGB_DATA6 47
#define EXAMPLE_LCD_IO_RGB_DATA7 21
#define EXAMPLE_LCD_IO_RGB_DATA8 14
#define EXAMPLE_LCD_IO_RGB_DATA9 13
#define EXAMPLE_LCD_IO_RGB_DATA10 12
#define EXAMPLE_LCD_IO_RGB_DATA11 11
#define EXAMPLE_LCD_IO_RGB_DATA12 10
#define EXAMPLE_LCD_IO_RGB_DATA13 9
#define EXAMPLE_LCD_IO_RGB_DATA14 46
#define EXAMPLE_LCD_IO_RGB_DATA15 3
#define EXAMPLE_LCD_IO_SPI_CS (IO_EXPANDER_PIN_NUM_5)
#define EXAMPLE_LCD_IO_SPI_SCL (IO_EXPANDER_PIN_NUM_4)
#define EXAMPLE_LCD_IO_SPI_SDA (IO_EXPANDER_PIN_NUM_12)
#define EXAMPLE_LCD_IO_RST (IO_EXPANDER_PIN_NUM_6)
#define EXAMPLE_PIN_NUM_BK_LIGHT (IO_EXPANDER_PIN_NUM_9)
#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 1
#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL
IRAM_ATTR static bool rgb_lcd_on_vsync_event(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx)
{
return lvgl_port_notify_rgb_vsync();
}
static const st7701_lcd_init_cmd_t lcd_init_cmds[] = {
// {cmd, { data }, data_size, delay_ms}
{0xFF, (uint8_t []){0x77, 0x01, 0x00, 0x00, 0x10}, 5, 0},
{0xC0, (uint8_t []){0x3B, 0x00}, 2, 0},
{0xC1, (uint8_t []){0x0D, 0x02}, 2, 0},
{0xC2, (uint8_t []){0x31, 0x05}, 2, 0},
{0xCD, (uint8_t []){0x00}, 1, 0},
{0xB0, (uint8_t []){0x00, 0x11, 0x18, 0x0E, 0x11, 0x06, 0x07, 0x08, 0x07, 0x22, 0x04, 0x12, 0x0F, 0xAA, 0x31, 0x18}, 16, 0},
{0xB1, (uint8_t []){0x00, 0x11, 0x19, 0x0E, 0x12, 0x07, 0x08, 0x08, 0x08, 0x22, 0x04, 0x11, 0x11, 0xA9, 0x32, 0x18}, 16, 0},
{0xFF, (uint8_t []){0x77, 0x01, 0x00, 0x00, 0x11}, 5, 0},
{0xB0, (uint8_t []){0x60}, 1, 0},
{0xB1, (uint8_t []){0x32}, 1, 0},
{0xB2, (uint8_t []){0x07}, 1, 0},
{0xB3, (uint8_t []){0x80}, 1, 0},
{0xB5, (uint8_t []){0x49}, 1, 0},
{0xB7, (uint8_t []){0x85}, 1, 0},
{0xB8, (uint8_t []){0x21}, 1, 0},
{0xC1, (uint8_t []){0x78}, 1, 0},
{0xC2, (uint8_t []){0x78}, 1, 0},
{0xE0, (uint8_t []){0x00, 0x1B, 0x02}, 3, 0},
{0xE1, (uint8_t []){0x08, 0xA0, 0x00, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x44, 0x44}, 11, 0},
{0xE2, (uint8_t []){0x11, 0x11, 0x44, 0x44, 0xED, 0xA0, 0x00, 0x00, 0xEC, 0xA0, 0x00, 0x00}, 12, 0},
{0xE3, (uint8_t []){0x00, 0x00, 0x11, 0x11}, 4, 0},
{0xE4, (uint8_t []){0x44, 0x44}, 2, 0},
{0xE5, (uint8_t []){0x0A, 0xE9, 0xD8, 0xA0, 0x0C, 0xEB, 0xD8, 0xA0, 0x0E, 0xED, 0xD8, 0xA0, 0x10, 0xEF, 0xD8, 0xA0}, 16, 0},
{0xE6, (uint8_t []){0x00, 0x00, 0x11, 0x11}, 4, 0},
{0xE7, (uint8_t []){0x44, 0x44}, 2, 0},
{0xE8, (uint8_t []){0x09, 0xE8, 0xD8, 0xA0, 0x0B, 0xEA, 0xD8, 0xA0, 0x0D, 0xEC, 0xD8, 0xA0, 0x0F, 0xEE, 0xD8, 0xA0}, 16, 0},
{0xEB, (uint8_t []){0x02, 0x00, 0xE4, 0xE4, 0x88, 0x00, 0x40}, 7, 0},
{0xEC, (uint8_t []){0x3C, 0x00}, 2, 0},
{0xED, (uint8_t []){0xAB, 0x89, 0x76, 0x54, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x20, 0x45, 0x67, 0x98, 0xBA}, 16, 0},
{0xFF, (uint8_t []){0x77, 0x01, 0x00, 0x00, 0x13}, 5, 0},
{0xE5, (uint8_t []){0xE4}, 1, 0},
{0xFF, (uint8_t []){0x77, 0x01, 0x00, 0x00, 0x00}, 5, 0},
{0x11, (uint8_t []){0x00}, 0, 120},
{0x29, (uint8_t []){0x00}, 0, 0},
};
void display_start()
{
//Define io_expander handle as suggested in https://github.com/espressif/esp-bsp/blob/master/components/io_expander/
//esp_io_expander_tca9554/README.md
esp_io_expander_handle_t io_expander_tft = NULL;
esp_io_expander_new_i2c_tca9554(I2C_NUM_0, ESP_IO_EXPANDER_I2C_TCA9554_ADDRESS_NEW, &io_expander_tft);
//Set pin 0 and pin 1 with output dircetion and low level
esp_io_expander_set_dir(io_expander_tft, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, IO_EXPANDER_OUTPUT);
esp_io_expander_set_level(io_expander_tft, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1, 0);
esp_io_expander_print_state(io_expander_tft);
if (EXAMPLE_PIN_NUM_BK_LIGHT >= 0) {
ESP_LOGI(TAG, "Turn off LCD backlight");
gpio_config_t bk_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT
};
ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
}
ESP_LOGI(TAG, "Install 3-wire SPI panel IO");
spi_line_config_t line_config = {
.cs_io_type = IO_TYPE_EXPANDER,
.cs_expander_pin = EXAMPLE_LCD_IO_SPI_CS,
.scl_io_type = IO_TYPE_EXPANDER,
.scl_gpio_num = EXAMPLE_LCD_IO_SPI_SCL,
.sda_io_type = IO_TYPE_EXPANDER,
.sda_gpio_num = EXAMPLE_LCD_IO_SPI_SDA,
.io_expander = io_expander_tft,
};
esp_lcd_panel_io_3wire_spi_config_t io_config = ST7701_PANEL_IO_3WIRE_SPI_CONFIG(line_config, 0);
esp_lcd_panel_io_handle_t io_handle = NULL;
ESP_ERROR_CHECK(esp_lcd_new_panel_io_3wire_spi(&io_config, &io_handle));
ESP_LOGI(TAG, "Install ST7701 panel driver");
esp_lcd_panel_handle_t lcd_handle = NULL;
esp_lcd_rgb_panel_config_t rgb_config = {
.clk_src = LCD_CLK_SRC_DEFAULT,
.psram_trans_align = 64,
.data_width = EXAMPLE_RGB_DATA_WIDTH,
.bits_per_pixel = EXAMPLE_RGB_BIT_PER_PIXEL,
.de_gpio_num = EXAMPLE_LCD_IO_RGB_DE,
.pclk_gpio_num = EXAMPLE_LCD_IO_RGB_PCLK,
.vsync_gpio_num = EXAMPLE_LCD_IO_RGB_VSYNC,
.hsync_gpio_num = EXAMPLE_LCD_IO_RGB_HSYNC,
.disp_gpio_num = EXAMPLE_LCD_IO_RGB_DISP,
.data_gpio_nums = {
EXAMPLE_LCD_IO_RGB_DATA0,
EXAMPLE_LCD_IO_RGB_DATA1,
EXAMPLE_LCD_IO_RGB_DATA2,
EXAMPLE_LCD_IO_RGB_DATA3,
EXAMPLE_LCD_IO_RGB_DATA4,
EXAMPLE_LCD_IO_RGB_DATA5,
EXAMPLE_LCD_IO_RGB_DATA6,
EXAMPLE_LCD_IO_RGB_DATA7,
EXAMPLE_LCD_IO_RGB_DATA8,
EXAMPLE_LCD_IO_RGB_DATA9,
EXAMPLE_LCD_IO_RGB_DATA10,
EXAMPLE_LCD_IO_RGB_DATA11,
EXAMPLE_LCD_IO_RGB_DATA12,
EXAMPLE_LCD_IO_RGB_DATA13,
EXAMPLE_LCD_IO_RGB_DATA14,
EXAMPLE_LCD_IO_RGB_DATA15,
},
.timings = ST7701_480_480_PANEL_60HZ_RGB_TIMING(),
.flags.fb_in_psram = 1,
.num_fbs = LVGL_PORT_LCD_RGB_BUFFER_NUMS,
.bounce_buffer_size_px = EXAMPLE_RGB_BOUNCE_BUFFER_SIZE,
};
//rgb_config.timings.h_res = EXAMPLE_LCD_H_RES;
//rgb_config.timings.v_res = EXAMPLE_LCD_V_RES;
st7701_vendor_config_t vendor_config = {
.rgb_config = &rgb_config,
.init_cmds = lcd_init_cmds, // Uncomment these line if use custom initialization commands
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
.flags = {
.auto_del_panel_io = 0, /**
* Set to 1 if panel IO is no longer needed after LCD initialization.
* If the panel IO pins are sharing other pins of the RGB interface to save GPIOs,
* Please set it to 1 to release the pins.
*/
.mirror_by_cmd = 1, // Set to 0 if `auto_del_panel_io` is enabled
},
};
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = EXAMPLE_LCD_IO_RST,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = EXAMPLE_LCD_BIT_PER_PIXEL,
.vendor_config = &vendor_config,
};
ESP_ERROR_CHECK(esp_lcd_new_panel_st7701(io_handle, &panel_config, &lcd_handle));
ESP_ERROR_CHECK(esp_lcd_panel_reset(lcd_handle));
ESP_ERROR_CHECK(esp_lcd_panel_init(lcd_handle));
esp_lcd_panel_disp_on_off(lcd_handle, true);
esp_lcd_touch_handle_t tp_handle = NULL;
ESP_ERROR_CHECK(lvgl_port_init(lcd_handle, tp_handle));
esp_lcd_rgb_panel_event_callbacks_t cbs = {
#if EXAMPLE_RGB_BOUNCE_BUFFER_SIZE > 0
.on_bounce_frame_finish = rgb_lcd_on_vsync_event,
#else
.on_vsync = rgb_lcd_on_vsync_event,
#endif
};
esp_lcd_rgb_panel_register_event_callbacks(lcd_handle, &cbs, NULL);
if (EXAMPLE_PIN_NUM_BK_LIGHT >= 0) {
ESP_LOGI(TAG, "Turn on LCD backlight");
gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);
}
ESP_LOGI(TAG, "Display LVGL demos");
// Lock the mutex due to the LVGL APIs are not thread-safe
if (lvgl_port_lock(-1)) {
// lv_demo_stress();
// lv_demo_benchmark();
//lv_demo_music();
// lv_demo_widgets();
// Release the mutex
lvgl_port_unlock();
}
}
Code: Select all
W (313) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
W (327) i2c: This driver is an old driver, please migrate your application code to adapt `driver/i2c_master.h`
I (337) sleep: Configure to isolate all GPIO pins in sleep state
I (344) sleep: Enable automatic switching of GPIO sleep configuration
I (351) app_start: Starting scheduler on CPU0
I (356) app_start: Starting scheduler on CPU1
I (356) main_task: Started on CPU0
I (366) main_task: Calling app_main()
[b]E (406) i2c: i2c_master_cmd_begin(1478): i2c driver not installed
E (416) tca9554: write_direction_reg(134): Write direction reg failed
E (416) tca9554: reset(152): Write dir reg failed
E (426) tca9554: esp_io_expander_new_i2c_tca9554(82): Reset failed
E (436) io_expander: esp_io_expander_set_dir(35): Invalid handle
E (436) io_expander: esp_io_expander_set_level(63): Invalid handle
E (446) io_expander: esp_io_expander_print_state(131): Invalid handle
I (456) display_example: Turn off LCD backlight
E (456) gpio: GPIO_PIN mask error[/b]
ESP_ERROR_CHECK failed: esp_err_t 0x102 (ESP_ERR_INVALID_ARG) at 0x420087fb
0x420087fb: display_start at C:/Users/User1/example/receiver/main/display.c:127 (discriminator 1)
file: "./main/display.c" line 127
func: display_start
expression: gpio_config(&bk_gpio_config)
abort() was called at PC 0x4037a4e3 on core 0
0x4037a4e3: _esp_error_check_failed at C:/Users/User1/ESP/esp-idf/components/esp_system/esp_err.c:50
Backtrace: 0x403758ee:0x3fca2160 0x4037a4ed:0x3fca2180 0x40380952:0x3fca21a0 0x4037a4e3:0x3fca2210 0x420087fb:0x3fca2240 0x42008787:0x3fca23a0 0x42048def:0x3fca23c0 0x4037cb71:0x3fca23f0
0x403758ee: panic_abort at C:/Users/User1/ESP/esp-idf/components/esp_system/panic.c:452
0x4037a4ed: esp_system_abort at C:/Users/User1/ESP/esp-idf/components/esp_system/port/esp_system_chip.c:93
0x40380952: abort at C:/Users/User1/ESP/esp-idf/components/newlib/abort.c:38
0x4037a4e3: _esp_error_check_failed at C:/Users/User1/ESP/esp-idf/components/esp_system/esp_err.c:50
0x420087fb: display_start at C:/Users/User1/example/receiver/main/display.c:127 (discriminator 1)
0x42008787: app_main at C:/Users/User1/example/receiver/main/main.c:5
0x42048def: main_task at C:/Users/User1/ESP/esp-idf/components/freertos/app_startup.c:208 (discriminator 13)
0x4037cb71: vPortTaskWrapper at C:/Users/User1/ESP/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:162
Code: Select all
ESP_RETURN_ON_FALSE(p_i2c_obj[i2c_num] != NULL, ESP_ERR_INVALID_STATE, I2C_TAG, I2C_DRIVER_NOT_INSTALL_ERR_STR)
I'm lost on how to address the issue and would appreciate some help.