1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

cpu/esp32: add LCD low-level parallel interface suppport

This commit is contained in:
Gunar Schorcht 2023-08-02 19:06:33 +02:00
parent 33d6281432
commit 70053c5284
13 changed files with 692 additions and 0 deletions

View File

@ -35,6 +35,7 @@ rsource "bootloader/Kconfig"
rsource "esp-ble-nimble/Kconfig"
rsource "esp-idf/Kconfig"
rsource "esp-idf-api/Kconfig"
rsource "esp-lcd/Kconfig"
rsource "periph/Kconfig"
endif

View File

@ -29,6 +29,10 @@ ifneq (, $(filter esp_freertos, $(USEMODULE)))
DIRS += freertos
endif
ifneq (, $(filter esp_lcd, $(USEMODULE)))
DIRS += esp-lcd
endif
ifneq (, $(filter stdio_usb_serial_jtag, $(USEMODULE)))
DIRS += stdio_usb_serial_jtag
endif

View File

@ -128,6 +128,12 @@ ifneq (,$(filter esp_idf_heap,$(USEMODULE)))
USEPKG += tlsf
endif
ifneq (,$(filter lcd_parallel_ll_mcu,$(USEMODULE)))
USEMODULE += esp_lcd
USEMODULE += esp_idf_lcd
USEMODULE += esp_idf_heap
endif
ifneq (,$(filter mtd periph_flashpage,$(USEMODULE)))
USEMODULE += esp_idf_spi_flash
endif

View File

@ -113,6 +113,7 @@ PSEUDOMODULES += esp_hw_counter
PSEUDOMODULES += esp_idf_gpio_hal
PSEUDOMODULES += esp_i2c_hw
PSEUDOMODULES += esp_jtag
PSEUDOMODULES += esp_lcd_gpio
PSEUDOMODULES += esp_rtc_timer_32k
PSEUDOMODULES += esp_spi_ram
PSEUDOMODULES += esp_spi_oct
@ -167,6 +168,10 @@ ifneq (,$(filter esp_spi_ram,$(USEMODULE)))
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_hw_support/include/soc/$(CPU_FAM)
endif
ifneq (,$(filter esp_idf_lcd,$(USEMODULE)))
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_lcd/include
endif
ifneq (,$(filter esp_idf_spi_flash,$(USEMODULE)))
INCLUDES += -I$(ESP32_SDK_DIR)/components/spi_flash/include
endif

View File

@ -0,0 +1,16 @@
# Copyright (c) 2022 Gunar Schorcht
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
config MODULE_ESP_IDF_LCD
bool
depends on TEST_KCONFIG
depends on MODULE_ESP_IDF && HAS_ESP_LCD
default y if MODULE_LCD_PARALLEL_LL_MCU
help
ESP-IDF code for peripheral GPIO.

View File

@ -0,0 +1,36 @@
MODULE = esp_idf_lcd
# source files to be compiled for this module
ESP32_SDK_SRC = \
components/esp_lcd/src/esp_lcd_common.c \
components/esp_lcd/src/esp_lcd_panel_io.c \
components/esp_pm/pm_locks.c \
components/soc/$(CPU_FAM)/lcd_periph.c \
#
ifeq (esp32s3,$(CPU_FAM))
ESP32_SDK_SRC += \
components/driver/gdma.c \
components/esp_lcd/src/esp_lcd_panel_io_i80.c \
components/hal/gdma_hal.c \
components/hal/lcd_hal.c \
components/soc/$(CPU_FAM)/gdma_periph.c \
#
else ifneq (,$(filter esp32 esp32s2,$(CPU_FAM)))
ESP32_SDK_SRC = \
components/driver/i2s.c \
components/esp_lcd/src/esp_lcd_panel_io_i2s.c \
components/hal/i2s_hal.c \
#
endif
# additional include pathes required by this module
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_lcd/include
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_lcd/interface
include $(RIOTBASE)/Makefile.base
ESP32_SDK_BIN = $(BINDIR)/$(MODULE)
include ../esp_idf.mk
include ../esp_idf_cflags.mk

54
cpu/esp32/esp-lcd/Kconfig Normal file
View File

@ -0,0 +1,54 @@
# Copyright (c) 2023 Gunar Schorcht
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
menuconfig MODULE_ESP_LCD
bool "Enable LCD low-level parallel interface driver"
depends on MODULE_LCD
default y if HAVE_LCD_PARALLEL_LL_MCU
help
Enabe the MCU-driven low-level MCU 8080 8-/16-bit parallel interface
driver.
if MODULE_ESP_LCD
config MODULE_ESP_LCD_GPIO
bool "GPIO-driven low-level parallel interface driver"
depends on !CPU_FAM_ESP32 && !CPU_FAM_ESP32S2 && !CPU_FAM_ESP32S3
default y
help
The ESP32x SoC variant used does not have a peripheral for the parallel
low-level interface. However, it can be emulated with special low-level
GPIO operations. It is faster than the GPIO-driven 8-/16-bit parallel
interface implemented in the LCD driver, but requires 4 kByte RAM for
8-bit data bus width and 8 kByte RAM for 16-bit data bus width.
config LCD_WRITE_CLOCK_MHZ
int "LCD write clock rate in MHz"
range 1 80
depends on CPU_FAM_ESP32 || CPU_FAM_ESP32S2 || CPU_FAM_ESP32S3
default 10 if CPU_FAM_ESP32
default 40 if CPU_FAM_ESP32S2
default 20 if CPU_FAM_ESP32S3
help
Defines the clock rate that is used for the LCD write signal. It
depends on used ESP32x SoC variant and used display interface.
config LCD_DATA_BUF_SIZE
int "LCD data buffer size in byte"
depends on CPU_FAM_ESP32 || CPU_FAM_ESP32S2 || CPU_FAM_ESP32S3
default 512
help
Defines the size of the buffers used to write data to the LCD
screen. Since double buffering is used, there are two buffers
of this size. One buffer is used first by the LCD driver to
write the data that needs to be transferred to the LCD, and
one buffer from which the DMA then transfers the data to the
LCD peripherals. This allows data to be written before the
DMA transfer is complete. The larger the buffers, the better
the performance, but the higher the memory requirements.
endif

View File

@ -0,0 +1,9 @@
MODULE = esp_lcd
ifneq (,$(filter esp32 esp32s2 esp32s3,$(CPU_FAM)))
SRC = esp_lcd_mcu.c
else
SRC = esp_lcd_gpio.c
endif
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,269 @@
/*
* Copyright (C) 2023 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32
* @{
*
* @file
* @brief GPIO-driven low-Level parallel interface implementation for LCDs
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#include <assert.h>
#include "periph/gpio.h"
#include "lcd.h"
#include "ztimer.h"
#if MODULE_ESP_LCD_GPIO
#include "soc/gpio_reg.h"
#define ENABLE_DEBUG 0
#include "debug.h"
typedef struct {
uint32_t set_mask_0; /* port 0 set mask */
uint32_t set_mask_1; /* port 0 set mask */
uint32_t clr_mask_0; /* port 1 clear mask */
uint32_t clr_mask_1; /* port 1 clear mask */
} _pin_mask_t;
static _pin_mask_t _low_byte_masks[256] = {};
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
static _pin_mask_t _high_byte_masks[256] = {};
#endif
/*
* Following functions are not implemented by intention to let the
* GPIO-driven low-level implementation handle the configuration
* of the GPIOs. The function `_lcd_ll_mcu_set_data_dir` is used to
* initialize the GPIO masks when the clear masks are completely 0.
*/
#if 0
static void _lcd_ll_mcu_init(lcd_t *dev)
{
(void)dev;
}
static void _lcd_ll_mcu_cmd_start(lcd_t *dev, uint8_t cmd, bool cont)
{
(void)dev;
(void)cmd;
(void)cont;
}
#endif
static void _lcd_ll_mcu_set_data_dir(lcd_t *dev, bool output)
{
DEBUG("[lcd_ll_mcu] %s %u\n", __func__, output);
/* sanity check to ensure that data pins can be handled as array */
assert((&dev->params->d7_pin - &dev->params->d0_pin) == 7);
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
assert((&dev->params->d15_pin - &dev->params->d8_pin) == 7);
#endif
if ((_low_byte_masks[0].clr_mask_0 == 0) &&
(_low_byte_masks[0].clr_mask_1 == 0)) {
/* initialize the mask array if it is not yet initialized */
const gpio_t *pins = &dev->params->d0_pin;
for (unsigned data = 0; data < 256; data++) {
for (unsigned i = 0; i < 8; i++) {
if (data & (1 << i)) {
/* set mask */
if (pins[i] < 32) {
_low_byte_masks[data].set_mask_0 |= 1 << pins[i];
}
else {
_low_byte_masks[data].set_mask_1 |= 1 << (pins[i] - 32);
}
}
else {
/* clear mask */
if (pins[i] < 32) {
_low_byte_masks[data].clr_mask_0 |= 1 << pins[i];
}
else {
_low_byte_masks[data].clr_mask_1 |= 1 << (pins[i] - 32);
}
}
}
}
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
pins = &dev->params->d8_pin;
for (unsigned data = 0; data < 256; data++) {
for (unsigned i = 0; i < 8; i++) {
if (data & (1 << i)) {
/* set mask */
if (pins[i] < 32) {
_high_byte_masks[data].set_mask_0 |= 1 << pins[i];
}
else {
_high_byte_masks[data].set_mask_1 |= 1 << (pins[i] - 32);
}
}
else {
/* clear mask */
if (pins[i] < 32) {
_high_byte_masks[data].clr_mask_0 |= 1 << pins[i];
}
else {
_high_byte_masks[data].clr_mask_1 |= 1 << (pins[i] - 32);
}
}
}
}
#endif
}
gpio_init(dev->params->d0_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d1_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d2_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d3_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d4_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d5_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d6_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d7_pin, output ? GPIO_OUT : GPIO_IN);
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
gpio_init(dev->params->d8_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d9_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d10_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d11_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d12_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d13_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d14_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d15_pin, output ? GPIO_OUT : GPIO_IN);
#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */
}
static void _lcd_ll_mcu_write_data(lcd_t *dev, bool cont,
uint16_t data, unsigned pin_num)
{
if (gpio_is_valid(dev->params->cs_pin)) {
gpio_clear(dev->params->cs_pin);
}
gpio_clear(dev->params->wrx_pin);
uint8_t _byte = data & 0xff;
uint32_t set_mask_0 = _low_byte_masks[_byte].set_mask_0;
uint32_t clr_mask_0 = _low_byte_masks[_byte].clr_mask_0;
uint32_t set_mask_1 = _low_byte_masks[_byte].set_mask_1;
uint32_t clr_mask_1 = _low_byte_masks[_byte].clr_mask_1;
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
_byte = data >> 8;
set_mask_0 |= _high_byte_masks[_byte].set_mask_0;
clr_mask_0 |= _high_byte_masks[_byte].clr_mask_0;
set_mask_1 |= _high_byte_masks[_byte].set_mask_1;
clr_mask_1 |= _high_byte_masks[_byte].clr_mask_1;
#endif
*((uint32_t *)GPIO_OUT_W1TS_REG) = set_mask_0;
*((uint32_t *)GPIO_OUT_W1TC_REG) = clr_mask_0;
*((uint32_t *)GPIO_OUT1_W1TS_REG) = set_mask_1;
*((uint32_t *)GPIO_OUT1_W1TC_REG) = clr_mask_1;
gpio_set(dev->params->wrx_pin);
if (gpio_is_valid(dev->params->cs_pin) && !cont) {
gpio_set(dev->params->cs_pin);
}
}
static uint16_t _lcd_ll_mcu_read_data(lcd_t *dev, bool cont, unsigned pin_num)
{
const gpio_t *pins = &dev->params->d0_pin;
if (gpio_is_valid(dev->params->cs_pin)) {
gpio_clear(dev->params->cs_pin);
}
gpio_clear(dev->params->rdx_pin);
uint32_t in_0 = *((uint32_t *)GPIO_IN_REG);
uint32_t in_1 = *((uint32_t *)GPIO_IN1_REG);
gpio_set(dev->params->rdx_pin);
if (gpio_is_valid(dev->params->cs_pin) && !cont) {
gpio_set(dev->params->cs_pin);
};
uint16_t in = 0;
for (unsigned i = 0; i < pin_num; i++) {
if (pins[i] < 32) {
in |= in_0 & (1 << pins[i]) ? 1 : 0;
}
else {
in |= in_1 & (1 << (pins[i] - 32)) ? 1 : 0;
}
}
return in;
}
static void _lcd_ll_mcu_write_byte(lcd_t *dev, bool cont, uint8_t out)
{
DEBUG("[lcd_ll_mcu] write byte: %02x\n", out);
_lcd_ll_mcu_write_data(dev, cont, out, 8);
}
static uint8_t _lcd_ll_mcu_read_byte(lcd_t *dev, bool cont)
{
return _lcd_ll_mcu_read_data(dev, cont, 8);
}
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
static void _lcd_ll_mcu_write_word(lcd_t *dev, bool cont, uint16_t out)
{
DEBUG("[lcd_ll_mcu] write word: %04x\n", out);
_lcd_ll_mcu_write_data(dev, cont, out, 16);
}
static uint16_t _lcd_ll_mcu_read_word(lcd_t *dev, bool cont)
{
return _lcd_ll_mcu_read_data(dev, cont, 16);
}
#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */
const lcd_ll_par_driver_t lcd_ll_par_driver = {
.init = lcd_ll_par_gpio_init, /* GPIO-driven `init` is used */
.set_data_dir = _lcd_ll_mcu_set_data_dir,
.cmd_start = lcd_ll_par_gpio_cmd_start, /* GPIO-driven `cmd_start` is used */
.write_byte = _lcd_ll_mcu_write_byte,
.read_byte = _lcd_ll_mcu_read_byte,
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
.write_word = _lcd_ll_mcu_write_word,
.read_word = _lcd_ll_mcu_read_word,
#endif
};
#else /* MODULE_ESP_LCD_GPIO */
/* the GPIO-driven low-level interface is not used */
const lcd_ll_par_driver_t lcd_ll_par_driver = {
};
#endif /* MODULE_ESP_LCD_GPIO */

View File

@ -0,0 +1,260 @@
/*
* Copyright (C) 2023 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32
* @{
*
* @file
* @brief Peripheral low-Level parallel interface implementation for LCDs
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#include <assert.h>
#include <string.h>
#include "lcd.h"
#include "lcd_internal.h"
#include "log.h"
#include "macros/units.h"
#include "periph/gpio.h"
#include "ztimer.h"
#include "esp_lcd_panel_io.h"
#include "soc/gpio_reg.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#if !defined(CPU_FAM_ESP32) && !defined(CPU_FAM_ESP32S2) && !defined(CPU_FAM_ESP32S3)
#error "ESP32x SoC family not supported"
#endif
#ifndef CONFIG_LCD_WRITE_CLOCK_MHZ
#if CONFIG_LCD_I80_COLOR_IN_PSRAM
/* PCLK has to be low enough for SPI RAM */
#define CONFIG_LCD_WRITE_CLOCK_MHZ 2
#else
#if defined(CPU_FAM_ESP32S3)
#define CONFIG_LCD_WRITE_CLOCK_MHZ 20
#elif defined(CPU_FAM_ESP32S2)
#define CONFIG_LCD_WRITE_CLOCK_MHZ 40
#else /* ESP32 */
#define CONFIG_LCD_WRITE_CLOCK_MHZ 10
#endif
#endif /* CONFIG_LCD_I80_COLOR_IN_PSRAM */
#endif /* CONFIG_LCD_WRITE_CLOCK_MHZ */
static_assert(CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE >= 32,
"CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE mus be at least 32");
/* ESP32x SoCs support only one LCD peripheral so we can use single instances
* of the following variables */
int _cmd = -1; /* means no command needed in ESP-IDF */
size_t _idx_bytes = 0;
uint8_t _data_bytes[CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE];
uint8_t _trans_bytes[CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE];
esp_lcd_i80_bus_handle_t _i80_bus_handle = NULL;
esp_lcd_panel_io_handle_t _i80_io_handle = NULL;
/* indicates that a transfer of the data buffer is still in progress and must
* not be overwritten */
static bool _dma_transfer_in_progress = false;
static bool _dma_transfer_done(esp_lcd_panel_io_handle_t io_handle,
esp_lcd_panel_io_event_data_t *io_event_data,
void *user_ctx)
{
(void)io_handle;
(void)io_event_data;
(void)user_ctx;
_dma_transfer_in_progress = false;
return false;
}
static void _lcd_ll_mcu_init(lcd_t *dev)
{
esp_lcd_i80_bus_config_t i80_bus_config = {
.dc_gpio_num = dev->params->dcx_pin,
.wr_gpio_num = dev->params->wrx_pin,
.clk_src = LCD_CLK_SRC_PLL160M,
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
.data_gpio_nums = {
dev->params->d0_pin,
dev->params->d1_pin,
dev->params->d2_pin,
dev->params->d3_pin,
dev->params->d4_pin,
dev->params->d5_pin,
dev->params->d6_pin,
dev->params->d7_pin,
dev->params->d8_pin,
dev->params->d9_pin,
dev->params->d10_pin,
dev->params->d11_pin,
dev->params->d12_pin,
dev->params->d13_pin,
dev->params->d14_pin,
dev->params->d15_pin,
},
.bus_width = 16,
#else
.data_gpio_nums = {
dev->params->d0_pin,
dev->params->d1_pin,
dev->params->d2_pin,
dev->params->d3_pin,
dev->params->d4_pin,
dev->params->d5_pin,
dev->params->d6_pin,
dev->params->d7_pin,
},
.bus_width = 8,
#endif
.max_transfer_bytes = dev->params->rgb_channels * 40 * sizeof(uint16_t),
};
esp_lcd_panel_io_i80_config_t i80_io_config = {
.cs_gpio_num = gpio_is_valid(dev->params->cs_pin) ? (int)dev->params->cs_pin
: -1,
.pclk_hz = MHZ(CONFIG_LCD_WRITE_CLOCK_MHZ),
.trans_queue_depth = 10,
.dc_levels = {
.dc_idle_level = 0,
.dc_cmd_level = 0,
.dc_dummy_level = 1,
.dc_data_level = 1,
},
.on_color_trans_done = _dma_transfer_done,
.user_ctx = NULL,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
esp_lcd_new_i80_bus(&i80_bus_config, &_i80_bus_handle);
esp_lcd_new_panel_io_i80(_i80_bus_handle, &i80_io_config, &_i80_io_handle);
if (gpio_is_valid(dev->params->rdx_pin)) {
gpio_init(dev->params->rdx_pin, GPIO_IN_PU);
gpio_set(dev->params->rdx_pin);
}
if (gpio_is_valid(dev->params->cs_pin)) {
gpio_init(dev->params->cs_pin, GPIO_OUT);
gpio_clear(dev->params->cs_pin);
}
}
static void _lcd_ll_mcu_set_data_dir(lcd_t *dev, bool output)
{
(void)dev;
(void)output;
LOG_ERROR("[lcd_ll_mcu] set dir: %d is not supported\n", output);
/* not supported yet */
}
static void _lcd_ll_mcu_cmd_start(lcd_t *dev, uint8_t cmd, bool cont)
{
DEBUG("[lcd_ll_mcu] write cmd: %02x\n", cmd);
if (!cont) {
/* cmd without parameters */
esp_lcd_panel_io_tx_param(_i80_io_handle, cmd, NULL, 0);
_cmd = -1;
}
else {
/* cmd with parameters */
_cmd = cmd;
}
}
static void _lcd_ll_mcu_transfer(lcd_t *dev, bool cont)
{
if (!cont) {
/* if no further data follow, send the command with the data in the buffer */
esp_lcd_panel_io_tx_param(_i80_io_handle, _cmd, _data_bytes, _idx_bytes);
_cmd = -1;
_idx_bytes = 0;
}
else if (_idx_bytes == CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE) {
/* spin lock as long as a DMA data transfer is still in progress */
while (_dma_transfer_in_progress) {}
/* copy data buffer to the DMA transfer buffer */
memcpy(_trans_bytes, _data_bytes, _idx_bytes);
/* start DMA data transfer */
_dma_transfer_in_progress = true;
esp_lcd_panel_io_tx_color(_i80_io_handle, _cmd, _data_bytes, _idx_bytes);
/* It should only be possible to follow more data than
* CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE with the RAMWR command.
* Transferring more data to continue the operation with cmd=-1 does
* not seem to work. Therefore a RAMWRC generated in this
* case for further data */
_cmd = (_cmd == LCD_CMD_RAMWR) ? LCD_CMD_RAMWRC : _cmd;
_idx_bytes = 0;
}
}
static void _lcd_ll_mcu_write_byte(lcd_t *dev, bool cont, uint8_t out)
{
DEBUG("[lcd_ll_mcu] write byte: %02x\n", out);
_data_bytes[_idx_bytes++] = out;
/* transfer the data if necessary */
_lcd_ll_mcu_transfer(dev, cont);
}
static uint8_t _lcd_ll_mcu_read_byte(lcd_t *dev, bool cont)
{
LOG_ERROR("[lcd_ll_mcu] read from LCD is not supported\n");
return 0;
}
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
static void _lcd_ll_mcu_write_word(lcd_t *dev, bool cont, uint16_t out)
{
DEBUG("[lcd_ll_mcu] write word: %04x\n", out);
/* out is given in BE order */
_data_bytes[_idx_bytes++] = out >> 8;
_data_bytes[_idx_bytes++] = out & 0xff;
/* transfer the data if necessary */
_lcd_ll_mcu_transfer(dev, cont);
}
static uint16_t _lcd_ll_mcu_read_word(lcd_t *dev, bool cont)
{
LOG_ERROR("[lcd_ll_mcu] read from LCD is not supported\n");
/* not supported yet */
return 0;
}
#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */
const lcd_ll_par_driver_t lcd_ll_par_driver = {
.init = _lcd_ll_mcu_init,
.set_data_dir = _lcd_ll_mcu_set_data_dir,
.cmd_start = _lcd_ll_mcu_cmd_start,
.write_byte = _lcd_ll_mcu_write_byte,
.read_byte = _lcd_ll_mcu_read_byte,
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
.write_word = _lcd_ll_mcu_write_word,
.read_word = _lcd_ll_mcu_read_word,
#endif
};

View File

@ -47,6 +47,7 @@ extern "C" {
#define CPU_INUM_WDT 13 /**< Level interrupt with low priority 1 */
#define CPU_INUM_SOFTWARE 17 /**< Level interrupt with low priority 1 */
#define CPU_INUM_ETH 18 /**< Level interrupt with low priority 1 */
#define CPU_INUM_LCD 18 /**< Level interrupt with low priority 1 */
#define CPU_INUM_TIMER 19 /**< Level interrupt with medium priority 2 */
#define CPU_INUM_FRC2 20 /**< Level interrupt with medium priority 2 */
#define CPU_INUM_SYSTIMER 20 /**< Level interrupt with medium priority 2 */

View File

@ -233,6 +233,17 @@
#endif /* !CONFIG_ESP_FLASHPAGE_CAPACITY */
/**
* LCD driver configuration
*/
#if MODULE_ESP_IDF_LCD
#ifndef CONFIG_LCD_DATA_BUF_SIZE
#define CONFIG_LCD_DATA_BUF_SIZE 512
#endif
#define CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE CONFIG_LCD_DATA_BUF_SIZE
#endif
#endif /* DOXYGEN */
/**

View File

@ -87,10 +87,19 @@ static const struct intr_handle_data_t _irq_data_table[] = {
{ ETS_USB_SERIAL_JTAG_INTR_SOURCE, CPU_INUM_SERIAL_JTAG, 1 },
#endif
{ ETS_RMT_INTR_SOURCE, CPU_INUM_RMT, 1 },
#if defined(CPU_FAM_ESP32) || defined(CPU_FAM_ESP32S2)
{ ETS_I2S0_INTR_SOURCE, CPU_INUM_LCD, 1 },
#elif defined(CPU_FAM_ESP32S3)
{ ETS_LCD_CAM_INTR_SOURCE, CPU_INUM_LCD, 1 },
#endif
};
#define IRQ_DATA_TABLE_SIZE ARRAY_SIZE(_irq_data_table)
#if defined(CPU_FAM_ESP32) && MODULE_ESP_LCD && MODULE_ESP_ETH
#error "esp_eth and esp_lcd can't be used at the same time because of an interrupt conflict"
#endif
void esp_irq_init(void)
{
#ifdef SOC_CPU_HAS_FLEXIBLE_INTC
@ -172,6 +181,17 @@ esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler,
return ESP_OK;
}
esp_err_t esp_intr_alloc_intrstatus(int source, int flags,
uint32_t reg, uint32_t mask,
intr_handler_t handler,
void *arg, intr_handle_t *ret_handle)
{
/* TODO status register and status mask handling for shared interrupts */
(void)reg;
(void)mask;
return esp_intr_alloc(source, flags, handler, arg, ret_handle);
}
esp_err_t esp_intr_free(intr_handle_t handle)
{
return esp_intr_disable(handle);