refactor(lcd): clean up GPIO initialization

This commit is contained in:
morris 2024-09-21 23:02:27 +08:00
parent 7e76d2e435
commit 611fb654ce
10 changed files with 81 additions and 85 deletions

View File

@ -52,6 +52,17 @@ esp_err_t gpio_sleep_pupd_config_unapply(gpio_num_t gpio_num);
*/
esp_err_t gpio_func_sel(gpio_num_t gpio_num, uint32_t func);
/**
* @brief Enable output for an IO
*
* @param gpio_num GPIO number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO number error
*/
esp_err_t gpio_output_enable(gpio_num_t gpio_num);
/**
* @brief Disable output for an IO
*

View File

@ -211,7 +211,7 @@ esp_err_t gpio_output_disable(gpio_num_t gpio_num)
return ESP_OK;
}
static esp_err_t gpio_output_enable(gpio_num_t gpio_num)
esp_err_t gpio_output_enable(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO output gpio_num error", ESP_ERR_INVALID_ARG);
gpio_hal_matrix_out_default(gpio_context.gpio_hal, gpio_num); // No peripheral output signal routed to the pin, just as a simple GPIO output

View File

@ -12,6 +12,7 @@ menu "LCD and Touch Panel"
if SOC_LCD_RGB_SUPPORTED
config LCD_RGB_ISR_IRAM_SAFE
bool "RGB LCD ISR IRAM-Safe"
select GDMA_ISR_IRAM_SAFE # bounce buffer mode relies on GDMA EOF interrupt
default n
help
Ensure the LCD interrupt is IRAM-Safe by allowing the interrupt handler to be
@ -22,7 +23,6 @@ menu "LCD and Touch Panel"
config LCD_RGB_RESTART_IN_VSYNC
bool "Restart transmission in VSYNC"
default n
select GDMA_CTRL_FUNC_IN_IRAM # need to restart GDMA in the LCD ISR
help
Reset the GDMA channel every VBlank to stop permanent desyncs from happening.
Only need to enable it when in your application, the DMA can't deliver data

View File

@ -39,14 +39,12 @@
#include "esp_private/periph_ctrl.h"
#include "esp_private/i2s_platform.h"
#include "esp_private/gdma_link.h"
#include "esp_private/gpio.h"
#include "soc/lcd_periph.h"
#include "hal/i2s_hal.h"
#include "hal/i2s_ll.h"
#include "hal/i2s_types.h"
// the DMA descriptor used by esp32 and esp32s2, each descriptor can carry 4095 bytes at most
#define LCD_DMA_DESCRIPTOR_BUFFER_MAX_SIZE 4095
static const char *TAG = "lcd_panel.io.i80";
typedef struct esp_lcd_i80_bus_t esp_lcd_i80_bus_t;
@ -61,7 +59,7 @@ static esp_err_t i2s_lcd_init_dma_link(esp_lcd_i80_bus_handle_t bus);
static esp_err_t i2s_lcd_configure_gpio(esp_lcd_i80_bus_handle_t bus, const esp_lcd_i80_bus_config_t *bus_config);
static void i2s_lcd_trigger_quick_trans_done_event(esp_lcd_i80_bus_handle_t bus);
static void lcd_i80_switch_devices(lcd_panel_io_i80_t *cur_device, lcd_panel_io_i80_t *next_device);
static void lcd_default_isr_handler(void *args);
static void i2s_lcd_default_isr_handler(void *args);
static esp_err_t panel_io_i80_register_event_callbacks(esp_lcd_panel_io_handle_t io, const esp_lcd_panel_io_callbacks_t *cbs, void *user_ctx);
struct esp_lcd_i80_bus_t {
@ -188,7 +186,7 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
int isr_flags = LCD_I80_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED;
ret = esp_intr_alloc_intrstatus(lcd_periph_i2s_signals.buses[bus->bus_id].irq_id, isr_flags,
(uint32_t)i2s_ll_get_intr_status_reg(bus->hal.dev),
I2S_LL_EVENT_TX_EOF, lcd_default_isr_handler, bus, &bus->intr);
I2S_LL_EVENT_TX_EOF, i2s_lcd_default_isr_handler, bus, &bus->intr);
ESP_GOTO_ON_ERROR(ret, err, TAG, "install interrupt failed");
i2s_ll_enable_intr(bus->hal.dev, I2S_LL_EVENT_TX_EOF, false); // disable interrupt temporarily
i2s_ll_clear_intr_status(bus->hal.dev, I2S_LL_EVENT_TX_EOF); // clear pending interrupt
@ -317,8 +315,8 @@ esp_err_t esp_lcd_new_panel_io_i80(esp_lcd_i80_bus_handle_t bus, const esp_lcd_p
if (io_config->cs_gpio_num >= 0) {
// CS signal is controlled by software
gpio_set_level(io_config->cs_gpio_num, !io_config->flags.cs_active_high); // de-assert by default
gpio_set_direction(io_config->cs_gpio_num, GPIO_MODE_OUTPUT);
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[io_config->cs_gpio_num], PIN_FUNC_GPIO);
gpio_func_sel(io_config->cs_gpio_num, PIN_FUNC_GPIO);
gpio_output_enable(io_config->cs_gpio_num);
}
*ret_io = &(i80_device->base);
ESP_LOGD(TAG, "new i80 lcd panel io @%p on bus(%d), pclk=%"PRIu32"Hz", i80_device, bus->bus_id, i80_device->pclk_hz);
@ -362,9 +360,8 @@ static esp_err_t panel_io_i80_del(esp_lcd_panel_io_t *io)
LIST_REMOVE(i80_device, device_list_entry);
portEXIT_CRITICAL(&bus->spinlock);
// reset CS GPIO
if (i80_device->cs_gpio_num >= 0) {
gpio_reset_pin(i80_device->cs_gpio_num);
gpio_output_disable(i80_device->cs_gpio_num);
}
ESP_LOGD(TAG, "del i80 lcd panel io @%p", i80_device);
@ -648,7 +645,7 @@ static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons
xQueueSend(next_device->trans_queue, &trans_desc, portMAX_DELAY);
next_device->num_trans_inflight++;
// enable interrupt and go into isr handler, where we fetch the transactions from trans_queue and start it
// we will go into `lcd_default_isr_handler` almost at once, because the "trans done" event is active at the moment
// we will go into `i2s_lcd_default_isr_handler` almost at once, because the "trans done" event is active at the moment
esp_intr_enable(bus->intr);
return ESP_OK;
}
@ -698,21 +695,20 @@ static esp_err_t i2s_lcd_configure_gpio(esp_lcd_i80_bus_handle_t bus, const esp_
// connect peripheral signals via GPIO matrix
// data line
for (size_t i = 0; i < bus_config->bus_width; i++) {
gpio_set_direction(bus_config->data_gpio_nums[i], GPIO_MODE_OUTPUT);
gpio_func_sel(bus_config->data_gpio_nums[i], PIN_FUNC_GPIO);
// the esp_rom_gpio_connect_out_signal function will also help enable the output path properly
#if SOC_I2S_TRANS_SIZE_ALIGN_WORD
esp_rom_gpio_connect_out_signal(bus_config->data_gpio_nums[i], lcd_periph_i2s_signals.buses[bus_id].data_sigs[i + 8], false, false);
#else
esp_rom_gpio_connect_out_signal(bus_config->data_gpio_nums[i], lcd_periph_i2s_signals.buses[bus_id].data_sigs[i + SOC_I2S_MAX_DATA_WIDTH - bus_config->bus_width], false, false);
#endif
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->data_gpio_nums[i]], PIN_FUNC_GPIO);
}
// WR signal (pclk)
gpio_set_direction(bus_config->wr_gpio_num, GPIO_MODE_OUTPUT);
gpio_func_sel(bus_config->wr_gpio_num, PIN_FUNC_GPIO);
esp_rom_gpio_connect_out_signal(bus_config->wr_gpio_num, lcd_periph_i2s_signals.buses[bus_id].wr_sig, true, false);
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->wr_gpio_num], PIN_FUNC_GPIO);
// DC signal is controlled by software, set as general purpose IO
gpio_set_direction(bus_config->dc_gpio_num, GPIO_MODE_OUTPUT);
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->dc_gpio_num], PIN_FUNC_GPIO);
gpio_func_sel(bus_config->dc_gpio_num, PIN_FUNC_GPIO);
gpio_output_enable(bus_config->dc_gpio_num);
return ESP_OK;
}
@ -756,7 +752,7 @@ static void lcd_i80_switch_devices(lcd_panel_io_i80_t *cur_device, lcd_panel_io_
bus->cur_device = next_device;
}
static IRAM_ATTR void lcd_default_isr_handler(void *args)
static IRAM_ATTR void i2s_lcd_default_isr_handler(void *args)
{
esp_lcd_i80_bus_t *bus = (esp_lcd_i80_bus_t *)args;
lcd_i80_trans_descriptor_t *trans_desc = NULL;

View File

@ -43,8 +43,6 @@
#include "hal/cache_ll.h"
#include "hal/cache_hal.h"
#define LCD_DMA_DESCRIPTOR_BUFFER_MAX_SIZE 4095
#if defined(SOC_GDMA_TRIG_PERIPH_LCD0_BUS) && (SOC_GDMA_TRIG_PERIPH_LCD0_BUS == SOC_GDMA_BUS_AHB)
#define LCD_GDMA_NEW_CHANNEL gdma_new_ahb_channel
#define LCD_GDMA_DESCRIPTOR_ALIGN 4
@ -76,7 +74,7 @@ static esp_err_t lcd_i80_select_periph_clock(esp_lcd_i80_bus_handle_t bus, lcd_c
static esp_err_t lcd_i80_bus_configure_gpio(esp_lcd_i80_bus_handle_t bus, const esp_lcd_i80_bus_config_t *bus_config);
static void lcd_i80_switch_devices(lcd_panel_io_i80_t *cur_device, lcd_panel_io_i80_t *next_device);
static void lcd_start_transaction(esp_lcd_i80_bus_t *bus, lcd_i80_trans_descriptor_t *trans_desc);
static void lcd_default_isr_handler(void *args);
static void i80_lcd_default_isr_handler(void *args);
static esp_err_t panel_io_i80_register_event_callbacks(esp_lcd_panel_io_handle_t io, const esp_lcd_panel_io_callbacks_t *cbs, void *user_ctx);
struct esp_lcd_i80_bus_t {
@ -157,18 +155,6 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
// allocate i80 bus memory
bus = heap_caps_calloc(1, sizeof(esp_lcd_i80_bus_t), LCD_I80_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(bus, ESP_ERR_NO_MEM, err, TAG, "no mem for i80 bus");
size_t num_dma_nodes = bus_config->max_transfer_bytes / LCD_DMA_DESCRIPTOR_BUFFER_MAX_SIZE + 1;
// create DMA link list
gdma_link_list_config_t dma_link_config = {
.buffer_alignment = 1, // no special buffer alignment for LCD TX buffer
.item_alignment = LCD_GDMA_DESCRIPTOR_ALIGN,
.num_items = num_dma_nodes,
.flags = {
.check_owner = true,
},
};
ESP_GOTO_ON_ERROR(gdma_new_link_list(&dma_link_config, &bus->dma_link), err, TAG, "create DMA link list failed");
bus->num_dma_nodes = num_dma_nodes;
bus->bus_width = bus_config->bus_width;
bus->bus_id = -1;
// allocate the format buffer from internal memory, with DMA capability
@ -208,7 +194,7 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
int isr_flags = LCD_I80_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED;
ret = esp_intr_alloc_intrstatus(lcd_periph_i80_signals.buses[bus_id].irq_id, isr_flags,
(uint32_t)lcd_ll_get_interrupt_status_reg(bus->hal.dev),
LCD_LL_EVENT_TRANS_DONE, lcd_default_isr_handler, bus, &bus->intr);
LCD_LL_EVENT_TRANS_DONE, i80_lcd_default_isr_handler, bus, &bus->intr);
ESP_GOTO_ON_ERROR(ret, err, TAG, "install interrupt failed");
lcd_ll_enable_interrupt(bus->hal.dev, LCD_LL_EVENT_TRANS_DONE, false); // disable all interrupts
lcd_ll_clear_interrupt_status(bus->hal.dev, UINT32_MAX); // clear pending interrupt
@ -355,9 +341,10 @@ esp_err_t esp_lcd_new_panel_io_i80(esp_lcd_i80_bus_handle_t bus, const esp_lcd_p
// we only configure the CS GPIO as output, don't connect to the peripheral signal at the moment
// we will connect the CS GPIO to peripheral signal when switching devices in lcd_i80_switch_devices()
if (io_config->cs_gpio_num >= 0) {
gpio_set_level(io_config->cs_gpio_num, !io_config->flags.cs_active_high);
gpio_set_direction(io_config->cs_gpio_num, GPIO_MODE_OUTPUT);
// CS signal is controlled by software
gpio_set_level(io_config->cs_gpio_num, !io_config->flags.cs_active_high); // de-assert by default
gpio_func_sel(io_config->cs_gpio_num, PIN_FUNC_GPIO);
gpio_output_enable(io_config->cs_gpio_num);
}
*ret_io = &(i80_device->base);
ESP_LOGD(TAG, "new i80 lcd panel io @%p on bus(%d)", i80_device, bus->bus_id);
@ -393,9 +380,8 @@ static esp_err_t panel_io_i80_del(esp_lcd_panel_io_t *io)
LIST_REMOVE(i80_device, device_list_entry);
portEXIT_CRITICAL(&bus->spinlock);
// reset CS to normal GPIO
if (i80_device->cs_gpio_num >= 0) {
gpio_reset_pin(i80_device->cs_gpio_num);
gpio_output_disable(i80_device->cs_gpio_num);
}
ESP_LOGD(TAG, "del i80 lcd panel io @%p", i80_device);
@ -572,7 +558,7 @@ static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons
xQueueSend(i80_device->trans_queue, &trans_desc, portMAX_DELAY);
i80_device->num_trans_inflight++;
// enable interrupt and go into isr handler, where we fetch the transactions from trans_queue and start it
// we will go into `lcd_default_isr_handler` almost at once, because the "trans done" event is active at the moment
// we will go into `i80_lcd_default_isr_handler` almost at once, because the "trans done" event is active at the moment
esp_intr_enable(bus->intr);
return ESP_OK;
}
@ -609,7 +595,7 @@ static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus, const esp_l
.direction = GDMA_CHANNEL_DIRECTION_TX,
};
ret = LCD_GDMA_NEW_CHANNEL(&dma_chan_config, &bus->dma_chan);
ESP_GOTO_ON_ERROR(ret, err, TAG, "alloc DMA channel failed");
ESP_RETURN_ON_ERROR(ret, TAG, "alloc DMA channel failed");
gdma_connect(bus->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_LCD, 0));
gdma_strategy_config_t strategy_config = {
.auto_update_desc = true,
@ -621,14 +607,23 @@ static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus, const esp_l
.max_data_burst_size = bus_config->dma_burst_size ? bus_config->dma_burst_size : 16, // Enable DMA burst transfer for better performance
.access_ext_mem = true, // the LCD can carry pixel buffer from the external memory
};
ESP_GOTO_ON_ERROR(gdma_config_transfer(bus->dma_chan, &trans_cfg), err, TAG, "config DMA transfer failed");
ESP_RETURN_ON_ERROR(gdma_config_transfer(bus->dma_chan, &trans_cfg), TAG, "config DMA transfer failed");
gdma_get_alignment_constraints(bus->dma_chan, &bus->int_mem_align, &bus->ext_mem_align);
size_t num_dma_nodes = bus_config->max_transfer_bytes / LCD_DMA_DESCRIPTOR_BUFFER_MAX_SIZE + 1;
// create DMA link list
gdma_link_list_config_t dma_link_config = {
.buffer_alignment = MAX(bus->int_mem_align, bus->ext_mem_align),
.item_alignment = LCD_GDMA_DESCRIPTOR_ALIGN,
.num_items = num_dma_nodes,
.flags = {
.check_owner = true,
},
};
ESP_RETURN_ON_ERROR(gdma_new_link_list(&dma_link_config, &bus->dma_link), TAG, "create DMA link list failed");
bus->num_dma_nodes = num_dma_nodes;
return ESP_OK;
err:
if (bus->dma_chan) {
gdma_del_channel(bus->dma_chan);
}
return ret;
}
void *esp_lcd_i80_alloc_draw_buffer(esp_lcd_panel_io_handle_t io, size_t size, uint32_t caps)
@ -660,17 +655,18 @@ static esp_err_t lcd_i80_bus_configure_gpio(esp_lcd_i80_bus_handle_t bus, const
// Set the number of output data lines
lcd_ll_set_data_wire_width(bus->hal.dev, bus_config->bus_width);
// connect peripheral signals via GPIO matrix
// data lines
for (size_t i = 0; i < bus_config->bus_width; i++) {
gpio_set_direction(bus_config->data_gpio_nums[i], GPIO_MODE_OUTPUT);
esp_rom_gpio_connect_out_signal(bus_config->data_gpio_nums[i], lcd_periph_i80_signals.buses[bus_id].data_sigs[i], false, false);
gpio_func_sel(bus_config->data_gpio_nums[i], PIN_FUNC_GPIO);
// the esp_rom_gpio_connect_out_signal function will also help enable the output path properly
esp_rom_gpio_connect_out_signal(bus_config->data_gpio_nums[i], lcd_periph_i80_signals.buses[bus_id].data_sigs[i], false, false);
}
gpio_set_direction(bus_config->dc_gpio_num, GPIO_MODE_OUTPUT);
esp_rom_gpio_connect_out_signal(bus_config->dc_gpio_num, lcd_periph_i80_signals.buses[bus_id].dc_sig, false, false);
// D/C signal
gpio_func_sel(bus_config->dc_gpio_num, PIN_FUNC_GPIO);
gpio_set_direction(bus_config->wr_gpio_num, GPIO_MODE_OUTPUT);
esp_rom_gpio_connect_out_signal(bus_config->wr_gpio_num, lcd_periph_i80_signals.buses[bus_id].wr_sig, false, false);
esp_rom_gpio_connect_out_signal(bus_config->dc_gpio_num, lcd_periph_i80_signals.buses[bus_id].dc_sig, false, false);
// WR signal (PCLK)
gpio_func_sel(bus_config->wr_gpio_num, PIN_FUNC_GPIO);
esp_rom_gpio_connect_out_signal(bus_config->wr_gpio_num, lcd_periph_i80_signals.buses[bus_id].wr_sig, false, false);
return ESP_OK;
}
@ -722,8 +718,7 @@ static void lcd_i80_switch_devices(lcd_panel_io_i80_t *cur_device, lcd_panel_io_
lcd_ll_set_dc_level(bus->hal.dev, next_device->dc_levels.dc_idle_level, next_device->dc_levels.dc_cmd_level,
next_device->dc_levels.dc_dummy_level, next_device->dc_levels.dc_data_level);
if (cur_device && cur_device->cs_gpio_num >= 0) {
// disconnect current CS GPIO from peripheral signal
esp_rom_gpio_connect_out_signal(cur_device->cs_gpio_num, SIG_GPIO_OUT_IDX, false, false);
gpio_output_disable(cur_device->cs_gpio_num);
}
if (next_device->cs_gpio_num >= 0) {
// connect CS signal to the new device
@ -733,7 +728,7 @@ static void lcd_i80_switch_devices(lcd_panel_io_i80_t *cur_device, lcd_panel_io_
}
}
IRAM_ATTR static void lcd_default_isr_handler(void *args)
IRAM_ATTR static void i80_lcd_default_isr_handler(void *args)
{
esp_lcd_i80_bus_t *bus = (esp_lcd_i80_bus_t *)args;
lcd_i80_trans_descriptor_t *trans_desc = NULL;

View File

@ -30,7 +30,7 @@ typedef struct {
size_t bus_width; /*!< Number of data lines, 8 or 16 */
size_t max_transfer_bytes; /*!< Maximum transfer size, this determines the length of internal DMA link */
union {
size_t psram_trans_align; /*!< DMA transfer alignment for data allocated from PSRAM */
size_t psram_trans_align __attribute__((deprecated)); /*!< DMA transfer alignment for data allocated from PSRAM */
size_t dma_burst_size; /*!< DMA burst size, in bytes */
};
size_t sram_trans_align __attribute__((deprecated)); /*!< DMA transfer alignment for data allocated from SRAM */

View File

@ -1,8 +1,9 @@
[mapping:esp_lcd_driver]
archive: libesp_lcd.a
[mapping:esp_lcd_gdma]
archive: libesp_hw_support.a
entries:
if LCD_RGB_ISR_IRAM_SAFE = y:
esp_lcd_common: lcd_com_mount_dma_data (noflash)
gdma: gdma_reset (noflash)
gdma: gdma_start (noflash)
[mapping:esp_lcd_hal]
archive: libhal.a

View File

@ -33,6 +33,8 @@ extern "C" {
#define LCD_CLOCK_SRC_ATOMIC()
#endif
#define LCD_DMA_DESCRIPTOR_BUFFER_MAX_SIZE 4095
#if SOC_LCDCAM_SUPPORTED
typedef enum {

View File

@ -28,17 +28,17 @@
#include "soc/soc_caps.h"
#include "esp_clk_tree.h"
#include "hal/dma_types.h"
#include "hal/gpio_hal.h"
#include "esp_private/gdma.h"
#include "driver/gpio.h"
#include "esp_bit_defs.h"
#include "esp_private/esp_clk_tree_common.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/gpio.h"
#include "esp_psram.h"
#include "esp_lcd_common.h"
#include "esp_memory_utils.h"
#include "soc/lcd_periph.h"
#include "soc/soc_caps.h"
#include "soc/io_mux_reg.h"
#include "hal/lcd_hal.h"
#include "hal/lcd_ll.h"
#include "hal/cache_hal.h"
@ -84,7 +84,7 @@ static esp_err_t lcd_rgb_create_dma_channel(esp_rgb_panel_t *panel);
static void lcd_rgb_panel_init_trans_link(esp_rgb_panel_t *panel);
static esp_err_t lcd_rgb_panel_configure_gpio(esp_rgb_panel_t *panel, const esp_lcd_rgb_panel_config_t *panel_config);
static void lcd_rgb_panel_start_transmission(esp_rgb_panel_t *rgb_panel);
static void lcd_default_isr_handler(void *args);
static void rgb_lcd_default_isr_handler(void *args);
struct esp_rgb_panel_t {
esp_lcd_panel_t base; // Base class of generic lcd panel
@ -336,7 +336,7 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
int isr_flags = LCD_RGB_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED;
ret = esp_intr_alloc_intrstatus(lcd_periph_rgb_signals.panels[panel_id].irq_id, isr_flags,
(uint32_t)lcd_ll_get_interrupt_status_reg(rgb_panel->hal.dev),
LCD_LL_EVENT_VSYNC_END, lcd_default_isr_handler, rgb_panel, &rgb_panel->intr);
LCD_LL_EVENT_VSYNC_END, rgb_lcd_default_isr_handler, rgb_panel, &rgb_panel->intr);
ESP_GOTO_ON_ERROR(ret, err, TAG, "install interrupt failed");
lcd_ll_enable_interrupt(rgb_panel->hal.dev, LCD_LL_EVENT_VSYNC_END, false); // disable all interrupts
lcd_ll_clear_interrupt_status(rgb_panel->hal.dev, UINT32_MAX); // clear pending interrupt
@ -848,51 +848,45 @@ static esp_err_t rgb_panel_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
return ESP_OK;
}
static esp_err_t lcd_rgb_panel_configure_gpio(esp_rgb_panel_t *panel, const esp_lcd_rgb_panel_config_t *panel_config)
static esp_err_t lcd_rgb_panel_configure_gpio(esp_rgb_panel_t *rgb_panel, const esp_lcd_rgb_panel_config_t *panel_config)
{
int panel_id = panel->panel_id;
int panel_id = rgb_panel->panel_id;
// Set the number of output data lines
lcd_ll_set_data_wire_width(panel->hal.dev, panel_config->data_width);
lcd_ll_set_data_wire_width(rgb_panel->hal.dev, panel_config->data_width);
// connect peripheral signals via GPIO matrix
for (size_t i = 0; i < panel_config->data_width; i++) {
if (panel_config->data_gpio_nums[i] >= 0) {
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[panel_config->data_gpio_nums[i]], PIN_FUNC_GPIO);
gpio_set_direction(panel_config->data_gpio_nums[i], GPIO_MODE_OUTPUT);
gpio_func_sel(panel_config->data_gpio_nums[i], PIN_FUNC_GPIO);
esp_rom_gpio_connect_out_signal(panel_config->data_gpio_nums[i],
lcd_periph_rgb_signals.panels[panel_id].data_sigs[i], false, false);
}
}
if (panel_config->hsync_gpio_num >= 0) {
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[panel_config->hsync_gpio_num], PIN_FUNC_GPIO);
gpio_set_direction(panel_config->hsync_gpio_num, GPIO_MODE_OUTPUT);
gpio_func_sel(panel_config->hsync_gpio_num, PIN_FUNC_GPIO);
esp_rom_gpio_connect_out_signal(panel_config->hsync_gpio_num,
lcd_periph_rgb_signals.panels[panel_id].hsync_sig, false, false);
}
if (panel_config->vsync_gpio_num >= 0) {
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[panel_config->vsync_gpio_num], PIN_FUNC_GPIO);
gpio_set_direction(panel_config->vsync_gpio_num, GPIO_MODE_OUTPUT);
gpio_func_sel(panel_config->vsync_gpio_num, PIN_FUNC_GPIO);
esp_rom_gpio_connect_out_signal(panel_config->vsync_gpio_num,
lcd_periph_rgb_signals.panels[panel_id].vsync_sig, false, false);
}
// PCLK may not be necessary in some cases (i.e. VGA output)
if (panel_config->pclk_gpio_num >= 0) {
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[panel_config->pclk_gpio_num], PIN_FUNC_GPIO);
gpio_set_direction(panel_config->pclk_gpio_num, GPIO_MODE_OUTPUT);
gpio_func_sel(panel_config->pclk_gpio_num, PIN_FUNC_GPIO);
esp_rom_gpio_connect_out_signal(panel_config->pclk_gpio_num,
lcd_periph_rgb_signals.panels[panel_id].pclk_sig, false, false);
}
// DE signal might not be necessary for some RGB LCD
if (panel_config->de_gpio_num >= 0) {
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[panel_config->de_gpio_num], PIN_FUNC_GPIO);
gpio_set_direction(panel_config->de_gpio_num, GPIO_MODE_OUTPUT);
gpio_func_sel(panel_config->de_gpio_num, PIN_FUNC_GPIO);
esp_rom_gpio_connect_out_signal(panel_config->de_gpio_num,
lcd_periph_rgb_signals.panels[panel_id].de_sig, false, false);
}
// disp enable GPIO is optional
// disp enable GPIO is optional, it is a general purpose output GPIO
if (panel_config->disp_gpio_num >= 0) {
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[panel_config->disp_gpio_num], PIN_FUNC_GPIO);
gpio_set_direction(panel_config->disp_gpio_num, GPIO_MODE_OUTPUT);
esp_rom_gpio_connect_out_signal(panel_config->disp_gpio_num, SIG_GPIO_OUT_IDX, false, false);
gpio_func_sel(panel_config->disp_gpio_num, PIN_FUNC_GPIO);
gpio_output_enable(panel_config->disp_gpio_num);
}
return ESP_OK;
}
@ -1147,7 +1141,7 @@ IRAM_ATTR static void lcd_rgb_panel_try_update_pclk(esp_rgb_panel_t *rgb_panel)
portEXIT_CRITICAL_ISR(&rgb_panel->spinlock);
}
IRAM_ATTR static void lcd_default_isr_handler(void *args)
IRAM_ATTR static void rgb_lcd_default_isr_handler(void *args)
{
esp_rgb_panel_t *rgb_panel = (esp_rgb_panel_t *)args;
bool need_yield = false;

View File

@ -1,8 +1,5 @@
CONFIG_COMPILER_DUMP_RTL_FILES=y
CONFIG_LCD_RGB_ISR_IRAM_SAFE=y
CONFIG_GDMA_CTRL_FUNC_IN_IRAM=y
# bounce buffer mode relies on GDMA EOF interrupt to be service-able
CONFIG_GDMA_ISR_IRAM_SAFE=y
CONFIG_COMPILER_OPTIMIZATION_NONE=y
# silent the error check, as the error string are stored in rodata, causing RTL check failure
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y