feat(driver): add ST7735, ST7789, ST7796, ILI9341 display drivers (#5020)

Co-authored-by: Zoltan Janosy <zjanosy@fishman.com>
Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
This commit is contained in:
Zoltan Janosy
2024-01-12 10:25:07 +01:00
committed by GitHub
parent ff9e63a393
commit a61e51f579
20 changed files with 2074 additions and 4 deletions

View File

@@ -0,0 +1,212 @@
=================================================
Generic MIPI DCS compatible LCD Controller driver
=================================================
Overview
-------------
From the `Wikipedia <https://en.wikipedia.org/wiki/MIPI_Alliance>`__:
`MIPI Allience <https://www.mipi.org/>`__ is a global business alliance that develops technical specifications
for the mobile ecosystem, particularly smart phones but including mobile-influenced industries. MIPI was founded in 2003 by Arm, Intel, Nokia, Samsung,
STMicroelectronics and Texas Instruments.
MIPI Allience published a series of specifications related to display devices, including DBI (Display Bus Interface), DSI (Display Serial Interface) and DCS
Display Command Set). Usually when one talks about a MIPI-compatible display, one thinks of a device with a DSI serial interface. However, the DBI specification
includes a number of other, legacy interfaces, like SPI and a 8080-compatible parallel interface, which are often used to interface LCD displays to microcontrollers.
Furthermore, the DCS specification contains a standard command set, which is supported by a large number of legacy TFT LCD controllers, including the popular Sitronix
(ST7735, ST7789, ST7796) and Ilitek (ILI9341) SOCs.
The DCS command set provides a common interface to configure display orientation, color resolution, various power modes, and provide generic video memory access. On top
of that standard command set each LCD controller chip has a number of vendor-specific commands to configure voltage generator levels, timings, or gamma curves.
It is important to understand that this generic MIPI LCD driver is not a hardware driver for displays with DSI interface. Instead, it implements the MIPI DCS command
set, and provides a common framework for chip-specific display controllers.
.. tip::
Although this is a generic driver, it can be used to support compatible chips which do not have a specific driver.
Prerequisites
-------------
There are no prerequisites.
Configuring the driver
----------------------
Enable the generic MIPI LCD driver support in lv_conf.h, by cmake compiler define or by KConfig
.. code:: c
#define LV_USE_GENERIC_MIPI 1
.. note::
:c:macro:`LV_USE_GENERIC_MIPI` is automatically enabled when a compatible driver is enabled.
Usage
-----
You need to implement two platform-dependent functions:
.. code:: c
/* Send short command to the LCD. This function shall wait until the transaction finishes. */
int32_t my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
{
...
}
/* Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. This function can do the transfer in the background. */
int32_t my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
{
...
}
The only difference between the :cpp:func:`my_lcd_send_cmd()` and :cpp:func:`my_lcd_send_color()` functions is that :cpp:func:`my_lcd_send_cmd()` is used to send short commands and it is expected
complete the transaction when it returns (in other words, it should be blocking), while :cpp:func:`my_lcd_send_color()` is only used to send pixel data, and it is recommended to use
DMA to transmit data in the background. More sophisticated methods can be also implemented, like queing transfers and scheduling them in the background.
Please note that while display flushing is handled by the driver, it is the user's responsibility to call :cpp:func:`lv_display_flush_ready()`
when the color transfer completes. In case of a DMA transfer this is usually done in a transfer ready callback.
.. note::
While it is acceptable to use a blocking implementation for the pixel transfer as well, performance will suffer.
.. tip::
Care must be taken to avoid sending a command while there is an active transfer going on in the background. It is the user's responsibility to implement this either
by polling the hardware, polling a global variable (which is reset at the end of the transfer), or by using a semaphore or other locking mechanism.
Please also note that the driver does not handle the draw buffer allocation, because this may be platform-dependent, too. Thus you need to allocate the buffers and assign them
to the display object as usual by calling :cpp:func:`lv_display_set_draw_buffers()`.
The driver can be used to create multiple displays. In such a configuration the callbacks must be able to distinguish between the displays. Usually one would
implement a separate set of callbacks for each display. Also note that the user must take care of arbitrating the bus when multiple devices are connected to it.
Example
-------
.. note::
You can find the actual implementation of the callbacks on an STM32F746 using STM32CubeIDE and the ST HAL libraries
`here <https://github.com/lvgl/lvgl/doc/integration/drivers/display/lcd_stm32_hal.rst>`__.
.. code:: c
#include "src/dev/display/st7789/lv_st7789.h"
#define LCD_H_RES 240
#define LCD_V_RES 320
#define LCD_BUF_LINES 60
lv_display_t *my_disp;
...
/* Initialize LCD I/O bus, reset LCD */
static int32_t my_lcd_io_init(void)
{
...
return HAL_OK;
}
/* Send command to the LCD controller */
static void my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
{
...
}
/* Send pixel data to the LCD controller */
static void my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
{
...
}
int main(int argc, char ** argv)
{
...
/* Initialize LVGL */
lv_init();
/* Initialize LCD bus I/O */
if (my_lcd_io_init() != 0)
return;
/* Create the LVGL display object and the LCD display driver */
my_disp = lv_lcd_generic_mipi_create(LCD_H_RES, LCD_V_RES, LV_LCD_FLAG_NONE, my_lcd_send_cmd, my_lcd_send_color);
/* Set display orientation to landscape */
lv_display_set_rotation(my_disp, LV_DISPLAY_ROTATION_90);
/* Configure draw buffers, etc. */
lv_color_t * buf1 = NULL;
lv_color_t * buf2 = NULL;
uint32_t buf_size = LCD_H_RES * LCD_BUF_LINES * lv_color_format_get_size(lv_disp_get_color_format(my_disp));
buf1 = lv_malloc(buf_size);
if(buf1 == NULL) {
LV_LOG_ERROR("display draw buffer malloc failed");
return;
}
/* Allocate secondary buffer if needed */
...
lv_display_set_buffers(my_disp, buf1, buf2, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
ui_init(my_disp);
while(true) {
...
/* Periodically call the lv_timer handler */
lv_timer_handler();
}
}
Advanced topics
---------------
Create flags
^^^^^^^^^^^^
The third argument of the :cpp:func:`lv_lcd_generic_mipi_create()` function is a flag array. This can be used to configure the orientation and RGB ordering of the panel if the
default settings do not work for you. In particular, the generic MIPI driver accepts the following flags:
.. code:: c
LV_LCD_FLAG_NONE
LV_LCD_FLAG_MIRROR_X
LV_LCD_FLAG_MIRROR_Y
LV_LCD_FLAG_BGR
You can pass multiple flags by ORing them together, e.g., :c:macro:`LV_LCD_FLAG_MIRROR_X | LV_LCD_FLAG_BGR`.
Custom command lists
^^^^^^^^^^^^^^^^^^^^
While the chip-specific drivers do their best to initialize the LCD controller correctly, it is possible, that different TFT panels need different configurations.
In particular a correct gamma setup is crucial for good color reproduction. Unfortunately, finding a good set of parameters is not easy. Usually the manufacturer
of the panel provides some example code with recommended register settings.
You can use the ``my_lcd_send_cmd()`` function to send an arbitrary command to the LCD controller. However, to make it easier to send a large number of parameters
the generic MIPI driver supports sending a custom command list to the controller. The commands must be put into a 'uint8_t' array:
.. code:: c
static const uint8_t init_cmd_list[] = {
<command 1>, <number of parameters>, <parameter 1>, ... <parameter N>,
<command 2>, <number of parameters>, <parameter 1>, ... <parameter N>,
...
LV_LCD_CMD_DELAY_MS, LV_LCD_CMD_EOF /* terminate list: this is required! */
};
...
lv_lcd_generic_mipi_send_cmd_list(my_disp, init_cmd_list);
You can add a delay between the commands by using the pseudo-command ``LV_LCD_CMD_DELAY_MS``, which must be followed by the delay given in 10ms units.
To terminate the command list you must use a delay with a value of ``LV_LCD_CMD_EOF``, as shown above.
See an actual example of sending a command list `here <https://github.com/lvgl/lvgl/src/dev/display/st7789/lv_st7789.c>`__.

View File

@@ -1,5 +1,68 @@
======= =============================
ILI9341 ILI9341 LCD Controller driver
======= =============================
TODO Overview
-------------
The `ILI9341 <https://www.buydisplay.com/download/ic/ILI9341.pdf>`__ is a 262,144-color single-chip SOC driver for a-TFT liquid crystal display with resolution of 240RGBx320
dots, comprising a 720-channel source driver, a 320-channel gate driver, 172,800 bytes GRAM for graphic
display data of 240RGBx320 dots, and power supply circuit.
ILI9341 supports parallel 8-/9-/16-/18-bit data bus MCU interface, 6-/16-/18-bit data bus RGB interface and
3-/4-line serial peripheral interface (SPI).
The ILI9341 LCD controller `driver <https://github.com/lvgl/lvgl/src/dev/display/ili9341>`__ is a platform-agnostic driver, based on the `generic MIPI driver <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
It implements display initialization, supports display rotation and implements the display flush callback. The user needs to implement only two platform-specific functions to send
a command or pixel data to the controller via SPI or parallel bus. Typically these are implemented by calling the appropriate SDK library functions on the given platform.
Prerequisites
-------------
There are no prerequisites.
Configuring the driver
----------------------
Enable the ILI9341 driver support in lv_conf.h, by cmake compiler define or by KConfig
.. code:: c
#define LV_USE_ILI9341 1
Usage
-----
You need to implement two platform-dependent functions:
.. code:: c
/* Send short command to the LCD. This function shall wait until the transaction finishes. */
int32_t my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
{
...
}
/* Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. This function can do the transfer in the background. */
int32_t my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
{
...
}
To create an ILI9341-based display use the function
.. code:: c
/**
* Create an LCD display with ILI9341 driver
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
* @return pointer to the created display
*/
lv_display_t * lv_ili9341_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_ili9341_send_cmd_cb_t send_cmd_cb, lv_ili9341_send_color_cb_t send_color_cb);
For additional details and a working example see the `generic MIPI driver documentation <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.

View File

@@ -6,3 +6,6 @@ Display
:maxdepth: 2 :maxdepth: 2
ili9341 ili9341
st7735
st7789
st7796

View File

@@ -0,0 +1,109 @@
==================================================================================================
LCD driver SPI bus I/O implementation example for STM32 devices using the STM32Cube HAL SPI driver
==================================================================================================
This is an example implementation of an SPI bus driver using STM32CubeIDE and the ST HAL libraries, tested on a Nucleo-F746ZG board. This code example only implements
the LCD driver specific parts, so you still have to configure the hardware using STM32CubeMX or STM32CubeIDE. It is not meant as the best possible implementation,
but since it uses DMA for the pixel transfer, it has a good performance.
To use this code without change you need to name the appropriate GPIO pins as follows:
.. code:: c
LCD_RESET /* Reset */
LCD_CS /* Chip Select */
LCD_DCX /* Data/Command Select */
The example code uses the SPI1 port. The SPI controller of the STM32F746 is capable of 16-bit transfers, and it can swap the 16-bit pixel data bytes on the fly, so
there is no need to do this in software. This improves the performance considerably.
This code implements a rather simple locking mechanism using a global variable :cpp:var:`my_disp_bus_busy` to prevent accessing the controller while there is a DMA transfer
going on in the background. In a more sophisticated implementation this could be replaced with a semaphore or a transaction queue.
.. code:: c
#include "stm32f7xx_hal.h"
#include "lvgl.h"
...
lv_display_t *my_disp;
volatile int my_disp_bus_busy = 0;
...
/* DMA transfer ready callback */
static void my_lcd_color_transfer_ready_cb(SPI_HandleTypeDef *hspi)
{
/* CS high */
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
my_disp_bus_busy = 0;
lv_display_flush_ready(my_disp);
}
/* Initialize LCD I/O bus, reset LCD */
static int32_t my_lcd_io_init(void)
{
/* Register SPI Tx Complete Callback */
HAL_SPI_RegisterCallback(&hspi1, HAL_SPI_TX_COMPLETE_CB_ID, stm32_lcd_color_transfer_ready_cb);
/* reset LCD */
HAL_GPIO_WritePin(LCD_RESET_GPIO_Port, LCD_RESET_Pin, GPIO_PIN_RESET);
HAL_Delay(100);
HAL_GPIO_WritePin(LCD_RESET_GPIO_Port, LCD_RESET_Pin, GPIO_PIN_SET);
HAL_Delay(100);
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET);
return HAL_OK;
}
/* Send short command to the LCD. This function shall wait until the transaction finishes. */
static void my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
{
LV_UNUSED(disp);
/* Set the SPI in 8-bit mode */
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
HAL_SPI_Init(&hspi1);
/* DCX low (command) */
HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_RESET);
/* CS low */
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
/* send command */
if (HAL_SPI_Transmit(&hspi1, cmd, cmd_size, BUS_SPI1_POLL_TIMEOUT) == HAL_OK) {
/* DCX high (data) */
HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET);
/* for short data blocks we use polling transfer */
HAL_SPI_Transmit(&hspi1, (uint8_t *)param, (uint16_t)param_size, BUS_SPI1_POLL_TIMEOUT);
/* CS high */
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
}
}
/* Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. This function can do the transfer in the background. */
static void my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
{
LV_UNUSED(disp);
while (my_disp_bus_busy); /* wait until previous transfer is finished */
/* Set the SPI in 8-bit mode */
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
HAL_SPI_Init(&hspi1);
/* DCX low (command) */
HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_RESET);
/* CS low */
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
/* send command */
if (HAL_SPI_Transmit(&hspi1, cmd, cmd_size, BUS_SPI1_POLL_TIMEOUT) == HAL_OK) {
/* DCX high (data) */
HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET);
/* for color data use DMA transfer */
/* Set the SPI in 16-bit mode to match endianess */
hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
HAL_SPI_Init(&hspi1);
my_disp_bus_busy = 1;
HAL_SPI_Transmit_DMA(&hspi1, param, (uint16_t)param_size / 2);
/* NOTE: CS will be reset in the transfer ready callback */
}
}

View File

@@ -0,0 +1,70 @@
=============================
ST7735 LCD Controller driver
=============================
Overview
-------------
The `ST7735S <https://www.buydisplay.com/download/ic/ST7735S.pdf>`__ is a single-chip controller/driver for 262K-color, graphic type TFT-LCD. It consists of 396
source line and 162 gate line driving circuits. This chip is capable of connecting directly to an external
microprocessor, and accepts Serial Peripheral Interface (SPI), 8-bit/9-bit/16-bit/18-bit parallel interface.
Display data can be stored in the on-chip display data RAM of 132 x 162 x 18 bits. It can perform display data
RAM read/write operation with no external operation clock to minimize power consumption. In addition,
because of the integrated power supply circuits necessary to drive liquid crystal, it is possible to make a
display system with fewer components.
The ST7735 LCD controller `driver <https://github.com/lvgl/lvgl/src/dev/display/st7735>`__ is a platform-agnostic driver, based on the `generic MIPI driver <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
It implements display initialization, supports display rotation and implements the display flush callback. The user needs to implement only two platform-specific functions to send
a command or pixel data to the controller via SPI or parallel bus. Typically these are implemented by calling the appropriate SDK library functions on the given platform.
Prerequisites
-------------
There are no prerequisites.
Configuring the driver
----------------------
Enable the ST7735 driver support in lv_conf.h, by cmake compiler define or by KConfig
.. code:: c
#define LV_USE_ST7735 1
Usage
-----
You need to implement two platform-dependent functions:
.. code:: c
/* Send short command to the LCD. This function shall wait until the transaction finishes. */
int32_t my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
{
...
}
/* Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. This function can do the transfer in the background. */
int32_t my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
{
...
}
To create an ST7735-based display use the function
.. code:: c
/**
* Create an LCD display with ST7735 driver
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
* @return pointer to the created display
*/
lv_display_t * lv_st7735_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7735_send_cmd_cb_t send_cmd_cb, lv_st7735_send_color_cb_t send_color_cb);
For additional details and a working example see the `generic MIPI driver documentation <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.

View File

@@ -0,0 +1,69 @@
=============================
ST7789 LCD Controller driver
=============================
Overview
-------------
The `ST7789 <https://www.buydisplay.com/download/ic/ST7789.pdf>`__ is a single-chip controller/driver for 262K-color, graphic type TFT-LCD. It consists of 720
source line and 320 gate line driving circuits. This chip is capable of connecting directly to an external
microprocessor, and accepts, 8-bits/9-bits/16-bits/18-bits parallel interface. Display data can be stored in the
on-chip display data RAM of 240x320x18 bits. It can perform display data RAM read/write operation with no
external operation clock to minimize power consumption. In addition, because of the integrated power supply
circuit necessary to drive liquid crystal; it is possible to make a display system with the fewest components.
The ST7789 LCD controller `driver <https://github.com/lvgl/lvgl/src/dev/display/st7789>`__ is a platform-agnostic driver, based on the `generic MIPI driver <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
It implements display initialization, supports display rotation and implements the display flush callback. The user needs to implement only two platform-specific functions to send
a command or pixel data to the controller via SPI or parallel bus. Typically these are implemented by calling the appropriate SDK library functions on the given platform.
Prerequisites
-------------
There are no prerequisites.
Configuring the driver
----------------------
Enable the ST7789 driver support in lv_conf.h, by cmake compiler define or by KConfig
.. code:: c
#define LV_USE_ST7789 1
Usage
-----
You need to implement two platform-dependent functions:
.. code:: c
/* Send short command to the LCD. This function shall wait until the transaction finishes. */
int32_t my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
{
...
}
/* Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. This function can do the transfer in the background. */
int32_t my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
{
...
}
To create an ST7789-based display use the function
.. code:: c
/**
* Create an LCD display with ST7789 driver
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
* @return pointer to the created display
*/
lv_display_t * lv_st7789_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7789_send_cmd_cb_t send_cmd_cb, lv_st7789_send_color_cb_t send_color_cb);
For additional details and a working example see the `generic MIPI driver documentation <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.

View File

@@ -0,0 +1,70 @@
=============================
ST7796 LCD Controller driver
=============================
Overview
-------------
The `ST7796S <https://www.buydisplay.com/download/ic/ST7796S.pdf>`__ is a single-chip controller/driver for 262K-color, graphic type TFT-LCD. It consists of 960
source lines and 480 gate lines driving circuits. The ST7796S is capable of connecting directly to an external
microprocessor, and accepts 8-bit/9-bit/16-bit/18-bit parallel interface, SPI, and the ST7796S also provides
MIPI interface. Display data can be stored in the on-chip display data RAM of 320x480x18 bits. It can perform
display data RAM read-/write-operation with no external clock to minimize power consumption. In addition,
because of the integrated power supply circuit necessary to drive liquid crystal; it is possible to make a display
system with fewest components.
The ST7796 LCD controller `driver <https://github.com/lvgl/lvgl/src/dev/display/st7796>`__ is a platform-agnostic driver, based on the `generic MIPI driver <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.
It implements display initialization, supports display rotation and implements the display flush callback. The user needs to implement only two platform-specific functions to send
a command or pixel data to the controller via SPI or parallel bus. Typically these are implemented by calling the appropriate SDK library functions on the given platform.
Prerequisites
-------------
There are no prerequisites.
Configuring the driver
----------------------
Enable the ST7796 driver support in lv_conf.h, by cmake compiler define or by KConfig
.. code:: c
#define LV_USE_ST7796 1
Usage
-----
You need to implement two platform-dependent functions:
.. code:: c
/* Send short command to the LCD. This function shall wait until the transaction finishes. */
int32_t my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
{
...
}
/* Send large array of pixel data to the LCD. If necessary, this function has to do the byte-swapping. This function can do the transfer in the background. */
int32_t my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
{
...
}
To create an ST7796-based display use the function
.. code:: c
/**
* Create an LCD display with ST7796 driver
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
* @return pointer to the created display
*/
lv_display_t * lv_st7796_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7796_send_cmd_cb_t send_cmd_cb, lv_st7796_send_color_cb_t send_color_cb);
For additional details and a working example see the `generic MIPI driver documentation <https://github.com/lvgl/lvgl/doc/integration/drivers/display/gen_mipi.rst>`__.

View File

@@ -856,6 +856,15 @@
/*Driver for evdev input devices*/ /*Driver for evdev input devices*/
#define LV_USE_EVDEV 0 #define LV_USE_EVDEV 0
/*Drivers for LCD devices connected via SPI/parallel port*/
#define LV_USE_ST7735 0
#define LV_USE_ST7789 0
#define LV_USE_ST7796 0
#define LV_USE_ILI9341 0
#define LV_USE_GENERIC_MIPI (LV_USE_ST7735 | LV_USE_ST7789 | LV_USE_ST7796 | LV_USE_ILI9341)
/*================== /*==================
* EXAMPLES * EXAMPLES
*==================*/ *==================*/

View File

@@ -0,0 +1,117 @@
/**
* @file lv_ili9341.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_ili9341.h"
#if LV_USE_ILI9341
/*********************
* DEFINES
*********************/
#define CMD_FRMCTR1 0xB1 /* Frame Rate Control (In Normal Mode/Full Colors) */
#define CMD_FRMCTR2 0xB2 /* Frame Rate Control (In Idle Mode/8 colors) */
#define CMD_FRMCTR3 0xB3 /* Frame Rate control (In Partial Mode/Full Colors) */
#define CMD_INVCTR 0xB4 /* Display Inversion Control */
#define CMD_DFUNCTR 0xB6 /* Display Function Control */
#define CMD_PWCTR1 0xC0 /* Power Control 1 */
#define CMD_PWCTR2 0xC1 /* Power Control 2 */
#define CMD_VMCTR1 0xC5 /* VCOM Control 1 */
#define CMD_VMCTR2 0xC7 /* VCOM Control 2 */
#define CMD_PWCTRA 0xCB /* Power Control A */
#define CMD_PWCTRB 0xCF /* Power Control B */
#define CMD_GMCTRP1 0xE0 /* Positive Gamma Correction */
#define CMD_GMCTRN1 0xE1 /* Negative Gamma Correction */
#define CMD_DTCTRA 0xE8 /* Driver timing control A */
#define CMD_DTCTRB 0xEA /* Driver timing control B */
#define CMD_PONSEQ 0xED /* Power On Sequence */
#define CMD_RDINDEX 0xD9 /* ili9341 */
#define CMD_IDXRD 0xDD /* ILI9341 only, indexed control register read */
#define CMD_ENA3G 0xF2 /* Enable 3 Gamma control */
#define CMD_IFCTR 0xF6 /* Interface Control */
#define CMD_PRCTR 0xF7 /* Pump ratio control */
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC CONSTANTS
**********************/
/* init commands based on LovyanGFX ILI9341 driver */
static const uint8_t init_cmd_list[] = {
CMD_PWCTRB, 3, 0x00, 0xC1, 0x30,
CMD_PONSEQ, 4, 0x64, 0x03, 0x12, 0x81,
CMD_DTCTRA, 3, 0x85, 0x00, 0x78,
CMD_PWCTRA, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
CMD_PRCTR, 1, 0x20,
CMD_DTCTRB, 2, 0x00, 0x00,
CMD_PWCTR1, 1, 0x23,
CMD_PWCTR2, 1, 0x10,
CMD_VMCTR1, 2, 0x3e, 0x28,
CMD_VMCTR2, 1, 0x86,
CMD_FRMCTR1, 2, 0x00, 0x13,
CMD_DFUNCTR, 2, 0x0A, 0xA2,
CMD_IFCTR, 3, 0x09, 0x30, 0x00,
CMD_ENA3G, 1, 0x00,
LV_LCD_CMD_SET_GAMMA_CURVE, 1, 0x01,
CMD_GMCTRP1, 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
CMD_GMCTRN1, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
LV_LCD_CMD_DELAY_MS, LV_LCD_CMD_EOF
};
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_ili9341_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_ili9341_send_cmd_cb_t send_cmd_cb, lv_ili9341_send_color_cb_t send_color_cb)
{
lv_display_t * disp = lv_lcd_generic_mipi_create(hor_res, ver_res, flags, send_cmd_cb, send_color_cb);
lv_lcd_generic_mipi_send_cmd_list(disp, init_cmd_list);
return disp;
}
void lv_ili9341_set_gap(lv_display_t * disp, uint16_t x, uint16_t y)
{
lv_lcd_generic_mipi_set_gap(disp, x, y);
}
void lv_ili9341_set_invert(lv_display_t * disp, bool invert)
{
lv_lcd_generic_mipi_set_invert(disp, invert);
}
void lv_ili9341_set_gamma_curve(lv_display_t * disp, uint8_t gamma)
{
lv_lcd_generic_mipi_set_gamma_curve(disp, gamma);
}
void lv_ili9341_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list)
{
lv_lcd_generic_mipi_send_cmd_list(disp, cmd_list);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_ILI9341*/

View File

@@ -0,0 +1,93 @@
/*
* lv_ili9341.h
*
* This driver is just a wrapper around the generic MIPI compatible LCD controller driver
*
*/
#ifndef LV_ILI9341_H
#define LV_ILI9341_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lcd/lv_lcd_generic_mipi.h"
#if LV_USE_ILI9341
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef lv_lcd_send_cmd_cb_t lv_ili9341_send_cmd_cb_t;
typedef lv_lcd_send_color_cb_t lv_ili9341_send_color_cb_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create an LCD display with ILI9341 driver
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
* @return pointer to the created display
*/
lv_display_t * lv_ili9341_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_ili9341_send_cmd_cb_t send_cmd_cb, lv_ili9341_send_color_cb_t send_color_cb);
/**
* Set gap, i.e., the offset of the (0,0) pixel in the VRAM
* @param disp display object
* @param x x offset
* @param y y offset
*/
void lv_ili9341_set_gap(lv_display_t * disp, uint16_t x, uint16_t y);
/**
* Set color inversion
* @param disp display object
* @param invert false: normal, true: invert
*/
void lv_ili9341_set_invert(lv_display_t * disp, bool invert);
/**
* Set gamma curve
* @param disp display object
* @param gamma gamma curve
*/
void lv_ili9341_set_gamma_curve(lv_display_t * disp, uint8_t gamma);
/**
* Send list of commands.
* @param disp display object
* @param cmd_list controller and panel-specific commands
*/
void lv_ili9341_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list);
/**********************
* OTHERS
**********************/
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_USE_ILI9341*/
#endif /* LV_ILI9341_H */

View File

@@ -0,0 +1,340 @@
/**
* @file lv_lcd_generic_mipi.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_lcd_generic_mipi.h"
#if LV_USE_GENERIC_MIPI
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void send_cmd(lv_lcd_generic_mipi_driver_t * drv, uint8_t cmd, uint8_t * param, size_t param_size);
static void send_color(lv_lcd_generic_mipi_driver_t * drv, uint8_t cmd, uint8_t * param, size_t param_size);
static void init(lv_lcd_generic_mipi_driver_t * drv, lv_lcd_flag_t flags);
static void set_mirror(lv_lcd_generic_mipi_driver_t * drv, bool mirror_x, bool mirror_y);
static void set_swap_xy(lv_lcd_generic_mipi_driver_t * drv, bool swap);
static void set_rotation(lv_lcd_generic_mipi_driver_t * drv, lv_display_rotation_t rot);
static void res_chg_event_cb(lv_event_t * e);
static lv_lcd_generic_mipi_driver_t * get_driver(lv_display_t * disp);
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_lcd_generic_mipi_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_lcd_send_cmd_cb_t send_cmd_cb, lv_lcd_send_color_cb_t send_color_cb)
{
lv_display_t * disp = lv_display_create(hor_res, ver_res);
if(disp == NULL) {
return NULL;
}
lv_lcd_generic_mipi_driver_t * drv = (lv_lcd_generic_mipi_driver_t *)lv_malloc(sizeof(lv_lcd_generic_mipi_driver_t));
if(drv == NULL) {
lv_display_delete(disp);
return NULL;
}
/* init driver struct */
drv->disp = disp;
drv->send_cmd = send_cmd_cb;
drv->send_color = send_color_cb;
lv_display_set_driver_data(disp, (void *)drv);
/* init controller */
init(drv, flags);
/* register resolution change callback (NOTE: this handles screen rotation as well) */
lv_display_add_event_cb(disp, res_chg_event_cb, LV_EVENT_RESOLUTION_CHANGED, NULL);
/* register flush callback */
lv_display_set_flush_cb(disp, flush_cb);
return disp;
}
void lv_lcd_generic_mipi_set_gap(lv_display_t * disp, uint16_t x, uint16_t y)
{
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
drv->x_gap = x;
drv->y_gap = y;
}
void lv_lcd_generic_mipi_set_invert(lv_display_t * disp, bool invert)
{
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
send_cmd(drv, invert ? LV_LCD_CMD_ENTER_INVERT_MODE : LV_LCD_CMD_EXIT_INVERT_MODE, NULL, 0);
}
void lv_lcd_generic_mipi_set_address_mode(lv_display_t * disp, bool mirror_x, bool mirror_y, bool swap_xy, bool bgr)
{
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
uint8_t mad = drv->madctl_reg & ~(LV_LCD_MASK_RGB_ORDER);
if(bgr) {
mad |= LV_LCD_BIT_RGB_ORDER__BGR;
}
drv->madctl_reg = mad;
drv->mirror_x = mirror_x;
drv->mirror_y = mirror_y;
drv->swap_xy = swap_xy;
set_rotation(drv, lv_display_get_rotation(disp)); /* update screen */
}
void lv_lcd_generic_mipi_set_gamma_curve(lv_display_t * disp, uint8_t gamma)
{
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
send_cmd(drv, LV_LCD_CMD_SET_GAMMA_CURVE, (uint8_t[]) {
gamma,
}, 1);
}
void lv_lcd_generic_mipi_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list)
{
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
while(1) {
uint8_t cmd = *cmd_list++;
uint8_t num = *cmd_list++;
if(cmd == LV_LCD_CMD_DELAY_MS) {
if(num == LV_LCD_CMD_EOF) /* end of list */
break;
else { /* delay in 10 ms units*/
lv_delay_ms((uint32_t)(num) * 10);
}
}
else {
drv->send_cmd(drv->disp, &cmd, 1, cmd_list, num);
cmd_list += num;
}
}
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Helper function to call the user-supplied 'send_cmd' function
* @param drv LCD driver object
* @param cmd command byte
* @param param parameter buffer
* @param param_size number of bytes of the parameters
*/
static void send_cmd(lv_lcd_generic_mipi_driver_t * drv, uint8_t cmd, uint8_t * param, size_t param_size)
{
uint8_t cmdbuf = cmd; /* MIPI uses 8 bit commands */
drv->send_cmd(drv->disp, &cmdbuf, 1, param, param_size);
}
/**
* Helper function to call the user-supplied 'send_color' function
* @param drv LCD driver object
* @param cmd command byte
* @param param parameter buffer
* @param param_size number of bytes of the parameters
*/
static void send_color(lv_lcd_generic_mipi_driver_t * drv, uint8_t cmd, uint8_t * param, size_t param_size)
{
uint8_t cmdbuf = cmd; /* MIPI uses 8 bit commands */
drv->send_color(drv->disp, &cmdbuf, 1, param, param_size);
}
/**
* Initialize LCD driver after a hard reset
* @param drv LCD driver object
*/
static void init(lv_lcd_generic_mipi_driver_t * drv, lv_lcd_flag_t flags)
{
drv->x_gap = 0;
drv->y_gap = 0;
/* init color mode and RGB order */
drv->madctl_reg = flags & LV_LCD_FLAG_BGR ? LV_LCD_BIT_RGB_ORDER__BGR : LV_LCD_BIT_RGB_ORDER__RGB;
drv->colmod_reg = flags & LV_LCD_FLAG_RGB666 ? LV_LCD_PIXEL_FORMAT_RGB666 : LV_LCD_PIXEL_FORMAT_RGB565;
/* init orientation */
drv->mirror_x = flags & LV_LCD_FLAG_MIRROR_X;
drv->mirror_y = flags & LV_LCD_FLAG_MIRROR_Y;
drv->swap_xy = false;
/* update madctl_reg */
set_swap_xy(drv, drv->swap_xy);
set_mirror(drv, drv->mirror_x, drv->mirror_y);
/* enter sleep mode first */
send_cmd(drv, LV_LCD_CMD_ENTER_SLEEP_MODE, NULL, 0);
lv_delay_ms(10);
/* perform software reset */
send_cmd(drv, LV_LCD_CMD_SOFT_RESET, NULL, 0);
lv_delay_ms(200);
/* LCD goes into sleep mode and display will be turned off after power on reset, exit sleep mode first */
send_cmd(drv, LV_LCD_CMD_EXIT_SLEEP_MODE, NULL, 0);
lv_delay_ms(300);
send_cmd(drv, LV_LCD_CMD_ENTER_NORMAL_MODE, NULL, 0);
send_cmd(drv, LV_LCD_CMD_SET_ADDRESS_MODE, (uint8_t[]) {
drv->madctl_reg,
}, 1);
send_cmd(drv, LV_LCD_CMD_SET_PIXEL_FORMAT, (uint8_t[]) {
drv->colmod_reg,
}, 1);
send_cmd(drv, LV_LCD_CMD_SET_DISPLAY_ON, NULL, 0);
}
/**
* Set readout directions (used for rotating the display)
* @param drv LCD driver object
* @param mirror_x false: normal, true: mirrored
* @param mirror_y false: normal, true: mirrored
*/
static void set_mirror(lv_lcd_generic_mipi_driver_t * drv, bool mirror_x, bool mirror_y)
{
uint8_t mad = drv->madctl_reg & ~(LV_LCD_MASK_COLUMN_ADDRESS_ORDER | LV_LCD_MASK_PAGE_ADDRESS_ORDER);
if(mirror_x) {
mad |= LV_LCD_BIT_COLUMN_ADDRESS_ORDER__RTOL;
}
if(mirror_y) {
mad |= LV_LCD_BIT_PAGE_ADDRESS_ORDER__BTOT;
}
drv->madctl_reg = mad;
}
/**
* Swap horizontal and vertical readout (used for rotating the display)
* @param drv LCD driver object
* @param swap false: normal, true: swapped
*/
static void set_swap_xy(lv_lcd_generic_mipi_driver_t * drv, bool swap)
{
uint8_t mad = drv->madctl_reg & ~(LV_LCD_MASK_PAGE_COLUMN_ORDER);
if(swap) {
mad |= LV_LCD_BIT_PAGE_COLUMN_ORDER__REVERSE;
}
drv->madctl_reg = mad;
}
/**
* Flush display buffer to the LCD
* @param disp display object
* @param hor_res horizontal resolution
* @param area area stored in the buffer
* @param px_map buffer containing pixel data
* @note transfers pixel data to the LCD controller using the callbacks 'send_cmd' and 'send_color', which were
* passed to the 'lv_st7789_create()' function
*/
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
{
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
int32_t x_start = area->x1;
int32_t x_end = area->x2 + 1;
int32_t y_start = area->y1;
int32_t y_end = area->y2 + 1;
LV_ASSERT((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position");
x_start += drv->x_gap;
x_end += drv->x_gap;
y_start += drv->y_gap;
y_end += drv->y_gap;
/* define an area of frame memory where MCU can access */
send_cmd(drv, LV_LCD_CMD_SET_COLUMN_ADDRESS, (uint8_t[]) {
(x_start >> 8) & 0xFF,
x_start & 0xFF,
((x_end - 1) >> 8) & 0xFF,
(x_end - 1) & 0xFF,
}, 4);
send_cmd(drv, LV_LCD_CMD_SET_PAGE_ADDRESS, (uint8_t[]) {
(y_start >> 8) & 0xFF,
y_start & 0xFF,
((y_end - 1) >> 8) & 0xFF,
(y_end - 1) & 0xFF,
}, 4);
/* transfer frame buffer */
size_t len = (x_end - x_start) * (y_end - y_start) * lv_color_format_get_size(lv_display_get_color_format(disp));
send_color(drv, LV_LCD_CMD_WRITE_MEMORY_START, px_map, len);
}
/**
* Set rotation taking into account the current mirror and swap settings
* @param drv LCD driver object
* @param rot rotation
*/
static void set_rotation(lv_lcd_generic_mipi_driver_t * drv, lv_display_rotation_t rot)
{
switch(rot) {
case LV_DISPLAY_ROTATION_0:
set_swap_xy(drv, drv->swap_xy);
set_mirror(drv, drv->mirror_x, drv->mirror_y);
break;
case LV_DISPLAY_ROTATION_90:
set_swap_xy(drv, !drv->swap_xy);
set_mirror(drv, !drv->mirror_x, drv->mirror_y);
break;
case LV_DISPLAY_ROTATION_180:
set_swap_xy(drv, drv->swap_xy);
set_mirror(drv, !drv->mirror_x, !drv->mirror_y);
break;
case LV_DISPLAY_ROTATION_270:
set_swap_xy(drv, !drv->swap_xy);
set_mirror(drv, drv->mirror_x, !drv->mirror_y);
break;
}
send_cmd(drv, LV_LCD_CMD_SET_ADDRESS_MODE, (uint8_t[]) {
drv->madctl_reg
}, 1);
}
/**
* Handle LV_EVENT_RESOLUTION_CHANGED event (handles both resolution and rotation change)
* @param e LV_EVENT_RESOLUTION_CHANGED event
*/
static void res_chg_event_cb(lv_event_t * e)
{
lv_display_t * disp = lv_event_get_target(e);
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
uint16_t hor_res = lv_display_get_horizontal_resolution(disp);
uint16_t ver_res = lv_display_get_vertical_resolution(disp);
lv_display_rotation_t rot = lv_display_get_rotation(disp);
/* TODO: implement resolution change */
LV_UNUSED(hor_res);
LV_UNUSED(ver_res);
/* handle rotation */
set_rotation(drv, rot);
}
static lv_lcd_generic_mipi_driver_t * get_driver(lv_display_t * disp)
{
return (lv_lcd_generic_mipi_driver_t *)lv_display_get_driver_data(disp);
}
#endif /*LV_USE_GENERIC_MIPI*/

View File

@@ -0,0 +1,241 @@
/*
* lv_lcd_generic_mipi.h
*
* Generic driver for controllers adhering to the MIPI DBI/DCS specification
*
* Works with:
*
* ST7735
* ST7789
* ST7796
* ILI9341
* ILI9488 (NOTE: in SPI mode ILI9488 only supports RGB666 mode, which is currently not supported)
*
* any probably many more
*
*/
#ifndef LV_LCD_GENERIC_MIPI_H
#define LV_LCD_GENERIC_MIPI_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../display/lv_display.h"
#if LV_USE_GENERIC_MIPI
/*********************
* DEFINES
*********************/
/* MIPI DCS (Display Command Set) v1.02.00 User Command Set */
#define LV_LCD_CMD_NOP 0x00 /* No Operation */
#define LV_LCD_CMD_SOFT_RESET 0x01 /* Software Reset */
#define LV_LCD_CMD_GET_POWER_MODE 0x0A /* Get the current power mode */
#define LV_LCD_CMD_GET_ADDRESS_MODE 0x0B /* Get the data order for transfers from the Host to the display module and from the frame memory to the display device */
#define LV_LCD_CMD_GET_PIXEL_FORMAT 0x0C /* Get the current pixel format */
#define LV_LCD_CMD_GET_DISPLAY_MODE 0x0D /* Get the current display mode from the peripheral */
#define LV_LCD_CMD_GET_SIGNAL_MODE 0x0E /* Get display module signaling mode */
#define LV_LCD_CMD_GET_DIAGNOSTIC_RESULT 0x0F /* Get Peripheral Self-Diagnostic Result */
#define LV_LCD_CMD_ENTER_SLEEP_MODE 0x10 /* Power for the display panel is off */
#define LV_LCD_CMD_EXIT_SLEEP_MODE 0x11 /* Power for the display panel is on */
#define LV_LCD_CMD_ENTER_PARTIAL_MODE 0x12 /* Part of the display area is used for image display */
#define LV_LCD_CMD_ENTER_NORMAL_MODE 0x13 /* The whole display area is used for image display */
#define LV_LCD_CMD_EXIT_INVERT_MODE 0x20 /* Displayed image colors are not inverted */
#define LV_LCD_CMD_ENTER_INVERT_MODE 0x21 /* Displayed image colors are inverted */
#define LV_LCD_CMD_SET_GAMMA_CURVE 0x26 /* Selects the gamma curve used by the display device */
#define LV_LCD_CMD_SET_DISPLAY_OFF 0x28 /* Blanks the display device */
#define LV_LCD_CMD_SET_DISPLAY_ON 0x29 /* Show the image on the display device */
#define LV_LCD_CMD_SET_COLUMN_ADDRESS 0x2A /* Set the column extent */
#define LV_LCD_CMD_SET_PAGE_ADDRESS 0x2B /* Set the page extent */
#define LV_LCD_CMD_WRITE_MEMORY_START 0x2C /* Transfer image data from the Host Processor to the peripheral starting at the location provided by set_column_address and set_page_address */
#define LV_LCD_CMD_READ_MEMORY_START 0x2E /* Transfer image data from the peripheral to the Host Processor interface starting at the location provided by set_column_address and set_page_address */
#define LV_LCD_CMD_SET_PARTIAL_ROWS 0x30 /* Defines the number of rows in the partial display area on the display device */
#define LV_LCD_CMD_SET_PARTIAL_COLUMNS 0x31 /* Defines the number of columns in the partial display area on the display device */
#define LV_LCD_CMD_SET_SCROLL_AREA 0x33 /* Defines the vertical scrolling and fixed area on display device */
#define LV_LCD_CMD_SET_TEAR_OFF 0x34 /* Synchronization information is not sent from the display module to the host processor */
#define LV_LCD_CMD_SET_TEAR_ON 0x35 /* Synchronization information is sent from the display module to the host processor at the start of VFP */
#define LV_LCD_CMD_SET_ADDRESS_MODE 0x36 /* Set the data order for transfers from the Host to the display module and from the frame memory to the display device */
#define LV_LCD_CMD_SET_SCROLL_START 0x37 /* Defines the vertical scrolling starting point */
#define LV_LCD_CMD_EXIT_IDLE_MODE 0x38 /* Full color depth is used on the display panel */
#define LV_LCD_CMD_ENTER_IDLE_MODE 0x39 /* Reduced color depth is used on the display panel */
#define LV_LCD_CMD_SET_PIXEL_FORMAT 0x3A /* Defines how many bits per pixel are used in the interface */
#define LV_LCD_CMD_WRITE_MEMORY_CONTINUE 0x3C /* Transfer image information from the Host Processor interface to the peripheral from the last written location */
#define LV_LCD_CMD_READ_MEMORY_CONTINUE 0x3E /* Read image data from the peripheral continuing after the last read_memory_continue or read_memory_start */
#define LV_LCD_CMD_SET_TEAR_SCANLINE 0x44 /* Synchronization information is sent from the display module to the host processor when the display device refresh reaches the provided scanline */
#define LV_LCD_CMD_GET_SCANLINE 0x45 /* Get the current scanline */
#define LV_LCD_CMD_READ_DDB_CONTINUE 0xA8 /* Continue reading the DDB from the last read location */
#define LV_LCD_CMD_READ_DDB_START 0xA1 /* Read the DDB from the provided location */
/* address mode flag masks */
#define LV_LCD_MASK_FLIP_VERTICAL (1 << 0) /* This bit flips the image shown on the display device top to bottom. No change is made to the frame memory */
#define LV_LCD_MASK_FLIP_HORIZONTAL (1 << 1) /* This bit flips the image shown on the display device left to right. No change is made to the frame memory */
#define LV_LCD_MASK_DATA_LATCH_DATA_ORDER (1 << 2) /* Display Data Latch Order */
#define LV_LCD_MASK_RGB_ORDER (1 << 3) /* RGB/BGR Order */
#define LV_LCD_MASK_LINE_ADDRESS_ORDER (1 << 4) /* Line Address Order */
#define LV_LCD_MASK_PAGE_COLUMN_ORDER (1 << 5) /* Page/Column Order */
#define LV_LCD_MASK_COLUMN_ADDRESS_ORDER (1 << 6) /* Column Address Order */
#define LV_LCD_MASK_PAGE_ADDRESS_ORDER (1 << 7) /* Page Address Order */
#define LV_LCD_BIT_FLIP_VERTICAL__NOT_FLIPPED 0
#define LV_LCD_BIT_FLIP_VERTICAL__FLIPPED LV_LCD_MASK_FLIP_VERTICAL /* This bit flips the image shown on the display device top to bottom. No change is made to the frame memory */
#define LV_LCD_BIT_FLIP_HORIZONTAL__NOT_FLIPPED 0
#define LV_LCD_BIT_FLIP_HORIZONTAL__FLIPPED LV_LCD_MASK_FLIP_HORIZONTAL /* This bit flips the image shown on the display device left to right. No change is made to the frame memory */
#define LV_LCD_BIT_DATA_LATCH_DATA_ORDER__LTOR 0 /* Display Data Latch Order: LCD Refresh Left to Right */
#define LV_LCD_BIT_DATA_LATCH_DATA_ORDER__RTOL LV_LCD_MASK_DATA_LATCH_DATA_ORDER /* Display Data Latch Order: LCD Refresh Right to Left */
#define LV_LCD_BIT_RGB_ORDER__RGB 0 /* RGB/BGR Order: RGB */
#define LV_LCD_BIT_RGB_ORDER__BGR LV_LCD_MASK_RGB_ORDER /* RGB/BGR Order: BGR */
#define LV_LCD_BIT_LINE_ADDRESS_ORDER__TTOB 0 /* Line Address Order: LCD Refresh Top to Bottom */
#define LV_LCD_BIT_LINE_ADDRESS_ORDER__BTOT LV_LCD_MASK_LINE_ADDRESS_ORDER /* Line Address Order: LCD Refresh Botton to Top */
#define LV_LCD_BIT_PAGE_COLUMN_ORDER__NORMAL 0 /* Page/Column Order: Normal Mode */
#define LV_LCD_BIT_PAGE_COLUMN_ORDER__REVERSE LV_LCD_MASK_PAGE_COLUMN_ORDER /* Page/Column Order: Reverse Mode */
#define LV_LCD_BIT_COLUMN_ADDRESS_ORDER__LTOR 0 /* Column Address Order: Left to Right */
#define LV_LCD_BIT_COLUMN_ADDRESS_ORDER__RTOL LV_LCD_MASK_COLUMN_ADDRESS_ORDER /* Column Address Order: Right to Left */
#define LV_LCD_BIT_PAGE_ADDRESS_ORDER__TTOB 0 /* Page Address Order: Top to Bottom */
#define LV_LCD_BIT_PAGE_ADDRESS_ORDER__BTOT LV_LCD_MASK_PAGE_ADDRESS_ORDER /* Page Address Order: Bottom to Top */
/* predefined gamma curves */
#define LV_LCD_GAMMA_2_2 0x01 /* 2.2 */
#define LV_LCD_GAMMA_1_8 0x02 /* 1.8 */
#define LV_LCD_GAMMA_2_5 0x04 /* 2.5 */
#define LV_LCD_GAMMA_1_0 0x08 /* 1.0 */
/* common pixel formats */
#define LV_LCD_PIXEL_FORMAT_RGB565 0x55 /* bus: 16 bits, pixel: 16 bits */
#define LV_LCD_PIXEL_FORMAT_RGB666 0x66 /* bus: 18 bits, pixel: 18 bits */
/* flags for lv_lcd_xxx_create() */
#define LV_LCD_FLAG_NONE 0x00000000UL
#define LV_LCD_FLAG_MIRROR_X 0x00000001UL
#define LV_LCD_FLAG_MIRROR_Y 0x00000002UL
#define LV_LCD_FLAG_BGR 0x00000008UL
#define LV_LCD_FLAG_RGB666 0x00000010UL
/* command list */
#define LV_LCD_CMD_DELAY_MS 0xff
#define LV_LCD_CMD_EOF 0xff
/**********************
* TYPEDEFS
**********************/
/**
* Configuration flags for lv_lcd_xxx_create()
*
*/
typedef uint32_t lv_lcd_flag_t;
/**
* Prototype of a platform-dependent callback to transfer commands and data to the LCD controller.
* @param disp display object
* @param cmd command buffer (can handle 16 bit commands as well)
* @param cmd_size number of bytes of the command
* @param param parameter buffer
* @param param_size number of bytes of the parameters
*/
typedef void (*lv_lcd_send_cmd_cb_t)(lv_display_t * disp, const uint8_t * cmd, size_t cmd_size, const uint8_t * param,
size_t param_size);
/**
* Prototype of a platform-dependent callback to transfer pixel data to the LCD controller.
* @param disp display object
* @param cmd command buffer (can handle 16 bit commands as well)
* @param cmd_size number of bytes of the command
* @param param parameter buffer
* @param param_size number of bytes of the parameters
*/
typedef void (*lv_lcd_send_color_cb_t)(lv_display_t * disp, const uint8_t * cmd, size_t cmd_size, uint8_t * param,
size_t param_size);
/**
* Generic MIPI compatible LCD driver
*/
typedef struct {
lv_display_t * disp; /* the associated LVGL display object */
lv_lcd_send_cmd_cb_t send_cmd; /* platform-specific implementation to send a command to the LCD controller */
lv_lcd_send_color_cb_t send_color; /* platform-specific implementation to send pixel data to the LCD controller */
uint16_t x_gap; /* x offset of the (0,0) pixel in VRAM */
uint16_t y_gap; /* y offset of the (0,0) pixel in VRAM */
uint8_t madctl_reg; /* current value of MADCTL register */
uint8_t colmod_reg; /* current value of COLMOD register */
bool mirror_x;
bool mirror_y;
bool swap_xy;
} lv_lcd_generic_mipi_driver_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a MIPI DCS compatible LCD display
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
* @return pointer to the created display
*/
lv_display_t * lv_lcd_generic_mipi_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_lcd_send_cmd_cb_t send_cmd_cb, lv_lcd_send_color_cb_t send_color_cb);
/**
* Set gap, i.e., the offset of the (0,0) pixel in the VRAM
* @param disp display object
* @param x x offset
* @param y y offset
*/
void lv_lcd_generic_mipi_set_gap(lv_display_t * disp, uint16_t x, uint16_t y);
/**
* Set color inversion
* @param disp display object
* @param invert false: normal, true: invert
*/
void lv_lcd_generic_mipi_set_invert(lv_display_t * disp, bool invert);
/**
* Set address mode
* @param disp display object
* @param mirror_x horizontal mirror (false: normal, true: mirrored)
* @param mirror_y vertical mirror (false: normal, true: mirrored)
* @param swap_xy swap axes (false: normal, true: swap)
* @param bgr RGB/BGR order (false: RGB, true: BGR)
*/
void lv_lcd_generic_mipi_set_address_mode(lv_display_t * disp, bool mirror_x, bool mirror_y, bool swap_xy, bool bgr);
/**
* Set gamma curve
* @param disp display object
* @param gamma gamma curve
*/
void lv_lcd_generic_mipi_set_gamma_curve(lv_display_t * disp, uint8_t gamma);
/**
* Send list of commands.
* @param disp display object
* @param cmd_list controller and panel-specific commands
*/
void lv_lcd_generic_mipi_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list);
/**********************
* OTHERS
**********************/
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_USE_GENERIC_MIPI*/
#endif /* LV_LCD_GENERIC_MIPI_H */

View File

@@ -0,0 +1,113 @@
/**
* @file lv_st7735.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_st7735.h"
#if LV_USE_ST7735
/*********************
* DEFINES
*********************/
#define CMD_GAMSET 0x26
#define CMD_FRMCTR1 0xB1
#define CMD_FRMCTR2 0xB2
#define CMD_FRMCTR3 0xB3
#define CMD_INVCTR 0xB4
#define CMD_DISSET5 0xB6
#define CMD_PWCTR1 0xC0
#define CMD_PWCTR2 0xC1
#define CMD_PWCTR3 0xC2
#define CMD_PWCTR4 0xC3
#define CMD_PWCTR5 0xC4
#define CMD_VMCTR1 0xC5
#define CMD_VMOFCTR 0xC7
#define CMD_NVFCTR1 0xD9
#define CMD_GMCTRP1 0xE0
#define CMD_GMCTRN1 0xE1
#define CMD_PWCTR6 0xFC
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC CONSTANTS
**********************/
/* init commands for buydisplay.com ER-TFTM018-3 */
static const uint8_t init_cmd_list[] = {
0xB1, 3, 0x05, 0x3C, 0x3C,
0xB2, 3, 0x05, 0x3C, 0x3C,
0xB3, 6, 0x05, 0x3C, 0x3C, 0x05, 0x3C, 0x3C,
0xB4, 1, 0x03,
0xC0, 3, 0x28, 0x08, 0x04,
0xC1, 1, 0XC0,
0xC2, 2, 0x0D, 0x00,
0xC3, 2, 0x8D, 0x2A,
0xC4, 2, 0x8D, 0xEE,
0xC5, 1, 0x10,
0xE0, 16, 0x04, 0x22, 0x07, 0x0A, 0x2E, 0x30, 0x25, 0x2A, 0x28, 0x26, 0x2E, 0x3A, 0x00, 0x01, 0x03, 0x13,
0xE1, 16, 0x04, 0x16, 0x06, 0x0D, 0x2D, 0x26, 0x23, 0x27, 0x27, 0x25, 0x2D, 0x3B, 0x00, 0x01, 0x04, 0x13,
LV_LCD_CMD_DELAY_MS, LV_LCD_CMD_EOF
};
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_st7735_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7735_send_cmd_cb_t send_cmd_cb, lv_st7735_send_color_cb_t send_color_cb)
{
lv_display_t * disp = lv_lcd_generic_mipi_create(hor_res, ver_res, flags, send_cmd_cb, send_color_cb);
lv_lcd_generic_mipi_send_cmd_list(disp, init_cmd_list);
return disp;
}
void lv_st7735_set_gap(lv_display_t * disp, uint16_t x, uint16_t y)
{
lv_lcd_generic_mipi_set_gap(disp, x, y);
}
void lv_st7735_set_invert(lv_display_t * disp, bool invert)
{
lv_lcd_generic_mipi_set_invert(disp, invert);
}
void lv_st7735_set_gamma_curve(lv_display_t * disp, uint8_t gamma)
{
lv_lcd_generic_mipi_set_gamma_curve(disp, gamma);
}
void lv_st7735_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list)
{
lv_lcd_generic_mipi_send_cmd_list(disp, cmd_list);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_ST7735*/

View File

@@ -0,0 +1,93 @@
/*
* lv_st7735.h
*
* This driver is just a wrapper around the generic MIPI compatible LCD controller driver
*
*/
#ifndef LV_ST7735_H
#define LV_ST7735_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lcd/lv_lcd_generic_mipi.h"
#if LV_USE_ST7735
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef lv_lcd_send_cmd_cb_t lv_st7735_send_cmd_cb_t;
typedef lv_lcd_send_color_cb_t lv_st7735_send_color_cb_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create an LCD display with ST7735 driver
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
* @return pointer to the created display
*/
lv_display_t * lv_st7735_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7735_send_cmd_cb_t send_cmd_cb, lv_st7735_send_color_cb_t send_color_cb);
/**
* Set gap, i.e., the offset of the (0,0) pixel in the VRAM
* @param disp display object
* @param x x offset
* @param y y offset
*/
void lv_st7735_set_gap(lv_display_t * disp, uint16_t x, uint16_t y);
/**
* Set color inversion
* @param disp display object
* @param invert false: normal, true: invert
*/
void lv_st7735_set_invert(lv_display_t * disp, bool invert);
/**
* Set gamma curve
* @param disp display object
* @param gamma gamma curve
*/
void lv_st7735_set_gamma_curve(lv_display_t * disp, uint8_t gamma);
/**
* Send list of commands.
* @param disp display object
* @param cmd_list controller and panel-specific commands
*/
void lv_st7735_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list);
/**********************
* OTHERS
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_ST7735*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /* LV_ST7735_H */

View File

@@ -0,0 +1,116 @@
/**
* @file lv_st7789.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_st7789.h"
#if LV_USE_ST7789
/*********************
* DEFINES
*********************/
#define CMD_FRMCTR1 0xB1
#define CMD_FRMCTR2 0xB2
#define CMD_FRMCTR3 0xB3
#define CMD_INVCTR 0xB4
#define CMD_DFUNCTR 0xB6
#define CMD_ETMOD 0xB7
#define CMD_PWCTR1 0xC0
#define CMD_PWCTR2 0xC1
#define CMD_PWCTR3 0xC2
#define CMD_PWCTR4 0xC3
#define CMD_PWCTR5 0xC4
#define CMD_VMCTR 0xC5
#define CMD_GMCTRP1 0xE0
#define CMD_GMCTRN1 0xE1
#define CMD_DOCA 0xE8
#define CMD_CSCON 0xF0
#define CMD_RAMCTRL 0xB0
#define CMD_PORCTRL 0xB2 /* Porch control */
#define CMD_GCTRL 0xB7 /* Gate control */
#define CMD_VCOMS 0xBB /* VCOMS setting */
#define CMD_LCMCTRL 0xC0 /* LCM control */
#define CMD_VDVVRHEN 0xC2 /* VDV and VRH command enable */
#define CMD_VRHS 0xC3 /* VRH set */
#define CMD_VDVSET 0xC4 /* VDV setting */
#define CMD_FRCTR2 0xC6 /* FR Control 2 */
#define CMD_PWCTRL1 0xD0 /* Power control 1 */
#define CMD_PVGAMCTRL 0xE0 /* Positive Gamma Correction */
#define CMD_NVGAMCTRL 0xE1 /* Negative Gamma Correction */
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC CONSTANTS
**********************/
/* init commands based on LovyanGFX ST7789 driver */
static const uint8_t init_cmd_list[] = {
CMD_GCTRL, 1, 0x44, /* GCTRL -- panel dependent */
CMD_VCOMS, 1, 0x24, /* VCOMS -- panel dependent */
CMD_VRHS, 1, 0x13, /* VRHS - panel dependent */
CMD_PWCTRL1, 2, 0xa4, 0xa1,
CMD_RAMCTRL, 2, 0x00, 0xC0, /* controls mapping of RGB565 to RGB666 */
CMD_PVGAMCTRL, 14, 0xd0, 0x00, 0x02, 0x07, 0x0a, 0x28, 0x32, 0x44, 0x42, 0x06, 0x0e, 0x12, 0x14, 0x17,
CMD_NVGAMCTRL, 14, 0xd0, 0x00, 0x02, 0x07, 0x0a, 0x28, 0x31, 0x54, 0x47, 0x0e, 0x1c, 0x17, 0x1b, 0x1e,
LV_LCD_CMD_SET_GAMMA_CURVE, 1, 0x01,
LV_LCD_CMD_DELAY_MS, LV_LCD_CMD_EOF
};
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_st7789_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7789_send_cmd_cb_t send_cmd_cb, lv_st7789_send_color_cb_t send_color_cb)
{
lv_display_t * disp = lv_lcd_generic_mipi_create(hor_res, ver_res, flags, send_cmd_cb, send_color_cb);
lv_lcd_generic_mipi_send_cmd_list(disp, init_cmd_list);
return disp;
}
void lv_st7789_set_gap(lv_display_t * disp, uint16_t x, uint16_t y)
{
lv_lcd_generic_mipi_set_gap(disp, x, y);
}
void lv_st7789_set_invert(lv_display_t * disp, bool invert)
{
lv_lcd_generic_mipi_set_invert(disp, invert);
}
void lv_st7789_set_gamma_curve(lv_display_t * disp, uint8_t gamma)
{
lv_lcd_generic_mipi_set_gamma_curve(disp, gamma);
}
void lv_st7789_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list)
{
lv_lcd_generic_mipi_send_cmd_list(disp, cmd_list);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_ST7789*/

View File

@@ -0,0 +1,93 @@
/*
* lv_st7789.h
*
* This driver is just a wrapper around the generic MIPI compatible LCD controller driver
*
*/
#ifndef LV_ST7789_H
#define LV_ST7789_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lcd/lv_lcd_generic_mipi.h"
#if LV_USE_ST7789
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef lv_lcd_send_cmd_cb_t lv_st7789_send_cmd_cb_t;
typedef lv_lcd_send_color_cb_t lv_st7789_send_color_cb_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create an LCD display with ST7789 driver
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
* @return pointer to the created display
*/
lv_display_t * lv_st7789_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7789_send_cmd_cb_t send_cmd_cb, lv_st7789_send_color_cb_t send_color_cb);
/**
* Set gap, i.e., the offset of the (0,0) pixel in the VRAM
* @param disp display object
* @param x x offset
* @param y y offset
*/
void lv_st7789_set_gap(lv_display_t * disp, uint16_t x, uint16_t y);
/**
* Set color inversion
* @param disp display object
* @param invert false: normal, true: invert
*/
void lv_st7789_set_invert(lv_display_t * disp, bool invert);
/**
* Set gamma curve
* @param disp display object
* @param gamma gamma curve
*/
void lv_st7789_set_gamma_curve(lv_display_t * disp, uint8_t gamma);
/**
* Send list of commands.
* @param disp display object
* @param cmd_list controller and panel-specific commands
*/
void lv_st7789_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list);
/**********************
* OTHERS
**********************/
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_USE_ST7789*/
#endif //LV_ST7789_H

View File

@@ -0,0 +1,122 @@
/**
* @file lv_st7796.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_st7796.h"
#if LV_USE_ST7796
/*********************
* DEFINES
*********************/
#define CMD_FRMCTR1 0xB1
#define CMD_FRMCTR2 0xB2
#define CMD_FRMCTR3 0xB3
#define CMD_INVCTR 0xB4
#define CMD_DFUNCTR 0xB6
#define CMD_ETMOD 0xB7
#define CMD_PWCTR1 0xC0
#define CMD_PWCTR2 0xC1
#define CMD_PWCTR3 0xC2
#define CMD_PWCTR4 0xC3
#define CMD_PWCTR5 0xC4
#define CMD_VMCTR 0xC5
#define CMD_GMCTRP1 0xE0
#define CMD_GMCTRN1 0xE1
#define CMD_DOCA 0xE8
#define CMD_CSCON 0xF0
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC CONSTANTS
**********************/
/* init commands based on LovyanGFX */
static const uint8_t init_cmd_list[] = {
CMD_CSCON, 1, 0xC3, /* Enable extension command 2 partI */
CMD_CSCON, 1, 0x96, /* Enable extension command 2 partII */
CMD_INVCTR, 1, 0x01, /* 1-dot inversion */
CMD_DFUNCTR, 3, 0x80, /* Display Function Control: Bypass */
0x22, /* Source Output Scan from S1 to S960, Gate Output scan from G1 to G480, scan cycle = 2 */
0x3B, /* LCD Drive Line = 8 * (59 + 1) */
CMD_DOCA, 8, 0x40, 0x8A, 0x00, 0x00,
0x29, /* Source equalizing period time = 22.5 us */
0x19, /* Timing for "Gate start" = 25 (Tclk) */
0xA5, /* Timing for "Gate End" = 37 (Tclk), Gate driver EQ function ON */
0x33,
CMD_PWCTR2, 1, 0x06, /* Power control2: VAP(GVDD) = 3.85 + (vcom + vcom offset), VAN(GVCL) = -3.85 + (vcom + vcom offset) */
CMD_PWCTR3, 1, 0xA7, /* Power control 3: Source driving current level = low, Gamma driving current level = High */
CMD_VMCTR, 1, 0x18, /* VCOM Control: VCOM = 0.9 */
LV_LCD_CMD_DELAY_MS, 12, /* delay 120 ms */
CMD_GMCTRP1, 14, /* Gamma */
0xF0, 0x09, 0x0B, 0x06, 0x04, 0x15, 0x2F,
0x54, 0x42, 0x3C, 0x17, 0x14, 0x18, 0x1B,
CMD_GMCTRN1, 14,
0xE0, 0x09, 0x0B, 0x06, 0x04, 0x03, 0x2B,
0x43, 0x42, 0x3B, 0x16, 0x14, 0x17, 0x1B,
LV_LCD_CMD_DELAY_MS, 12, /* delay 120 ms */
CMD_CSCON, 1, 0x3C, /* Disable extension command 2 partI */
CMD_CSCON, 1, 0x69, /* Disable extension command 2 partII */
LV_LCD_CMD_DELAY_MS, LV_LCD_CMD_EOF
};
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_st7796_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7796_send_cmd_cb_t send_cmd_cb, lv_st7796_send_color_cb_t send_color_cb)
{
lv_display_t * disp = lv_lcd_generic_mipi_create(hor_res, ver_res, flags, send_cmd_cb, send_color_cb);
lv_lcd_generic_mipi_send_cmd_list(disp, init_cmd_list);
return disp;
}
void lv_st7796_set_gap(lv_display_t * disp, uint16_t x, uint16_t y)
{
lv_lcd_generic_mipi_set_gap(disp, x, y);
}
void lv_st7796_set_invert(lv_display_t * disp, bool invert)
{
lv_lcd_generic_mipi_set_invert(disp, invert);
}
void lv_st7796_set_gamma_curve(lv_display_t * disp, uint8_t gamma)
{
/* NOTE: the generic method is not supported on ST7796, TODO: implement gamma tables */
LV_UNUSED(disp);
LV_UNUSED(gamma);
}
void lv_st7796_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list)
{
lv_lcd_generic_mipi_send_cmd_list(disp, cmd_list);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_ST7796*/

View File

@@ -0,0 +1,93 @@
/*
* lv_st7796.h
*
* This driver is just a wrapper around the generic MIPI compatible LCD controller driver
*
*/
#ifndef LV_ST7796_H
#define LV_ST7796_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lcd/lv_lcd_generic_mipi.h"
#if LV_USE_ST7796
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef lv_lcd_send_cmd_cb_t lv_st7796_send_cmd_cb_t;
typedef lv_lcd_send_color_cb_t lv_st7796_send_color_cb_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create an LCD display with ST7796 driver
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
* @return pointer to the created display
*/
lv_display_t * lv_st7796_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7796_send_cmd_cb_t send_cmd_cb, lv_st7796_send_color_cb_t send_color_cb);
/**
* Set gap, i.e., the offset of the (0,0) pixel in the VRAM
* @param disp display object
* @param x x offset
* @param y y offset
*/
void lv_st7796_set_gap(lv_display_t * disp, uint16_t x, uint16_t y);
/**
* Set color inversion
* @param disp display object
* @param invert false: normal, true: invert
*/
void lv_st7796_set_invert(lv_display_t * disp, bool invert);
/**
* Set gamma curve
* @param disp display object
* @param gamma gamma curve
*/
void lv_st7796_set_gamma_curve(lv_display_t * disp, uint8_t gamma);
/**
* Send list of commands.
* @param disp display object
* @param cmd_list controller and panel-specific commands
*/
void lv_st7796_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list);
/**********************
* OTHERS
**********************/
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_USE_ST7796*/
#endif /* LV_ST7796_H */

View File

@@ -2826,6 +2826,45 @@
#endif #endif
#endif #endif
/*Drivers for LCD devices connected via SPI/parallel port*/
#ifndef LV_USE_ST7735
#ifdef CONFIG_LV_USE_ST7735
#define LV_USE_ST7735 CONFIG_LV_USE_ST7735
#else
#define LV_USE_ST7735 0
#endif
#endif
#ifndef LV_USE_ST7789
#ifdef CONFIG_LV_USE_ST7789
#define LV_USE_ST7789 CONFIG_LV_USE_ST7789
#else
#define LV_USE_ST7789 0
#endif
#endif
#ifndef LV_USE_ST7796
#ifdef CONFIG_LV_USE_ST7796
#define LV_USE_ST7796 CONFIG_LV_USE_ST7796
#else
#define LV_USE_ST7796 0
#endif
#endif
#ifndef LV_USE_ILI9341
#ifdef CONFIG_LV_USE_ILI9341
#define LV_USE_ILI9341 CONFIG_LV_USE_ILI9341
#else
#define LV_USE_ILI9341 0
#endif
#endif
#ifndef LV_USE_GENERIC_MIPI
#ifdef CONFIG_LV_USE_GENERIC_MIPI
#define LV_USE_GENERIC_MIPI CONFIG_LV_USE_GENERIC_MIPI
#else
#define LV_USE_GENERIC_MIPI (LV_USE_ST7735 | LV_USE_ST7789 | LV_USE_ST7796 | LV_USE_ILI9341)
#endif
#endif
/*================== /*==================
* EXAMPLES * EXAMPLES
*==================*/ *==================*/

View File

@@ -99,6 +99,11 @@
#define LV_CACHE_DEF_SIZE (10 * 1024 * 1024) #define LV_CACHE_DEF_SIZE (10 * 1024 * 1024)
#define LV_USE_ILI9341 1
#define LV_USE_ST7735 1
#define LV_USE_ST7789 1
#define LV_USE_ST7796 1
#define LV_USE_FREETYPE 1 #define LV_USE_FREETYPE 1
#define LV_FREETYPE_CACHE_SIZE 768 #define LV_FREETYPE_CACHE_SIZE 768
#define LV_FREETYPE_USE_LVGL_PORT 0 #define LV_FREETYPE_USE_LVGL_PORT 0