Grafik & Görüntü
TEKNİK REHBER GRAFİK & GÖRÜNTÜ LVGL 2026

LVGL —
embedded grafik kütüphanesi.

64KB RAM ile çalışan, MCU'dan Linux'a taşınabilir MIT lisanslı C99 grafik kütüphanesi. Widget sistemi, CSS-benzeri style, flexbox layout, animasyon ve Squareline Studio GUI tasarımı.

00 LVGL nedir

LVGL (Light and Versatile Graphics Library), gömülü sistemler için geliştirilmiş açık kaynak bir grafik kütüphanesidir. MCU'dan Linux'a kadar geniş bir hedef yelpazesinde çalışır.

Temel özellikler

Lisans
MIT — ticari ürünlerde telif hakkı bildirimi dışında kısıtlama yoktur.
Dil
C99 — C++ veya Rust ile de kullanılabilir. Harici bağımlılık yoktur.
Minimum gereksinimler
64KB RAM, 256KB Flash. 8-bit MCU'lardan 64-bit Linux'a kadar çalışır.
Widget sayısı
30'dan fazla hazır widget: button, label, slider, chart, gauge, calendar, keyboard, list, tabview, tileview.
Render
Yazılım renderer (her platformda çalışır). isteğe bağlı GPU hızlandırma: STM32 Chrom-ART, NXP PXP, SDL2 backend.

Desteklenen platformlar

Platform listesi
MCU      : STM32, ESP32, RP2040, nRF52840, PIC32, AVR32
RTOS     : FreeRTOS, Zephyr, ThreadX, RT-Thread, NuttX
Linux    : fbdev (/dev/fb0), DRM/KMS, SDL2, X11, Wayland
Simülasyon: PC (SDL2 ile) — hedef donanım olmadan geliştirme

LVGL sürüm yapısı

bash — kaynak edinme
# En son stabil (v9.x)
git clone --branch release/v9.2 --depth 1 \
    https://github.com/lvgl/lvgl.git

# Simülatör ile başla (SDL2 backend)
git clone https://github.com/lvgl/lv_port_pc_eclipse.git

# Linux port (fbdev + DRM)
git clone https://github.com/lvgl/lv_port_linux.git

01 Porting — lv_conf.h, display driver, tick callback

LVGL'i yeni bir platforma taşımak için üç şey gerekir: konfigürasyon dosyası, display flush callback ve millisaniye tick kaynağı.

lv_conf.h — temel ayarlar

lv_conf.h (özet)
#define LV_COLOR_DEPTH     16      /* RGB565; 32 = ARGB8888 */
#define LV_HOR_RES_MAX    480      /* yatay çözünürlük */
#define LV_VER_RES_MAX    320      /* dikey çözünürlük */

/* Bellek havuzu boyutu (internal renderer için) */
#define LV_MEM_SIZE       (64 * 1024U)  /* 64KB */

/* Render buffer sayısı */
#define LV_DISP_BUF_SIZE  (LV_HOR_RES_MAX * 10)

/* Animasyon, font ve diğer özellikler */
#define LV_USE_ANIMATION   1
#define LV_USE_FONT_MONTSERRAT_16  1
#define LV_USE_PERF_MONITOR  1     /* FPS sayacı */

/* Log seviyesi */
#define LV_USE_LOG         1
#define LV_LOG_LEVEL       LV_LOG_LEVEL_WARN

Display driver — flush_cb

C — display driver kaydı
#include "lvgl/lvgl.h"

static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf1[LV_HOR_RES_MAX * 10];   /* render tamponu */

/* LVGL bu fonksiyonu çağırır: render bölgesini ekrana yaz */
static void disp_flush(lv_disp_drv_t *drv,
                       const lv_area_t *area,
                       lv_color_t *color_p)
{
    /* platform'a özgü: fbdev'e, SPI'a veya SDRAM'a yaz */
    int32_t x, y;
    for (y = area->y1; y <= area->y2; y++) {
        for (x = area->x1; x <= area->x2; x++) {
            fb_pixels[y * FB_WIDTH + x] =
                lv_color_to16(*color_p);
            color_p++;
        }
    }

    /* Flush tamamlandı — LVGL'e bildir (zorunlu!) */
    lv_disp_flush_ready(drv);
}

void display_init(void)
{
    lv_init();

    lv_disp_draw_buf_init(&draw_buf, buf1, NULL,
        LV_HOR_RES_MAX * 10);

    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res   = LV_HOR_RES_MAX;
    disp_drv.ver_res   = LV_VER_RES_MAX;
    disp_drv.flush_cb  = disp_flush;
    disp_drv.draw_buf  = &draw_buf;
    lv_disp_drv_register(&disp_drv);
}

Tick callback ve task handler

C — Linux tick ve handler
#include <time.h>
#include <pthread.h>

/* Tick thread: her 1ms lv_tick_inc() çağır */
static void *tick_thread(void *arg)
{
    (void)arg;
    while (1) {
        usleep(1000);           /* 1ms */
        lv_tick_inc(1);
    }
    return NULL;
}

/* Ana döngü */
int main(void)
{
    display_init();
    input_init();     /* touch/mouse driver */
    ui_init();        /* widget'ları oluştur */

    pthread_t tid;
    pthread_create(&tid, NULL, tick_thread, NULL);

    while (1) {
        lv_task_handler();  /* LVGL görevlerini işle */
        usleep(5000);        /* ~200 FPS max */
    }
    return 0;
}

Linux /dev/fb0 backend (hazır port)

bash — lv_port_linux derleme
cd lv_port_linux
# lv_conf.h ayarlarını düzenle
cmake -B build \
    -DLV_CONF_PATH=$(pwd)/lv_conf.h \
    -DBACKEND=fbdev
cmake --build build -j$(nproc)

# /dev/fb0 erişimi için gerekirse
sudo ./build/lvgl_demo

02 Widget sistemi

LVGL'deki tüm görsel elemanlar lv_obj_t tipindedir. Her widget bu temel tipten türer ve aynı event/style/layout altyapısını paylaşır.

Temel widget'lar

C — sık kullanılan widget'lar
/* Label */
lv_obj_t *label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Sıcaklık: 72°C");
lv_obj_set_pos(label, 10, 10);

/* Button */
lv_obj_t *btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 120, 50);
lv_obj_add_event_cb(btn, btn_handler, LV_EVENT_CLICKED, NULL);
lv_obj_t *btn_lbl = lv_label_create(btn);
lv_label_set_text(btn_lbl, "Başlat");
lv_obj_center(btn_lbl);

/* Slider */
lv_obj_t *slider = lv_slider_create(lv_scr_act());
lv_obj_set_size(slider, 200, 10);
lv_slider_set_range(slider, 0, 100);
lv_slider_set_value(slider, 60, LV_ANIM_ON);
lv_obj_add_event_cb(slider, slider_handler,
    LV_EVENT_VALUE_CHANGED, NULL);

/* Chart (gerçek zamanlı grafik) */
lv_obj_t *chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 300, 150);
lv_chart_set_type(chart, LV_CHART_TYPE_LINE);
lv_chart_series_t *ser =
    lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED),
        LV_CHART_AXIS_PRIMARY_Y);
lv_chart_set_next_value(chart, ser, 72);  /* veri ekle */

Tabview ve Tileview

C — tabview
/* Tabview: üstte tab bar */
lv_obj_t *tabview = lv_tabview_create(lv_scr_act(),
    LV_DIR_TOP, 50);

lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "Sensörler");
lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "Kontrol");
lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "Ayarlar");

/* Tab 1 içeriği */
lv_obj_t *lbl = lv_label_create(tab1);
lv_label_set_text(lbl, "Sıcaklık: 72°C");

/* Kaydırmalı tile view */
lv_obj_t *tileview = lv_tileview_create(lv_scr_act());
lv_obj_t *tile1 = lv_tileview_add_tile(tileview,
    0, 0, LV_DIR_HOR);
lv_obj_t *tile2 = lv_tileview_add_tile(tileview,
    1, 0, LV_DIR_HOR);

Event callback sistemi

C — event handler
static void btn_handler(lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t *btn = lv_event_get_target(e);

    if (code == LV_EVENT_CLICKED) {
        static int count = 0;
        lv_obj_t *lbl = lv_obj_get_child(btn, 0);
        lv_label_set_text_fmt(lbl, "Tıklama: %d", ++count);
    } else if (code == LV_EVENT_LONG_PRESSED) {
        LV_LOG_USER("Uzun basış!");
    }
}

03 Style sistemi — CSS-benzeri kalıtım, state, opacity

LVGL'in style sistemi CSS'e benzer: style nesneleri oluşturulur, widget'lara ve state'lere atanır, kalıtımla alt nesnelere aktarılır.

lv_style_t kullanımı

C — style oluşturma ve uygulama
static lv_style_t style_btn;
static lv_style_t style_btn_pressed;

void styles_init(void)
{
    /* Normal durum */
    lv_style_init(&style_btn);
    lv_style_set_bg_color(&style_btn,
        lv_color_hex(0x2196F3));          /* mavi */
    lv_style_set_bg_opa(&style_btn, LV_OPA_COVER);
    lv_style_set_radius(&style_btn, 8);
    lv_style_set_pad_all(&style_btn, 12);
    lv_style_set_text_color(&style_btn,
        lv_color_white());
    lv_style_set_shadow_width(&style_btn, 4);
    lv_style_set_shadow_ofs_y(&style_btn, 4);

    /* Basılı durum */
    lv_style_init(&style_btn_pressed);
    lv_style_set_bg_color(&style_btn_pressed,
        lv_color_hex(0x1565C0));          /* koyu mavi */
    lv_style_set_translate_y(&style_btn_pressed, 2);
    lv_style_set_shadow_width(&style_btn_pressed, 0);
}

lv_obj_t *btn = lv_btn_create(lv_scr_act());
lv_obj_add_style(btn, &style_btn, LV_STATE_DEFAULT);
lv_obj_add_style(btn, &style_btn_pressed, LV_STATE_PRESSED);

State'ler

LV_STATE_DEFAULT
Normal, aktif durumu olmayan hal.
LV_STATE_PRESSED
Dokunmatik basış veya fare tıklaması sırasında.
LV_STATE_FOCUSED
Klavye navigasyonu ile seçili nesne.
LV_STATE_DISABLED
Etkileşim devre dışı. lv_obj_add_state(obj, LV_STATE_DISABLED) ile ayarla.
LV_STATE_CHECKED
Checkbox, switch veya toggle button aktif durumu.

Tema sistemi

C — tema seçimi
/* Yerleşik temalar */
lv_theme_t *theme = lv_theme_default_init(
    lv_disp_get_default(),
    lv_palette_main(LV_PALETTE_BLUE),    /* primary renk */
    lv_palette_main(LV_PALETTE_RED),     /* secondary renk */
    true,                                 /* dark mode */
    LV_FONT_DEFAULT);

lv_disp_set_theme(lv_disp_get_default(), theme);

04 Layout — Flexbox, Grid, scroll, snap

LVGL v8+, CSS Flexbox ve CSS Grid benzeri yerleşim sistemleri sunar. Sabit koordinat yerine dinamik yerleşim, farklı çözünürlüklerde uyumlu arayüz sağlar.

Flexbox layout

C — Flex layout
lv_obj_t *flex_box = lv_obj_create(lv_scr_act());
lv_obj_set_size(flex_box, LV_PCT(100), LV_CONTENT);

/* Flex layout: yatay, merkeze hizalı, sarma */
lv_obj_set_layout(flex_box, LV_LAYOUT_FLEX);
lv_obj_set_flex_flow(flex_box, LV_FLEX_FLOW_ROW_WRAP);
lv_obj_set_flex_align(flex_box,
    LV_FLEX_ALIGN_CENTER,    /* main axis (yatay) */
    LV_FLEX_ALIGN_CENTER,    /* cross axis (dikey) */
    LV_FLEX_ALIGN_START);    /* satır hizalama */
lv_obj_set_style_pad_column(flex_box, 10, 0);
lv_obj_set_style_pad_row(flex_box, 10, 0);

/* Çocuk nesneler otomatik yerleşir */
for (int i = 0; i < 6; i++) {
    lv_obj_t *btn = lv_btn_create(flex_box);
    lv_obj_set_size(btn, 100, 50);
    lv_obj_t *lbl = lv_label_create(btn);
    lv_label_set_text_fmt(lbl, "BTN %d", i + 1);
    lv_obj_center(lbl);
}

Grid layout

C — Grid layout
/* 3 sütun, 2 satır grid */
static lv_coord_t col_dsc[] = {
    LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_FR(1),
    LV_GRID_TEMPLATE_LAST
};
static lv_coord_t row_dsc[] = {
    60, 60,
    LV_GRID_TEMPLATE_LAST
};

lv_obj_t *grid = lv_obj_create(lv_scr_act());
lv_obj_set_size(grid, 320, 160);
lv_obj_set_layout(grid, LV_LAYOUT_GRID);
lv_obj_set_grid_dsc_array(grid, col_dsc, row_dsc);

/* Nesneyi grid hücresine yerleştir */
lv_obj_t *obj = lv_obj_create(grid);
lv_obj_set_grid_cell(obj,
    LV_GRID_ALIGN_STRETCH, 1, 1,    /* sütun: pos=1, span=1 */
    LV_GRID_ALIGN_STRETCH, 0, 1);   /* satır: pos=0, span=1 */

Scroll ve Snap

C — scroll snap
/* Yatay scroll snap listesi */
lv_obj_t *list = lv_obj_create(lv_scr_act());
lv_obj_set_size(list, 320, 100);
lv_obj_set_flex_flow(list, LV_FLEX_FLOW_ROW);
lv_obj_set_scroll_dir(list, LV_DIR_HOR);
lv_obj_set_scroll_snap_x(list, LV_SCROLL_SNAP_CENTER);

for (int i = 0; i < 10; i++) {
    lv_obj_t *item = lv_obj_create(list);
    lv_obj_set_size(item, 100, 80);  /* tam snap için eşit genişlik */
    lv_obj_t *lbl = lv_label_create(item);
    lv_label_set_text_fmt(lbl, "Sayfa %d", i + 1);
    lv_obj_center(lbl);
}
lv_obj_update_snap(list, LV_ANIM_ON);

05 Animasyon — lv_anim_t, path_cb, timeline

LVGL animasyon sistemi, herhangi bir sayısal özelliği başlangıç ve bitiş değeri arasında smooth geçişle değiştirir. Easing fonksiyonları ve timeline ile karmaşık sekanslar mümkündür.

Temel animasyon

C — lv_anim_t
lv_anim_t a;
lv_anim_init(&a);

/* Hedef nesne ve setter fonksiyonu */
lv_anim_set_var(&a, obj);
lv_anim_set_exec_cb(&a,
    (lv_anim_exec_xcb_t) lv_obj_set_x);  /* X konumunu değiştir */

/* Değer aralığı ve süre */
lv_anim_set_values(&a, 0, 200);         /* 0 → 200 px */
lv_anim_set_time(&a, 500);              /* 500 ms */
lv_anim_set_delay(&a, 100);             /* 100 ms gecikme */

/* Easing: kolaydan zora */
lv_anim_set_path_cb(&a, lv_anim_path_ease_in_out);

/* Tekrar: -1 = sonsuz */
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_repeat_delay(&a, 200);
lv_anim_set_playback_time(&a, 500);     /* geri oynat */

lv_anim_start(&a);

Hazır easing fonksiyonları

lv_anim_path_linear
Sabit hız. Mekanik görünüm.
lv_anim_path_ease_in
Yavaş başlar, hızlanır.
lv_anim_path_ease_out
Hızlı başlar, yavaşlar.
lv_anim_path_ease_in_out
Yavaş başlar, ortada hızlanır, yavaş biter. En doğal görünüm.
lv_anim_path_bounce
Sonunda zıplama efekti.
lv_anim_path_overshoot
Hedefi aşar, geri döner.

Animasyon timeline

C — timeline (paralel/sıralı)
lv_anim_timeline_t *timeline = lv_anim_timeline_create();

/* obj1: 0ms'de başla */
lv_anim_t a1;
lv_anim_init(&a1);
lv_anim_set_var(&a1, obj1);
lv_anim_set_exec_cb(&a1, (lv_anim_exec_xcb_t)lv_obj_set_y);
lv_anim_set_values(&a1, -50, 10);
lv_anim_set_time(&a1, 400);
lv_anim_set_path_cb(&a1, lv_anim_path_ease_out);
lv_anim_timeline_add(timeline, 0, &a1);

/* obj2: 200ms'de başla (overlap) */
lv_anim_t a2;
lv_anim_init(&a2);
lv_anim_set_var(&a2, obj2);
lv_anim_set_exec_cb(&a2, (lv_anim_exec_xcb_t)lv_obj_set_opacity);
lv_anim_set_values(&a2, LV_OPA_TRANSP, LV_OPA_COVER);
lv_anim_set_time(&a2, 300);
lv_anim_timeline_add(timeline, 200, &a2);

lv_anim_timeline_start(timeline);

06 Squareline Studio — GUI tasarımı ve C export

Squareline Studio, LVGL için sürükle-bırak GUI tasarım aracıdır. Tasarlanan arayüzü C koduna export eder; bu kod doğrudan LVGL projesine entegre edilir.

Squareline Studio iş akışı

  Squareline Studio (PC)
       ↓
  Widget'ları sürükle-bırak
  Style ve animasyon tanımla
       ↓
  Export → C source (ui.c, ui.h)
       ↓
  LVGL projesine kopyala
       ↓
  main() içinde ui_init() çağır
    

Export edilen kodun kullanımı

C — Squareline export entegrasyonu
/* Squareline export'tan gelen dosyalar */
#include "ui.h"    /* ui_init(), ui_Screen1, lv_obj'ler */

int main(void)
{
    lv_init();
    display_init();
    input_init();

    /* Squareline tarafından üretilen UI'ı başlat */
    ui_init();

    /* Squareline'dan event binding — C callback'e bağla */
    lv_obj_add_event_cb(ui_StartButton, on_start_clicked,
        LV_EVENT_CLICKED, NULL);

    while (1) {
        lv_task_handler();
        usleep(5000);
    }
    return 0;
}

Image converter — RGB565 / ARGB8888

bash — lvgl image converter
# Python tabanlı LVGL image converter
pip install lv_img_conv

# PNG → RGB565 C array
lv_img_conv logo.png -f CF_RGB565 -o logo.c

# PNG → ARGB8888 (alpha kanal ile)
lv_img_conv icon.png -f CF_TRUE_COLOR_ALPHA -o icon.c

# Kullanım:
# LV_IMG_DECLARE(logo);
# lv_img_set_src(img_obj, &logo);

07 Zephyr + LVGL — CONFIG_LVGL, nRF52840 OLED

Zephyr RTOS, LVGL'i display subsystem üzerinden entegre eder. CONFIG_LVGL ile otomatik tick ve display driver bağlantısı yapılır.

prj.conf yapılandırması

prj.conf
CONFIG_LVGL=y
CONFIG_LV_Z_MEM_POOL_SIZE=8192

# Display subsystem
CONFIG_DISPLAY=y
CONFIG_SSD1306=y              # SSD1306 OLED sürücüsü
CONFIG_DISPLAY_LOG_LEVEL_ERR=y

# Touch input (dokunmatik varsa)
CONFIG_INPUT=y
CONFIG_INPUT_LVGL=y

# Tick kaynağı (otomatik)
CONFIG_LV_Z_TICK_PERIOD_MS=1

# Font
CONFIG_LV_FONT_MONTSERRAT_14=y

# Thread stack
CONFIG_MAIN_STACK_SIZE=4096

Zephyr LVGL uygulama

main.c — nRF52840 + SSD1306
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/display.h>
#include <lvgl.h>

int main(void)
{
    const struct device *display =
        DEVICE_DT_GET(DT_CHOSEN(zephyr_display));

    if (!device_is_ready(display)) {
        printk("Display hazır değil\n");
        return -1;
    }

    display_blanking_off(display);

    /* Basit sayaç UI */
    lv_obj_t *count_label = lv_label_create(lv_scr_act());
    lv_label_set_text(count_label, "0");
    lv_obj_align(count_label, LV_ALIGN_CENTER, 0, 0);

    int count = 0;
    while (1) {
        lv_label_set_text_fmt(count_label, "%d", count++);
        lv_task_handler();
        k_msleep(100);
    }
    return 0;
}

Device tree — SSD1306 OLED bağlantısı

nrf52840dk_nrf52840.overlay
&i2c0 {
    ssd1306: ssd1306@3c {
        compatible = "solomon,ssd1306fb";
        reg = <0x3c>;
        width = <128>;
        height = <64>;
        segment-offset = <0>;
        page-offset = <0>;
        display-offset = <0>;
        multiplex-ratio = <63>;
        prechargep = <0x22>;
    };
};

/ {
    chosen {
        zephyr,display = &ssd1306;
    };
};

08 Pratik

Üç gerçek dünya senaryosu: Linux /dev/fb0 backend ile full-screen demo, STM32F429 Discovery dokunmatik ekran ve Raspberry Pi performans benchmarkı.

Linux /dev/fb0 — full-screen LVGL demo

C — fbdev flush callback
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include "lvgl/lvgl.h"

static int fb_fd;
static uint16_t *fb_pixels;  /* RGB565 */
static uint32_t fb_line_length;

static void fbdev_flush(lv_disp_drv_t *drv,
                        const lv_area_t *area,
                        lv_color_t *color_p)
{
    for (int32_t y = area->y1; y <= area->y2; y++) {
        memcpy(&fb_pixels[y * (fb_line_length / 2) + area->x1],
               color_p,
               (area->x2 - area->x1 + 1) * 2);
        color_p += (area->x2 - area->x1 + 1);
    }
    lv_disp_flush_ready(drv);
}

void fbdev_init(int width, int height)
{
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;

    fb_fd = open("/dev/fb0", O_RDWR);
    ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo);
    ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo);

    fb_line_length = finfo.line_length;
    size_t fb_size = finfo.line_length * vinfo.yres;
    fb_pixels = mmap(NULL, fb_size,
        PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
}

STM32F429 Discovery — touchscreen

C — STM32 touch driver
/* STM32 HAL + STMPE811 touch controller */
static void touch_read(lv_indev_drv_t *drv,
                       lv_indev_data_t *data)
{
    static uint16_t last_x, last_y;

    if (BSP_TS_GetState(&ts_state) == TS_OK) {
        if (ts_state.TouchDetected) {
            data->point.x = ts_state.X;
            data->point.y = ts_state.Y;
            data->state   = LV_INDEV_STATE_PR;
            last_x = data->point.x;
            last_y = data->point.y;
        } else {
            data->point.x = last_x;
            data->point.y = last_y;
            data->state   = LV_INDEV_STATE_REL;
        }
    }
}

/* Kayıt */
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type    = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = touch_read;
lv_indev_drv_register(&indev_drv);

Raspberry Pi performans benchmarkı

bash — LVGL benchmark
# lv_conf.h içinde benchmark'ı etkinleştir
# #define LV_USE_DEMO_BENCHMARK  1

# Derle ve çalıştır
cmake -B build -DLV_CONF_PATH=... -DBACKEND=fbdev
cmake --build build -j4
sudo ./build/lvgl_demo

# Örnek sonuçlar (RGB565, yazılım renderer):
# RPi Zero 2W  (1GHz Cortex-A53):  ~45 FPS
# RPi 4B       (1.8GHz Cortex-A72): ~120 FPS
# STM32F429    (168MHz Cortex-M4):   ~30 FPS
# DMA2D (Chrom-ART) ile STM32:       ~60 FPS