=============================
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 :ref:`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 <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 :ref:`generic MIPI driver`
documentation.
