diff --git a/drivers/lcd/ili9341.c b/drivers/lcd/ili9341.c new file mode 100644 index 0000000000..66c186bf40 --- /dev/null +++ b/drivers/lcd/ili9341.c @@ -0,0 +1,1263 @@ +/****************************************************************************** + * drivers/lcd/ili9341.c + * + * LCD driver for the ILI9341 LCD Single Chip Driver + * + * Copyright (C) 2014 Marco Krahl. All rights reserved. + * Author: Marco Krahl + * + * References: ILI9341_DS_V1.10.pdf (Rev: 1.10), "a-Si TFT LCD Single Chip + * Driver 240RGBx320 Resolution and 262K color", + * ILI TECHNOLOGY CORP., http://www.ilitek.com. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior writen permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + +/****************************************************************************** + * Included Files + ******************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/****************************************************************************** + * Pre-processor Definitions + ******************************************************************************/ + +/* + * This is the generic lcd driver interface for the ili9341 Single Chip LCD + * driver. The driver supports multiple displays, each connected with an own + * ili9341 Single Chip LCD driver. The communication with the LCD single chip + * driver must be provide by a subdriver accessable trough the ili9341_dev_s + * structure which is platform and MCU interface specific. + * + * Supported MCU interfaces (planed to support) + * + * Interface I + * + * 8080 MCU 8-bit bus interface + * 8080 MCU 16-bit bus interface + * 8080 MCU 9-bit bus interface + * 8080 MCU 18-bit bus interface + * 3-wire 9-bit data serial interface + * 4-wire 8-bit data serial interface + * + * Interface II + * + * 8080 MCU 8-bit bus interface + * 8080 MCU 16-bit bus interface + * 8080 MCU 9-bit bus interface + * 8080 MCU 18-bit bus interface + * 3-wire 9-bit data serial Interface + * 4-wire 8-bit data serial Interface + * + * Note! RGB interface will not supported by the lcd driver. + * It should be use with the platform specific RGB grapic controller and the + * nuttx framebuffer interface. + * + */ + +/* Fundamental command and parameter definition */ + +/* Interface control (IFCTL) + * + * + * Parameter 1: 0x0001 + * + * MY_EOR: 0 + * MX_EOR: 0 + * MV_EOR: 0 + * BGR_EOR: 0 + * WEMODE: 1 Reset column and page if data transfer exceeds + */ +#define ILI9341_IFCTL_MYEOR 0 +#define ILI9341_IFCTL_MXEOR 0 +#define ILI9341_IFCTL_MVEOR 0 +#define ILI9341_IFCTL_BGREOR 0 +#define ILI9341_IFCTL_WEMODE ILI9341_INTERFACE_CONTROL_WEMODE + +#define ILI9341_IFCTL_PARAM1 ILI9341_IFCTL_MYEOR | ILI9341_IFCTL_MXEOR | \ + ILI9341_IFCTL_MVEOR | ILI9341_IFCTL_BGREOR | \ + ILI9341_IFCTL_WEMODE + +/* Parameter 2: 0x0000 + * + * EPF: 0 65k color format for RGB interface, not used set to default + * MDT: 0 Display data transfer mode, not used + * + * Note! If RGB666 and 16-bit 8080-I interface supported by the driver, MDT must + * be defined for each selected driver instance. Leave it empty for now. + */ + +#define ILI9341_IFCTL_EPF ILI9341_INTERFACE_CONTROL_EPF(0) +#define ILI9341_IFCTL_MDT ILI9341_INTERFACE_CONTROL_MDT(0) + +#define ILI9341_IFCTL_PARAM2 ILI9341_IFCTL_EPF | ILI9341_IFCTL_MDT + + +/* Parameter 3: 0x0000/0x0020 + * + * ENDIAN: 0/1 Depending on endian mode of the mcu? + * DM: 0 Internal clock operation + * RM: 0 System interface/VSYNC interface + * RIM: 0 RGB interface mode, unimportant set to default + * + */ + +#ifdef CONFIG_ENDIAN_BIG +# define ILI9341_IFCTL_ENDIAN 0 +#else +# define ILI9341_IFCTL_ENDIAN ILI9341_INTERFACE_CONTROL_ENDIAN +#endif +#define ILI9341_IFCTL_DM ILI9341_INTERFACE_CONTROL_DM(0) +#define ILI9341_IFCTL_RM 0 +#define ILI9341_IFCTL_RIM 0 + +#define ILI9341_IFCTL_PARAM3 ILI9341_IFCTL_RIM | ILI9341_IFCTL_RM | \ + ILI9341_IFCTL_DM | ILI9341_IFCTL_ENDIAN + + +/* Memory access control (MADCTL) */ + +/* + * Landscape: 00100000 / 00101000 / h28 + * + * MY: 0 + * MX: 0 + * MV: 1 + * ML: 0 + * BGR: 0/1 Depending on endian mode of the mcu? + * MH: 0 + */ + +#define ILI9341_MADCTL_LANDSCAPE_MY 0 +#define ILI9341_MADCTL_LANDSCAPE_MX 0 +#define ILI9341_MADCTL_LANDSCAPE_MV ILI9341_MEMORY_ACCESS_CONTROL_MV +#define ILI9341_MADCTL_LANDSCAPE_ML 0 +#ifdef CONFIG_BIG_ENDIAN +# define ILI9341_MADCTL_LANDSCAPE_BGR 0 +#else +# define ILI9341_MADCTL_LANDSCAPE_BGR ILI9341_MEMORY_ACCESS_CONTROL_BGR +#endif +#define ILI9341_MADCTL_LANDSCAPE_MH 0 + +#define ILI9341_MADCTL_LANDSCAPE_PARAM1 (ILI9341_MADCTL_LANDSCAPE_MY | \ + ILI9341_MADCTL_LANDSCAPE_MX | \ + ILI9341_MADCTL_LANDSCAPE_MV | \ + ILI9341_MADCTL_LANDSCAPE_ML | \ + ILI9341_MADCTL_LANDSCAPE_BGR | \ + ILI9341_MADCTL_LANDSCAPE_MH) + +/* + * Portrait: 00000000 / 00001000 / h08 + * + * MY: 0 + * MX: 0 + * MV: 0 + * ML: 0 + * BGR: 0/1 Depending on endian mode of the mcu? + * MH: 0 + */ + +#define ILI9341_MADCTL_PORTRAIT_MY 0 +#define ILI9341_MADCTL_PORTRAIT_MX 0 +#define ILI9341_MADCTL_PORTRAIT_MV 0 +#define ILI9341_MADCTL_PORTRAIT_ML 0 +#ifdef CONFIG_BIG_ENDIAN +# define ILI9341_MADCTL_PORTRAIT_BGR 0 +#else +# define ILI9341_MADCTL_PORTRAIT_BGR ILI9341_MEMORY_ACCESS_CONTROL_BGR +#endif +#define ILI9341_MADCTL_PORTRAIT_MH 0 + +#define ILI9341_MADCTL_PORTRAIT_PARAM1 (ILI9341_MADCTL_PORTRAIT_MY | \ + ILI9341_MADCTL_PORTRAIT_MX | \ + ILI9341_MADCTL_PORTRAIT_MV | \ + ILI9341_MADCTL_PORTRAIT_ML | \ + ILI9341_MADCTL_PORTRAIT_BGR | \ + ILI9341_MADCTL_PORTRAIT_MH) +/* + * RLandscape: 01100000 / 01101000 / h68 + * + * MY: 0 + * MX: 1 + * MV: 1 + * ML: 0 + * BGR: 0/1 Depending on endian mode of the mcu? + * MH: 0 + */ + +#define ILI9341_MADCTL_RLANDSCAPE_MY 0 +#define ILI9341_MADCTL_RLANDSCAPE_MX ILI9341_MEMORY_ACCESS_CONTROL_MX +#define ILI9341_MADCTL_RLANDSCAPE_MV ILI9341_MEMORY_ACCESS_CONTROL_MV +#define ILI9341_MADCTL_RLANDSCAPE_ML 0 +#ifdef CONFIG_BIG_ENDIAN +# define ILI9341_MADCTL_RLANDSCAPE_BGR 0 +#else +# define ILI9341_MADCTL_RLANDSCAPE_BGR ILI9341_MEMORY_ACCESS_CONTROL_BGR +#endif +#define ILI9341_MADCTL_RLANDSCAPE_MH 0 + +#define ILI9341_MADCTL_RLANDSCAPE_PARAM1 \ + (ILI9341_MADCTL_RLANDSCAPE_MY | \ + ILI9341_MADCTL_RLANDSCAPE_MX | \ + ILI9341_MADCTL_RLANDSCAPE_MV | \ + ILI9341_MADCTL_RLANDSCAPE_ML | \ + ILI9341_MADCTL_RLANDSCAPE_BGR | \ + ILI9341_MADCTL_RLANDSCAPE_MH) + +/* + * RPortrait: 11000000 / 11001000 / hc8 + * + * MY: 1 + * MX: 1 + * MV: 0 + * ML: 0 + * BGR: 0/1 Depending on endian mode of the mcu? + * MH: 0 + * + */ + +#define ILI9341_MADCTL_RPORTRAIT_MY ILI9341_MEMORY_ACCESS_CONTROL_MY +#define ILI9341_MADCTL_RPORTRAIT_MX ILI9341_MEMORY_ACCESS_CONTROL_MX +#define ILI9341_MADCTL_RPORTRAIT_MV 0 +#define ILI9341_MADCTL_RPORTRAIT_ML 0 +#ifdef CONFIG_BIG_ENDIAN +# define ILI9341_MADCTL_RPORTRAIT_BGR 0 +#else +# define ILI9341_MADCTL_RPORTRAIT_BGR ILI9341_MEMORY_ACCESS_CONTROL_BGR +#endif +#define ILI9341_MADCTL_RPORTRAIT_MH 0 + +#define ILI9341_MADCTL_RPORTRAIT_PARAM1 (ILI9341_MADCTL_RPORTRAIT_MY | \ + ILI9341_MADCTL_RPORTRAIT_MX | \ + ILI9341_MADCTL_RPORTRAIT_MV | \ + ILI9341_MADCTL_RPORTRAIT_ML | \ + ILI9341_MADCTL_RPORTRAIT_BGR | \ + ILI9341_MADCTL_RPORTRAIT_MH) + +/* Pixel Format Set (COLMOD) + * + * Note! RGB interface settings (DPI) is unimportant for the MCU interface + * mode but set the register to the defined state equal to the MCU interface + * pixel format. + * + * 16 Bit MCU: 01010101 / h55 + * + * DPI: 5 (RGB16-565 RGB interface, not used) + * DBI: 5 (RGB16-565 MCU interface + */ + +#define ILI9341_PIXSET_16BITDPI ILI9341_PIXEL_FORMAT_SET_DPI(5) +#define ILI9341_PIXSET_16BITDBI ILI9341_PIXEL_FORMAT_SET_DBI(5) + +#define ILI9341_PIXSET_16BITMCU_PARAM1 (ILI9341_PIXSET_16BITDPI | \ + ILI9341_PIXSET_16BITDBI) + +/* + * 18-bit MCU: 01100110 / h66 (not supported by nuttx until now) + * + * DPI: 6 (RGB18-666 RGB interface) + * DBI: 6 (RGB18-666 MCU interface) + */ + +#define ILI9341_PIXSET_18BITDPI ILI9341_PIXEL_FORMAT_SET_DPI(6) +#define ILI9341_PIXSET_18BITDBI ILI9341_PIXEL_FORMAT_SET_DBI(6) + +#define ILI9341_PIXSET_18BITMCU_PARAM1 (ILI9341_PIXSET_18BITDPI | \ + ILI9341_PIXSET_18BITDBI) + + +/* General fix display resolution */ + +#define ILI9341_XRES 240 +#define ILI9341_YRES 320 + + +/* Validate configuration */ + +#if CONFIG_LCD_ILI9341_NINTERFACES < 1 +# undef CONFIG_LCD_ILI9341_IFACE0 +#elif CONFIG_LCD_ILI9341_NINTERFACES < 2 +# undef CONFIG_LCD_ILI9341_IFACE1 +#endif + + +/* First LCD display */ + +#ifdef CONFIG_LCD_ILI9341_IFACE0 +# ifdef CONFIG_LCD_ILI9341_IFACE0_LANDSCAPE +# define ILI9341_IFACE0_ORIENT ILI9341_MADCTL_LANDSCAPE_PARAM1 +# define ILI9341_IFACE0_STRIDE ILI9341_YRES +# elif CONFIG_LCD_ILI9341_IFACE0_PORTRAIT +# define ILI9341_IFACE0_ORIENT ILI9341_MADCTL_PORTRAIT_PARAM1 +# define ILI9341_IFACE0_STRIDE ILI9341_XRES +# elif CONFIG_LCD_ILI9341_IFACE0_RLANDSCAPE +# define ILI9341_IFACE0_ORIENT ILI9341_MADCTL_RLANDSCAPE_PARAM1 +# define ILI9341_IFACE0_STRIDE ILI9341_YRES +# elif CONFIG_LCD_ILI9341_IFACE0_RPORTRAIT +# define ILI9341_IFACE0_ORIENT ILI9341_MADCTL_RPORTRAIT_PARAM1 +# define ILI9341_IFACE0_STRIDE ILI9341_XRES +# endif +# ifdef CONFIG_LCD_ILI9341_IFACE0_RGB565 +# define ILI9341_IFACE0_PXFMT FB_FMT_RGB16_565 +# define ILI9341_IFACE0_BPP 16 +# define ILI9341_IFACE0_BUFFER ILI9341_IFACE0_STRIDE +# else +# error "undefined pixel format for lcd interface 0" +# endif +#endif + +/* Second LCD display */ + +#ifdef CONFIG_LCD_ILI9341_IFACE1 +# ifdef CONFIG_LCD_ILI9341_IFACE1_LANDSCAPE +# define ILI9341_IFACE1_ORIENT ILI9341_MADCTL_LANDSCAPE_PARAM1 +# define ILI9341_IFACE1_STRIDE ILI9341_YRES +# elif CONFIG_LCD_ILI9341_IFACE1_PORTRAIT +# define ILI9341_IFACE1_ORIENT ILI9341_MADCTL_PORTRAIT_PARAM1 +# define ILI9341_IFACE1_STRIDE ILI9341_XRES +# elif CONFIG_LCD_ILI9341_IFACE1_RLANDSCAPE +# define ILI9341_IFACE1_ORIENT ILI9341_MADCTL_RLANDSCAPE_PARAM1 +# define ILI9341_IFACE1_STRIDE ILI9341_YRES +# elif CONFIG_LCD_ILI9341_IFACE1_RPORTRAIT +# define ILI9341_IFACE1_ORIENT ILI9341_MADCTL_RPORTRAIT_PARAM1 +# define ILI9341_IFACE1_STRIDE ILI9341_XRES +# endif +# ifdef CONFIG_LCD_ILI9341_IFACE1_RGB565 +# define ILI9341_IFACE1_PXFMT FB_FMT_RGB16_565 +# define ILI9341_IFACE1_BPP 16 +# define ILI9341_IFACE1_BUFFER ILI9341_IFACE1_STRIDE +# else +# error "undefined pixel format for lcd interface 1" +# endif +#endif + +/* Add next LCD display */ + +/* Debug option */ + +#ifdef CONFIG_DEBUG_LCD +# define lcddbg dbg +# define lcdvdbg vdbg +#else +# define lcddbg(x...) +# define lcdvdbg(x...) +#endif + +/****************************************************************************** + * Private Type Definition + ******************************************************************************/ + +/* + * Each single connected ili9341 LCD driver needs an own driver instance + * to provide a unique getrun and putrun method. Also store fundamental + * parameter in driver internal structure. This minimal overhead should be + * acceptable. + */ + +struct ili9341_dev_s +{ + /* Publically visible device structure */ + + struct lcd_dev_s dev; + + /* Private driver-specific information follows */ + + FAR struct ili9341_lcd_s *lcd; + + /* Driver specific putrun function */ + + int (*putrun)(fb_coord_t row, fb_coord_t col, + FAR const uint8_t * buffer, size_t npixels); +#ifndef CONFIG_LCD_NOGETRUN + /* Driver specific getrun function */ + + int (*getrun)(fb_coord_t row, fb_coord_t col, + FAR uint8_t * buffer, size_t npixels); +#endif + /* Run buffer for the device */ + + uint16_t *runbuffer; + + /* Display orientation, e.g. Landscape, Portrait */ + + uint8_t orient; + + /* LCD driver pixel format */ + + uint8_t pxfmt; + + /* LCD driver color depth */ + + uint8_t bpp; + + /* Current power state of the device */ + + uint8_t power; +}; + + +/****************************************************************************** + * Private Function Protototypes + ******************************************************************************/ + +/* Internal low level helpers */ + +static inline uint16_t ili9341_getxres(FAR struct ili9341_dev_s *dev); +static inline uint16_t ili9341_getyres(FAR struct ili9341_dev_s *dev); + +/* lcd data transfer methods */ + +static int ili9341_putrun(int devno, fb_coord_t row, fb_coord_t col, + FAR const uint8_t * buffer, size_t npixels); +#ifndef CONFIG_LCD_NOGETRUN +static int ili9341_getrun(int devno, fb_coord_t row, fb_coord_t col, + FAR uint8_t * buffer, size_t npixels); +#endif +/* + * Definition of the public visible getrun / putrun methods + * each for a single LCD driver + */ + +#ifdef CONFIG_LCD_ILI9341_IFACE0 +static int ili9341_putrun0(fb_coord_t row, fb_coord_t col, + FAR const uint8_t * buffer, size_t npixsels); +#endif +#ifdef CONFIG_LCD_ILI9341_IFACE1 +static int ili9341_putrun1(fb_coord_t row, fb_coord_t col, + FAR const uint8_t * buffer, size_t npixsels); +#endif + +#ifndef CONFIG_LCD_NOGETRUN +# ifdef CONFIG_LCD_ILI9341_IFACE0 +static int ili9341_getrun0(fb_coord_t row, fb_coord_t col, + FAR uint8_t * buffer, size_t npixsels); +# endif +# ifdef CONFIG_LCD_ILI9341_IFACE1 +static int ili9341_getrun1(fb_coord_t row, fb_coord_t col, + FAR uint8_t * buffer, size_t npixsels); +# endif +#endif + +/* lcd configuration */ + +static int ili9341_getvideoinfo(FAR struct lcd_dev_s *dev, + FAR struct fb_videoinfo_s *vinfo); +static int ili9341_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, + FAR struct lcd_planeinfo_s *pinfo); + +/* lcd specific controls */ + +static int ili9341_getpower(struct lcd_dev_s *dev); +static int ili9341_setpower(struct lcd_dev_s *dev, int power); +static int ili9341_getcontrast(struct lcd_dev_s *dev); +static int ili9341_setcontrast(struct lcd_dev_s *dev, unsigned int contrast); + +/****************************************************************************** + * Private Data + ******************************************************************************/ + +/* Initialize driver instance 1 < LCD_ILI9341_NINTERFACES */ + +#ifdef CONFIG_LCD_ILI9341_IFACE0 +static uint16_t g_runbuffer0[ILI9341_IFACE0_BUFFER]; +#endif +#ifdef CONFIG_LCD_ILI9341_IFACE1 +static uint16_t g_runbuffer1[ILI9341_IFACE1_BUFFER]; +#endif + +static struct ili9341_dev_s g_lcddev[CONFIG_LCD_ILI9341_NINTERFACES] = +{ +#ifdef CONFIG_LCD_ILI9341_IFACE0 + { + .lcd = 0, + .putrun = ili9341_putrun0, +# ifndef CONFIG_LCD_NOGETRUN + .getrun = ili9341_getrun0, +# endif + .runbuffer = g_runbuffer0, + .orient = ILI9341_IFACE0_ORIENT, + .pxfmt = ILI9341_IFACE0_PXFMT, + .bpp = ILI9341_IFACE0_BPP, + .power = 0, + }, +#endif +#ifdef CONFIG_LCD_ILI9341_IFACE1 + { + .lcd = 0, + .putrun = ili9341_putrun1, +# ifndef CONFIG_LCD_NOGETRUN + .getrun = ili9341_getrun1, +# endif + .runbuffer = g_runbuffer1, + .orient = ILI9341_IFACE1_ORIENT, + .pxfmt = ILI9341_IFACE1_PXFMT, + .bpp = ILI9341_IFACE1_BPP, + .power = 0, + }, +#endif +}; + +/****************************************************************************** + * Private Functions + ******************************************************************************/ + +/****************************************************************************** + * Name: ili9341_getxres + * + * Description: + * Get horicontal resolution of the connected LCD driver depending on the + * configured display orientation. + * + * Parameters: + * dev - Reference to private driver structure + * + * Return Value: + * + * Horicontal resolution + * + ******************************************************************************/ + +static inline uint16_t ili9341_getxres(FAR struct ili9341_dev_s *dev) +{ + if (dev->orient == ILI9341_MADCTL_LANDSCAPE_PARAM1 || + dev->orient == ILI9341_MADCTL_RLANDSCAPE_PARAM1) + { + return ILI9341_YRES; + } + + return ILI9341_XRES; +} + + +/******************************************************************************* + * Name: ili9341_getyres + * + * Description: + * Get vertical resolution of the connected LCD driver depending on the + * configured display orientation. + * + * Parameter: + * dev - Reference to private driver structure + * + * Return Value: + * + * Vertical resolution + * + ******************************************************************************/ + +static inline uint16_t ili9341_getyres(FAR struct ili9341_dev_s *dev) +{ + if (dev->orient == ILI9341_MADCTL_LANDSCAPE_PARAM1 || + dev->orient == ILI9341_MADCTL_RLANDSCAPE_PARAM1) + { + return ILI9341_XRES; + } + + return ILI9341_YRES; +} + + +/******************************************************************************* + * Name: ili9341_selectarea + * + * Description: + * Select the active area for displaying pixel + * + * Parameter: + * lcd - Reference to private driver structure + * x0 - Start x position + * y0 - Start y position + * x1 - End x position + * y1 - End y position + * + ******************************************************************************/ + +static void ili9341_selectarea(FAR struct ili9341_lcd_s *lcd, + uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) +{ + /* Select column */ + + lcd->sendcmd(lcd, ILI9341_COLUMN_ADDRESS_SET); + lcd->sendparam(lcd, (x0 >> 8)); + lcd->sendparam(lcd, (x0 & 0xff)); + lcd->sendparam(lcd, (x1 >> 8)); + lcd->sendparam(lcd, (x1 & 0xff)); + + /* Select page */ + + lcd->sendcmd(lcd, ILI9341_PAGE_ADDRESS_SET); + lcd->sendparam(lcd, (y0 >> 8)); + lcd->sendparam(lcd, (y0 & 0xff)); + lcd->sendparam(lcd, (y1 >> 8)); + lcd->sendparam(lcd, (y1 & 0xff)); +} + + +/******************************************************************************* + * Name: ili9341_putrun + * + * Description: + * Write a partial raster line to the LCD. + * + * Parameters: + * devno - Number of lcd device + * row - Starting row to write to (range: 0 <= row < yres) + * col - Starting column to write to (range: 0 <= col <= xres-npixels) + * buffer - The buffer containing the run to be writen to the LCD + * npixels - The number of pixels to write to the + * (range: 0 < npixels <= xres-col) + * + * Returned Value: + * + * On success - OK + * On error - -EINVAL + * + ******************************************************************************/ + +static int ili9341_putrun(int devno, fb_coord_t row, fb_coord_t col, + FAR const uint8_t * buffer, size_t npixels) +{ + FAR struct ili9341_dev_s *dev = &g_lcddev[devno]; + FAR struct ili9341_lcd_s *lcd = dev->lcd; + FAR const uint16_t *src = (const uint16_t*)buffer; + + DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0); + + /* Check if position outside of area */ + if (col + npixels > ili9341_getxres(dev) || row > ili9341_getyres(dev)) + { + return -EINVAL; + } + + /* Select lcd driver */ + + lcd->select(lcd); + + /* Select column and area similar to the partial raster line */ + + ili9341_selectarea(lcd, col, row, col + npixels - 1, row); + + /* Send memory write cmd */ + + lcd->sendcmd(lcd, ILI9341_MEMORY_WRITE); + + /* Send pixel to gram */ + + lcd->sendgram(lcd, src, npixels); + + /* Deselect the lcd driver */ + + lcd->deselect(lcd); + + return OK; +} + + +/******************************************************************************* + * Name: ili9341_getrun + * + * Description: + * Read a partial raster line from the LCD. + * + * Parameter: + * devno - Number of the lcd device + * row - Starting row to read from (range: 0 <= row < yres) + * col - Starting column to read read (range: 0 <= col <= xres-npixels) + * buffer - The buffer in which to return the run read from the LCD + * npixels - The number of pixels to read from the LCD + * (range: 0 < npixels <= xres-col) + * + * Returned Value: + * + * On success - OK + * On error - -EINVAL + * + ******************************************************************************/ + +# ifndef CONFIG_LCD_NOGETRUN +static int ili9341_getrun(int devno, fb_coord_t row, fb_coord_t col, + FAR uint8_t * buffer, size_t npixels) +{ + FAR struct ili9341_dev_s *dev = &g_lcddev[devno]; + FAR struct ili9341_lcd_s *lcd = dev->lcd; + FAR uint16_t *dest = (uint16_t*)buffer; + + DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0); + + /* Check if position outside of area */ + if (col + npixels > ili9341_getxres(dev) || row > ili9341_getyres(dev)) + { + return -EINVAL; + } + + /* Select lcd driver */ + + lcd->select(lcd); + + /* Select column and area similar to the partial raster line */ + + ili9341_selectarea(lcd, col, row, col + npixels - 1, row); + + /* Send memory read cmd */ + + lcd->sendcmd(lcd, ILI9341_MEMORY_READ); + + /* Receive pixel to gram */ + + lcd->recvgram(lcd, dest, npixels); + + /* Deselect the lcd driver */ + + lcd->deselect(lcd); + + return OK; +} +#endif + +/******************************************************************************* + * Name: ili9341_hwinitialize + * + * Description: + * Initialize and configure the ILI9341 LCD driver hardware. + * + * Parameter: + * dev - A reference to the driver specific structure + * + * Returned Value: + * + * On success - OK + * On error - EINVAL + * + ******************************************************************************/ + +static int ili9341_hwinitialize(FAR struct ili9341_dev_s *dev) +{ +#ifdef CONFIG_DEBUG_LCD + uint8_t param; +#endif + FAR struct ili9341_lcd_s *lcd = dev->lcd; + + /* Select spi device */ + + lcddbg("Initialize lcd driver\n"); + lcd->select(lcd); + +#ifdef CONFIG_DEBUG_LCD + /* Read display identification */ + + lcd->sendcmd(lcd, ILI9341_READ_ID1); + lcd->recvparam(lcd, ¶m); + lcddbg("ili9341 LCD driver: LCD modules manufacturer ID: %d\n", param); + lcd->sendcmd(lcd, ILI9341_READ_ID2); + lcd->recvparam(lcd, ¶m); + lcddbg("ili9341 LCD driver: LCD modules driver version ID: %d\n", param); + lcd->sendcmd(lcd, ILI9341_READ_ID3); + lcd->recvparam(lcd, ¶m); + lcddbg("ili9341 LCD driver: LCD modules driver ID: %d\n", param); +#endif + + /* Reset the lcd display to the default state */ + + lcdvdbg("ili9341 LCD driver: Software Reset\n"); + lcd->sendcmd(lcd, ILI9341_SOFTWARE_RESET); + up_mdelay(5); + + lcdvdbg("ili9341 LCD driver: set Memory Access Control: %04x\n", dev->orient); + lcd->sendcmd(lcd, ILI9341_MEMORY_ACCESS_CONTROL); + lcd->sendparam(lcd, dev->orient); + + /* Select column and area */ + + ili9341_selectarea(lcd, 0, 0, ILI9341_XRES, ILI9341_YRES); + + /* Pixel Format set */ + + lcd->sendcmd(lcd, ILI9341_PIXEL_FORMAT_SET); + + /* 16 bit RGB565 */ + + lcdvdbg("ili9341 LCD driver: Set Pixel Format: %04x\n", + ILI9341_PIXSET_16BITMCU_PARAM1); + lcd->sendparam(lcd, ILI9341_PIXSET_16BITMCU_PARAM1); + + /* 18 bit RGB666, add settings here */ + + lcdvdbg("ili9341 LCD driver: Set Interface control\n"); + lcd->sendcmd(lcd, ILI9341_INTERFACE_CONTROL); + lcd->sendparam(lcd, ILI9341_IFCTL_PARAM1); + lcd->sendparam(lcd, ILI9341_IFCTL_PARAM2); + lcd->sendparam(lcd, ILI9341_IFCTL_PARAM3); + + /* Sleep out */ + + lcdvdbg("ili9341 LCD driver: Sleep Out\n"); + lcd->sendcmd(lcd, ILI9341_SLEEP_OUT); + up_mdelay(120); + + /* Deselect the device */ + + lcd->deselect(lcd); + + /* Switch display off */ + + ili9341_setpower(&dev->dev, 0); + + return OK; +} + + +/******************************************************************************* + * Public Functions + ******************************************************************************/ + +/******************************************************************************* + * Name: ili9341_putrunx + * + * Description: + * Write a partial raster line to the LCD. + * + * Parameter: + * row - Starting row to write to (range: 0 <= row < yres) + * col - Starting column to write to (range: 0 <= col <= xres-npixels) + * buffer - The buffer containing the run to be writen to the LCD + * npixels - The number of pixels to write to the + * (range: 0 < npixels <= xres-col) + * + * Returned Value: + * + * On success - OK + * On error - -EINVAL + * + ******************************************************************************/ + +#ifdef CONFIG_LCD_ILI9341_IFACE0 +static int ili9341_putrun0(fb_coord_t row, fb_coord_t col, + FAR const uint8_t * buffer, size_t npixels) +{ + return ili9341_putrun(0, row, col, buffer, npixels); +} +#endif + +#ifdef CONFIG_LCD_ILI9341_IFACE1 +static int ili9341_putrun1(fb_coord_t row, fb_coord_t col, + FAR const uint8_t * buffer, size_t npixels) +{ + return ili9341_putrun(1, row, col, buffer, npixels); +} +#endif + + +/******************************************************************************* + * Name: ili9341_getrunx + * + * Description: + * Read a partial raster line from the LCD. + * + * Parameter: + * row - Starting row to read from (range: 0 <= row < yres) + * col - Starting column to read from (range: 0 <= col <= xres-npixels) + * buffer - The buffer containing the run to be writen to the LCD + * npixels - The number of pixels to read from the + * (range: 0 < npixels <= xres-col) + * + * Returned Value: + * + * On success - OK + * On error - -EINVAL + * + ******************************************************************************/ + +#ifndef CONFIG_LCD_NOGETRUN +# ifdef CONFIG_LCD_ILI9341_IFACE0 +static int ili9341_getrun0(fb_coord_t row, fb_coord_t col, + FAR uint8_t * buffer, size_t npixels) +{ + return ili9341_getrun(0, row, col, buffer, npixels); +} +# endif + +# ifdef CONFIG_LCD_ILI9341_IFACE1 +static int ili9341_getrun1(fb_coord_t row, fb_coord_t col, + FAR uint8_t * buffer, size_t npixels) +{ + return ili9341_getrun(1, row, col, buffer, npixels); +} +# endif +#endif + + +/******************************************************************************* + * Name: ili9341_getvideoinfo + * + * Description: + * Get information about the LCD video controller configuration. + * + * Parameter: + * dev - A reference to the driver specific structure + * vinfo - A reference to the videoinfo structure + * + * Returned Value: + * + * On success - OK + * On error - -EINVAL + * + ******************************************************************************/ + +static int ili9341_getvideoinfo(FAR struct lcd_dev_s *dev, + FAR struct fb_videoinfo_s *vinfo) +{ + if (dev && vinfo) + { + FAR struct ili9341_dev_s *priv = (FAR struct ili9341_dev_s *)dev; + + vinfo->fmt = priv->pxfmt; + vinfo->xres = ili9341_getxres(priv); + vinfo->yres = ili9341_getyres(priv); + vinfo->nplanes = 1; + + lcdvdbg("fmt: %d xres: %d yres: %d nplanes: %d\n", + vinfo->fmt, vinfo->xres, vinfo->yres, vinfo->nplanes); + + return OK; + } + + return -EINVAL; +} + +/******************************************************************************* + * Name: ili9341_getplaneinfo + * + * Description: + * Get information about the configuration of each LCD color plane. + * + * Parameter: + * dev - A reference to the driver specific structure + * planeno - The plane number + * pinfo - A reference to the planeinfo structure + * + * Returned Value: + * + * On success - OK + * On error - -EINVAL + * + ******************************************************************************/ + +static int ili9341_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, + FAR struct lcd_planeinfo_s *pinfo) +{ + if (dev && pinfo && planeno == 0) + { + FAR struct ili9341_dev_s *priv = (FAR struct ili9341_dev_s *)dev; + + pinfo->putrun = priv->putrun; +#ifndef CONFIG_LCD_NOGETRUN + pinfo->getrun = priv->getrun; +#endif + pinfo->bpp = priv->bpp; + pinfo->buffer = (uint8_t*)priv->runbuffer; /* Run scratch buffer */ + + lcdvdbg("planeno: %d bpp: %d\n", planeno, pinfo->bpp); + + return OK; + } + + return -EINVAL; +} + +/******************************************************************************* + * Name: ili9341_getpower + * + * Description: + * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on. + * On backlit LCDs, this setting may correspond to the backlight setting. + * + * Parameter: + * dev - A reference to the driver specific structure + * + * Returned Value: + * + * On success - OK + * On error - -EINVAL + * + ******************************************************************************/ + +static int ili9341_getpower(FAR struct lcd_dev_s *dev) +{ + FAR struct ili9341_dev_s *priv = (FAR struct ili9341_dev_s *)dev; + + if (priv) + { + lcddbg("%d\n", priv->power); + + return priv->power; + } + + return -EINVAL; +} + +/******************************************************************************* + * Name: ili9341_setpower + * + * Description: + * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). + * On backlight LCDs, this setting may correspond to the backlight setting. + * + * Parameter: + * dev - A reference to the driver specific structure + * power - Value of the power + * + * Returned Value: + * + * On success - OK + * On error - -EINVAL + * + ******************************************************************************/ + +static int ili9341_setpower(FAR struct lcd_dev_s *dev, int power) +{ + FAR struct ili9341_dev_s *priv = (FAR struct ili9341_dev_s *)dev; + FAR struct ili9341_lcd_s *lcd = priv->lcd; + + if (dev) + { + lcddbg("%d\n", power); + + lcd->select(lcd); + + if (power > 0) + { + /* Set backlight level */ + + lcd->backlight(lcd, power); + + /* And switch LCD on */ + + lcd->sendcmd(lcd, ILI9341_DISPLAY_ON); + up_mdelay(120); + } + else + { + /* Switch LCD off */ + + lcd->sendcmd(lcd, ILI9341_DISPLAY_OFF); + } + + lcd->deselect(lcd); + + priv->power = power; + + return OK; + } + + return -EINVAL; +} + +/******************************************************************************* + * Name: ili9341_getcontrast + * + * Description: + * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST). + * + * Parameter: + * dev - A reference to the lcd driver structure + * + * Returned Value: + * + * On success - current contrast value + * On error - -ENOSYS, not supported by the ili9341. + * + ******************************************************************************/ + +static int ili9341_getcontrast(struct lcd_dev_s *dev) +{ + lcdvdbg("Not implemented\n"); + return -ENOSYS; +} + +/******************************************************************************* + * Name: ili9341_setcontrast + * + * Description: + * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST). + * + * Parameter: + * dev - A reference to the lcd driver structure + * + * Returned Value: + * + * On success - OK + * On error - -ENOSYS, not supported by the ili9341. + * + ******************************************************************************/ + +static int ili9341_setcontrast(struct lcd_dev_s *dev, unsigned int contrast) +{ + lcdvdbg("contrast: %d\n", contrast); + return -ENOSYS; +} + + +/******************************************************************************* + * Name: ili9341_initialize + * + * Description: + * Initialize the LCD video driver internal sturcture. Also initialize the + * lcd hardware if not done. The control of the LCD driver is depend on the + * selected MCU interface and part of the platform specific subdriver (see + * config/stm32f429i-disco/src/stm32_ili93414ws.c) + * + * Input Parameters: + * + * lcd - A reference to the platform specific driver instance to control the + * ili9341 display driver. + * devno - A value in the range of 0 through CONFIG_ILI9341_NINTERFACES-1. + * This allows support for multiple LCD devices. + * + * Returned Value: + * + * On success, this function returns a reference to the LCD driver object for + * the specified LCD driver. NULL is returned on any failure. + * + ******************************************************************************/ + +FAR struct lcd_dev_s *ili9341_initialize( + FAR struct ili9341_lcd_s *lcd, int devno) +{ + if (lcd && devno >= 0 && devno < CONFIG_LCD_ILI9341_NINTERFACES) + { + FAR struct ili9341_dev_s *priv = &g_lcddev[devno]; + + /* Check if initialized */ + + if (!priv->lcd) + { + FAR struct lcd_dev_s *dev = &priv->dev; + int ret; + + /* Initialize internal structure */ + + dev->getvideoinfo = ili9341_getvideoinfo; + dev->getplaneinfo = ili9341_getplaneinfo; + dev->getpower = ili9341_getpower; + dev->setpower = ili9341_setpower; + dev->getcontrast = ili9341_getcontrast; + dev->setcontrast = ili9341_setcontrast; + priv->lcd = lcd; + + /* Initialze the LCD driver */ + + ret = ili9341_hwinitialize(priv); + + if (ret == OK) + { + return &priv->dev; + } + + errno = EINVAL; + } + } + + return NULL; +} + + +/****************************************************************************** + * Name: ili9341_clear + * + * Description: + * This is a non-standard LCD interface. Because of the various rotations, + * clearing the display in the normal way by writing a sequences of runs that + * covers the entire display can be very slow. Here the display is cleared by + * simply setting all GRAM memory to the specified color. + * + * Parameter: + * dev - A reference to the lcd driver structure + * color - The background color + * + * Returned Value: + * + * On success - OK + * On error - -EINVAL + * + ******************************************************************************/ + +int ili9341_clear(FAR struct lcd_dev_s *dev, uint16_t color) +{ + FAR struct ili9341_dev_s *priv = (FAR struct ili9341_dev_s *)dev; + FAR struct ili9341_lcd_s *lcd = priv->lcd; + uint16_t xres = ili9341_getxres(priv); + uint16_t yres = ili9341_getyres(priv); + uint32_t n; + + if (!lcd) + { + return -EINVAL; + } + + /* Select lcd driver */ + + lcd->select(lcd); + + /* Select column and area similar to the visible area */ + + ili9341_selectarea(lcd, 0, 0, xres, yres); + + /* Send memory write cmd */ + + lcd->sendcmd(lcd, ILI9341_MEMORY_WRITE); + + /* clear the visible area */ + + for (n = 0; n < xres * yres; n++) + { + /* Send pixel to gram */ + + lcd->sendgram(lcd, &color, 1); + } + + /* Deselect the lcd driver */ + + lcd->deselect(lcd); + + return OK; +}