lcd: refactor ut into test app

This commit is contained in:
morris
2021-09-23 12:06:13 +08:00
parent f8dc675318
commit dbfde65515
53 changed files with 648 additions and 372 deletions
@@ -0,0 +1,5 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(i2c_lcd_panel_test)
@@ -0,0 +1 @@
This test app is used to test LCDs with I2C interface.
@@ -0,0 +1,7 @@
set(srcs "test_app_main.c"
"test_i2c_lcd_panel.c")
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES esp_lcd unity)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u test_app_include_i2c_lcd")
@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2022 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();
}
@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2022 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
@@ -0,0 +1,73 @@
/*
* SPDX-FileCopyrightText: 2022 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"
void test_app_include_i2c_lcd(void)
{
}
TEST_CASE("lcd_panel_with_i2c_interface_(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,
.color_space = ESP_LCD_COLOR_SPACE_MONOCHROME,
.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));
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));
}
@@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.supported_targets
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'release',
],
indirect=True,
)
def test_i2c_lcd(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('*')
dut.expect_unity_test_output()
@@ -0,0 +1,3 @@
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
@@ -0,0 +1,2 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT=n
@@ -0,0 +1,5 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(i80_lcd_panel_test)
@@ -0,0 +1,4 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- |
This test app is used to test LCDs with intel 8080 interface.
@@ -0,0 +1,7 @@
set(srcs "test_app_main.c"
"test_i80_lcd_panel.c")
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES esp_lcd unity)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u test_app_include_i80_lcd")
@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2022 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 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();
}
@@ -0,0 +1,85 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#define TEST_LCD_H_RES (240)
#define TEST_LCD_V_RES (280)
#if CONFIG_IDF_TARGET_ESP32S3
#define TEST_LCD_BK_LIGHT_GPIO (1)
#define TEST_LCD_RST_GPIO (2)
#define TEST_LCD_CS_GPIO (3)
#define TEST_LCD_DC_GPIO (4)
#define TEST_LCD_PCLK_GPIO (5)
#define TEST_LCD_DATA0_GPIO (6)
#define TEST_LCD_DATA1_GPIO (7)
#define TEST_LCD_DATA2_GPIO (8)
#define TEST_LCD_DATA3_GPIO (9)
#define TEST_LCD_DATA4_GPIO (10)
#define TEST_LCD_DATA5_GPIO (11)
#define TEST_LCD_DATA6_GPIO (12)
#define TEST_LCD_DATA7_GPIO (13)
#define TEST_LCD_DATA8_GPIO (14)
#define TEST_LCD_DATA9_GPIO (15)
#define TEST_LCD_DATA10_GPIO (16)
#define TEST_LCD_DATA11_GPIO (17)
#define TEST_LCD_DATA12_GPIO (18)
#define TEST_LCD_DATA13_GPIO (19)
#define TEST_LCD_DATA14_GPIO (20)
#define TEST_LCD_DATA15_GPIO (21)
#elif CONFIG_IDF_TARGET_ESP32S2
#define TEST_LCD_BK_LIGHT_GPIO (0)
#define TEST_LCD_RST_GPIO (18)
#define TEST_LCD_CS_GPIO (19)
#define TEST_LCD_DC_GPIO (38)
#define TEST_LCD_PCLK_GPIO (33)
#define TEST_LCD_DATA0_GPIO (1)
#define TEST_LCD_DATA1_GPIO (10)
#define TEST_LCD_DATA2_GPIO (2)
#define TEST_LCD_DATA3_GPIO (11)
#define TEST_LCD_DATA4_GPIO (3)
#define TEST_LCD_DATA5_GPIO (12)
#define TEST_LCD_DATA6_GPIO (4)
#define TEST_LCD_DATA7_GPIO (13)
#define TEST_LCD_DATA8_GPIO (5)
#define TEST_LCD_DATA9_GPIO (14)
#define TEST_LCD_DATA10_GPIO (6)
#define TEST_LCD_DATA11_GPIO (15)
#define TEST_LCD_DATA12_GPIO (7)
#define TEST_LCD_DATA13_GPIO (16)
#define TEST_LCD_DATA14_GPIO (8)
#define TEST_LCD_DATA15_GPIO (17)
#elif CONFIG_IDF_TARGET_ESP32
#define TEST_LCD_BK_LIGHT_GPIO (2)
#define TEST_LCD_RST_GPIO (-1)
#define TEST_LCD_CS_GPIO (4)
#define TEST_LCD_DC_GPIO (5)
#define TEST_LCD_PCLK_GPIO (18)
#define TEST_LCD_DATA0_GPIO (19)
#define TEST_LCD_DATA1_GPIO (21)
#define TEST_LCD_DATA2_GPIO (0)
#define TEST_LCD_DATA3_GPIO (22)
#define TEST_LCD_DATA4_GPIO (23)
#define TEST_LCD_DATA5_GPIO (33)
#define TEST_LCD_DATA6_GPIO (32)
#define TEST_LCD_DATA7_GPIO (27)
#define TEST_LCD_DATA8_GPIO (12)
#define TEST_LCD_DATA9_GPIO (13)
#define TEST_LCD_DATA10_GPIO (14)
#define TEST_LCD_DATA11_GPIO (15)
#define TEST_LCD_DATA12_GPIO (26)
#define TEST_LCD_DATA13_GPIO (25)
#define TEST_LCD_DATA14_GPIO (16)
#define TEST_LCD_DATA15_GPIO (17)
#endif
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,454 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "unity.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "soc/soc_caps.h"
#include "driver/gpio.h"
#include "test_i80_board.h"
void test_app_include_i80_lcd(void)
{
}
#if SOC_I2S_LCD_I80_VARIANT
#include "driver/i2s.h"
TEST_CASE("i80_and_i2s_driver_co-existence", "[lcd][i2s]")
{
esp_lcd_i80_bus_handle_t i80_bus = NULL;
esp_lcd_i80_bus_config_t bus_config = {
.dc_gpio_num = TEST_LCD_DC_GPIO,
.wr_gpio_num = TEST_LCD_PCLK_GPIO,
.data_gpio_nums = {
TEST_LCD_DATA0_GPIO,
TEST_LCD_DATA1_GPIO,
TEST_LCD_DATA2_GPIO,
TEST_LCD_DATA3_GPIO,
TEST_LCD_DATA4_GPIO,
TEST_LCD_DATA5_GPIO,
TEST_LCD_DATA6_GPIO,
TEST_LCD_DATA7_GPIO,
},
.bus_width = 8,
.max_transfer_bytes = 20,
};
TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 36000,
.bits_per_sample = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_desc_num = 6,
.dma_frame_num = 60,
};
// I2S driver won't be installed as the same I2S port has been used by LCD
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, i2s_driver_install(0, &i2s_config, 0, NULL));
TEST_ESP_OK(esp_lcd_del_i80_bus(i80_bus));
}
#endif // SOC_I2S_LCD_I80_VARIANT
#if SOC_LCDCAM_SUPPORTED
TEST_CASE("lcd_i80_device_swap_color_bytes", "[lcd]")
{
esp_lcd_i80_bus_handle_t i80_bus = NULL;
esp_lcd_i80_bus_config_t bus_config = {
.dc_gpio_num = TEST_LCD_DC_GPIO,
.wr_gpio_num = TEST_LCD_PCLK_GPIO,
.data_gpio_nums = {
TEST_LCD_DATA0_GPIO,
TEST_LCD_DATA1_GPIO,
TEST_LCD_DATA2_GPIO,
TEST_LCD_DATA3_GPIO,
TEST_LCD_DATA4_GPIO,
TEST_LCD_DATA5_GPIO,
TEST_LCD_DATA6_GPIO,
TEST_LCD_DATA7_GPIO,
},
.bus_width = 8,
.max_transfer_bytes = 20,
};
TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
esp_lcd_panel_io_handle_t io_handles[4] = {};
esp_lcd_panel_io_i80_config_t io_config = {
.cs_gpio_num = TEST_LCD_CS_GPIO,
.pclk_hz = 5000000,
.trans_queue_depth = 10,
.dc_levels = {
.dc_idle_level = 0,
.dc_cmd_level = 0,
.dc_dummy_level = 0,
.dc_data_level = 1,
},
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
io_config.flags.reverse_color_bits = 0;
io_config.flags.swap_color_bytes = 0;
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handles[0]));
io_config.flags.reverse_color_bits = 0;
io_config.flags.swap_color_bytes = 1;
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handles[1]));
io_config.flags.reverse_color_bits = 1;
io_config.flags.swap_color_bytes = 0;
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handles[2]));
io_config.flags.reverse_color_bits = 1;
io_config.flags.swap_color_bytes = 1;
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handles[3]));
for (int i = 0; i < 4; i++) {
esp_lcd_panel_io_tx_param(io_handles[i], 0xA5, (uint8_t[]) {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06
}, 6);
esp_lcd_panel_io_tx_color(io_handles[i], 0x5A, (uint8_t[]) {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06
}, 6);
TEST_ESP_OK(esp_lcd_panel_io_del(io_handles[i]));
}
TEST_ESP_OK(esp_lcd_del_i80_bus(i80_bus));
}
TEST_CASE("lcd_i80_device_clock_mode", "[lcd]")
{
esp_lcd_i80_bus_handle_t i80_bus = NULL;
esp_lcd_i80_bus_config_t bus_config = {
.dc_gpio_num = TEST_LCD_DC_GPIO,
.wr_gpio_num = TEST_LCD_PCLK_GPIO,
.data_gpio_nums = {
TEST_LCD_DATA0_GPIO,
TEST_LCD_DATA1_GPIO,
TEST_LCD_DATA2_GPIO,
TEST_LCD_DATA3_GPIO,
TEST_LCD_DATA4_GPIO,
TEST_LCD_DATA5_GPIO,
TEST_LCD_DATA6_GPIO,
TEST_LCD_DATA7_GPIO,
},
.bus_width = 8,
.max_transfer_bytes = 20,
};
TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
esp_lcd_panel_io_handle_t io_handles[4] = {};
esp_lcd_panel_io_i80_config_t io_config = {
.cs_gpio_num = TEST_LCD_CS_GPIO,
.pclk_hz = 5000000,
.trans_queue_depth = 10,
.dc_levels = {
.dc_idle_level = 0,
.dc_cmd_level = 0,
.dc_dummy_level = 0,
.dc_data_level = 1,
},
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
io_config.flags.pclk_idle_low = 0;
io_config.flags.pclk_active_neg = 0;
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handles[0]));
io_config.flags.pclk_idle_low = 0;
io_config.flags.pclk_active_neg = 1;
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handles[1]));
io_config.flags.pclk_idle_low = 1;
io_config.flags.pclk_active_neg = 0;
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handles[2]));
io_config.flags.pclk_idle_low = 1;
io_config.flags.pclk_active_neg = 1;
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handles[3]));
for (int i = 0; i < 4; i++) {
esp_lcd_panel_io_tx_param(io_handles[i], 0xA5, (uint8_t[]) {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06
}, 6);
TEST_ESP_OK(esp_lcd_panel_io_del(io_handles[i]));
}
TEST_ESP_OK(esp_lcd_del_i80_bus(i80_bus));
}
#endif // SOC_LCDCAM_SUPPORTED
TEST_CASE("lcd_i80_bus_and_device_allocation", "[lcd]")
{
esp_lcd_i80_bus_handle_t i80_buses[SOC_LCD_I80_BUSES] = {};
esp_lcd_i80_bus_config_t bus_config = {
.dc_gpio_num = TEST_LCD_DC_GPIO,
.wr_gpio_num = TEST_LCD_PCLK_GPIO,
.data_gpio_nums = {
TEST_LCD_DATA0_GPIO,
TEST_LCD_DATA1_GPIO,
TEST_LCD_DATA2_GPIO,
TEST_LCD_DATA3_GPIO,
TEST_LCD_DATA4_GPIO,
TEST_LCD_DATA5_GPIO,
TEST_LCD_DATA6_GPIO,
TEST_LCD_DATA7_GPIO,
},
.bus_width = 8,
.max_transfer_bytes = TEST_LCD_H_RES * 40 * sizeof(uint16_t)
};
for (int i = 0; i < SOC_LCD_I80_BUSES; i++) {
TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_buses[i]));
}
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, esp_lcd_new_i80_bus(&bus_config, &i80_buses[0]));
esp_lcd_panel_io_handle_t io_handles[10] = {};
esp_lcd_panel_io_i80_config_t io_config = {
.cs_gpio_num = TEST_LCD_CS_GPIO,
.pclk_hz = 5000000,
.trans_queue_depth = 4,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
for (int i = 0; i < 10; i++) {
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_buses[0], &io_config, &io_handles[i]));
}
// can't delete bus handle before we delete all devices
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_lcd_del_i80_bus(i80_buses[0]));
for (int i = 0; i < 10; i++) {
TEST_ESP_OK(esp_lcd_panel_io_del(io_handles[i]));
}
for (int i = 0; i < SOC_LCD_I80_BUSES; i++) {
TEST_ESP_OK(esp_lcd_del_i80_bus(i80_buses[i]));
}
}
TEST_CASE("lcd_i80_bus_exclusively_owned_by_one_device", "[lcd]")
{
esp_lcd_i80_bus_handle_t i80_bus_handle = NULL;
esp_lcd_i80_bus_config_t bus_config = {
.dc_gpio_num = TEST_LCD_DC_GPIO,
.wr_gpio_num = TEST_LCD_PCLK_GPIO,
.data_gpio_nums = {
TEST_LCD_DATA0_GPIO,
TEST_LCD_DATA1_GPIO,
TEST_LCD_DATA2_GPIO,
TEST_LCD_DATA3_GPIO,
TEST_LCD_DATA4_GPIO,
TEST_LCD_DATA5_GPIO,
TEST_LCD_DATA6_GPIO,
TEST_LCD_DATA7_GPIO,
},
.bus_width = 8,
.max_transfer_bytes = TEST_LCD_H_RES * 40 * sizeof(uint16_t)
};
TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus_handle));
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_io_i80_config_t io_config = {
.cs_gpio_num = -1, // own the bus exclusively
.pclk_hz = 5000000,
.trans_queue_depth = 4,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus_handle, &io_config, &io_handle));
io_config.cs_gpio_num = 0;
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_lcd_new_panel_io_i80(i80_bus_handle, &io_config, &io_handle));
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(esp_lcd_del_i80_bus(i80_bus_handle));
}
TEST_CASE("lcd_panel_i80_io_test", "[lcd]")
{
esp_lcd_i80_bus_handle_t i80_bus = NULL;
esp_lcd_i80_bus_config_t bus_config = {
.dc_gpio_num = TEST_LCD_DC_GPIO,
.wr_gpio_num = TEST_LCD_PCLK_GPIO,
.data_gpio_nums = {
TEST_LCD_DATA0_GPIO,
TEST_LCD_DATA1_GPIO,
TEST_LCD_DATA2_GPIO,
TEST_LCD_DATA3_GPIO,
TEST_LCD_DATA4_GPIO,
TEST_LCD_DATA5_GPIO,
TEST_LCD_DATA6_GPIO,
TEST_LCD_DATA7_GPIO,
TEST_LCD_DATA8_GPIO,
TEST_LCD_DATA9_GPIO,
TEST_LCD_DATA10_GPIO,
TEST_LCD_DATA11_GPIO,
TEST_LCD_DATA12_GPIO,
TEST_LCD_DATA13_GPIO,
TEST_LCD_DATA14_GPIO,
TEST_LCD_DATA15_GPIO,
},
.bus_width = 16,
.max_transfer_bytes = 100,
};
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_io_i80_config_t io_config = {
.cs_gpio_num = TEST_LCD_CS_GPIO,
.pclk_hz = 8000000, // 8MHz
.trans_queue_depth = 10,
.dc_levels = {
.dc_idle_level = 0,
.dc_cmd_level = 0,
.dc_dummy_level = 0,
.dc_data_level = 1,
},
};
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = TEST_LCD_RST_GPIO,
.color_space = ESP_LCD_COLOR_SPACE_RGB,
.bits_per_pixel = 16,
};
printf("testing bus-width=16bit, cmd/param bit-width=8bit\r\n");
bus_config.bus_width = 16;
TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
io_config.lcd_cmd_bits = 8;
io_config.lcd_param_bits = 8;
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
esp_lcd_panel_io_tx_param(io_handle, 0x1A, NULL, 0);
esp_lcd_panel_io_tx_param(io_handle, 0x1B, (uint8_t[]) {
0x11, 0x22, 0x33
}, 3);
esp_lcd_panel_io_tx_param(io_handle, 0x1C, NULL, 0);
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(esp_lcd_del_i80_bus(i80_bus));
printf("testing bus-width=16bit, cmd/param bit-width=16bit\r\n");
bus_config.bus_width = 16;
TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
io_config.lcd_cmd_bits = 16;
io_config.lcd_param_bits = 16;
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
TEST_ESP_OK(esp_lcd_new_panel_nt35510(io_handle, &panel_config, &panel_handle));
esp_lcd_panel_io_tx_param(io_handle, 0x1A01, NULL, 0);
esp_lcd_panel_io_tx_param(io_handle, 0x1B02, (uint16_t[]) {
0x11, 0x22, 0x33
}, 6);
esp_lcd_panel_io_tx_param(io_handle, 0x1C03, NULL, 0);
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(esp_lcd_del_i80_bus(i80_bus));
printf("testing bus-width=8bit, cmd/param bit-width=8bit\r\n");
bus_config.bus_width = 8;
TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
io_config.lcd_cmd_bits = 8;
io_config.lcd_param_bits = 8;
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
esp_lcd_panel_io_tx_param(io_handle, 0x1A, NULL, 0);
esp_lcd_panel_io_tx_param(io_handle, 0x1B, (uint8_t[]) {
0x11, 0x22, 0x33
}, 3);
esp_lcd_panel_io_tx_param(io_handle, 0x1C, NULL, 0);
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(esp_lcd_del_i80_bus(i80_bus));
printf("testing bus-width=8bit, cmd/param bit-width=16bit\r\n");
bus_config.bus_width = 8;
TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
io_config.lcd_cmd_bits = 16;
io_config.lcd_param_bits = 16;
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
TEST_ESP_OK(esp_lcd_new_panel_nt35510(io_handle, &panel_config, &panel_handle));
esp_lcd_panel_io_tx_param(io_handle, 0x1A01, NULL, 0);
esp_lcd_panel_io_tx_param(io_handle, 0x1B02, (uint16_t[]) {
0x11, 0x22, 0x33
}, 6);
esp_lcd_panel_io_tx_param(io_handle, 0x1C03, NULL, 0);
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(esp_lcd_del_i80_bus(i80_bus));
}
TEST_CASE("lcd_panel_with_i80_interface_(st7789, 8bits)", "[lcd]")
{
#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t))
uint8_t *img = heap_caps_malloc(TEST_IMG_SIZE, MALLOC_CAP_DMA);
TEST_ASSERT_NOT_NULL(img);
gpio_config_t bk_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << TEST_LCD_BK_LIGHT_GPIO
};
TEST_ESP_OK(gpio_config(&bk_gpio_config));
esp_lcd_i80_bus_handle_t i80_bus = NULL;
esp_lcd_i80_bus_config_t bus_config = {
.dc_gpio_num = TEST_LCD_DC_GPIO,
.wr_gpio_num = TEST_LCD_PCLK_GPIO,
.data_gpio_nums = {
TEST_LCD_DATA0_GPIO,
TEST_LCD_DATA1_GPIO,
TEST_LCD_DATA2_GPIO,
TEST_LCD_DATA3_GPIO,
TEST_LCD_DATA4_GPIO,
TEST_LCD_DATA5_GPIO,
TEST_LCD_DATA6_GPIO,
TEST_LCD_DATA7_GPIO,
},
.bus_width = 8,
.max_transfer_bytes = TEST_IMG_SIZE + 10,
};
TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_io_i80_config_t io_config = {
.cs_gpio_num = TEST_LCD_CS_GPIO,
.pclk_hz = 8000000, // 8MHz
.trans_queue_depth = 10,
.dc_levels = {
.dc_idle_level = 0,
.dc_cmd_level = 0,
.dc_dummy_level = 0,
.dc_data_level = 1,
},
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = TEST_LCD_RST_GPIO,
.color_space = ESP_LCD_COLOR_SPACE_RGB,
.bits_per_pixel = 16,
};
TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
// turn off backlight
gpio_set_level(TEST_LCD_BK_LIGHT_GPIO, 0);
esp_lcd_panel_reset(panel_handle);
esp_lcd_panel_init(panel_handle);
esp_lcd_panel_invert_color(panel_handle, true);
// the gap is LCD panel specific, even panels with the same driver IC, can have different gap value
esp_lcd_panel_set_gap(panel_handle, 0, 20);
// turn on backlight
gpio_set_level(TEST_LCD_BK_LIGHT_GPIO, 1);
for (int i = 0; i < 200; i++) {
uint8_t color_byte = esp_random() & 0xFF;
int x_start = esp_random() % (TEST_LCD_H_RES - 100);
int y_start = esp_random() % (TEST_LCD_V_RES - 100);
memset(img, color_byte, TEST_IMG_SIZE);
esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 100, y_start + 100, img);
}
esp_lcd_panel_disp_off(panel_handle, true); // turn off screen
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(esp_lcd_del_i80_bus(i80_bus));
TEST_ESP_OK(gpio_reset_pin(TEST_LCD_BK_LIGHT_GPIO));
free(img);
#undef TEST_IMG_SIZE
}
@@ -0,0 +1,22 @@
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.esp32s2
@pytest.mark.esp32s3
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'release',
],
indirect=True,
)
def test_i80_lcd(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('*')
dut.expect_unity_test_output()
@@ -0,0 +1,5 @@
CONFIG_PM_ENABLE=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
@@ -0,0 +1,2 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT=n
@@ -0,0 +1,5 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(rgb_lcd_panel_test)
@@ -0,0 +1,4 @@
| Supported Targets | ESP32-S3 |
| ----------------- | -------- |
This test app is used to test RGB565 interfaced LCDs.
@@ -0,0 +1,7 @@
set(srcs "test_app_main.c"
"test_rgb_panel.c")
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES esp_lcd unity)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u test_app_include_rgb_lcd")
@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2022 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 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();
}
@@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#define TEST_LCD_H_RES 480
#define TEST_LCD_V_RES 272
#define TEST_LCD_VSYNC_GPIO 48
#define TEST_LCD_HSYNC_GPIO 47
#define TEST_LCD_DE_GPIO 45
#define TEST_LCD_PCLK_GPIO 21
#define TEST_LCD_DATA0_GPIO 3 // B0
#define TEST_LCD_DATA1_GPIO 4 // B1
#define TEST_LCD_DATA2_GPIO 5 // B2
#define TEST_LCD_DATA3_GPIO 6 // B3
#define TEST_LCD_DATA4_GPIO 7 // B4
#define TEST_LCD_DATA5_GPIO 8 // G0
#define TEST_LCD_DATA6_GPIO 9 // G1
#define TEST_LCD_DATA7_GPIO 10 // G2
#define TEST_LCD_DATA8_GPIO 11 // G3
#define TEST_LCD_DATA9_GPIO 12 // G4
#define TEST_LCD_DATA10_GPIO 13 // G5
#define TEST_LCD_DATA11_GPIO 14 // R0
#define TEST_LCD_DATA12_GPIO 15 // R1
#define TEST_LCD_DATA13_GPIO 16 // R2
#define TEST_LCD_DATA14_GPIO 17 // R3
#define TEST_LCD_DATA15_GPIO 18 // R4
#define TEST_LCD_DISP_EN_GPIO -1
#define TEST_LCD_PIXEL_CLOCK_HZ (10 * 1000 * 1000)
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,85 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "unity.h"
#include "esp_lcd_panel_rgb.h"
#include "esp_lcd_panel_ops.h"
#include "esp_system.h"
#include "test_rgb_board.h"
void test_app_include_rgb_lcd(void)
{
}
TEST_CASE("lcd_rgb_lcd_panel", "[lcd]")
{
#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t))
uint8_t *img = malloc(TEST_IMG_SIZE);
TEST_ASSERT_NOT_NULL(img);
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_rgb_panel_config_t panel_config = {
.data_width = 16,
.psram_trans_align = 64,
.clk_src = LCD_CLK_SRC_PLL160M,
.disp_gpio_num = TEST_LCD_DISP_EN_GPIO,
.pclk_gpio_num = TEST_LCD_PCLK_GPIO,
.vsync_gpio_num = TEST_LCD_VSYNC_GPIO,
.hsync_gpio_num = TEST_LCD_HSYNC_GPIO,
.de_gpio_num = TEST_LCD_DE_GPIO,
.data_gpio_nums = {
TEST_LCD_DATA0_GPIO,
TEST_LCD_DATA1_GPIO,
TEST_LCD_DATA2_GPIO,
TEST_LCD_DATA3_GPIO,
TEST_LCD_DATA4_GPIO,
TEST_LCD_DATA5_GPIO,
TEST_LCD_DATA6_GPIO,
TEST_LCD_DATA7_GPIO,
TEST_LCD_DATA8_GPIO,
TEST_LCD_DATA9_GPIO,
TEST_LCD_DATA10_GPIO,
TEST_LCD_DATA11_GPIO,
TEST_LCD_DATA12_GPIO,
TEST_LCD_DATA13_GPIO,
TEST_LCD_DATA14_GPIO,
TEST_LCD_DATA15_GPIO,
},
.timings = {
.pclk_hz = TEST_LCD_PIXEL_CLOCK_HZ,
.h_res = TEST_LCD_H_RES,
.v_res = TEST_LCD_V_RES,
.hsync_back_porch = 68,
.hsync_front_porch = 20,
.hsync_pulse_width = 5,
.vsync_back_porch = 18,
.vsync_front_porch = 4,
.vsync_pulse_width = 1,
.flags.pclk_active_neg = 1, // RGB data is clocked out on falling edge
},
.flags.fb_in_psram = 1, // allocate frame buffer in PSRAM
};
// Test stream mode and one-off mode
for (int i = 0; i < 2; i++) {
panel_config.flags.relax_on_idle = i;
TEST_ESP_OK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));
TEST_ESP_OK(esp_lcd_panel_reset(panel_handle));
TEST_ESP_OK(esp_lcd_panel_init(panel_handle));
for (int i = 0; i < 200; i++) {
uint8_t color_byte = esp_random() & 0xFF;
int x_start = esp_random() % (TEST_LCD_H_RES - 100);
int y_start = esp_random() % (TEST_LCD_V_RES - 100);
memset(img, color_byte, TEST_IMG_SIZE);
esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 100, y_start + 100, img);
}
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
}
free(img);
#undef TEST_IMG_SIZE
}
@@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32s3
@pytest.mark.octal_psram
@pytest.mark.parametrize(
'config',
[
'release',
],
indirect=True,
)
def test_rgb_lcd(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('*')
dut.expect_unity_test_output()
@@ -0,0 +1,5 @@
CONFIG_PM_ENABLE=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
@@ -0,0 +1,2 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT=n
@@ -0,0 +1,3 @@
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y
@@ -0,0 +1,5 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(spi_lcd_panel_test)
@@ -0,0 +1 @@
This test app is used to test LCDs with SPI interface.
@@ -0,0 +1,7 @@
set(srcs "test_app_main.c"
"test_spi_lcd_panel.c")
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES esp_lcd unity)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u test_app_include_spi_lcd")
@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2022 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();
}
@@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#define TEST_LCD_H_RES 240
#define TEST_LCD_V_RES 280
#define TEST_LCD_BK_LIGHT_GPIO 18
#define TEST_LCD_RST_GPIO 5
#define TEST_LCD_CS_GPIO 0
#define TEST_LCD_DC_GPIO 19
#define TEST_LCD_PCLK_GPIO 2
#define TEST_LCD_DATA0_GPIO 4
#define TEST_LCD_DATA1_GPIO 7
#define TEST_LCD_DATA2_GPIO 8
#define TEST_LCD_DATA3_GPIO 9
#define TEST_LCD_DATA4_GPIO 10
#define TEST_LCD_DATA5_GPIO 11
#define TEST_LCD_DATA6_GPIO 12
#define TEST_LCD_DATA7_GPIO 13
#define TEST_LCD_PIXEL_CLOCK_HZ (20 * 1000 * 1000)
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,189 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "unity.h"
#include "driver/spi_master.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 "soc/soc_caps.h"
#include "test_spi_board.h"
#define TEST_SPI_HOST_ID SPI2_HOST
void test_app_include_spi_lcd(void)
{
}
void test_spi_lcd_common_initialize(esp_lcd_panel_io_handle_t *io_handle, esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done,
void *user_data, int cmd_bits, int param_bits, bool oct_mode)
{
// turn off backlight
gpio_config_t bk_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << TEST_LCD_BK_LIGHT_GPIO
};
TEST_ESP_OK(gpio_config(&bk_gpio_config));
gpio_set_level(TEST_LCD_BK_LIGHT_GPIO, 0);
spi_bus_config_t buscfg = {
.sclk_io_num = TEST_LCD_PCLK_GPIO,
.mosi_io_num = TEST_LCD_DATA0_GPIO,
.miso_io_num = -1,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = TEST_LCD_H_RES * TEST_LCD_V_RES * sizeof(uint16_t)
};
if (oct_mode) {
buscfg.data1_io_num = TEST_LCD_DATA1_GPIO;
buscfg.data2_io_num = TEST_LCD_DATA2_GPIO;
buscfg.data3_io_num = TEST_LCD_DATA3_GPIO;
buscfg.data4_io_num = TEST_LCD_DATA4_GPIO;
buscfg.data5_io_num = TEST_LCD_DATA5_GPIO;
buscfg.data6_io_num = TEST_LCD_DATA6_GPIO;
buscfg.data7_io_num = TEST_LCD_DATA7_GPIO;
buscfg.flags = SPICOMMON_BUSFLAG_OCTAL;
}
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST_ID, &buscfg, SPI_DMA_CH_AUTO));
esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = TEST_LCD_DC_GPIO,
.cs_gpio_num = TEST_LCD_CS_GPIO,
.pclk_hz = TEST_LCD_PIXEL_CLOCK_HZ,
.spi_mode = 0,
.trans_queue_depth = 10,
.lcd_cmd_bits = cmd_bits,
.lcd_param_bits = param_bits,
.on_color_trans_done = on_color_trans_done,
.user_ctx = user_data,
};
if (oct_mode) {
io_config.flags.octal_mode = 1;
io_config.spi_mode = 3;
}
TEST_ESP_OK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TEST_SPI_HOST_ID, &io_config, io_handle));
}
static void lcd_panel_test(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_handle_t panel_handle)
{
#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t))
uint8_t *img = heap_caps_malloc(TEST_IMG_SIZE, MALLOC_CAP_DMA);
TEST_ASSERT_NOT_NULL(img);
esp_lcd_panel_reset(panel_handle);
esp_lcd_panel_init(panel_handle);
esp_lcd_panel_invert_color(panel_handle, true);
// the gap is LCD panel specific, even panels with the same driver IC, can have different gap value
esp_lcd_panel_set_gap(panel_handle, 0, 20);
// turn on backlight
gpio_set_level(TEST_LCD_BK_LIGHT_GPIO, 1);
for (int i = 0; i < 200; i++) {
uint8_t color_byte = esp_random() & 0xFF;
int x_start = esp_random() % (TEST_LCD_H_RES - 100);
int y_start = esp_random() % (TEST_LCD_V_RES - 100);
memset(img, color_byte, TEST_IMG_SIZE);
esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 100, y_start + 100, img);
}
// turn off screen
esp_lcd_panel_disp_off(panel_handle, true);
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST_ID));
TEST_ESP_OK(gpio_reset_pin(TEST_LCD_BK_LIGHT_GPIO));
free(img);
#undef TEST_IMG_SIZE
}
TEST_CASE("lcd_panel_spi_io_test", "[lcd]")
{
esp_lcd_panel_io_handle_t io_handle = NULL;
test_spi_lcd_common_initialize(&io_handle, NULL, NULL, 8, 8, false);
esp_lcd_panel_io_tx_param(io_handle, 0x1A, NULL, 0);
esp_lcd_panel_io_tx_param(io_handle, 0x1B, (uint8_t[]) {
0x11, 0x22, 0x33
}, 3);
esp_lcd_panel_io_tx_param(io_handle, 0x1C, NULL, 0);
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST_ID));
test_spi_lcd_common_initialize(&io_handle, NULL, NULL, 16, 16, false);
esp_lcd_panel_io_tx_param(io_handle, 0x1A01, NULL, 0);
esp_lcd_panel_io_tx_param(io_handle, 0x1B02, (uint16_t[]) {
0x11, 0x22, 0x33
}, 6);
esp_lcd_panel_io_tx_param(io_handle, 0x1C03, NULL, 0);
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST_ID));
#if SOC_SPI_SUPPORT_OCT
test_spi_lcd_common_initialize(&io_handle, NULL, NULL, 8, 8, true);
esp_lcd_panel_io_tx_param(io_handle, 0x1A, NULL, 0);
esp_lcd_panel_io_tx_param(io_handle, 0x1B, (uint8_t[]) {
0x11, 0x22, 0x33
}, 3);
esp_lcd_panel_io_tx_param(io_handle, 0x1C, NULL, 0);
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST_ID));
test_spi_lcd_common_initialize(&io_handle, NULL, NULL, 16, 16, true);
esp_lcd_panel_io_tx_param(io_handle, 0x1A01, NULL, 0);
esp_lcd_panel_io_tx_param(io_handle, 0x1B02, (uint16_t[]) {
0x11, 0x22, 0x33
}, 6);
esp_lcd_panel_io_tx_param(io_handle, 0x1C03, NULL, 0);
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST_ID));
#endif // SOC_SPI_SUPPORT_OCT
}
#if SOC_SPI_SUPPORT_OCT
TEST_CASE("lcd_panel_with_8-line_spi_interface_(st7789)", "[lcd]")
{
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_handle_t panel_handle = NULL;
test_spi_lcd_common_initialize(&io_handle, NULL, NULL, 8, 8, true);
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = TEST_LCD_RST_GPIO,
.color_space = ESP_LCD_COLOR_SPACE_RGB,
.bits_per_pixel = 16,
};
TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
lcd_panel_test(io_handle, panel_handle);
}
TEST_CASE("lcd_panel_with_8-line_spi_interface_(nt35510)", "[lcd]")
{
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_handle_t panel_handle = NULL;
test_spi_lcd_common_initialize(&io_handle, NULL, NULL, 16, 16, true);
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = TEST_LCD_RST_GPIO,
.color_space = ESP_LCD_COLOR_SPACE_RGB,
.bits_per_pixel = 16,
};
TEST_ESP_OK(esp_lcd_new_panel_nt35510(io_handle, &panel_config, &panel_handle));
lcd_panel_test(io_handle, panel_handle);
}
#endif // SOC_SPI_SUPPORT_OCT
TEST_CASE("lcd_panel_with_1-line_spi_interface_(st7789)", "[lcd]")
{
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_handle_t panel_handle = NULL;
test_spi_lcd_common_initialize(&io_handle, NULL, NULL, 8, 8, false);
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = TEST_LCD_RST_GPIO,
.color_space = ESP_LCD_COLOR_SPACE_RGB,
.bits_per_pixel = 16,
};
TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
lcd_panel_test(io_handle, panel_handle);
}
@@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.supported_targets
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'release',
],
indirect=True,
)
def test_spi_lcd(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.write('*')
dut.expect_unity_test_output()
@@ -0,0 +1,3 @@
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
@@ -0,0 +1,2 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT=n