feat(lcd): Add new version LCD implementation to adapt new I2C APIs

This commit is contained in:
Cao Sen Miao
2023-08-03 12:31:36 +08:00
parent 4ef94fc0dc
commit b6cbeeae01
15 changed files with 463 additions and 19 deletions

View File

@@ -8,6 +8,13 @@ components/esp_lcd/test_apps/i2c_lcd:
temporary: true
reason: insufficient runners
components/esp_lcd/test_apps/i2c_lcd_legacy:
disable:
- if: SOC_I2C_SUPPORTED != 1
disable_test:
- if: IDF_TARGET not in ["esp32c3"]
temporary: true
reason: insufficient runners
components/esp_lcd/test_apps/i80_lcd:
disable:

View File

@@ -1,13 +1,14 @@
set(srcs "src/esp_lcd_common.c"
"src/esp_lcd_panel_io.c"
"src/esp_lcd_panel_io_i2c.c"
"src/esp_lcd_panel_io_i2c_v1.c"
"src/esp_lcd_panel_io_i2c_v2.c"
"src/esp_lcd_panel_io_spi.c"
"src/esp_lcd_panel_nt35510.c"
"src/esp_lcd_panel_ssd1306.c"
"src/esp_lcd_panel_st7789.c"
"src/esp_lcd_panel_ops.c")
set(includes "include" "interface")
set(priv_requires "driver" "esp_mm" "esp_psram")
set(priv_requires "esp_mm" "esp_psram")
if(CONFIG_SOC_I2S_LCD_I80_VARIANT)
list(APPEND srcs "src/esp_lcd_panel_io_i2s.c")
@@ -20,4 +21,5 @@ endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${includes}
PRIV_REQUIRES ${priv_requires}
REQUIRES driver
LDFRAGMENTS linker.lf)

View File

@@ -10,13 +10,15 @@
#include "esp_lcd_types.h"
#include "soc/soc_caps.h"
#include "hal/lcd_types.h"
#include "hal/i2c_types.h"
#include "driver/i2c_types.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void *esp_lcd_spi_bus_handle_t; /*!< Type of LCD SPI bus handle */
typedef void *esp_lcd_i2c_bus_handle_t; /*!< Type of LCD I2C bus handle */
typedef uint32_t esp_lcd_i2c_bus_handle_t; /*!< Type of LCD I2C bus handle */
typedef struct esp_lcd_i80_bus_t *esp_lcd_i80_bus_handle_t; /*!< Type of LCD intel 8080 bus handle */
/**
@@ -171,10 +173,43 @@ typedef struct {
unsigned int dc_low_on_data: 1; /*!< If this flag is enabled, DC line = 0 means transfer data, DC line = 1 means transfer command; vice versa */
unsigned int disable_control_phase: 1; /*!< If this flag is enabled, the control phase isn't used */
} flags; /*!< Extra flags to fine-tune the I2C device */
uint32_t scl_speed_hz; /*!< I2C LCD SCL frequency (hz) */
} esp_lcd_panel_io_i2c_config_t;
/**
* @brief Create LCD panel IO handle, for I2C interface
* @brief Create LCD panel IO handle, for I2C interface in legacy implementation
*
* @param[in] bus I2C bus handle, (in uint32_t)
* @param[in] io_config IO configuration, for I2C interface
* @param[out] ret_io Returned IO handle
*
* @note Please don't call this function in your project directly. Please call `esp_lcd_new_panel_to_i2c` instead.
*
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
esp_err_t esp_lcd_new_panel_io_i2c_v1(uint32_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io);
/**
* @brief Create LCD panel IO handle, for I2C interface in new implementation
*
* @param[in] bus I2C bus handle, (in i2c_master_dev_handle_t)
* @param[in] io_config IO configuration, for I2C interface
* @param[out] ret_io Returned IO handle
*
* @note Please don't call this function in your project directly. Please call `esp_lcd_new_panel_to_i2c` instead.
*
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
esp_err_t esp_lcd_new_panel_io_i2c_v2(i2c_master_bus_handle_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io);
/**
* @brief Create LCD panel IO handle
*
* @param[in] bus I2C bus handle
* @param[in] io_config IO configuration, for I2C interface
@@ -184,7 +219,9 @@ typedef struct {
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
esp_err_t esp_lcd_new_panel_io_i2c(esp_lcd_i2c_bus_handle_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io);
#define esp_lcd_new_panel_io_i2c(bus, io_config, ret_io) _Generic((bus), \
i2c_master_bus_handle_t : esp_lcd_new_panel_io_i2c_v2, \
default : esp_lcd_new_panel_io_i2c_v1) (bus, io_config, ret_io) \
#if SOC_LCD_I80_SUPPORTED
/**

View File

@@ -45,7 +45,7 @@ typedef struct {
uint8_t cmdlink_buffer[]; // pre-alloc I2C command link buffer, to be reused in all transactions
} lcd_panel_io_i2c_t;
esp_err_t esp_lcd_new_panel_io_i2c(esp_lcd_i2c_bus_handle_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io)
esp_err_t esp_lcd_new_panel_io_i2c_v1(uint32_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io)
{
#if CONFIG_LCD_ENABLE_DEBUG_LOG
esp_log_level_set(TAG, ESP_LOG_DEBUG);
@@ -54,10 +54,11 @@ esp_err_t esp_lcd_new_panel_io_i2c(esp_lcd_i2c_bus_handle_t bus, const esp_lcd_p
lcd_panel_io_i2c_t *i2c_panel_io = NULL;
ESP_GOTO_ON_FALSE(io_config && ret_io, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(io_config->control_phase_bytes * 8 > io_config->dc_bit_offset, ESP_ERR_INVALID_ARG, err, TAG, "D/C bit exceeds control bytes");
ESP_GOTO_ON_FALSE(io_config->scl_speed_hz == 0, ESP_ERR_INVALID_ARG, err, TAG, "scl_speed_hz is not need to set in legacy i2c_lcd driver");
i2c_panel_io = calloc(1, sizeof(lcd_panel_io_i2c_t) + CMD_HANDLER_BUFFER_SIZE); // expand zero-length array cmdlink_buffer
ESP_GOTO_ON_FALSE(i2c_panel_io, ESP_ERR_NO_MEM, err, TAG, "no mem for i2c panel io");
i2c_panel_io->i2c_bus_id = (uint32_t)bus;
i2c_panel_io->i2c_bus_id = bus;
i2c_panel_io->lcd_cmd_bits = io_config->lcd_cmd_bits;
i2c_panel_io->lcd_param_bits = io_config->lcd_param_bits;
i2c_panel_io->on_color_trans_done = io_config->on_color_trans_done;
@@ -84,7 +85,7 @@ static esp_err_t panel_io_i2c_del(esp_lcd_panel_io_t *io)
esp_err_t ret = ESP_OK;
lcd_panel_io_i2c_t *i2c_panel_io = __containerof(io, lcd_panel_io_i2c_t, base);
ESP_LOGD(TAG, "del lcd panel io spi @%p", i2c_panel_io);
ESP_LOGD(TAG, "del lcd panel i2c @%p", i2c_panel_io);
free(i2c_panel_io);
return ret;
}

View File

@@ -0,0 +1,207 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include "sdkconfig.h"
#if CONFIG_LCD_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
// Set the maximum log level for this source file
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#endif
#include "esp_lcd_panel_io_interface.h"
#include "esp_lcd_panel_io.h"
#include "driver/i2c_master.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "esp_heap_caps.h"
static const char *TAG = "lcd_panel.io.i2c";
#define BYTESHIFT(VAR, IDX) (((VAR) >> ((IDX) * 8)) & 0xFF)
#define CONTROL_PHASE_LENGTH (1)
#define CMD_LENGTH (4)
static esp_err_t panel_io_i2c_del(esp_lcd_panel_io_t *io);
static esp_err_t panel_io_i2c_rx_param(esp_lcd_panel_io_t *io, int lcd_cmd, void *param, size_t param_size);
static esp_err_t panel_io_i2c_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, const void *param, size_t param_size);
static esp_err_t panel_io_i2c_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, const void *color, size_t color_size);
static esp_err_t panel_io_i2c_register_event_callbacks(esp_lcd_panel_io_handle_t io, const esp_lcd_panel_io_callbacks_t *cbs, void *user_ctx);
typedef struct {
esp_lcd_panel_io_t base; // Base class of generic lcd panel io
i2c_master_dev_handle_t i2c_handle; // I2C master driver handle.
uint32_t dev_addr; // Device address
int lcd_cmd_bits; // Bit width of LCD command
int lcd_param_bits; // Bit width of LCD parameter
bool control_phase_enabled; // Is control phase enabled
uint32_t control_phase_cmd; // control byte when transferring command
uint32_t control_phase_data; // control byte when transferring data
esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; // User register's callback, invoked when color data trans done
void *user_ctx; // User's private data, passed directly to callback on_color_trans_done()
} lcd_panel_io_i2c_t;
esp_err_t esp_lcd_new_panel_io_i2c_v2(i2c_master_bus_handle_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io)
{
#if CONFIG_LCD_ENABLE_DEBUG_LOG
esp_log_level_set(TAG, ESP_LOG_DEBUG);
#endif
esp_err_t ret = ESP_OK;
lcd_panel_io_i2c_t *i2c_panel_io = NULL;
i2c_master_dev_handle_t i2c_handle = NULL;
ESP_GOTO_ON_FALSE(io_config && ret_io, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(io_config->control_phase_bytes * 8 > io_config->dc_bit_offset, ESP_ERR_INVALID_ARG, err, TAG, "D/C bit exceeds control bytes");
i2c_panel_io = calloc(1, sizeof(lcd_panel_io_i2c_t));
ESP_GOTO_ON_FALSE(i2c_panel_io, ESP_ERR_NO_MEM, err, TAG, "no mem for i2c panel io");
i2c_device_config_t i2c_lcd_cfg = {
.device_address = io_config->dev_addr,
.scl_speed_hz = io_config->scl_speed_hz,
};
ESP_GOTO_ON_ERROR(i2c_master_bus_add_device(bus, &i2c_lcd_cfg, &i2c_handle), err, TAG, "i2c add device fail");
i2c_panel_io->i2c_handle = i2c_handle;
i2c_panel_io->lcd_cmd_bits = io_config->lcd_cmd_bits;
i2c_panel_io->lcd_param_bits = io_config->lcd_param_bits;
i2c_panel_io->on_color_trans_done = io_config->on_color_trans_done;
i2c_panel_io->user_ctx = io_config->user_ctx;
i2c_panel_io->control_phase_enabled = (!io_config->flags.disable_control_phase);
i2c_panel_io->control_phase_data = (!io_config->flags.dc_low_on_data) << (io_config->dc_bit_offset);
i2c_panel_io->control_phase_cmd = (io_config->flags.dc_low_on_data) << (io_config->dc_bit_offset);
i2c_panel_io->dev_addr = io_config->dev_addr;
i2c_panel_io->base.del = panel_io_i2c_del;
i2c_panel_io->base.rx_param = panel_io_i2c_rx_param;
i2c_panel_io->base.tx_param = panel_io_i2c_tx_param;
i2c_panel_io->base.tx_color = panel_io_i2c_tx_color;
i2c_panel_io->base.register_event_callbacks = panel_io_i2c_register_event_callbacks;
*ret_io = &(i2c_panel_io->base);
ESP_LOGD(TAG, "new i2c lcd panel io @%p", i2c_panel_io);
return ESP_OK;
err:
if (i2c_panel_io) {
free(i2c_panel_io);
}
return ret;
}
static esp_err_t panel_io_i2c_del(esp_lcd_panel_io_t *io)
{
esp_err_t ret = ESP_OK;
lcd_panel_io_i2c_t *i2c_panel_io = __containerof(io, lcd_panel_io_i2c_t, base);
ESP_LOGD(TAG, "del lcd panel io i2c @%p", i2c_panel_io);
ESP_ERROR_CHECK(i2c_master_bus_rm_device(i2c_panel_io->i2c_handle));
free(i2c_panel_io);
return ret;
}
static esp_err_t panel_io_i2c_register_event_callbacks(esp_lcd_panel_io_handle_t io, const esp_lcd_panel_io_callbacks_t *cbs, void *user_ctx)
{
lcd_panel_io_i2c_t *i2c_panel_io = __containerof(io, lcd_panel_io_i2c_t, base);
if(i2c_panel_io->on_color_trans_done != NULL) {
ESP_LOGW(TAG, "Callback on_color_trans_done was already set and now it was owerwritten!");
}
i2c_panel_io->on_color_trans_done = cbs->on_color_trans_done;
i2c_panel_io->user_ctx = user_ctx;
return ESP_OK;
}
static esp_err_t panel_io_i2c_rx_buffer(esp_lcd_panel_io_t *io, int lcd_cmd, void *buffer, size_t buffer_size)
{
esp_err_t ret = ESP_OK;
lcd_panel_io_i2c_t *i2c_panel_io = __containerof(io, lcd_panel_io_i2c_t, base);
bool send_param = (lcd_cmd >= 0);
int write_size = 0;
uint8_t write_buffer[CONTROL_PHASE_LENGTH + CMD_LENGTH] = {0};
if (send_param) {
if (i2c_panel_io->control_phase_enabled) {
write_buffer[0] = i2c_panel_io->control_phase_cmd;
write_size += 1;
}
uint8_t cmds[4] = {BYTESHIFT(lcd_cmd, 3), BYTESHIFT(lcd_cmd, 2), BYTESHIFT(lcd_cmd, 1), BYTESHIFT(lcd_cmd, 0)};
size_t cmds_size = i2c_panel_io->lcd_cmd_bits / 8;
if (cmds_size > 0 && cmds_size <= sizeof(cmds)) {
memcpy(write_buffer + write_size, cmds + (sizeof(cmds) - cmds_size), cmds_size);
write_size += cmds_size;
}
}
ESP_GOTO_ON_ERROR(i2c_master_transmit_receive(i2c_panel_io->i2c_handle, write_buffer, write_size, buffer, buffer_size, -1), err, TAG, "i2c transaction failed");
return ESP_OK;
err:
return ret;
}
static esp_err_t panel_io_i2c_tx_buffer(esp_lcd_panel_io_t *io, int lcd_cmd, const void *buffer, size_t buffer_size, bool is_param)
{
esp_err_t ret = ESP_OK;
lcd_panel_io_i2c_t *i2c_panel_io = __containerof(io, lcd_panel_io_i2c_t, base);
bool send_param = (lcd_cmd >= 0);
int write_size = 0;
uint8_t *write_buffer = (uint8_t*)heap_caps_malloc(CONTROL_PHASE_LENGTH + CMD_LENGTH + buffer_size, MALLOC_CAP_8BIT);
ESP_GOTO_ON_FALSE(write_buffer, ESP_ERR_NO_MEM, err, TAG, "no mem for write buffer");
if (i2c_panel_io->control_phase_enabled) {
write_buffer[0] = is_param ? i2c_panel_io->control_phase_cmd : i2c_panel_io->control_phase_data;
write_size += 1;
}
// some displays don't want any additional commands on data transfers
if (send_param)
{
uint8_t cmds[4] = {BYTESHIFT(lcd_cmd, 3), BYTESHIFT(lcd_cmd, 2), BYTESHIFT(lcd_cmd, 1), BYTESHIFT(lcd_cmd, 0)};
size_t cmds_size = i2c_panel_io->lcd_cmd_bits / 8;
if (cmds_size > 0 && cmds_size <= sizeof(cmds)) {
memcpy(write_buffer + write_size, cmds + (sizeof(cmds) - cmds_size), cmds_size);
write_size += cmds_size;
}
}
if (buffer) {
memcpy(write_buffer + write_size, buffer, buffer_size);
write_size += buffer_size;
}
ESP_GOTO_ON_ERROR(i2c_master_transmit(i2c_panel_io->i2c_handle, write_buffer, write_size, -1), err, TAG, "i2c transaction failed");
free(write_buffer);
if (!is_param) {
// trans done callback
if (i2c_panel_io->on_color_trans_done) {
i2c_panel_io->on_color_trans_done(&(i2c_panel_io->base), NULL, i2c_panel_io->user_ctx);
}
}
return ESP_OK;
err:
if (write_buffer) {
free(write_buffer);
}
return ret;
}
static esp_err_t panel_io_i2c_rx_param(esp_lcd_panel_io_t *io, int lcd_cmd, void *param, size_t param_size)
{
return panel_io_i2c_rx_buffer(io, lcd_cmd, param, param_size);
}
static esp_err_t panel_io_i2c_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, const void *param, size_t param_size)
{
return panel_io_i2c_tx_buffer(io, lcd_cmd, param, param_size, true);
}
static esp_err_t panel_io_i2c_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, const void *color, size_t color_size)
{
return panel_io_i2c_tx_buffer(io, lcd_cmd, color, color_size, false);
}

View File

@@ -1,12 +1,12 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "unity.h"
#include "driver/i2c.h"
#include "driver/i2c_master.h"
#include "driver/gpio.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
@@ -26,26 +26,27 @@ TEST_CASE("lcd_panel_with_i2c_interface_(ssd1306)", "[lcd]")
}
};
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
i2c_master_bus_config_t i2c_bus_conf = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.sda_io_num = TEST_I2C_SDA_GPIO,
.scl_io_num = TEST_I2C_SCL_GPIO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = TEST_LCD_PIXEL_CLOCK_HZ,
.i2c_port = -1,
};
TEST_ESP_OK(i2c_param_config(TEST_I2C_HOST_ID, &conf));
TEST_ESP_OK(i2c_driver_install(TEST_I2C_HOST_ID, I2C_MODE_MASTER, 0, 0, 0));
i2c_master_bus_handle_t bus_handle;
TEST_ESP_OK(i2c_new_master_bus(&i2c_bus_conf, &bus_handle));
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_io_i2c_config_t io_config = {
.dev_addr = TEST_I2C_DEV_ADDR,
.scl_speed_hz = TEST_LCD_PIXEL_CLOCK_HZ,
.control_phase_bytes = 1, // According to SSD1306 datasheet
.dc_bit_offset = 6, // According to SSD1306 datasheet
.lcd_cmd_bits = 8, // According to SSD1306 datasheet
.lcd_param_bits = 8, // According to SSD1306 datasheet
};
TEST_ESP_OK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)TEST_I2C_HOST_ID, &io_config, &io_handle));
TEST_ESP_OK(esp_lcd_new_panel_io_i2c(bus_handle, &io_config, &io_handle));
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_panel_dev_config_t panel_config = {
@@ -66,5 +67,5 @@ TEST_CASE("lcd_panel_with_i2c_interface_(ssd1306)", "[lcd]")
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(i2c_driver_delete(TEST_I2C_HOST_ID));
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
}

View File

@@ -0,0 +1,5 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(legacy_i2c_lcd_panel_test)

View File

@@ -0,0 +1,4 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
This test app is used to test LCDs with I2C interface.

View File

@@ -0,0 +1,7 @@
set(srcs "test_app_main.c"
"test_i2c_lcd_legacy_panel.c")
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRCS ${srcs}
WHOLE_ARCHIVE)

View File

@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include "unity.h"
#include "unity_test_runner.h"
#include "esp_heap_caps.h"
// Some resources are lazy allocated in the LCD driver, the threadhold is left for that case
#define TEST_MEMORY_LEAK_THRESHOLD (-300)
static size_t before_free_8bit;
static size_t before_free_32bit;
static void check_leak(size_t before_free, size_t after_free, const char *type)
{
ssize_t delta = after_free - before_free;
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
}
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
check_leak(before_free_8bit, after_free_8bit, "8BIT");
check_leak(before_free_32bit, after_free_32bit, "32BIT");
}
void app_main(void)
{
// ___ ____ ____ _ ____ ____ _____ _
// |_ _|___ \ / ___| | | / ___| _ \ |_ _|__ ___| |_
// | | __) | | | | | | | | | | | |/ _ \/ __| __|
// | | / __/| |___ | |__| |___| |_| | | | __/\__ \ |_
// |___|_____|\____| |_____\____|____/ |_|\___||___/\__|
printf(" ___ ____ ____ _ ____ ____ _____ _\r\n");
printf("|_ _|___ \\ / ___| | | / ___| _ \\ |_ _|__ ___| |_\r\n");
printf(" | | __) | | | | | | | | | | | |/ _ \\/ __| __|\r\n");
printf(" | | / __/| |___ | |__| |___| |_| | | | __/\\__ \\ |_\r\n");
printf("|___|_____|\\____| |_____\\____|____/ |_|\\___||___/\\__|\r\n");
unity_run_menu();
}

View File

@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#define TEST_LCD_H_RES 128
#define TEST_LCD_V_RES 64
#define TEST_I2C_SDA_GPIO 0
#define TEST_I2C_SCL_GPIO 2
#define TEST_I2C_HOST_ID 0
#define TEST_I2C_DEV_ADDR 0x3C
#define TEST_LCD_PIXEL_CLOCK_HZ (400 * 1000)
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,70 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "unity.h"
#include "driver/i2c.h"
#include "driver/gpio.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_system.h"
#include "test_i2c_board.h"
TEST_CASE("lcd_panel_with_i2c_interface legacy_(ssd1306)", "[lcd]")
{
const uint8_t pattern[][16] = {{
0x00, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x00,
0x00, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x00
},
{
0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81,
0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81
}
};
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = TEST_I2C_SDA_GPIO,
.scl_io_num = TEST_I2C_SCL_GPIO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = TEST_LCD_PIXEL_CLOCK_HZ,
};
TEST_ESP_OK(i2c_param_config(TEST_I2C_HOST_ID, &conf));
TEST_ESP_OK(i2c_driver_install(TEST_I2C_HOST_ID, I2C_MODE_MASTER, 0, 0, 0));
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_io_i2c_config_t io_config = {
.dev_addr = TEST_I2C_DEV_ADDR,
.control_phase_bytes = 1, // According to SSD1306 datasheet
.dc_bit_offset = 6, // According to SSD1306 datasheet
.lcd_cmd_bits = 8, // According to SSD1306 datasheet
.lcd_param_bits = 8, // According to SSD1306 datasheet
};
TEST_ESP_OK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)TEST_I2C_HOST_ID, &io_config, &io_handle));
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_panel_dev_config_t panel_config = {
.bits_per_pixel = 1,
.reset_gpio_num = -1,
};
TEST_ESP_OK(esp_lcd_new_panel_ssd1306(io_handle, &panel_config, &panel_handle));
TEST_ESP_OK(esp_lcd_panel_reset(panel_handle));
TEST_ESP_OK(esp_lcd_panel_init(panel_handle));
// turn on display
TEST_ESP_OK(esp_lcd_panel_disp_on_off(panel_handle, true));
for (int i = 0; i < TEST_LCD_H_RES / 16; i++) {
for (int j = 0; j < TEST_LCD_V_RES / 8; j++) {
TEST_ESP_OK(esp_lcd_panel_draw_bitmap(panel_handle, i * 16, j * 8, i * 16 + 16, j * 8 + 8, pattern[i & 0x01]));
}
}
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(i2c_driver_delete(TEST_I2C_HOST_ID));
}

View File

@@ -0,0 +1,18 @@
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32c3
@pytest.mark.i2c_oled
@pytest.mark.parametrize(
'config',
[
'release',
],
indirect=True,
)
def test_i2c_lcd_legacy(dut: Dut) -> None:
dut.run_all_single_board_cases()

View File

@@ -0,0 +1,3 @@
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

View File

@@ -0,0 +1,5 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
# CONFIG_ESP_TASK_WDT_INIT is not set
CONFIG_FREERTOS_HZ=1000