mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 17:19:09 -04:00
refactor(lcd): clean up GPIO initialization
This commit is contained in:
parent
7e76d2e435
commit
611fb654ce
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user