From 856bed29661527e5b8ee183326fb895a5681509a Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Nihei Date: Tue, 16 Mar 2021 16:34:15 -0300 Subject: [PATCH] boards/esp32-wrover-kit: Add LCD support via ILI9341 controller --- boards/xtensa/esp32/common/Kconfig | 10 + boards/xtensa/esp32/common/src/Make.defs | 4 + .../xtensa/esp32/common/src/esp32_board_spi.c | 20 + .../xtensa/esp32/common/src/esp32_ili9341.c | 456 ++++++++++++++++++ .../esp32/esp32-wrover-kit/include/board.h | 9 + 5 files changed, 499 insertions(+) create mode 100644 boards/xtensa/esp32/common/src/esp32_ili9341.c diff --git a/boards/xtensa/esp32/common/Kconfig b/boards/xtensa/esp32/common/Kconfig index 6492574ae4..bd3e8621f1 100644 --- a/boards/xtensa/esp32/common/Kconfig +++ b/boards/xtensa/esp32/common/Kconfig @@ -46,3 +46,13 @@ config ESP32_SPIFLASH_TEST_ADDRESS depends on ESP32_SPIFLASH_ENCRYPTION_TEST ---help--- SPI Flash encryption test read/write address. + +config ESP32_LCD_OVERCLOCK + bool "Run LCD at higher clock speed than allowed" + default n + depends on LCD_ILI9341 + ---help--- + The ILI9341 and ST7789 specify that the maximum clock speed for the + SPI interface is 10MHz. However, in practice the driver chips work + fine with a higher clock rate, and using that gives a better + framerate. Select this to try using the out-of-spec clock rate. diff --git a/boards/xtensa/esp32/common/src/Make.defs b/boards/xtensa/esp32/common/src/Make.defs index 2cfeef40e9..2504119791 100644 --- a/boards/xtensa/esp32/common/src/Make.defs +++ b/boards/xtensa/esp32/common/src/Make.defs @@ -46,6 +46,10 @@ ifeq ($(CONFIG_CAN_MCP2515),y) CSRCS += esp32_mcp2515.c endif +ifeq ($(CONFIG_LCD_ILI9341),y) + CSRCS += esp32_ili9341.c +endif + DEPPATH += --dep-path src VPATH += :src CFLAGS += $(shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src) diff --git a/boards/xtensa/esp32/common/src/esp32_board_spi.c b/boards/xtensa/esp32/common/src/esp32_board_spi.c index 3b7d32d4f1..a9024473c6 100644 --- a/boards/xtensa/esp32/common/src/esp32_board_spi.c +++ b/boards/xtensa/esp32/common/src/esp32_board_spi.c @@ -52,6 +52,13 @@ static inline uint8_t spi_status(FAR struct spi_dev_s *dev, uint32_t devid) } #endif +#ifdef CONFIG_LCD_ILI9341 + if (devid == SPIDEV_DISPLAY(0)) + { + status |= SPI_STATUS_PRESENT; + } +#endif + return status; } @@ -64,6 +71,19 @@ static inline uint8_t spi_status(FAR struct spi_dev_s *dev, uint32_t devid) static inline int spi_cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd) { +#ifdef CONFIG_LCD_ILI9341 + if (devid == SPIDEV_DISPLAY(0)) + { + /* This is the Data/Command control pad which determines whether the + * data bits are data or a command. + */ + + esp32_gpiowrite(DISPLAY_DC, !cmd); + + return OK; + } +#endif + return -ENODEV; } diff --git a/boards/xtensa/esp32/common/src/esp32_ili9341.c b/boards/xtensa/esp32/common/src/esp32_ili9341.c new file mode 100644 index 0000000000..995f055be1 --- /dev/null +++ b/boards/xtensa/esp32/common/src/esp32_ili9341.c @@ -0,0 +1,456 @@ +/**************************************************************************** + * boards/xtensa/esp32/common/src/esp32_ili9341.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "esp32_gpio.h" +#include "esp32_spi.h" +#include "hardware/esp32_gpio_sigmap.h" + +/**************************************************************************** + * Preprocessor Definitions + ****************************************************************************/ + +/* Check if the following are defined in the board.h */ + +#ifndef DISPLAY_RST +# error "DISPLAY_RST must be defined in board.h!" +#endif +#ifndef DISPLAY_DC +# error "DISPLAY_DC must be defined in board.h!" +#endif +#ifndef DISPLAY_SPI +# error "DISPLAY_SPI must be defined in board.h!" +#endif + +#ifdef CONFIG_ESP32_LCD_OVERCLOCK +# define ILI9341_SPI_MAXFREQUENCY 40*1000*1000 +#else +# define ILI9341_SPI_MAXFREQUENCY 10*1000*1000 +#endif + +#ifndef CONFIG_SPI_CMDDATA +# error "The ILI9341 driver requires CONFIG_SPI_CMDATA in the configuration" +#endif + +/**************************************************************************** + * Private Type Definition + ****************************************************************************/ + +struct ili93414ws_lcd_s +{ + struct ili9341_lcd_s dev; + struct spi_dev_s *spi; +}; + +/**************************************************************************** + * Private Function Protototypes + ****************************************************************************/ + +static void esp32_ili93414ws_select(FAR struct ili9341_lcd_s *lcd); +static void esp32_ili93414ws_deselect(FAR struct ili9341_lcd_s *lcd); +static int esp32_ili93414ws_backlight(FAR struct ili9341_lcd_s *lcd, + int level); +static int esp32_ili93414ws_sendcmd(FAR struct ili9341_lcd_s *lcd, + const uint8_t cmd); +static int esp32_ili93414ws_sendparam(FAR struct ili9341_lcd_s *lcd, + const uint8_t param); +static int esp32_ili93414ws_sendgram(FAR struct ili9341_lcd_s *lcd, + const uint16_t *wd, uint32_t nwords); +static int esp32_ili93414ws_recvparam(FAR struct ili9341_lcd_s *lcd, + uint8_t *param); +static int esp32_ili93414ws_recvgram(FAR struct ili9341_lcd_s *lcd, + uint16_t *wd, uint32_t nwords); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct ili93414ws_lcd_s g_lcddev; +static struct lcd_dev_s *g_lcd = NULL; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32_ili93414ws_select + * + * Description: + * Select the SPI, lock and reconfigure if necessary + * + * Input Parameters: + * lcd - Reference to the public driver structure + * + ****************************************************************************/ + +static void esp32_ili93414ws_select(FAR struct ili9341_lcd_s *lcd) +{ + FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd; + + SPI_LOCK(priv->spi, true); + SPI_SELECT(priv->spi, SPIDEV_DISPLAY(0), true); +} + +/**************************************************************************** + * Name: esp32_ili93414ws_deselect + * + * Description: + * De-select the SPI + * + * Input Parameters: + * lcd - Reference to the public driver structure + * + ****************************************************************************/ + +static void esp32_ili93414ws_deselect(FAR struct ili9341_lcd_s *lcd) +{ + FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd; + + SPI_SELECT(priv->spi, SPIDEV_DISPLAY(0), false); + SPI_LOCK(priv->spi, false); +} + +/**************************************************************************** + * Name: esp32_ili93414ws_backlight + * + * Description: + * Set the backlight level of the connected display. + * NOTE: Currently this function either sets the brightness to the maximum + * level (level > 0) or turns the display off (level == 0). Although + * the ILI9341 chip provides an interface for configuring the + * backlight level via WRITE_DISPLAY_BRIGHTNESS (0x51), it depends on + * the actual circuit of the display device. Usually the backlight + * pins are hardwired to Vcc, making the backlight level setting + * effectless. + * + * Input Parameters: + * lcd - Reference to the public driver structure + * level - Backlight level + * + * Returned Value: + * OK - On Success + * + ****************************************************************************/ + +static int esp32_ili93414ws_backlight(FAR struct ili9341_lcd_s *lcd, + int level) +{ + if (level > 0) + { + lcd->sendcmd(lcd, ILI9341_WRITE_CTRL_DISPLAY); + lcd->sendparam(lcd, 0x24); + } + else + { + lcd->sendcmd(lcd, ILI9341_WRITE_CTRL_DISPLAY); + lcd->sendparam(lcd, 0x0); + } + + return OK; +} + +/**************************************************************************** + * Name: esp32_ili93414ws_sendcmd + * + * Description: + * Send a command to the lcd driver. + * + * Input Parameters: + * lcd - Reference to the ili9341_lcd_s driver structure + * cmd - command to send + * + * Returned Value: + * On success - OK + * + ****************************************************************************/ + +static int esp32_ili93414ws_sendcmd(FAR struct ili9341_lcd_s *lcd, + const uint8_t cmd) +{ + FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd; + + lcdinfo("%02x\n", cmd); + + SPI_SETBITS(priv->spi, 8); + + SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY(0), true); + SPI_SEND(priv->spi, cmd); + SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY(0), false); + + return OK; +} + +/**************************************************************************** + * Name: esp32_ili93414ws_sendparam + * + * Description: + * Send a parameter to the lcd driver. + * + * Input Parameters: + * lcd - Reference to the ili9341_lcd_s driver structure + * param - Parameter to send + * + * Returned Value: + * OK - On Success + * + ****************************************************************************/ + +static int esp32_ili93414ws_sendparam(FAR struct ili9341_lcd_s *lcd, + const uint8_t param) +{ + FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd; + + lcdinfo("param=%04x\n", param); + + SPI_SETBITS(priv->spi, 8); + + SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY(0), false); + SPI_SEND(priv->spi, param); + + return OK; +} + +/**************************************************************************** + * Name: esp32_ili93414ws_sendgram + * + * Description: + * Send a number of pixel words to the lcd driver gram. + * + * Input Parameters: + * lcd - Reference to the ili9341_lcd_s driver structure + * wd - Reference to the words to send + * nwords - Number of words to send + * + * Returned Value: + * OK - On Success + * + ****************************************************************************/ + +static int esp32_ili93414ws_sendgram(FAR struct ili9341_lcd_s *lcd, + const uint16_t *wd, uint32_t nwords) +{ + FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd; + + lcdinfo("lcd:%p, wd=%p, nwords=%" PRIu32 "\n", lcd, wd, nwords); + + SPI_SETBITS(priv->spi, 16); + SPI_SNDBLOCK(priv->spi, wd, nwords); + + return OK; +} + +/**************************************************************************** + * Name: esp32_ili93414ws_recvparam + * + * Description: + * Receive a parameter from the lcd driver. + * + * Input Parameters: + * lcd - Reference to the ili9341_lcd_s driver structure + * param - Reference to where parameter is received + * + * Returned Value: + * OK - On Success + * + ****************************************************************************/ + +static int esp32_ili93414ws_recvparam(FAR struct ili9341_lcd_s *lcd, + uint8_t *param) +{ + FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd; + + SPI_SETBITS(priv->spi, 8); + + SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY(0), false); + + *param = (uint8_t)(SPI_SEND(priv->spi, (uintptr_t)param) & 0xff); + + return OK; +} + +/**************************************************************************** + * Name: esp32_ili93414ws_recvgram + * + * Description: + * Receive pixel words from the lcd driver gram. + * + * Input Parameters: + * lcd - Reference to the public driver structure + * wd - Reference to where the pixel words are received + * nwords - Number of pixel words to receive + * + * Returned Value: + * OK - On Success + * + ****************************************************************************/ + +static int esp32_ili93414ws_recvgram(FAR struct ili9341_lcd_s *lcd, + uint16_t *wd, uint32_t nwords) +{ + FAR struct ili93414ws_lcd_s *priv = (FAR struct ili93414ws_lcd_s *)lcd; + + lcdinfo("wd=%p, nwords=%" PRIu32 "\n", wd, nwords); + + SPI_SETBITS(priv->spi, 16); + SPI_RECVBLOCK(priv->spi, wd, nwords); + + return OK; +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_lcd_initialize + * + * Description: + * Initialize the LCD video hardware. The initial state of the LCD is fully + * initialized, display memory cleared, and the LCD ready to use, but with + * the power setting at 0 (full off). + * + ****************************************************************************/ + +int board_lcd_initialize(void) +{ + FAR struct ili93414ws_lcd_s *priv = &g_lcddev; + FAR struct spi_dev_s *spi; + lcdinfo("Initializing LCD\n"); + + if (g_lcd == NULL) + { + spi = esp32_spibus_initialize(DISPLAY_SPI); + if (!spi) + { + lcderr("Failed to initialize SPI bus.\n"); + return -ENODEV; + } + + priv->spi = spi; + + /* Initialize non-SPI GPIOs */ + + esp32_configgpio(DISPLAY_DC, OUTPUT_FUNCTION_3); + esp32_gpio_matrix_out(DISPLAY_DC, SIG_GPIO_OUT_IDX, 0, 0); + + esp32_configgpio(DISPLAY_RST, INPUT_FUNCTION_3); + esp32_gpio_matrix_out(DISPLAY_RST, SIG_GPIO_OUT_IDX, 0, 0); + + esp32_configgpio(DISPLAY_BCKL, OUTPUT_FUNCTION_3); + esp32_gpio_matrix_out(DISPLAY_BCKL, SIG_GPIO_OUT_IDX, 0, 0); + + /* Reset ILI9341 */ + + up_mdelay(10); + esp32_gpiowrite(DISPLAY_RST, false); + up_mdelay(10); + esp32_gpiowrite(DISPLAY_RST, true); + up_mdelay(50); + + /* Configure SPI */ + + SPI_SETMODE(priv->spi, SPIDEV_MODE0); + SPI_SETBITS(priv->spi, 8); + SPI_HWFEATURES(priv->spi, 0); + SPI_SETFREQUENCY(priv->spi, ILI9341_SPI_MAXFREQUENCY); + + /* Initialize ILI9341 driver with necessary methods */ + + priv->dev.select = esp32_ili93414ws_select; + priv->dev.deselect = esp32_ili93414ws_deselect; + priv->dev.sendcmd = esp32_ili93414ws_sendcmd; + priv->dev.sendparam = esp32_ili93414ws_sendparam; + priv->dev.recvparam = esp32_ili93414ws_recvparam; + priv->dev.sendgram = esp32_ili93414ws_sendgram; + priv->dev.recvgram = esp32_ili93414ws_recvgram; + priv->dev.backlight = esp32_ili93414ws_backlight; + + g_lcd = ili9341_initialize(&priv->dev, 0); + + if (g_lcd != NULL) + { + /* Turn the LCD on at 100% power */ + + g_lcd->setpower(g_lcd, CONFIG_LCD_MAXPOWER); + } + } + + return OK; +} + +/**************************************************************************** + * Name: board_lcd_getdev + * + * Description: + * Return a reference to the LCD object for the specified LCD. This allows + * support for multiple LCD devices. + * + ****************************************************************************/ + +FAR struct lcd_dev_s *board_lcd_getdev(int lcddev) +{ + if (lcddev == 0) + { + return g_lcd; + } + + return NULL; +} + +/**************************************************************************** + * Name: board_lcd_uninitialize + * + * Description: + * Uninitialize the LCD support. + * + ****************************************************************************/ + +void board_lcd_uninitialize(void) +{ + lcdinfo("Terminating LCD\n"); + + if (g_lcd != NULL) + { + /* Turn the display off */ + + g_lcd->setpower(g_lcd, 0); + + g_lcd = NULL; + } +} diff --git a/boards/xtensa/esp32/esp32-wrover-kit/include/board.h b/boards/xtensa/esp32/esp32-wrover-kit/include/board.h index 260655bc71..4725215cdb 100644 --- a/boards/xtensa/esp32/esp32-wrover-kit/include/board.h +++ b/boards/xtensa/esp32/esp32-wrover-kit/include/board.h @@ -72,6 +72,15 @@ #endif #endif +/* GPIO definitions *********************************************************/ + +/* Display */ + +#define DISPLAY_SPI 2 +#define DISPLAY_DC 21 +#define DISPLAY_RST 18 +#define DISPLAY_BCKL 5 + /* LED definitions **********************************************************/ /* Define how many LEDs this board has (needed by userleds) */