Running LVGL on teensy 4.1

Description

This is the first time I have tried to use LVGL as I just learnt about it a couple hours ago. I am trying to get the LVGL arduino example to work on a teensy 4.1 with ILI9341 display. But when I go to compile I get a shitload of undeclared functions and variables.

What MCU/Processor/Board and compiler are you using?

I am using a teensy 4.1 with arduino ide v1.8.13

What do you want to achieve?

For it to work and understand why it isn’t.

Code to reproduce

/*Using LVGL with Arduino requires some extra steps:
 *Be sure to read the docs here: https://docs.lvgl.io/master/get-started/platforms/arduino.html  */

#include <lvgl.h>
#include <TFT_eSPI.h>

/*To use the built-in examples and demos of LVGL uncomment the includes below respectively.
 *You also need to copy `lvgl/examples` to `lvgl/src/examples`. Similarly for the demos `lvgl/demos` to `lvgl/src/demos`.
 *Note that the `lv_examples` library is for LVGL v7 and you shouldn't install it for this version (since LVGL v8)
 *as the examples and demos are now part of the main LVGL library. */

//#include <examples/lv_examples.h>
//#include <demos/lv_demos.h>

/*Change to your screen resolution*/
static const uint16_t screenWidth  = 320;
static const uint16_t screenHeight = 240;

static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ screenWidth * screenHeight / 10 ];

TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); /* TFT instance */

#if LV_USE_LOG != 0
/* Serial debugging */
void my_print( lv_log_level_t level, const char * buf )
{
    LV_UNUSED(level);
    Serial.flush();
}
#endif

/* Display flushing */
void my_disp_flush( lv_disp_t *disp, const lv_area_t *area, lv_color_t *color_p )
{
    uint32_t w = ( area->x2 - area->x1 + 1 );
    uint32_t h = ( area->y2 - area->y1 + 1 );

    tft.startWrite();
    tft.setAddrWindow( area->x1, area->y1, w, h );
    tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
    tft.endWrite();

    lv_disp_flush_ready( disp );
}

/*Read the touchpad*/
void my_touchpad_read( lv_indev_t * indev_driver, lv_indev_data_t * data )
{
    uint16_t touchX, touchY;

    bool touched = tft.getTouch( &touchX, &touchY, 600 );

    if( !touched )
    {
        data->state = LV_INDEV_STATE_REL;
    }
    else
    {
        data->state = LV_INDEV_STATE_PR;

        /*Set the coordinates*/
        data->point.x = touchX;
        data->point.y = touchY;

        Serial.print( "Data x " );
        Serial.println( touchX );

        Serial.print( "Data y " );
        Serial.println( touchY );
    }
}

void setup()
{
    Serial.begin( 115200 ); /* prepare for possible serial debug */

    String LVGL_Arduino = "Hello Arduino! ";
    LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();

    Serial.println( LVGL_Arduino );
    Serial.println( "I am LVGL_Arduino" );

    lv_init();

#if LV_USE_LOG != 0
    lv_log_register_print_cb( my_print ); /* register print function for debugging */
#endif

    tft.begin();          /* TFT init */
    tft.setRotation( 3 ); /* Landscape orientation, flipped */

    /*Set the touchscreen calibration data,
     the actual data for your display can be acquired using
     the Generic -> Touch_calibrate example from the TFT_eSPI library*/
    uint16_t calData[5] = { 275, 3620, 264, 3532, 1 };
    tft.setTouch( calData );

    lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * screenHeight / 10 );

    /*Initialize the display*/
    static lv_disp_t disp_drv;
    lv_disp_drv_init( &disp_drv );
    /*Change the following line to your display resolution*/
    disp_drv.hor_res = screenWidth;
    disp_drv.ver_res = screenHeight;
    disp_drv.flush_cb = my_disp_flush;
    disp_drv.draw_buf = &draw_buf;
    lv_disp_drv_register( &disp_drv );

    /*Initialize the (dummy) input device driver*/
    static lv_indev_t indev_drv;
    lv_indev_drv_init( &indev_drv );
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = my_touchpad_read;
    lv_indev_drv_register( &indev_drv );

    /* Create simple label */
    //lv_obj_t *label = lv_label_create( lv_scr_act() );
    //lv_label_set_text( label, LVGL_Arduino.c_str() );
    //lv_obj_align( label, LV_ALIGN_CENTER, 0, 0 );
 
    /* Try an example. See all the examples 
     * online: https://docs.lvgl.io/master/examples.html
     * source codes: https://github.com/lvgl/lvgl/tree/e7f88efa5853128bf871dde335c0ca8da9eb7731/examples */
     //lv_example_btn_1();
   
     /*Or try out a demo. Don't forget to enable the demos in lv_conf.h. E.g. LV_USE_DEMOS_WIDGETS*/
    lv_demo_widgets();               
    // lv_demo_benchmark();          
    // lv_demo_keypad_encoder();     
    // lv_demo_music();              
    // lv_demo_printer();
    // lv_demo_stress();             

    Serial.println( "Setup done" );
}

void loop()
{
    lv_timer_handler(); /* let the GUI do its work */
    delay( 5 );
}

Compilation Error

Arduino: 1.8.13 (Windows 10), TD: 1.58, Board: “Teensy 4.1, Serial, 600 MHz, Faster, US English”

In file included from c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl-master\lvgl.h:79,

             from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\lvgl-master\src/lvgl.h:17,

             from C:\Users\DERKS_~1\AppData\Local\Temp\arduino_modified_sketch_735231\LVGL_Arduino.ino:4:

c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl-master\src/others/sysmon/lv_sysmon.h:69:2: warning: #warning “lv_sysmon: lv_sysmon is required. Enable it in lv_conf.h (LV_USE_SYSMON 1)” [-Wcpp]

69 | #warning “lv_sysmon: lv_sysmon is required. Enable it in lv_conf.h (LV_USE_SYSMON 1)”

  |  ^~~~~~~

In file included from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\lvgl-master\src/lvgl.h:17,

             from C:\Users\DERKS_~1\AppData\Local\Temp\arduino_modified_sketch_735231\LVGL_Arduino.ino:4:

c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl-master\lvgl.h:121:2: warning: #warning “You are using the development version of LVGL which is not stable at this moment. For production use the release/v8.3 branch. To silence this warning add #define LV_USE_DEV_VERSION to lv_conf.h” [-Wcpp]

121 | #warning “You are using the development version of LVGL which is not stable at this moment. For production use the release/v8.3 branch. To silence this warning add #define LV_USE_DEV_VERSION to lv_conf.h”

  |  ^~~~~~~

In file included from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\TFT_eSPI/User_Setup_Select.h:30,

             from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\TFT_eSPI/TFT_eSPI.h:68,

             from C:\Users\DERKS_~1\AppData\Local\Temp\arduino_modified_sketch_735231\LVGL_Arduino.ino:5:

C:\Users\derks_ptmjitt\Documents\Arduino\libraries\TFT_eSPI/User_Setup.h:205: warning: “TFT_CS” redefined

205 | #define TFT_CS 10 // Chip select control pin

  | 

C:\Users\derks_ptmjitt\Documents\Arduino\libraries\TFT_eSPI/User_Setup.h:169: note: this is the location of the previous definition

169 | #define TFT_CS PIN_D8 // Chip select control pin D8

  | 

C:\Users\derks_ptmjitt\Documents\Arduino\libraries\TFT_eSPI/User_Setup.h:206: warning: “TFT_DC” redefined

206 | #define TFT_DC 9 // Data Command control pin

  | 

C:\Users\derks_ptmjitt\Documents\Arduino\libraries\TFT_eSPI/User_Setup.h:170: note: this is the location of the previous definition

170 | #define TFT_DC PIN_D3 // Data Command control pin

  | 

C:\Users\derks_ptmjitt\Documents\Arduino\libraries\TFT_eSPI/User_Setup.h:208: warning: “TFT_RST” redefined

208 | #define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST

  | 

C:\Users\derks_ptmjitt\Documents\Arduino\libraries\TFT_eSPI/User_Setup.h:171: note: this is the location of the previous definition

171 | #define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)

  | 

In file included from C:\Users\DERKS_~1\AppData\Local\Temp\arduino_modified_sketch_735231\LVGL_Arduino.ino:5:

C:\Users\derks_ptmjitt\Documents\Arduino\libraries\TFT_eSPI/TFT_eSPI.h:89: warning: “PROGMEM” redefined

89 | #define PROGMEM

  | 

In file included from C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/WProgram.h:42,

             from C:\Users\DERKS_~1\AppData\Local\Temp\arduino_build_204466\pch\Arduino.h:6:

C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy4/avr/pgmspace.h:30: note: this is the location of the previous definition

30 | #define PROGMEM attribute((section(“.progmem”)))

  | 

In file included from C:\Users\DERKS_~1\AppData\Local\Temp\arduino_modified_sketch_735231\LVGL_Arduino.ino:5:

C:\Users\derks_ptmjitt\Documents\Arduino\libraries\TFT_eSPI/TFT_eSPI.h:909:8: warning: #warning >>>>------>> TOUCH_CS pin not defined, TFT_eSPI touch functions will not be available! [-Wcpp]

909 | #warning >>>>------>> TOUCH_CS pin not defined, TFT_eSPI touch functions will not be available!

  |        ^~~~~~~

LVGL_Arduino:19: error: ‘lv_disp_draw_buf_t’ does not name a type

19 | static lv_disp_draw_buf_t draw_buf;

  |        ^~~~~~~~~~~~~~~~~~

LVGL_Arduino: In function ‘void my_disp_flush(lv_disp_t*, const lv_area_t*, lv_color_t*)’:

LVGL_Arduino:41: error: ‘lv_color_t’ {aka ‘struct lv_color16_t’} has no member named ‘full’

41 | tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );

  |                                             ^~~~

LVGL_Arduino: In function ‘void my_touchpad_read(lv_indev_t*, lv_indev_data_t*)’:

LVGL_Arduino:52: error: ‘class TFT_eSPI’ has no member named ‘getTouch’

52 | bool touched = tft.getTouch( &touchX, &touchY, 600 );

  |                        ^~~~~~~~

LVGL_Arduino: In function ‘void setup()’:

LVGL_Arduino:97: error: ‘class TFT_eSPI’ has no member named ‘setTouch’

97 | tft.setTouch( calData );

  |         ^~~~~~~~

LVGL_Arduino:99: error: ‘draw_buf’ was not declared in this scope

99 | lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * screenHeight / 10 );

  |                             ^~~~~~~~

LVGL_Arduino:99: error: ‘lv_disp_draw_buf_init’ was not declared in this scope; did you mean ‘lv_obj_draw_dsc_init’?

99 | lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * screenHeight / 10 );

  |     ^~~~~~~~~~~~~~~~~~~~~

  |     lv_obj_draw_dsc_init

LVGL_Arduino:103: error: ‘lv_disp_drv_init’ was not declared in this scope; did you mean ‘lv_fs_drv_init’?

103 | lv_disp_drv_init( &disp_drv );

  |     ^~~~~~~~~~~~~~~~

  |     lv_fs_drv_init

LVGL_Arduino:108: error: ‘lv_disp_t’ {aka ‘struct _lv_disp_t’} has no member named ‘draw_buf’; did you mean ‘draw_buf_1’?

108 | disp_drv.draw_buf = &draw_buf;

  |              ^~~~~~~~

  |              draw_buf_1

LVGL_Arduino:109: error: ‘lv_disp_drv_register’ was not declared in this scope; did you mean ‘lv_fs_drv_register’?

109 | lv_disp_drv_register( &disp_drv );

  |     ^~~~~~~~~~~~~~~~~~~~

  |     lv_fs_drv_register

LVGL_Arduino:113: error: ‘lv_indev_drv_init’ was not declared in this scope; did you mean ‘lv_fs_drv_init’?

113 | lv_indev_drv_init( &indev_drv );

  |     ^~~~~~~~~~~~~~~~~

  |     lv_fs_drv_init

LVGL_Arduino:116: error: ‘lv_indev_drv_register’ was not declared in this scope; did you mean ‘lv_fs_drv_register’?

116 | lv_indev_drv_register( &indev_drv );

  |     ^~~~~~~~~~~~~~~~~~~~~

  |     lv_fs_drv_register

LVGL_Arduino:129: error: ‘lv_demo_widgets’ was not declared in this scope

129 | lv_demo_widgets();

  |     ^~~~~~~~~~~~~~~

‘lv_disp_draw_buf_t’ does not name a type

Invalid library found in C:\Program Files (x86)\Arduino\libraries\Adafruit_ILI9341-master: no headers files (.h) found in C:\Program Files (x86)\Arduino\libraries\Adafruit_ILI9341-master

Invalid library found in C:\Program Files (x86)\Arduino\libraries\OneWire-master: no headers files (.h) found in C:\Program Files (x86)\Arduino\libraries\OneWire-master

Invalid library found in C:\Program Files (x86)\Arduino\libraries\XPT2046_Touchscreen-master: no headers files (.h) found in C:\Program Files (x86)\Arduino\libraries\XPT2046_Touchscreen-master

Invalid library found in C:\Program Files (x86)\Arduino\libraries\Adafruit_ILI9341-master: no headers files (.h) found in C:\Program Files (x86)\Arduino\libraries\Adafruit_ILI9341-master

Invalid library found in C:\Program Files (x86)\Arduino\libraries\OneWire-master: no headers files (.h) found in C:\Program Files (x86)\Arduino\libraries\OneWire-master

Invalid library found in C:\Program Files (x86)\Arduino\libraries\XPT2046_Touchscreen-master: no headers files (.h) found in C:\Program Files (x86)\Arduino\libraries\XPT2046_Touchscreen-master

Invalid library found in C:\Program Files (x86)\Arduino\libraries\Adafruit_ILI9341-master: no headers files (.h) found in C:\Program Files (x86)\Arduino\libraries\Adafruit_ILI9341-master

Invalid library found in C:\Program Files (x86)\Arduino\libraries\OneWire-master: no headers files (.h) found in C:\Program Files (x86)\Arduino\libraries\OneWire-master

Invalid library found in C:\Program Files (x86)\Arduino\libraries\XPT2046_Touchscreen-master: no headers files (.h) found in C:\Program Files (x86)\Arduino\libraries\XPT2046_Touchscreen-master

This report would have more information with
“Show verbose output during compilation”
option enabled in File → Preferences.

I reinstalled everything and found a couple problems I missed and now I am getting different error messages. I would appreciate it if anyone has any ideas.

LVGL_Arduino: In function 'void my_disp_flush(lv_disp_t*, const lv_area_t*, lv_color_t*)':
LVGL_Arduino:41: error: cannot convert 'lv_disp_t*' {aka '_lv_disp_t*'} to 'lv_disp_drv_t*' {aka '_lv_disp_drv_t*'}
   41 |     lv_disp_flush_ready( disp );
      |                          ^~~~
      |                          |
      |                          lv_disp_t* {aka _lv_disp_t*}
In file included from c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\src/hal/lv_hal.h:16,
                 from c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\lvgl.h:33,
                 from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\lvgl\src/lvgl.h:17,
                 from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\lvgl\examples\arduino\LVGL_Arduino\LVGL_Arduino.ino:4:
c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\src/hal/lv_hal_disp.h:335:67: note:   initializing argument 1 of 'void lv_disp_flush_ready(lv_disp_drv_t*)'
  335 | LV_ATTRIBUTE_FLUSH_READY void lv_disp_flush_ready(lv_disp_drv_t * disp_drv);
      |                                                   ~~~~~~~~~~~~~~~~^~~~~~~~
LVGL_Arduino: In function 'void setup()':
LVGL_Arduino:100: error: cannot convert 'lv_disp_t*' {aka '_lv_disp_t*'} to 'lv_disp_drv_t*' {aka '_lv_disp_drv_t*'}
  100 |     lv_disp_drv_init( &disp_drv );
      |                       ^~~~~~~~~
      |                       |
      |                       lv_disp_t* {aka _lv_disp_t*}
In file included from c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\src/hal/lv_hal.h:16,
                 from c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\lvgl.h:33,
                 from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\lvgl\src/lvgl.h:17,
                 from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\lvgl\examples\arduino\LVGL_Arduino\LVGL_Arduino.ino:4:
c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\src/hal/lv_hal_disp.h:206:39: note:   initializing argument 1 of 'void lv_disp_drv_init(lv_disp_drv_t*)'
  206 | void lv_disp_drv_init(lv_disp_drv_t * driver);
      |                       ~~~~~~~~~~~~~~~~^~~~~~
LVGL_Arduino:102: error: 'lv_disp_t' {aka 'struct _lv_disp_t'} has no member named 'hor_res'
  102 |     disp_drv.hor_res = screenWidth;
      |              ^~~~~~~
LVGL_Arduino:103: error: 'lv_disp_t' {aka 'struct _lv_disp_t'} has no member named 'ver_res'
  103 |     disp_drv.ver_res = screenHeight;
      |              ^~~~~~~
LVGL_Arduino:104: error: 'lv_disp_t' {aka 'struct _lv_disp_t'} has no member named 'flush_cb'
  104 |     disp_drv.flush_cb = my_disp_flush;
      |              ^~~~~~~~
LVGL_Arduino:105: error: 'lv_disp_t' {aka 'struct _lv_disp_t'} has no member named 'draw_buf'
  105 |     disp_drv.draw_buf = &draw_buf;
      |              ^~~~~~~~
LVGL_Arduino:106: error: cannot convert 'lv_disp_t*' {aka '_lv_disp_t*'} to 'lv_disp_drv_t*' {aka '_lv_disp_drv_t*'}
  106 |     lv_disp_drv_register( &disp_drv );
      |                           ^~~~~~~~~
      |                           |
      |                           lv_disp_t* {aka _lv_disp_t*}
In file included from c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\src/hal/lv_hal.h:16,
                 from c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\lvgl.h:33,
                 from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\lvgl\src/lvgl.h:17,
                 from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\lvgl\examples\arduino\LVGL_Arduino\LVGL_Arduino.ino:4:
c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\src/hal/lv_hal_disp.h:231:50: note:   initializing argument 1 of 'lv_disp_t* lv_disp_drv_register(lv_disp_drv_t*)'
  231 | lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver);
      |                                  ~~~~~~~~~~~~~~~~^~~~~~
LVGL_Arduino:110: error: cannot convert 'lv_indev_t*' {aka '_lv_indev_t*'} to '_lv_indev_drv_t*'
  110 |     lv_indev_drv_init( &indev_drv );
      |                        ^~~~~~~~~~
      |                        |
      |                        lv_indev_t* {aka _lv_indev_t*}
In file included from c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\src/hal/lv_hal.h:17,
                 from c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\lvgl.h:33,
                 from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\lvgl\src/lvgl.h:17,
                 from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\lvgl\examples\arduino\LVGL_Arduino\LVGL_Arduino.ino:4:
c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\src/hal/lv_hal_indev.h:195:49: note:   initializing argument 1 of 'void lv_indev_drv_init(_lv_indev_drv_t*)'
  195 | void lv_indev_drv_init(struct _lv_indev_drv_t * driver);
      |                        ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
LVGL_Arduino:111: error: 'lv_indev_t' {aka 'struct _lv_indev_t'} has no member named 'type'
  111 |     indev_drv.type = LV_INDEV_TYPE_POINTER;
      |               ^~~~
LVGL_Arduino:112: error: 'lv_indev_t' {aka 'struct _lv_indev_t'} has no member named 'read_cb'
  112 |     indev_drv.read_cb = my_touchpad_read;
      |               ^~~~~~~
LVGL_Arduino:113: error: cannot convert 'lv_indev_t*' {aka '_lv_indev_t*'} to '_lv_indev_drv_t*'
  113 |     lv_indev_drv_register( &indev_drv );
      |                            ^~~~~~~~~~
      |                            |
      |                            lv_indev_t* {aka _lv_indev_t*}
In file included from c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\src/hal/lv_hal.h:17,
                 from c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\lvgl.h:33,
                 from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\lvgl\src/lvgl.h:17,
                 from C:\Users\derks_ptmjitt\Documents\Arduino\libraries\lvgl\examples\arduino\LVGL_Arduino\LVGL_Arduino.ino:4:
c:\users\derks_ptmjitt\documents\arduino\libraries\lvgl\src/hal/lv_hal_indev.h:202:61: note:   initializing argument 1 of 'lv_indev_t* lv_indev_drv_register(_lv_indev_drv_t*)'
  202 | lv_indev_t * lv_indev_drv_register(struct _lv_indev_drv_t * driver);
      |                                    ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
LVGL_Arduino:127: error: 'lv_demo_widgets' was not declared in this scope
  127 |     lv_demo_widgets();            // OK
      |     ^~~~~~~~~~~~~~~
cannot convert 'lv_disp_t*' {aka '_lv_disp_t*'} to 'lv_disp_drv_t*' {aka '_lv_disp_drv_t*'}

well right out of the gate your flush function doesn’t have any named parameters… so I am not sure how you can call lv_disp_flush_ready passing “disp” when there is no “disp” to be passed.

'void my_disp_flush(lv_disp_t*, const lv_area_t*, lv_color_t*)'

You are also using the wrong documentation for the version of LVGL you are using. There is no lv_disp_drv_t in version 9.0 it has been renamed to lv_disp_t. so you have a mixing of 2 different versions. I believe you are using code snippits from version 9 documentation but you are running probably 8.3.

It would be easier if I was able to see the code instead of the compilation output.

Thanks. All the code I am using is the example included with the LVGL library, I didn’t write any of it at all. I included the code in the first post but I updated LVGL and got a very slightly different code. And I should add I followed all the extra setup steps that the link has below.

Just checked and I am using version 8.3.7

/*Using LVGL with Arduino requires some extra steps:
 *Be sure to read the docs here: https://docs.lvgl.io/master/get-started/platforms/arduino.html  */

#include <lvgl.h>
#include <TFT_eSPI.h>

/*To use the built-in examples and demos of LVGL uncomment the includes below respectively.
 *You also need to copy `lvgl/examples` to `lvgl/src/examples`. Similarly for the demos `lvgl/demos` to `lvgl/src/demos`.
 Note that the `lv_examples` library is for LVGL v7 and you shouldn't install it for this version (since LVGL v8)
 as the examples and demos are now part of the main LVGL library. */

/*Change to your screen resolution*/
static const uint16_t screenWidth  = 320;
static const uint16_t screenHeight = 240;

static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ screenWidth * 10 ];

TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); /* TFT instance */

#if LV_USE_LOG != 0
/* Serial debugging */
void my_print(const char * buf)
{
    Serial.printf(buf);
    Serial.flush();
}
#endif

/* Display flushing */
void my_disp_flush( lv_disp_t *disp, const lv_area_t *area, lv_color_t *color_p )
{
    uint32_t w = ( area->x2 - area->x1 + 1 );
    uint32_t h = ( area->y2 - area->y1 + 1 );

    tft.startWrite();
    tft.setAddrWindow( area->x1, area->y1, w, h );
    tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
    tft.endWrite();

    lv_disp_flush_ready( disp );
}

/*Read the touchpad*/
void my_touchpad_read( lv_indev_t * indev_driver, lv_indev_data_t * data )
{
    uint16_t touchX, touchY;

    bool touched = tft.getTouch( &touchX, &touchY, 600 );

    if( !touched )
    {
        data->state = LV_INDEV_STATE_REL;
    }
    else
    {
        data->state = LV_INDEV_STATE_PR;

        /*Set the coordinates*/
        data->point.x = touchX;
        data->point.y = touchY;

        Serial.print( "Data x " );
        Serial.println( touchX );

        Serial.print( "Data y " );
        Serial.println( touchY );
    }
}

void setup()
{
    Serial.begin( 115200 ); /* prepare for possible serial debug */

    String LVGL_Arduino = "Hello Arduino! ";
    LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();

    Serial.println( LVGL_Arduino );
    Serial.println( "I am LVGL_Arduino" );

    lv_init();

#if LV_USE_LOG != 0
    lv_log_register_print_cb( my_print ); /* register print function for debugging */
#endif

    tft.begin();          /* TFT init */
    tft.setRotation( 3 ); /* Landscape orientation, flipped */

    /*Set the touchscreen calibration data,
     the actual data for your display can be acquired using
     the Generic -> Touch_calibrate example from the TFT_eSPI library*/
    uint16_t calData[5] = { 275, 3620, 264, 3532, 1 };
    tft.setTouch( calData );

    lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * 10 );

    /*Initialize the display*/
    static lv_disp_t disp_drv;
    lv_disp_drv_init( &disp_drv );
    /*Change the following line to your display resolution*/
    disp_drv.hor_res = screenWidth;
    disp_drv.ver_res = screenHeight;
    disp_drv.flush_cb = my_disp_flush;
    disp_drv.draw_buf = &draw_buf;
    lv_disp_drv_register( &disp_drv );

    /*Initialize the (dummy) input device driver*/
    static lv_indev_t indev_drv;
    lv_indev_drv_init( &indev_drv );
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = my_touchpad_read;
    lv_indev_drv_register( &indev_drv );

#if 0
    /* Create simple label */
    lv_obj_t *label = lv_label_create( lv_scr_act() );
    lv_label_set_text( label, LVGL_Arduino.c_str() );
    lv_obj_align( label, LV_ALIGN_CENTER, 0, 0 );
#else
    /* Try an example from the lv_examples Arduino library
       make sure to include it as written above.
    lv_example_btn_1();
   */

    // uncomment one of these demos
    lv_demo_widgets();            // OK
    // lv_demo_benchmark();          // OK
    // lv_demo_keypad_encoder();     // works, but I haven't an encoder
    // lv_demo_music();              // NOK
    // lv_demo_printer();
    // lv_demo_stress();             // seems to be OK
#endif
    Serial.println( "Setup done" );
}

void loop()
{
    lv_timer_handler(); /* let the GUI do its work */
    delay( 5 );
}