diff --git a/docs/src/details/integration/external_display_controllers/index.rst b/docs/src/details/integration/external_display_controllers/index.rst index 38050c5de3..38b6ce4a92 100644 --- a/docs/src/details/integration/external_display_controllers/index.rst +++ b/docs/src/details/integration/external_display_controllers/index.rst @@ -13,3 +13,4 @@ Display Controller Support st7735 st7789 st7796 + nv3007 diff --git a/docs/src/details/integration/external_display_controllers/nv3007.rst b/docs/src/details/integration/external_display_controllers/nv3007.rst new file mode 100644 index 0000000000..0e0c6b4736 --- /dev/null +++ b/docs/src/details/integration/external_display_controllers/nv3007.rst @@ -0,0 +1,182 @@ +============================= +NV3007 LCD Controller driver +============================= + +Overview +-------- + +The `NV3007 `__ is a single-chip driver for 262,144-color, a-Si TFT liquid crystal display +with maximum resolution of 168RGBx428 dots. It contains 252-channel source driver, +a 24-channel GIP driver which used for dual-gate control, 161,784-byte GRAM for +graphic display data, internal precise power supply circuit which supports full color, +8-color display mode and sleep mode +NV3007 supports 3-/4-line serial peripheral interface (SPI) , quad serial +peripheral interface (QSPI). The display area can be specified in internal GRAM by +window address function. + +The NV3007 LCD controller `driver `__ is a platform-agnostic driver, based on the `generic MIPI driver `__. +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 NV3007 driver support in lv_conf.h, by cmake compiler define or by KConfig + +.. code-block:: c + + #define LV_USE_NV3007 1 + +Usage +----- + +You need to implement two platform-dependent functions: + +.. code-block:: c + + /* Send short command to the LCD. This function shall wait until the transaction finishes. */ + 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 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. */ + void 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 NV3007-based display use the function + +.. code-block:: c + + /** + * Create an LCD display with NV3007 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_nv3007_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags, + lv_nv3007_send_cmd_cb_t send_cmd_cb, lv_nv3007_send_color_cb_t send_color_cb); + + +Arduino Example +--------------- + +Here is a simple example of using the NV3007 display with Arduino framework and SPI interface: + +.. code-block:: cpp + + #include + + /* Platform-specific includes */ + #include + + #define LCD_DC 21 + #define LCD_CS 5 + #define LCD_RST 4 + #define LCD_SCK 18 + #define LCD_MOSI 23 + #define LCD_MISO -1 + #define LCD_BL 15 + #define SPI_CLK 40000000 + + #define BUFFER_SIZE 142 * 50 + uint8_t buf[BUFFER_SIZE]; + + /* Define your platform-specific functions to send commands and data */ + 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) + { + SPI.beginTransaction(SPISettings(SPI_CLK, MSBFIRST, SPI_MODE0)); + /* Send command */ + digitalWrite(LCD_DC, LOW); /* command mode */ + digitalWrite(LCD_CS, LOW); /* CS low */ + SPI.transferBytes(cmd, NULL, cmd_size); + + /* Send parameters (if any) */ + if (param != NULL && param_size > 0) + { + digitalWrite(LCD_DC, HIGH); /* data mode */ + SPI.transferBytes(param, NULL, param_size); + } + digitalWrite(LCD_CS, HIGH); /* CS high */ + SPI.endTransaction(); + } + + void my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size) + { + SPI.beginTransaction(SPISettings(SPI_CLK, MSBFIRST, SPI_MODE0)); + digitalWrite(LCD_CS, LOW); + + /* Send the command first */ + digitalWrite(LCD_DC, LOW); + SPI.transferBytes(cmd, NULL, cmd_size); + + /* Then send the pixel data */ + if (param && param_size > 0) + { + digitalWrite(LCD_DC, HIGH); + SPI.transferBytes(param, NULL, param_size); + } + + digitalWrite(LCD_CS, HIGH); + SPI.endTransaction(); + + /* Important: signal LVGL that we're done */ + lv_display_flush_ready(disp); + } + + void setup() + { + + pinMode(LCD_BL, OUTPUT); + digitalWrite(LCD_BL, HIGH); /* turn on backlight */ + + pinMode(LCD_DC, OUTPUT); + pinMode(LCD_CS, OUTPUT); + pinMode(LCD_RST, OUTPUT); + /* reset sequence */ + digitalWrite(LCD_RST, HIGH); + delay(100); + digitalWrite(LCD_RST, LOW); + delay(120); + digitalWrite(LCD_RST, HIGH); + delay(120); + + SPI.begin(LCD_SCK, LCD_MISO, LCD_MOSI, LCD_CS); /* SCK, MISO, MOSI, SS */ + + digitalWrite(LCD_CS, HIGH); /* disable device */ + delay(100); /* wait for device to stabilize */ + + lv_init(); + + lv_tick_set_cb(my_tick); + + /* Create NV3007 display */ + lv_display_t *disp = lv_nv3007_create(142, 428, LV_LCD_FLAG_NONE, my_lcd_send_cmd, my_lcd_send_color); + lv_nv3007_set_gap(disp, 0, 14); + lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270); + lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565_SWAPPED); + lv_display_set_buffers(disp, buf, NULL, BUFFER_SIZE, LV_DISP_RENDER_MODE_PARTIAL); + + /* Create a simple label on the display */ + lv_obj_t *label = lv_label_create(lv_screen_active()); + lv_label_set_text(label, "Hello NV3007!"); + lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); + } + + void loop() + { + lv_task_handler(); + delay(5); + } + +For additional details and a working example see the `generic MIPI driver documentation `__. diff --git a/lv_conf_template.h b/lv_conf_template.h index b6672119ee..332d18b184 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -1332,8 +1332,9 @@ #define LV_USE_ST7796 0 #define LV_USE_ILI9341 0 #define LV_USE_FT81X 0 +#define LV_USE_NV3007 0 -#if (LV_USE_ST7735 | LV_USE_ST7789 | LV_USE_ST7796 | LV_USE_ILI9341) +#if (LV_USE_ST7735 | LV_USE_ST7789 | LV_USE_ST7796 | LV_USE_ILI9341 | LV_USE_NV3007) #define LV_USE_GENERIC_MIPI 1 #else #define LV_USE_GENERIC_MIPI 0 diff --git a/src/drivers/display/nv3007/lv_nv3007.c b/src/drivers/display/nv3007/lv_nv3007.c new file mode 100644 index 0000000000..5e96adc7e8 --- /dev/null +++ b/src/drivers/display/nv3007/lv_nv3007.c @@ -0,0 +1,226 @@ +/** + * @file lv_nv3007.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_nv3007.h" + +#if LV_USE_NV3007 + +/********************* + * DEFINES + *********************/ + +#define NV3007_SLPIN 0x10 +#define NV3007_SLPOUT 0x11 + +#define NV3007_INVOFF 0x20 +#define NV3007_INVON 0x21 +#define NV3007_DISPOFF 0x28 +#define NV3007_DISPON 0x29 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC CONSTANTS + **********************/ + +/* init commands based on ArduinoGFX NV3007 driver */ +static const uint8_t init_cmd_list[] = { + 0x9a, 1, 0x08, + 0x9b, 1, 0x08, + 0x9c, 1, 0xb0, + 0x9d, 1, 0x16, + 0x9e, 1, 0xc4, + 0x8f, 2, 0x55, 0x04, + 0x84, 1, 0x90, + 0x83, 1, 0x7b, + 0x85, 1, 0x33, + 0x60, 1, 0x00, + 0x70, 1, 0x00, + 0x61, 1, 0x02, + 0x71, 1, 0x02, + 0x62, 1, 0x04, + 0x72, 1, 0x04, + 0x6c, 1, 0x29, + 0x7c, 1, 0x29, + 0x6d, 1, 0x31, + 0x7d, 1, 0x31, + 0x6e, 1, 0x0f, + 0x7e, 1, 0x0f, + 0x66, 1, 0x21, + 0x76, 1, 0x21, + 0x68, 1, 0x3A, + 0x78, 1, 0x3A, + 0x63, 1, 0x07, + 0x73, 1, 0x07, + 0x64, 1, 0x05, + 0x74, 1, 0x05, + 0x65, 1, 0x02, + 0x75, 1, 0x02, + 0x67, 1, 0x23, + 0x77, 1, 0x23, + 0x69, 1, 0x08, + 0x79, 1, 0x08, + 0x6a, 1, 0x13, + 0x7a, 1, 0x13, + 0x6b, 1, 0x13, + 0x7b, 1, 0x13, + 0x6f, 1, 0x00, + 0x7f, 1, 0x00, + 0x50, 1, 0x00, + 0x52, 1, 0xd6, + 0x53, 1, 0x08, + 0x54, 1, 0x08, + 0x55, 1, 0x1e, + 0x56, 1, 0x1c, + + 0xa0, 3, 0x2b, 0x24, 0x00, + + 0xa1, 1, 0x87, + 0xa2, 1, 0x86, + 0xa5, 1, 0x00, + 0xa6, 1, 0x00, + 0xa7, 1, 0x00, + 0xa8, 1, 0x36, + 0xa9, 1, 0x7e, + 0xaa, 1, 0x7e, + 0xB9, 1, 0x85, + 0xBA, 1, 0x84, + 0xBB, 1, 0x83, + 0xBC, 1, 0x82, + 0xBD, 1, 0x81, + 0xBE, 1, 0x80, + 0xBF, 1, 0x01, + 0xC0, 1, 0x02, + 0xc1, 1, 0x00, + 0xc2, 1, 0x00, + 0xc3, 1, 0x00, + 0xc4, 1, 0x33, + 0xc5, 1, 0x7e, + 0xc6, 1, 0x7e, + 0xC8, 2, 0x33, 0x33, + 0xC9, 1, 0x68, + 0xCA, 1, 0x69, + 0xCB, 1, 0x6a, + 0xCC, 1, 0x6b, + 0xCD, 2, 0x33, 0x33, + 0xCE, 1, 0x6c, + 0xCF, 1, 0x6d, + 0xD0, 1, 0x6e, + 0xD1, 1, 0x6f, + 0xAB, 2, 0x03, 0x67, + 0xAC, 2, 0x03, 0x6b, + 0xAD, 2, 0x03, 0x68, + 0xAE, 2, 0x03, 0x6c, + 0xb3, 1, 0x00, + 0xb4, 1, 0x00, + 0xb5, 1, 0x00, + 0xB6, 1, 0x32, + 0xB7, 1, 0x7e, + 0xB8, 1, 0x7e, + 0xe0, 1, 0x00, + 0xe1, 2, 0x03, 0x0f, + 0xe2, 1, 0x04, + 0xe3, 1, 0x01, + 0xe4, 1, 0x0e, + 0xe5, 1, 0x01, + 0xe6, 1, 0x19, + 0xe7, 1, 0x10, + 0xe8, 1, 0x10, + 0xea, 1, 0x12, + 0xeb, 1, 0xd0, + 0xec, 1, 0x04, + 0xed, 1, 0x07, + 0xee, 1, 0x07, + 0xef, 1, 0x09, + 0xf0, 1, 0xd0, + 0xf1, 1, 0x0e, + 0xF9, 1, 0x17, + + 0xf2, 4, 0x2c, 0x1b, 0x0b, 0x20, + + 0xe9, 1, 0x29, + 0xec, 1, 0x04, + 0x35, 1, 0x00, + 0x44, 2, 0x00, 0x10, + 0x46, 1, 0x10, + + LV_LCD_CMD_DELAY_MS, LV_LCD_CMD_EOF +}; + +static const uint8_t init_cmd_list_2[] = { + 0x3a, 1, 0x05, + NV3007_SLPOUT, 0, + LV_LCD_CMD_DELAY_MS, 22, + NV3007_DISPON, 0, + + LV_LCD_CMD_DELAY_MS, LV_LCD_CMD_EOF +}; + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_display_t * lv_nv3007_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags, + lv_nv3007_send_cmd_cb_t send_cmd_cb, lv_nv3007_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); + + send_cmd_cb(disp, (const uint8_t[]) { + 0xFF + }, 1, (const uint8_t[]) { + 0xA5 + }, 1); + lv_lcd_generic_mipi_send_cmd_list(disp, init_cmd_list); + send_cmd_cb(disp, (const uint8_t[]) { + 0xFF + }, 1, (const uint8_t[]) { + 0x00 + }, 1); + lv_lcd_generic_mipi_send_cmd_list(disp, init_cmd_list_2); + return disp; +} + +void lv_nv3007_set_gap(lv_display_t * disp, uint16_t x, uint16_t y) +{ + lv_lcd_generic_mipi_set_gap(disp, x, y); +} + +void lv_nv3007_set_invert(lv_display_t * disp, bool invert) +{ + lv_lcd_generic_mipi_set_invert(disp, invert); +} + +void lv_nv3007_set_gamma_curve(lv_display_t * disp, uint8_t gamma) +{ + lv_lcd_generic_mipi_set_gamma_curve(disp, gamma); +} + +void lv_nv3007_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_NV3007*/ diff --git a/src/drivers/display/nv3007/lv_nv3007.h b/src/drivers/display/nv3007/lv_nv3007.h new file mode 100644 index 0000000000..9b5d581e6f --- /dev/null +++ b/src/drivers/display/nv3007/lv_nv3007.h @@ -0,0 +1,94 @@ +/** + * @file lv_nv3007.h + * + * This driver is just a wrapper around the generic MIPI compatible LCD controller driver + * + */ + +#ifndef LV_NV3007_H +#define LV_NV3007_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "../lcd/lv_lcd_generic_mipi.h" + +#if LV_USE_NV3007 + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef lv_lcd_send_cmd_cb_t lv_nv3007_send_cmd_cb_t; +typedef lv_lcd_send_color_cb_t lv_nv3007_send_color_cb_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create an LCD display with NV3007 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_nv3007_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags, + lv_nv3007_send_cmd_cb_t send_cmd_cb, lv_nv3007_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_nv3007_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_nv3007_set_invert(lv_display_t * disp, bool invert); + +/** + * Set gamma curve + * @param disp display object + * @param gamma gamma curve + */ +void lv_nv3007_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_nv3007_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list); + +/********************** + * OTHERS + **********************/ + +/********************** + * MACROS + **********************/ + + +#endif /*LV_USE_NV3007*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_NV3007_H*/ diff --git a/src/drivers/lv_drivers.h b/src/drivers/lv_drivers.h index 25a38f4baf..8cc91ce21a 100644 --- a/src/drivers/lv_drivers.h +++ b/src/drivers/lv_drivers.h @@ -31,6 +31,7 @@ extern "C" { #include "display/st7735/lv_st7735.h" #include "display/st7789/lv_st7789.h" #include "display/st7796/lv_st7796.h" +#include "display/nv3007/lv_nv3007.h" #include "display/renesas_glcdc/lv_renesas_glcdc.h" #include "display/st_ltdc/lv_st_ltdc.h" diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 2bf167e68a..d6bc01ce30 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -4301,8 +4301,15 @@ #define LV_USE_FT81X 0 #endif #endif +#ifndef LV_USE_NV3007 + #ifdef CONFIG_LV_USE_NV3007 + #define LV_USE_NV3007 CONFIG_LV_USE_NV3007 + #else + #define LV_USE_NV3007 0 + #endif +#endif -#if (LV_USE_ST7735 | LV_USE_ST7789 | LV_USE_ST7796 | LV_USE_ILI9341) +#if (LV_USE_ST7735 | LV_USE_ST7789 | LV_USE_ST7796 | LV_USE_ILI9341 | LV_USE_NV3007) #ifndef LV_USE_GENERIC_MIPI #ifdef LV_KCONFIG_PRESENT #ifdef CONFIG_LV_USE_GENERIC_MIPI