임베디드를 좋아하는 조금 특이한 개발자?

[Buildroot] LVGL 개발을 위한 환경 구축 본문

Embedded/Buildroot

[Buildroot] LVGL 개발을 위한 환경 구축

Gordon_ 2025. 7. 9. 00:39

- 개발 환경

개발 보드 : Raspberrypi 4

WSL2 (Ubuntu 22.04 LTS)

buildroot(2025.02)

LVGL(9.2.2)


1. 서론

  buildroot로 커스텀 리눅스를 빌드하고 실행하는 것 까지 완성하였습니다. 이제 해당 리눅스에서 동작하는 GUI 어플리케이션을 개발하기 위한 방법을 알아볼 것 입니다. 개발을 위해 QT를 사용하여도 좋지만 QT는 환경 구축이 좀더 까다롭고 라이센스가 오픈소스가 아닌 경우 상용으로 쓰기 까다로워 진다는 점입니다. 그렇기에 LVGL를 사용하여 GUI 어플리케이션을 개발하여 상용 제품으로 사용해도 손색 없을 정도로 개발 하는 것이 목표입니다.

  아래 git repo는 제가 이 포스트를 바탕으로 제작한 프로젝트 입니다. 모르는 부분이나 이상한 부분은 해당 repo를 참고해 주시기 바랍니다.

https://github.com/MainForm/LVGL_application_for_linux

 

GitHub - MainForm/LVGL_application_for_linux

Contribute to MainForm/LVGL_application_for_linux development by creating an account on GitHub.

github.com

 

2. 개발 환경 구축

# 프로젝트 폴더 생성 및 이동
mkdir lvgl_application && cd lvgl_application

# lvgl 프로젝트 클론
git clone --branch v9.2.2 https://github.com/lvgl/lvgl.git

 

2.1. LVGL 환경 설정

 LVGL를 개발하기 전 LVGL을 어떠한 환경에서 개발하는 lv_conf.h 헤더파일을 통해 설정해 주어야 합니다. lv_conf.h 헤더파일은 lvgl 폴더 내 lv_conf_template.h를 복사하여 사용합니다.

# lvgl 설정 헤더 파일 복사
cp ./lvgl/lv_conf_template.h ./lv_conf.h

 

이제 본격적으로 lv_conf.h 헤더파일을 통해 설정을 하도록 합시다. 설정해야 하는 변수가 많으므로 값을 변경해야하는 변수만 다룰 것이며 귀찮다면, 따로 첨부한 헤더파일을 다운로드하여 사용하셔도 상관 없습니다.

lv_conf.h
0.03MB

// lv_conf.h 파일 내용
// lv_conf.h 헤더파일 활성화
#if 1 /*Set it to "1" to enable content*/

// 표준 C라이브러리 사용
#define LV_USE_STDLIB_MALLOC    LV_STDLIB_CLIB
#define LV_USE_STDLIB_STRING    LV_STDLIB_CLIB
#define LV_USE_STDLIB_SPRINTF   LV_STDLIB_CLIB

// lvgl에서의 최대 프레임 제한 (16 -> 60fps)
#define LV_DEF_REFR_PERIOD  16      /*[ms]*/

// pthread(POSIX Thread)를 사용하는 리눅스에 대한 설정 
#define LV_USE_OS   LV_OS_PTHREAD

#define LV_DRAW_TRANSFORM_USE_MATRIX            1

/*The target buffer size for simple layer chunks.*/
#define LV_DRAW_LAYER_SIMPLE_BUF_SIZE    (1024 * 1024)   /*[bytes]*/
#define LV_DRAW_THREAD_STACK_SIZE    (32 * 1024)   /*[bytes]*/

#define LV_DRAW_SW_DRAW_UNIT_CNT    2
  
#define LV_USE_LOG 1

#define LV_LOG_PRINTF 1

#define LV_COLOR_MIX_ROUND_OFS  0

#define LV_OBJ_STYLE_CACHE      1

#define LV_USE_VG_LITE_THORVG  1
#define LV_VG_LITE_THORVG_LVGL_BLEND_SUPPORT 1
#define LV_VG_LITE_THORVG_THREAD_RENDER 1

#define LV_USE_FLOAT            1
#define LV_USE_MATRIX           1

#define LV_FONT_MONTSERRAT_16 1
#define LV_FONT_MONTSERRAT_20 1
#define LV_FONT_MONTSERRAT_24 1
#define LV_FONT_MONTSERRAT_26 1

#define LV_FONT_MONTSERRAT_28_COMPRESSED 1
#define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 1

#define LV_FONT_UNSCII_8  1

#define LV_USE_LOTTIE     1

#define LV_BIN_DECODER_RAM_LOAD 1

#define LV_USE_VECTOR_GRAPHIC  1

#define LV_USE_THORVG_INTERNAL 1

#define LV_USE_SYSMON   1
#define LV_USE_PERF_MONITOR 1

#define LV_USE_LINUX_DRM        1

#define LV_USE_DEMO_WIDGETS 1

#define LV_USE_DEMO_BENCHMARK 1

2.2. Main 함수 작성

  이제 main.c 파일을 생성하여 lvgl의 데모를 실행하는 어플리케이션을 개발하도록 하겠습니다.

# 작성할 소스코드 위치 생성
mkdir src

# src폴더 내 main.c 파일 생성
touch ./src/main.c

  

 

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <stdbool.h>

#include "lvgl.h"
#include "lvgl/demos/lv_demos.h"

const char *getenv_default(const char *name, const char *dflt)
{
    return getenv(name) ?: dflt;
}

void lv_linux_disp_init(void)
{
    const char *device = getenv_default("LV_LINUX_DRM_CARD", "/dev/dri/card1");
    lv_display_t *disp = lv_linux_drm_create();

    lv_linux_drm_set_file(disp, device, -1);
}

int main(void){

    lv_init();

    lv_linux_disp_init();

    lv_demo_benchmark();

    while(true){

        lv_timer_handler(); // Handle LVGL tasks
        
        usleep(5000);
    }

    return 0;
}

 

2.3. 빌드 하기 위한 Makefile 작성

  LVGL은 CMake 및 Makefile을 사용해 빌드를 할 수 있습니다. CMake를 사용하는 것이 훨신 쉽게 빌드 할 수 있지만 LVGL를 어떻게 빌드를 하는지 방법이 궁금하기에 Makefile를 사용해 보도록 하겠습니다.

# 프로젝트를 빌드할 Makefile 생성
touch Makefile

 

- 중요

  반드시 COMPILER_DIR을 설정해주어야 합니다. SDK의 위치는 각 개발환경마다 다르기 때문에 해당 위치를 설정하여야 합니다. 

 

- Makefile 내용

# buildroot sdk 위치
COMPILER_DIR := /home/gordon/sdk/aarch64-buildroot-linux-gnu_sdk-buildroot

# Compiler 설정
CC = $(COMPILER_DIR)/bin/aarch64-buildroot-linux-gnu-gcc
CXX = $(COMPILER_DIR)/bin/aarch64-buildroot-linux-gnu-g++

# Compiler flags 및 include paths 설정
CFLAGS = -Wall -O2 
CFLAGS += -I.
CFLAGS += -I$(COMPILER_DIR)/aarch64-buildroot-linux-gnu/sysroot/usr/include
CFLAGS += -I$(COMPILER_DIR)/aarch64-buildroot-linux-gnu/sysroot/usr/include/libdrm

# Linker flags 설정
LDFLAGS = -lm -ldrm

# Source 및 Build 디렉토리 설정
SRC_DIR = ./src
BUILD_DIR = ./build

# 소스 파일 및 오브젝트 파일 목록 생성
CSRCS = $(shell find $(SRC_DIR) -name '*.c')
COBJS = $(CSRCS:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)

# LVGL Path 설정
LVGL_PATH = ./lvgl

# LVGL 내 C언어 소스 파일 및 오브젝트 파일 목록 생성
LVGL_CSRCS = $(shell find $(LVGL_PATH) -type f -name '*.c')
LVGL_COBJS = $(LVGL_CSRCS:$(LVGL_PATH)/%.c=$(BUILD_DIR)/lvgl/%.o)

# LVGL 내 CPP언어 소스 파일 및 오브젝트 파일 목록 생성
LVGL_CXXSRCS = $(shell find $(LVGL_PATH) -type f -name '*.cpp')
LVGL_CXXOBJS = $(LVGL_CXXSRCS:$(LVGL_PATH)/%.cpp=$(BUILD_DIR)/lvgl/%.o)

# 최종 빌드 타겟 이름 설정
TARGET = lv_banchmark

# include the variable to build the lvgl library

.PHONY: all clean

all: $(TARGET)

# 빌드 타겟 생성
$(TARGET): $(COBJS) $(LVGL_COBJS) $(LVGL_CXXOBJS)
	$(CXX) $(LDFLAGS) $(CFLAGS) -o $(BUILD_DIR)/$@  $^

# 프로젝트 내 C언어 소스 파일 컴파일
$(COBJS): $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) -I$(LVGL_PATH) -c $^ -o $@

# LVGL C언어 소스 파일 컴파일
$(LVGL_COBJS): $(BUILD_DIR)/%.o: %.c
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) -I$(LVGL_PATH) -c $^ -o $@

# LVGL CPP언어 소스 파일 컴파일
$(LVGL_CXXOBJS): $(BUILD_DIR)/%.o: %.cpp
	@mkdir -p $(dir $@)
	$(CXX) $(CFLAGS) -I$(LVGL_PATH) -c $^ -o $@

clean:
	rm -rf $(BUILD_DIR)

 

3. 프로젝트 빌드

# 프로젝트 빌드
make

# 프로그램 생성 확인
ls ./build/lv_application

 

  이제 lv_application을 타겟 보드에서 실행하면 정상 실행되는 것을 할 수 있습니다.

- 참고 문서

https://docs.lvgl.io/master/details/integration/os/buildroot/index.html

https://github.com/lvgl/lv_buildroot

https://github.com/EDGEMTech/lv_benchmark