SDAA158 December   2025 MSPM33C321A

 

  1.   1
  2.   Abstract
  3.   Trademarks
  4. 1Overview
    1. 1.1 LVGL Project Setup
    2. 1.2 Configuration
    3. 1.3 Initialization
    4. 1.4 LVGL Output
    5. 1.5 LVGL Input
    6. 1.6 LVGL Update
  5. 2LVGL Example
    1. 2.1 Hardware Connections
    2. 2.2 Software
    3. 2.3 LVGL Example Summary
  6. 3Summary
  7. 4Revision History

Software

The following describes the software configurations that were made for the LVGL example:

  • Configuration
    • MCU: The following values are specifically configured for this example:
      • GPIO: Several GPIO pins are configured in this example to be initally set high or low, as defined in Table 2-2. These values are dependent on the requirements from the display and touch drivers.
        Table 2-2 LVGL Example GPIO Pin Configuration
        Pin Name Direction Initial Value Assigned Pin

        LCD_SCS

        Output Set PB6
        LCD_SDC Output Cleared PB30
        LCD_RESET Output Set PA10
        LCD_PWM Output Cleared PB3
        CTP_RST Output Set PC4
        CTP_INT Input N/A PC5
      • SYSCTL: The SYSCTL module has been configured to use an external high frequency clock input to serve as the input to the MCLK. The HFXT is set to run at 40MHz
      • I2C: The I2C peripheral selected, UC3, has been configured to operate as a Controller and run in Fast Mode (400kHz), with SDA and SCL lines assigned to PA0 and PA1 respectively
      • SPI: The SPI peripheral selected, UC2, has been configured to operate as a Controller, run at 40Mhz, use CS1 as the Chip Select, and run in Motorola 4-wire mode, with SCLK, PICO, POCI, and CS1 being assigned to PA8, PA9, PB19, and PB6
      • TIMER: The Timer module selected, TIMG8_0, has been configured to be sourced by the BUSCLK, prescaled by a factor of 40, and setup in Periodic Down Counting at a period of 1ms. An interupt has been confiogured to be triggered at the Zero event of the timer
    • LVGL:
      • In this example, LVGL has been configured with the specifications of the TFT display being used. Many of the optional fonts and widgets are enable as the LVGL demo utilizes many different modules. The demo configuration value, LV_USE_DEMO_WIDGETS, is also specifically enabled so that the LVGL demo is compiled and run.
        #define MY_DISP_HOR_RES        480
        #define MY_DISP_VER_RES        320
        ...
        #define LV_COLOR_DEPTH          16
        ...
        #define LV_MEM_SIZE   (48U * 1024U) // [bytes]
        ...
        #define LV_DRAW_COMPLEX 1
        ...
        #define LV_USE_DEMO_WIDGETS 1
  • Initalization
    • The first thing that needs to be initalized are the peripherals configured previously through SysConfig
    • Next, the timer interupt that is used to trigger the system tick needs to be initalized
    • After the peripherals and timers, the LVGL specific items need to be initalized
      • LVGL Initalization: LVGL needs to be initalized by calling lv_init
      • Output Initialization: The LVGL display driver is initalized by calling lv_port_disp_init
        • In this example, lv_port_disp_init follows the initalization steps defined in Section 1.3.The flush callback is defined later in this section
          void lv_port_disp_init(void)
          {
              disp_init(); // Initialize your display
          
              static lv_disp_draw_buf_t draw_buf_dsc_1;
              static lv_color_t buf_1[MY_DISP_HOR_RES * 10];                          /*A buffer for 10 rows*/
              lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10);   /*Initialize the display buffer*/
          
              static lv_disp_drv_t disp_drv;                         /*Descriptor of a display driver*/
              lv_disp_drv_init(&disp_drv);                    /*Basic initialization*/
          
              disp_drv.hor_res = MY_DISP_HOR_RES;
              disp_drv.ver_res = MY_DISP_VER_RES;
          
              disp_drv.flush_cb = disp_flush;
          
              disp_drv.draw_buf = &draw_buf_dsc_1;
          
              lv_disp_drv_register(&disp_drv); 
          }
      • Input Initialization: The LVGL input device driver is initalized by calling lv_port_indev_init
        • In this example, lv_port_indev_init follows the initalization steps defined in Section 1.3. The input read callback is defined later in this section
          void lv_port_indev_init(void)
          {
              static lv_indev_drv_t indev_drv;
          
              touchpad_init(); //Initialize your touchpad
          
              lv_indev_drv_init(&indev_drv); //Register a touchpad input device
              indev_drv.type = LV_INDEV_TYPE_POINTER;
              indev_drv.read_cb = touchpad_read;
              indev_touchpad = lv_indev_drv_register(&indev_drv);
          }
    • Finally, the system tick timer is started
      int main(void)
      {
          SYSCFG_DL_init();
      
          NVIC_EnableIRQ(TIMER_0_INST_INT_IRQN);
      
          lv_init(); // init LVGL
          lv_port_disp_init();
          lv_port_indev_init();
      
          DL_TimerG_startCounter(TIMER_0_INST);
      
  • Output
    • LVGL sends out pixel data by calling the flush callback method previously defined in the initalization section. In this example, disp_flush calls the low level driver code, lvgl_LCD_Color_Fill, which handles the SPI communcation, and then notifies LVGL that the flush is ready
      static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
      {
          lvgl_LCD_Color_Fill(area->x1, area->y1, area->x2, area->y2, color_p);
          lv_disp_flush_ready(disp_drv); //Inform the graphics library that you are ready with the flushing
      }
  • Input
    • LVGL attempts to read for user input by calling the input read callback method previously defined in the initalization section. In this example, touchpad_read calls the low level driver code, which handles the I2C communcation, to check if the touchpad has been pressed, and then processes the location of the press if the press occurred
      static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
      {
          static lv_coord_t last_x = 0;
          static lv_coord_t last_y = 0;
      
          if(touchpad_is_pressed()) {
              touchpad_get_xy(&last_x, &last_y); //Save the pressed coordinates and the state
              data->state = LV_INDEV_STATE_PR;
          }
          else {
              data->state = LV_INDEV_STATE_REL;
          }
      
          data->point.x = last_x; //Set the last pressed coordinates
          data->point.y = last_y;
      }
      
  • Update
    • The LVGL system tick was triggered via the TIMG8_0 timer interupt configured earlier. This interupt triggered every millisecond.
      void TIMER_0_INST_IRQHandler(void)
      {
          switch (DL_TimerG_getPendingInterrupt(TIMER_0_INST)) {
              case DL_TIMER_IIDX_ZERO:
      
                  lv_tick_inc(1);     //LVGL Heart Beat
      
                  break;
              default:
                  break;
          }
      }
    • The LVGL timer triggers are being handled in the main while loop of the example. There is a delay of 320 cycle to not hog all of the CPU processing.
      while (1) {
              // update LVGL task
              lv_task_handler();
      
              delay_cycles(320);
          }
  • Main Demo
    • The main demo is defined in lv_demo_widgets, which is included in the LVGL library. This demo showcases the primarily widgets that are included in LVGL. To use this demo, the header file for the demo was included in the main source file for this demo.
      #include "lv_demo_widgets.h"
      ...
      int main(void)
      {
      ...
          lv_demo_widgets();
      ...
      }