How to run LVGL on M5Stack



  • Honestly I started off reading the LVGL online help and even though I am still learning I did not have much problem making the lib work on the Core2.
    However I spent some significant time before understanding the whole concept (probably because I am getting too old :) ) and you seem to be way more experienced than me so you will make it work quickly :)

    My GitHub project is private (because it might end up being commercially used) but if you want I can extract the minimum code I used to display something if it can help and make it public.

    By looking at the error (If I remember I got more or less the same) this looks like invalide pointer / memory allocation.

    I realized that just initializing everything for LVGL to work is a real pain (when you've never played with it) but after you've understood the basic concepts it comes much clearer.
    At this stage all basic things are working fine I am now moving on to Event management (button press, sliders move etc...).

    Btw you can also have a look at the EdgeLine application which is a kind of LVGL companion allowing you to WYSIWYG to C/Python code automatically for you. I am very bad at designing UIs so I am starting using it for my project and it can also help you understand the code which is generated.



  • Haha, thank you, but I started learning C/C++ this Monday 👀
    I'll try to investigate more about pointers /memory exceptions.
    Everything I'll do will be on my GitHub in public repositories, my aim is to create a Tamagotchi for my daughter ^^'



  • FYI, I correctly display a button, I have many things left to do next, like finding the reason why my DrawingBoard.cpp pointers are badly set, but in the end, you help me a lot!
    Thanks again!

    For people reading this, I'll do my best to improve my GitHub repository in order to have a simple example for M5Core, explaining which parameters must be configured in lv_conf.h :)



  • Hi Pierre,

    Sorry I don't feel I did much for you but my (real) work is really taking much of my time (even what is supposed to be my free time) and I wish I could have spent more time working this out with you.
    In any case my offer still stands, I can help you building up a simple template with comments for people to get started.
    I already spent much time on it and I believe I have understood all the basic concepts .
    As already said, now i need to go one step further with event management.
    Also I am quite used to code in C (this is the language I started with a loooong time ago) I am not an expert but at least I can understand the most of what I do :)
    Btw a good platform that I have adopted now since several months is VSCode + PIO...Very neat combination!



  • I will omit the details,
    Currently, M5Stack Core2 is working with LVGL v8.1.0 and Arduino IDE.

    0_1641616885852_LVGL_8.1.0_Core2.jpg

    About lv_conf.h
    The following three settings are required.

    lvgl-master v8.1.0 / src / lv_conf.h

    1. /* clang-format off */
      #if 1 /Set it to "1" to enable content/

    2. #define LV_COLOR_DEPTH 16

    3. #define LV_TICK_CUSTOM 1
      #if LV_TICK_CUSTOM
      #define LV_TICK_CUSTOM_INCLUDE "Arduino.h"



  • Thank you @macsbug , this is exactly what I add to edit in my lv_conf.h in order to make it works!
    https://github.com/PierreRambaud/drawing-board/blob/master/drawing-board.ino#L4

    @erich I updated my repository, it now works, but not as expected. I've two issues:

    • I'm not able to change the label text each time I press a button (the reason of the seg fault)
    • I'm not able to draw on the right side like the lvgl take the wrong space, or the tft I don't know yet which one ^^'

    After that, everything will be ok (at least for this first project)

    As you said, a good platform for development is the key, I work with emacs for years, but I never configured it for C language.
    I've Arduino software open beside, only to compile & transfer.



  • Thank you @GoT , This is a great program.
    0_1641678571847_Got.jpg
    Thank you for publishing to github.

    problem

    1. not able to change the label text.
    2. The right side cannot be drawn.

    Change DrawingBoard.cpp.

    static lv_style_t style_color_label;
    static lv_style_t style_size_label;
    static lv_style_t style_clear_label;
    static lv_style_t style_label;

    void DrawingBoard::setup() {
    //lv_obj_t* _size_label = lv_label_create(lv_scr_act());
    _size_label = lv_label_create(lv_scr_act());

    //lv_obj_add_style(_size_label, &style_label, 0);
    lv_obj_add_style(_size_label, &style_size_label, 0);

    //lv_obj_add_style(_clear_label, &style_label, 0);
    lv_obj_add_style(_clear_label, &style_clear_label, 0);

    void DrawingBoard::drawPoint(int32_t x, int32_t y) {
    //_tft.drawCircle(x, y, _size, getColor());
    //_tft.fillCircle(x, y, _size, getColor());
    M5.Lcd.drawCircle(x, y, _size, getColor());
    M5.Lcd.fillCircle(x, y, _size, getColor());

    void DrawingBoard::changeSize() {
    //lv_label_set_text_fmt(_size_label, "Size: %d", _size);
    lv_label_set_text_fmt(_size_label, "Size: %d", _size);

    void DrawingBoard::clear() {
    //_tft.fillScreen(TFT_BLACK);
    M5.Lcd.fillScreen(TFT_WHITE);

    postscript:
    All 'tft's are possible with 'M5.Lcd'.
    It is possible with M5.Lcd without using TFT_eSPI.
    Development environment: LVGL 8.1.0 + Arduino IDE 1.8.19



  • @macsbug you're right, I did mention using TFT_eSPI instead of M5.Lcd only for portability reason.
    I would like to create a set of sample files that I can use with any display and not only with M5Stack devices.



  • OMG, it works as expected! <3
    If both of you have GitHub account, I'd be glad to add you as credit for the awesome help!



  • Great, I'm glad it works for you!
    I don't feel I did much to help but anyways here is my GH account: https://github.com/erich74
    At the moment I juste have a couple of private reps but I am planning to add public stuff when I get more used to M5Stack devices as this is becoming my main development/iot device platform.
    I will come back to this thread as I will probably need some help when I progress with my current project ;)



  • @erich you did more than you think.
    Feel free to ask when you will need it, if the M5Core2 is enough to run your program, I would be glad to help as you did



  • @got thanks, I will for sure ;)



  • Here is what I came up with (and works with lvgl/lvgl 8.1 on my Core 2).

    #include <M5Core2.h>
    #include <Arduino.h>
    #include <lvgl.h>
    #include <Wire.h>
    #include <SPI.h>
    
    // init the tft espi
    static lv_disp_draw_buf_t draw_buf;
    static lv_disp_drv_t disp_drv;  // Descriptor of a display driver
    static lv_indev_drv_t indev_drv; // Descriptor of a touch driver
    
    M5Display *tft;
    
    static void ta_event_cb(lv_event_t * e);
    static lv_obj_t * kb;
    
    static void ta_event_cb(lv_event_t * e)
    {
        lv_event_code_t code = lv_event_get_code(e);
        lv_obj_t * ta = lv_event_get_target(e);
        if(code == LV_EVENT_CLICKED || code == LV_EVENT_FOCUSED) {
            /*Focus on the clicked text area*/
            if(kb != NULL) lv_keyboard_set_textarea(kb, ta);
        }
    
        else if(code == LV_EVENT_READY) {
            LV_LOG_USER("Ready, current text: %s", lv_textarea_get_text(ta));
        }
    }
    
    static void btnPowerOff_event(lv_event_t * event)
    {
        M5.Axp.PowerOff();
    }
    
    void tft_lv_initialization() {
      M5.begin();
    
      lv_init();
    
      static lv_color_t buf1[(LV_HOR_RES_MAX * LV_VER_RES_MAX) / 10];  // Declare a buffer for 1/10 screen siz
      static lv_color_t buf2[(LV_HOR_RES_MAX * LV_VER_RES_MAX) / 10];  // second buffer is optionnal
    
      // Initialize `disp_buf` display buffer with the buffer(s).
      lv_disp_draw_buf_init(&draw_buf, buf1, buf2, (LV_HOR_RES_MAX * LV_VER_RES_MAX) / 10);
    
      tft = &M5.Lcd;
    }
    
    // Display flushing
    void my_disp_flush(lv_disp_drv_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);
    }
    
    void init_disp_driver() {
      lv_disp_drv_init(&disp_drv);  // Basic initialization
    
      disp_drv.flush_cb = my_disp_flush;  // Set your driver function
      disp_drv.draw_buf = &draw_buf;      // Assign the buffer to the display
      disp_drv.hor_res = LV_HOR_RES_MAX;  // Set the horizontal resolution of the display
      disp_drv.ver_res = LV_VER_RES_MAX;  // Set the vertical resolution of the display
    
      lv_disp_drv_register(&disp_drv);                   // Finally register the driver
      lv_disp_set_bg_color(NULL, lv_color_hex3(0x000));  // Set default background color to black
    }
    
    void my_touchpad_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
    {
      TouchPoint_t pos = M5.Touch.getPressPoint();
      bool touched = ( pos.x == -1 ) ? false : true;  
    
      if(!touched) {    
        data->state = LV_INDEV_STATE_RELEASED;
      } else {
        data->state = LV_INDEV_STATE_PRESSED; 
        data->point.x = pos.x;
        data->point.y = pos.y;
      }
    }
    
    void init_touch_driver() {
      lv_disp_drv_register(&disp_drv);
    
      lv_indev_drv_init(&indev_drv);
      indev_drv.type = LV_INDEV_TYPE_POINTER;
      indev_drv.read_cb = my_touchpad_read;
      lv_indev_t * my_indev = lv_indev_drv_register(&indev_drv);  // register
    }
    
    void setup()
    {
      tft_lv_initialization();
      init_disp_driver();
      init_touch_driver();
    
      lv_obj_t * btn1 = lv_btn_create(lv_scr_act());
      lv_obj_t * label = lv_label_create(btn1);
      lv_obj_align(btn1, LV_ALIGN_CENTER, 0, 0);
      lv_label_set_text(label, "Power Off");
      lv_obj_center(label);
      lv_obj_add_event_cb(btn1, btnPowerOff_event, LV_EVENT_CLICKED, NULL);
    }
    
    void loop()
    {
      M5.update();
      lv_task_handler();
    }
    


  • @jackrazors Thanks for sharing!



  • I'm struggling with edgline but just realized the code which is automatically generated is not compatible with LVGL 8.x, only version 7.
    Looks like they have not updated the tools since a while, not even sure if they still want to maintain it.
    I am going back to old school manual coding...I don't mind writing lines of code but I am bad at designing UIs and EdgeLine seemed to be my savior (but not anymore unfortunately)



  • @jackrazors hello, I tried to run your code, but the function my_touchpad_read is never called..

    Would be possible for you to share the repo ?
    Thanks !!



  • @lunard said in How to run LVGL on M5Stack:

    @jackrazors hello, I tried to run your code, but the function my_touchpad_read is never called..

    Would be possible for you to share the repo ?
    Thanks !!

    Ok @JackRazors was missing lv_tick_inc(1); in the loop function



  • Hello@erich

    LVGL 8.0.2 is listed below.

    LVGL 8.0.2
    LVGL 8 demo with M5Stack , M5Stamp C3
    https://forum.m5stack.com/topic/4161/lvgl-8-demo-with-m5stack-m5stamp-c3



  • Would be perfect to use with the M5Stack Atom Display with a 7 inch display.

    But does it run on an Atom ?



  • Hello,

    I have try to run the the sketch "drawing-board" on my Core2.
    Have some problem with the lv_config.h file. My question is where to store exactly this file?
    Have tried several locations but always the error messages

    /Users/jankromhout/Documents/Arduino/libraries/lvgl/src/../src/misc/../lv_conf_internal.h:46:120: note: #pragma message: Possible failure to include lv_conf.h, please read the comment in this file if you get errors
    #pragma message("Possible failure to include lv_conf.h, please read the comment in this file if you get errors")

    And with changes needed to be done.

    I'm using the latest version of lvgl.

    Any help is welcome.
    Cheers,
    Jan