feat(drivers): NV3007 driver & docs (#9021)

This commit is contained in:
Felix Biego
2025-10-09 05:44:04 +03:00
committed by GitHub
parent 4d1180d0fc
commit ae32d5ae6c
7 changed files with 514 additions and 2 deletions
@@ -13,3 +13,4 @@ Display Controller Support
st7735
st7789
st7796
nv3007
@@ -0,0 +1,182 @@
=============================
NV3007 LCD Controller driver
=============================
Overview
--------
The `NV3007 <https://www.buydisplay.com/download/ic/NV3007.pdf>`__ 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 <https://github.com/lvgl/lvgl/tree/master/src/drivers/display/nv3007>`__ is a platform-agnostic driver, based on the `generic MIPI driver <https://github.com/lvgl/lvgl/blob/master/docs/src/details/integration/external_display_controllers/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 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 <lvgl.h>
/* Platform-specific includes */
#include <SPI.h>
#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 <https://github.com/lvgl/lvgl/blob/master/docs/src/details/integration/external_display_controllers/gen_mipi.rst>`__.
+2 -1
View File
@@ -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
+226
View File
@@ -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*/
+94
View File
@@ -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*/
+1
View File
@@ -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"
+8 -1
View File
@@ -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