feat(lcd): support parlio lcd interface
This commit is contained in:
committed by
Chen Ji Chang
parent
b6b0758e42
commit
e890b4bd7e
@@ -30,6 +30,10 @@ if(CONFIG_SOC_I2S_SUPPORTS_LCD_CAMERA)
|
||||
list(APPEND srcs "i80/esp_lcd_panel_io_i2s.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_PARLIO_SUPPORT_SPI_LCD)
|
||||
list(APPEND srcs "parl/esp_lcd_panel_io_parl.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_LCDCAM_I80_LCD_SUPPORTED)
|
||||
list(APPEND srcs "i80/esp_lcd_panel_io_i80.c")
|
||||
endif()
|
||||
|
||||
@@ -376,7 +376,7 @@ static esp_err_t panel_io_i80_register_event_callbacks(esp_lcd_panel_io_handle_t
|
||||
lcd_panel_io_i80_t *i80_device = __containerof(io, lcd_panel_io_i80_t, base);
|
||||
|
||||
if (i80_device->on_color_trans_done != NULL) {
|
||||
ESP_LOGW(TAG, "Callback on_color_trans_done was already set and now it was owerwritten!");
|
||||
ESP_LOGW(TAG, "Callback on_color_trans_done was already set and now it was overwritten!");
|
||||
}
|
||||
|
||||
i80_device->on_color_trans_done = cbs->on_color_trans_done;
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_lcd_types.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "driver/parlio_types.h"
|
||||
|
||||
#define ESP_PARLIO_LCD_WIDTH_MAX 8 /*!< Maximum data width of parlio lcd interface */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if SOC_PARLIO_SUPPORTED
|
||||
/**
|
||||
* @brief Parallel Panel IO configuration structure, for intel 8080 interface(8 data-lines) or SPI interface(1 data-lines)
|
||||
*/
|
||||
typedef struct {
|
||||
int dc_gpio_num; /*!< GPIO used for D/C line */
|
||||
int clk_gpio_num; /*!< GPIO used for CLK line */
|
||||
int cs_gpio_num; /*!< GPIO used for CS line */
|
||||
int data_gpio_nums[ESP_PARLIO_LCD_WIDTH_MAX]; /*!< GPIOs used for data lines */
|
||||
size_t data_width; /*!< Number of data lines, 1(SPI) or 8(I80) */
|
||||
uint32_t pclk_hz; /*!< Frequency of pixel clock */
|
||||
parlio_clock_source_t clk_src; /*!< Clock source for the Parlio peripheral */
|
||||
size_t max_transfer_bytes; /*!< Maximum transfer size, this determines the length of internal DMA link */
|
||||
size_t dma_burst_size; /*!< DMA burst size, in bytes */
|
||||
size_t trans_queue_depth; /*!< Transaction queue size, larger queue, higher throughput */
|
||||
int lcd_cmd_bits; /*!< Bit-width of LCD command */
|
||||
int lcd_param_bits; /*!< Bit-width of LCD parameter */
|
||||
struct {
|
||||
unsigned int dc_cmd_level: 1; /*!< Level of DC line in CMD phase */
|
||||
unsigned int dc_data_level: 1; /*!< Level of DC line in DATA phase */
|
||||
} dc_levels; /*!< Each LCD device might have its own D/C control logic */
|
||||
struct {
|
||||
unsigned int cs_active_high: 1; /*!< If set, a high level of CS line will select the device, otherwise, CS line is low level active */
|
||||
} flags; /*!< Panel IO config flags */
|
||||
} esp_lcd_panel_io_parl_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create LCD panel IO, for parlio interface
|
||||
*
|
||||
* @param[in] io_config IO configuration, for parlio interface
|
||||
* @param[out] ret_io Returned panel IO handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_ERR_NOT_SUPPORTED if some configuration can't be satisfied, e.g. pixel clock out of the range
|
||||
* - ESP_ERR_NO_MEM if out of memory
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_lcd_new_panel_io_parl(const esp_lcd_panel_io_parl_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io);
|
||||
|
||||
/**
|
||||
* @brief Allocate a draw buffer that can be used by parlio interface LCD panel
|
||||
*
|
||||
* @note This function differs from the normal 'heap_caps_*' functions in that it can also automatically handle the alignment required by DMA burst, cache line size, etc.
|
||||
*
|
||||
* @param[in] io Panel IO handle, created by `esp_lcd_new_panel_io_parl()`
|
||||
* @param[in] size Size of memory to be allocated
|
||||
* @param[in] caps Bitwise OR of MALLOC_CAP_* flags indicating the type of memory desired for the allocation
|
||||
* @return Pointer to a new buffer of size 'size' with capabilities 'caps', or NULL if allocation failed
|
||||
*/
|
||||
void *esp_lcd_parlio_alloc_draw_buffer(esp_lcd_panel_io_handle_t io, size_t size, uint32_t caps);
|
||||
|
||||
#endif // SOC_PARLIO_SUPPORTED
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "esp_lcd_io_i80.h"
|
||||
#include "esp_lcd_io_i2c.h"
|
||||
#include "esp_lcd_io_spi.h"
|
||||
#include "esp_lcd_io_parl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Although we're manipulating Parlio peripheral, it has nothing to do with the Parlio.
|
||||
// In fact, we're simulating the Intel 8080 (8 data-width) or SPI(1 data-width) interface with Parlio peripheral.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.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 "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/lcd_periph.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/parlio_tx.h"
|
||||
#include "driver/parlio_types.h"
|
||||
#include "esp_private/gpio.h"
|
||||
#include "esp_private/parlio_private.h"
|
||||
#include "esp_lcd_panel_io_interface.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_common.h"
|
||||
|
||||
static const char *TAG = "lcd_panel.io.parl";
|
||||
|
||||
typedef struct lcd_panel_io_parlio_t lcd_panel_io_parlio_t;
|
||||
typedef struct parlio_trans_descriptor_t parlio_trans_descriptor_t;
|
||||
|
||||
static esp_err_t panel_io_parl_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, const void *param, size_t param_size);
|
||||
static esp_err_t panel_io_parl_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, const void *color, size_t color_size);
|
||||
static esp_err_t panel_io_parl_del(esp_lcd_panel_io_t *io);
|
||||
static bool lcd_default_isr_callback(parlio_tx_unit_handle_t tx_unit, const parlio_tx_done_event_data_t *edata, void *user_ctx);
|
||||
static esp_err_t panel_io_parl_register_event_callbacks(esp_lcd_panel_io_handle_t io, const esp_lcd_panel_io_callbacks_t *cbs, void *user_ctx);
|
||||
|
||||
struct parlio_trans_descriptor_t {
|
||||
lcd_panel_io_parlio_t *parlio_device; // parlio device issuing this transaction
|
||||
const void *data; // Data buffer
|
||||
uint32_t data_length; // Data buffer size
|
||||
struct {
|
||||
unsigned int en_trans_done_cb: 1;
|
||||
} flags;
|
||||
};
|
||||
|
||||
struct lcd_panel_io_parlio_t {
|
||||
esp_lcd_panel_io_t base; // Base class of generic lcd panel io
|
||||
parlio_tx_unit_handle_t tx_unit; // Parlio TX unit
|
||||
size_t data_width; // Number of data lines
|
||||
int dc_gpio_num; // GPIO used for DC line
|
||||
int cs_gpio_num; // GPIO used for CS line
|
||||
int lcd_cmd_bits; // Bit width of LCD command
|
||||
int lcd_param_bits; // Bit width of LCD parameter
|
||||
void *user_ctx; // private data used when transfer color data
|
||||
esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; // color data trans done callback
|
||||
struct {
|
||||
unsigned int dc_cmd_level: 1; // Level of DC line in CMD phase
|
||||
unsigned int dc_data_level: 1; // Level of DC line in DATA phase
|
||||
} dc_levels;
|
||||
parlio_trans_descriptor_t trans_desc; // Transaction description
|
||||
};
|
||||
|
||||
esp_err_t esp_lcd_new_panel_io_parl(const esp_lcd_panel_io_parl_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
lcd_panel_io_parlio_t *parlio_device = NULL;
|
||||
|
||||
ESP_GOTO_ON_FALSE(io_config && ret_io, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
// Only support 1-bit(SPI) or 8-bit(I80) data width
|
||||
#if SOC_PARLIO_SUPPORT_I80_LCD
|
||||
ESP_GOTO_ON_FALSE(io_config->data_width == 1 || io_config->data_width == 8, ESP_ERR_INVALID_ARG, err,
|
||||
TAG, "invalid bus width:%d", io_config->data_width);
|
||||
#else
|
||||
ESP_GOTO_ON_FALSE(io_config->data_width == 1, ESP_ERR_INVALID_ARG, err,
|
||||
TAG, "invalid bus width:%d", io_config->data_width);
|
||||
#endif
|
||||
|
||||
// allocate parlio device memory
|
||||
parlio_device = heap_caps_calloc(1, sizeof(lcd_panel_io_parlio_t), MALLOC_CAP_DEFAULT);
|
||||
ESP_GOTO_ON_FALSE(parlio_device, ESP_ERR_NO_MEM, err, TAG, "no mem for parlio device");
|
||||
|
||||
// initialize the parlio unit
|
||||
parlio_tx_unit_handle_t tx_unit = NULL;
|
||||
parlio_tx_unit_config_t pio_config = {
|
||||
.clk_src = io_config->clk_src,
|
||||
.data_width = io_config->data_width,
|
||||
.clk_in_gpio_num = -1, // use internal clock source
|
||||
.valid_gpio_num = io_config->cs_gpio_num,
|
||||
.clk_out_gpio_num = io_config->clk_gpio_num,
|
||||
.data_gpio_nums = {
|
||||
io_config->data_gpio_nums[0],
|
||||
io_config->data_gpio_nums[1],
|
||||
io_config->data_gpio_nums[2],
|
||||
io_config->data_gpio_nums[3],
|
||||
io_config->data_gpio_nums[4],
|
||||
io_config->data_gpio_nums[5],
|
||||
io_config->data_gpio_nums[6],
|
||||
io_config->data_gpio_nums[7],
|
||||
},
|
||||
.output_clk_freq_hz = io_config->pclk_hz,
|
||||
.trans_queue_depth = io_config->trans_queue_depth ? io_config->trans_queue_depth : 4,
|
||||
.max_transfer_size = io_config->max_transfer_bytes,
|
||||
.sample_edge = PARLIO_SAMPLE_EDGE_POS,
|
||||
.bit_pack_order = PARLIO_BIT_PACK_ORDER_MSB,
|
||||
.dma_burst_size = io_config->dma_burst_size,
|
||||
.flags.invert_valid_out = !io_config->flags.cs_active_high,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(parlio_new_tx_unit(&pio_config, &tx_unit), err, TAG, "config parlio tx unit failed");
|
||||
|
||||
parlio_tx_event_callbacks_t parlio_cbs = {
|
||||
.on_trans_done = lcd_default_isr_callback,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(parlio_tx_unit_register_event_callbacks(tx_unit, &parlio_cbs, parlio_device), err, TAG, "register parlio tx callback failed");
|
||||
|
||||
// DC signal is controlled by software, set as general purpose IO
|
||||
gpio_func_sel(io_config->dc_gpio_num, PIN_FUNC_GPIO);
|
||||
gpio_output_enable(io_config->dc_gpio_num);
|
||||
|
||||
parlio_device->dc_gpio_num = io_config->dc_gpio_num;
|
||||
parlio_device->tx_unit = tx_unit;
|
||||
parlio_device->data_width = io_config->data_width;
|
||||
parlio_device->lcd_cmd_bits = io_config->lcd_cmd_bits;
|
||||
parlio_device->lcd_param_bits = io_config->lcd_param_bits;
|
||||
parlio_device->dc_levels.dc_cmd_level = io_config->dc_levels.dc_cmd_level;
|
||||
parlio_device->dc_levels.dc_data_level = io_config->dc_levels.dc_data_level;
|
||||
parlio_device->cs_gpio_num = io_config->cs_gpio_num;
|
||||
parlio_device->trans_desc.parlio_device = parlio_device;
|
||||
|
||||
// fill panel io function table
|
||||
parlio_device->base.del = panel_io_parl_del;
|
||||
parlio_device->base.tx_param = panel_io_parl_tx_param;
|
||||
parlio_device->base.tx_color = panel_io_parl_tx_color;
|
||||
parlio_device->base.register_event_callbacks = panel_io_parl_register_event_callbacks;
|
||||
|
||||
// enable parlio tx unit finally
|
||||
ESP_GOTO_ON_ERROR(parlio_tx_unit_enable(tx_unit), err, TAG, "enable parlio tx unit failed");
|
||||
|
||||
*ret_io = &(parlio_device->base);
|
||||
ESP_LOGD(TAG, "new parlio lcd panel io @%p", parlio_device);
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (parlio_device) {
|
||||
if (parlio_device->tx_unit) {
|
||||
parlio_del_tx_unit(parlio_device->tx_unit);
|
||||
}
|
||||
free(parlio_device);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *esp_lcd_parlio_alloc_draw_buffer(esp_lcd_panel_io_handle_t io, size_t size, uint32_t caps)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(io, NULL, TAG, "invalid argument");
|
||||
lcd_panel_io_parlio_t *parlio_device = __containerof(io, lcd_panel_io_parlio_t, base);
|
||||
size_t int_mem_align = 0;
|
||||
size_t ext_mem_align = 0;
|
||||
void *buf = NULL;
|
||||
parlio_tx_get_alignment_constraints(parlio_device->tx_unit, &int_mem_align, &ext_mem_align);
|
||||
// alloc from external memory
|
||||
if (caps & MALLOC_CAP_SPIRAM) {
|
||||
buf = heap_caps_aligned_calloc(ext_mem_align, 1, size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA);
|
||||
} else {
|
||||
buf = heap_caps_aligned_calloc(int_mem_align, 1, size, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static esp_err_t panel_io_parl_del(esp_lcd_panel_io_t *io)
|
||||
{
|
||||
lcd_panel_io_parlio_t *parlio_device = __containerof(io, lcd_panel_io_parlio_t, base);
|
||||
// wait all pending transaction to finish
|
||||
ESP_RETURN_ON_ERROR(parlio_tx_unit_wait_all_done(parlio_device->tx_unit, -1), TAG, "error waiting transmit done");
|
||||
ESP_LOGD(TAG, "del parlio lcd panel io @%p", parlio_device);
|
||||
|
||||
ESP_RETURN_ON_ERROR(parlio_tx_unit_disable(parlio_device->tx_unit), TAG, "disable parlio tx unit failed");
|
||||
ESP_RETURN_ON_ERROR(parlio_del_tx_unit(parlio_device->tx_unit), TAG, "del parlio tx unit failed");
|
||||
|
||||
free(parlio_device);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_io_parl_register_event_callbacks(esp_lcd_panel_io_handle_t io, const esp_lcd_panel_io_callbacks_t *cbs, void *user_ctx)
|
||||
{
|
||||
lcd_panel_io_parlio_t *parlio_device = __containerof(io, lcd_panel_io_parlio_t, base);
|
||||
if (parlio_device->on_color_trans_done != NULL) {
|
||||
ESP_LOGW(TAG, "Callback on_color_trans_done was already set and now it was overwritten!");
|
||||
}
|
||||
parlio_device->on_color_trans_done = cbs->on_color_trans_done;
|
||||
parlio_device->user_ctx = user_ctx;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void parlio_lcd_prepare_cmd_buffer(parlio_trans_descriptor_t *trans_desc, const void *cmd)
|
||||
{
|
||||
lcd_panel_io_parlio_t *parlio_device = trans_desc->parlio_device;
|
||||
uint8_t *from = (uint8_t *)cmd;
|
||||
// LCD is big-endian, e.g. to send command 0x1234, byte 0x12 should appear on the data bus first
|
||||
// However, the Parlio peripheral will send 0x34 first, so we reversed the order below
|
||||
if (parlio_device->data_width < parlio_device->lcd_cmd_bits) {
|
||||
int start = 0;
|
||||
int end = parlio_device->lcd_cmd_bits / 8 - 1;
|
||||
lcd_com_reverse_buffer_bytes(from, start, end);
|
||||
}
|
||||
trans_desc->data = cmd;
|
||||
trans_desc->data_length = MAX(parlio_device->lcd_cmd_bits, parlio_device->data_width) / 8;
|
||||
}
|
||||
|
||||
static void parlio_lcd_prepare_param_buffer(parlio_trans_descriptor_t *trans_desc, const void *param, size_t param_num)
|
||||
{
|
||||
lcd_panel_io_parlio_t *parlio_device = trans_desc->parlio_device;
|
||||
uint8_t *from = (uint8_t *)param;
|
||||
int param_size = parlio_device->lcd_param_bits / 8;
|
||||
// LCD is big-endian, e.g. to send param 0x1234, byte 0x12 should appear on the data bus first
|
||||
// However, the Parlio peripheral will send 0x34 first, so we reversed the order below
|
||||
if (parlio_device->data_width < parlio_device->lcd_param_bits) {
|
||||
for (size_t i = 0; i < param_num; i++) {
|
||||
int start = i * param_size;
|
||||
int end = start + param_size - 1;
|
||||
lcd_com_reverse_buffer_bytes(from, start, end);
|
||||
}
|
||||
}
|
||||
trans_desc->data = param;
|
||||
trans_desc->data_length = param_num;
|
||||
}
|
||||
|
||||
static void parlio_lcd_prepare_color_buffer(parlio_trans_descriptor_t *trans_desc, const void *color, size_t color_size)
|
||||
{
|
||||
trans_desc->data = color;
|
||||
trans_desc->data_length = color_size;
|
||||
}
|
||||
|
||||
static esp_err_t panel_io_parl_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, const void *param, size_t param_size)
|
||||
{
|
||||
lcd_panel_io_parlio_t *parlio_device = __containerof(io, lcd_panel_io_parlio_t, base);
|
||||
parlio_trans_descriptor_t *trans_desc = NULL;
|
||||
|
||||
// before issue a polling transaction, need to wait queued transactions finished
|
||||
ESP_RETURN_ON_ERROR(parlio_tx_unit_wait_all_done(parlio_device->tx_unit, -1), TAG, "error waiting transmit done");
|
||||
trans_desc = &parlio_device->trans_desc;
|
||||
trans_desc->flags.en_trans_done_cb = false;
|
||||
parlio_lcd_prepare_cmd_buffer(trans_desc, &lcd_cmd);
|
||||
|
||||
gpio_set_level(parlio_device->dc_gpio_num, parlio_device->dc_levels.dc_cmd_level);
|
||||
parlio_transmit_config_t transmit_config = {
|
||||
.idle_value = 0x00,
|
||||
};
|
||||
|
||||
ESP_RETURN_ON_ERROR(parlio_tx_unit_transmit(parlio_device->tx_unit, trans_desc->data, trans_desc->data_length * 8, &transmit_config), TAG, "error transmit");
|
||||
if (param && param_size) {
|
||||
parlio_lcd_prepare_param_buffer(trans_desc, param, param_size * 8 / parlio_device->lcd_param_bits);
|
||||
// wait transmit done before changing DC level
|
||||
ESP_RETURN_ON_ERROR(parlio_tx_unit_wait_all_done(parlio_device->tx_unit, -1), TAG, "error waiting transmit done");
|
||||
gpio_set_level(parlio_device->dc_gpio_num, parlio_device->dc_levels.dc_data_level);
|
||||
ESP_RETURN_ON_ERROR(parlio_tx_unit_transmit(parlio_device->tx_unit, trans_desc->data, trans_desc->data_length * 8, &transmit_config), TAG, "error transmit");
|
||||
}
|
||||
// In case the lcd_cmd/param data is on the stack, wait transmit done to prevent it from being recycled
|
||||
ESP_RETURN_ON_ERROR(parlio_tx_unit_wait_all_done(parlio_device->tx_unit, -1), TAG, "error waiting transmit done");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_io_parl_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, const void *color, size_t color_size)
|
||||
{
|
||||
lcd_panel_io_parlio_t *parlio_device = __containerof(io, lcd_panel_io_parlio_t, base);
|
||||
parlio_trans_descriptor_t *trans_desc = NULL;
|
||||
trans_desc = &parlio_device->trans_desc;
|
||||
|
||||
if (lcd_cmd != -1) {
|
||||
// wait transmit done to prevent skipping previous color transfer callback
|
||||
ESP_RETURN_ON_ERROR(parlio_tx_unit_wait_all_done(parlio_device->tx_unit, -1), TAG, "error waiting transmit done");
|
||||
trans_desc->flags.en_trans_done_cb = false; // no callback for command transfer
|
||||
parlio_lcd_prepare_cmd_buffer(trans_desc, &lcd_cmd);
|
||||
gpio_set_level(parlio_device->dc_gpio_num, parlio_device->dc_levels.dc_cmd_level);
|
||||
parlio_transmit_config_t transmit_config = {
|
||||
.idle_value = 0x00,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(parlio_tx_unit_transmit(parlio_device->tx_unit, trans_desc->data, trans_desc->data_length * 8, &transmit_config), TAG, "error transmit");
|
||||
// wait transmit done before changing DC level
|
||||
ESP_RETURN_ON_ERROR(parlio_tx_unit_wait_all_done(parlio_device->tx_unit, -1), TAG, "error waiting transmit done");
|
||||
}
|
||||
|
||||
parlio_lcd_prepare_color_buffer(trans_desc, color, color_size);
|
||||
trans_desc->flags.en_trans_done_cb = true;
|
||||
|
||||
gpio_set_level(parlio_device->dc_gpio_num, parlio_device->dc_levels.dc_data_level);
|
||||
parlio_transmit_config_t transmit_config = {
|
||||
.idle_value = 0x00,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(parlio_tx_unit_transmit(parlio_device->tx_unit, trans_desc->data, trans_desc->data_length * 8, &transmit_config), TAG, "error transmit");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
IRAM_ATTR static bool lcd_default_isr_callback(parlio_tx_unit_handle_t tx_unit, const parlio_tx_done_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
lcd_panel_io_parlio_t *parlio_device = (lcd_panel_io_parlio_t *)user_ctx;
|
||||
parlio_trans_descriptor_t *trans_desc = &parlio_device->trans_desc;
|
||||
bool need_yield = false;
|
||||
|
||||
// device callback
|
||||
if (trans_desc->flags.en_trans_done_cb) {
|
||||
if (parlio_device->on_color_trans_done) {
|
||||
if (parlio_device->on_color_trans_done(&parlio_device->base, NULL, parlio_device->user_ctx)) {
|
||||
need_yield = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return need_yield;
|
||||
}
|
||||
@@ -40,6 +40,13 @@ components/esp_lcd/test_apps/mipi_dsi_lcd:
|
||||
temporary: true
|
||||
reason: lack of runners, DSI can't work without an LCD connected
|
||||
|
||||
components/esp_lcd/test_apps/parlio_lcd:
|
||||
depends_components:
|
||||
- esp_lcd
|
||||
- esp_driver_parlio
|
||||
disable:
|
||||
- if: SOC_PARLIO_SUPPORT_SPI_LCD != 1
|
||||
|
||||
components/esp_lcd/test_apps/rgb_lcd:
|
||||
depends_components:
|
||||
- esp_lcd
|
||||
|
||||
@@ -12,13 +12,13 @@ extern "C" {
|
||||
#define TEST_LCD_H_RES (240)
|
||||
#define TEST_LCD_V_RES (280)
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4
|
||||
#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)
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#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)
|
||||
@@ -78,6 +78,28 @@ extern "C" {
|
||||
#define TEST_LCD_DATA13_GPIO (25)
|
||||
#define TEST_LCD_DATA14_GPIO (16)
|
||||
#define TEST_LCD_DATA15_GPIO (17)
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#define TEST_LCD_BK_LIGHT_GPIO (48)
|
||||
#define TEST_LCD_RST_GPIO (35)
|
||||
#define TEST_LCD_PCLK_GPIO (33)
|
||||
#define TEST_LCD_CS_GPIO (32)
|
||||
#define TEST_LCD_DC_GPIO (34)
|
||||
#define TEST_LCD_DATA0_GPIO (24)
|
||||
#define TEST_LCD_DATA1_GPIO (25)
|
||||
#define TEST_LCD_DATA2_GPIO (26)
|
||||
#define TEST_LCD_DATA3_GPIO (27)
|
||||
#define TEST_LCD_DATA4_GPIO (28)
|
||||
#define TEST_LCD_DATA5_GPIO (29)
|
||||
#define TEST_LCD_DATA6_GPIO (30)
|
||||
#define TEST_LCD_DATA7_GPIO (31)
|
||||
#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
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(parlio_lcd_panel_test)
|
||||
@@ -0,0 +1,4 @@
|
||||
| Supported Targets | ESP32-C5 | ESP32-H2 | ESP32-P4 |
|
||||
| ----------------- | -------- | -------- | -------- |
|
||||
|
||||
This test app is used to test LCDs with intel 8080 interface.
|
||||
@@ -0,0 +1,8 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_parlio_lcd_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}
|
||||
PRIV_REQUIRES esp_lcd unity driver esp_driver_parlio
|
||||
WHOLE_ARCHIVE)
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 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,49 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 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_ESP32P4
|
||||
#define TEST_LCD_BK_LIGHT_GPIO (48)
|
||||
#define TEST_LCD_RST_GPIO (35)
|
||||
#define TEST_LCD_PCLK_GPIO (33)
|
||||
#define TEST_LCD_CS_GPIO (32)
|
||||
#define TEST_LCD_DC_GPIO (34)
|
||||
#define TEST_LCD_DATA0_GPIO (24)
|
||||
#define TEST_LCD_DATA1_GPIO (25)
|
||||
#define TEST_LCD_DATA2_GPIO (26)
|
||||
#define TEST_LCD_DATA3_GPIO (27)
|
||||
#define TEST_LCD_DATA4_GPIO (28)
|
||||
#define TEST_LCD_DATA5_GPIO (29)
|
||||
#define TEST_LCD_DATA6_GPIO (30)
|
||||
#define TEST_LCD_DATA7_GPIO (31)
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
#define TEST_LCD_BK_LIGHT_GPIO (2)
|
||||
#define TEST_LCD_RST_GPIO (14)
|
||||
#define TEST_LCD_CS_GPIO (3)
|
||||
#define TEST_LCD_DC_GPIO (13)
|
||||
#define TEST_LCD_PCLK_GPIO (5)
|
||||
#define TEST_LCD_DATA0_GPIO (4)
|
||||
#elif CONFIG_IDF_TARGET_ESP32C5
|
||||
#define TEST_LCD_BK_LIGHT_GPIO (1)
|
||||
#define TEST_LCD_RST_GPIO (7)
|
||||
#define TEST_LCD_CS_GPIO (27)
|
||||
#define TEST_LCD_DC_GPIO (6)
|
||||
#define TEST_LCD_PCLK_GPIO (25)
|
||||
#define TEST_LCD_DATA0_GPIO (26)
|
||||
#endif
|
||||
|
||||
#define TEST_LCD_PIXEL_CLOCK_HZ (10 * 1000 * 1000)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 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_random.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_lcd_panel_commands.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/parlio_tx.h"
|
||||
#include "test_parlio_board.h"
|
||||
|
||||
#define TEST_SPI_DATA_WIDTH 1
|
||||
#define TEST_I80_DATA_WIDTH 8
|
||||
|
||||
#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t))
|
||||
static void lcd_parlio_panel_with_st7789_interface(esp_lcd_panel_io_handle_t io_handle)
|
||||
{
|
||||
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_panel_handle_t panel_handle = NULL;
|
||||
esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = TEST_LCD_RST_GPIO,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_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 display
|
||||
esp_lcd_panel_disp_on_off(panel_handle, true);
|
||||
// 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_on_off(panel_handle, false);
|
||||
|
||||
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
|
||||
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
|
||||
TEST_ESP_OK(gpio_reset_pin(TEST_LCD_BK_LIGHT_GPIO));
|
||||
free(img);
|
||||
}
|
||||
|
||||
TEST_CASE("lcd_panel_simulate_SPI_interface(st7789)", "[lcd]")
|
||||
{
|
||||
esp_lcd_panel_io_parl_config_t io_config = {
|
||||
.dc_gpio_num = TEST_LCD_DC_GPIO,
|
||||
.clk_gpio_num = TEST_LCD_PCLK_GPIO,
|
||||
.clk_src = PARLIO_CLK_SRC_DEFAULT,
|
||||
.data_gpio_nums = {
|
||||
TEST_LCD_DATA0_GPIO,
|
||||
},
|
||||
.data_width = TEST_SPI_DATA_WIDTH,
|
||||
.max_transfer_bytes = TEST_IMG_SIZE,
|
||||
.cs_gpio_num = TEST_LCD_CS_GPIO,
|
||||
.pclk_hz = TEST_LCD_PIXEL_CLOCK_HZ,
|
||||
.trans_queue_depth = 10,
|
||||
.dc_levels = {
|
||||
.dc_cmd_level = 0,
|
||||
.dc_data_level = 1,
|
||||
},
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 8,
|
||||
};
|
||||
esp_lcd_panel_io_handle_t spi_io_handle = NULL;
|
||||
TEST_ESP_OK(esp_lcd_new_panel_io_parl(&io_config, &spi_io_handle));
|
||||
esp_lcd_panel_io_handle_t another_io_handle = NULL;
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, esp_lcd_new_panel_io_parl(&io_config, &another_io_handle));
|
||||
lcd_parlio_panel_with_st7789_interface(spi_io_handle);
|
||||
}
|
||||
|
||||
#if SOC_PARLIO_SUPPORT_I80_LCD
|
||||
TEST_CASE("lcd_panel_simulate_I80_interface(st7789)", "[lcd]")
|
||||
{
|
||||
esp_lcd_panel_io_parl_config_t io_config = {
|
||||
.dc_gpio_num = TEST_LCD_DC_GPIO,
|
||||
.clk_gpio_num = TEST_LCD_PCLK_GPIO,
|
||||
.clk_src = PARLIO_CLK_SRC_DEFAULT,
|
||||
.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,
|
||||
},
|
||||
.data_width = TEST_I80_DATA_WIDTH,
|
||||
.max_transfer_bytes = TEST_IMG_SIZE,
|
||||
.cs_gpio_num = TEST_LCD_CS_GPIO,
|
||||
.pclk_hz = TEST_LCD_PIXEL_CLOCK_HZ,
|
||||
.trans_queue_depth = 10,
|
||||
.dc_levels = {
|
||||
.dc_cmd_level = 0,
|
||||
.dc_data_level = 1,
|
||||
},
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 8,
|
||||
};
|
||||
esp_lcd_panel_io_handle_t i80_io_handle = NULL;
|
||||
TEST_ESP_OK(esp_lcd_new_panel_io_parl(&io_config, &i80_io_handle));
|
||||
lcd_parlio_panel_with_st7789_interface(i80_io_handle);
|
||||
}
|
||||
#endif
|
||||
#undef TEST_IMG_SIZE
|
||||
|
||||
static bool on_color_trans_done(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
uint32_t *isr_counter = (uint32_t *)user_ctx;
|
||||
(*isr_counter)++;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void lcd_parlio_send_colors_to_fixed_region(size_t data_width)
|
||||
{
|
||||
int x_start = 100;
|
||||
int y_start = 100;
|
||||
int x_end = 200;
|
||||
int y_end = 200;
|
||||
size_t color_size = (x_end - x_start) * (y_end - y_start) * 2;
|
||||
void *color_data = malloc(color_size);
|
||||
TEST_ASSERT_NOT_NULL(color_data);
|
||||
uint8_t color_byte = esp_random() & 0xFF;
|
||||
memset(color_data, color_byte, color_size);
|
||||
uint32_t isr_counter = 0;
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
esp_lcd_panel_io_parl_config_t io_config = {
|
||||
.cs_gpio_num = TEST_LCD_CS_GPIO,
|
||||
.pclk_hz = TEST_LCD_PIXEL_CLOCK_HZ,
|
||||
.trans_queue_depth = 10,
|
||||
.dc_levels = {
|
||||
.dc_cmd_level = 0,
|
||||
.dc_data_level = 1,
|
||||
},
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 8,
|
||||
.dc_gpio_num = TEST_LCD_DC_GPIO,
|
||||
.clk_gpio_num = TEST_LCD_PCLK_GPIO,
|
||||
.clk_src = PARLIO_CLK_SRC_DEFAULT,
|
||||
.data_gpio_nums = {
|
||||
TEST_LCD_DATA0_GPIO,
|
||||
#if SOC_PARLIO_SUPPORT_I80_LCD
|
||||
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,
|
||||
#endif
|
||||
},
|
||||
.data_width = data_width,
|
||||
.max_transfer_bytes = color_size * 2,
|
||||
};
|
||||
TEST_ESP_OK(esp_lcd_new_panel_io_parl(&io_config, &io_handle));
|
||||
|
||||
printf("Register io panel event callback");
|
||||
const esp_lcd_panel_io_callbacks_t cbs = {
|
||||
.on_color_trans_done = on_color_trans_done,
|
||||
};
|
||||
/* Register done callback */
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, &isr_counter));
|
||||
|
||||
printf("creating LCD panel\r\n");
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = TEST_LCD_RST_GPIO,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
.bits_per_pixel = 16,
|
||||
};
|
||||
TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
|
||||
|
||||
// we don't use the panel handle in this test, creating the panel just for a quick initialization
|
||||
printf("initialize LCD panel\r\n");
|
||||
// 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 display
|
||||
esp_lcd_panel_disp_on_off(panel_handle, true);
|
||||
// turn on backlight
|
||||
gpio_set_level(TEST_LCD_BK_LIGHT_GPIO, 1);
|
||||
|
||||
printf("set the flush window for only once\r\n");
|
||||
esp_lcd_panel_io_tx_param(io_handle, LCD_CMD_CASET, (uint8_t[]) {
|
||||
(x_start >> 8) & 0xFF,
|
||||
x_start & 0xFF,
|
||||
((x_end - 1) >> 8) & 0xFF,
|
||||
(x_end - 1) & 0xFF,
|
||||
}, 4);
|
||||
esp_lcd_panel_io_tx_param(io_handle, LCD_CMD_RASET, (uint8_t[]) {
|
||||
(y_start >> 8) & 0xFF,
|
||||
y_start & 0xFF,
|
||||
((y_end - 1) >> 8) & 0xFF,
|
||||
(y_end - 1) & 0xFF,
|
||||
}, 4);
|
||||
esp_lcd_panel_io_tx_param(io_handle, LCD_CMD_RAMWR, NULL, 0);
|
||||
|
||||
printf("send colors to the fixed region in multiple steps\r\n");
|
||||
const int steps = 10;
|
||||
int color_size_per_step = color_size / steps;
|
||||
for (int i = 0; i < steps; i++) {
|
||||
TEST_ESP_OK(esp_lcd_panel_io_tx_color(io_handle, -1, color_data + i * color_size_per_step, color_size_per_step));
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
TEST_ASSERT_EQUAL(steps, isr_counter);
|
||||
// change to another color
|
||||
color_byte = esp_random() & 0xFF;
|
||||
memset(color_data, color_byte, color_size);
|
||||
for (int i = 0; i < steps; i++) {
|
||||
TEST_ESP_OK(esp_lcd_panel_io_tx_color(io_handle, -1, color_data + i * color_size_per_step, color_size_per_step));
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
TEST_ASSERT_EQUAL(steps * 2, isr_counter);
|
||||
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
|
||||
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
|
||||
free(color_data);
|
||||
}
|
||||
|
||||
TEST_CASE("lcd_parlio_send_colors_to_fixed_region(SPI)", "[lcd]")
|
||||
{
|
||||
lcd_parlio_send_colors_to_fixed_region(TEST_SPI_DATA_WIDTH);
|
||||
}
|
||||
|
||||
#if SOC_PARLIO_SUPPORT_I80_LCD
|
||||
TEST_CASE("lcd_parlio_send_colors_to_fixed_region(I80)", "[lcd]")
|
||||
{
|
||||
lcd_parlio_send_colors_to_fixed_region(TEST_I80_DATA_WIDTH);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.esp32h2
|
||||
@pytest.mark.esp32c5
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'release',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_parlio_lcd(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
@@ -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,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
|
||||
@@ -36,19 +36,19 @@ extern "C" {
|
||||
#define TEST_LCD_PCLK_GPIO 2
|
||||
#define TEST_LCD_DATA0_GPIO 4
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#define TEST_LCD_BK_LIGHT_GPIO 23
|
||||
#define TEST_LCD_RST_GPIO 6
|
||||
#define TEST_LCD_CS_GPIO 4
|
||||
#define TEST_LCD_DC_GPIO 3
|
||||
#define TEST_LCD_PCLK_GPIO 2
|
||||
#define TEST_LCD_DATA0_GPIO 32
|
||||
#define TEST_LCD_DATA1_GPIO 33
|
||||
#define TEST_LCD_DATA2_GPIO 22
|
||||
#define TEST_LCD_DATA3_GPIO 8
|
||||
#define TEST_LCD_DATA4_GPIO 21
|
||||
#define TEST_LCD_DATA5_GPIO 53
|
||||
#define TEST_LCD_DATA6_GPIO 20
|
||||
#define TEST_LCD_DATA7_GPIO 5
|
||||
#define TEST_LCD_BK_LIGHT_GPIO 48
|
||||
#define TEST_LCD_RST_GPIO 35
|
||||
#define TEST_LCD_PCLK_GPIO 33
|
||||
#define TEST_LCD_CS_GPIO 32
|
||||
#define TEST_LCD_DC_GPIO 34
|
||||
#define TEST_LCD_DATA0_GPIO 24
|
||||
#define TEST_LCD_DATA1_GPIO 25
|
||||
#define TEST_LCD_DATA2_GPIO 26
|
||||
#define TEST_LCD_DATA3_GPIO 27
|
||||
#define TEST_LCD_DATA4_GPIO 28
|
||||
#define TEST_LCD_DATA5_GPIO 29
|
||||
#define TEST_LCD_DATA6_GPIO 30
|
||||
#define TEST_LCD_DATA7_GPIO 31
|
||||
#else
|
||||
#define TEST_LCD_BK_LIGHT_GPIO 18
|
||||
#define TEST_LCD_RST_GPIO 5
|
||||
|
||||
Reference in New Issue
Block a user