How to run LVGL on M5Stack



  • 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 ?