High CPU and FPS Issue on NXP MIMXRT1062 with LVGL V8.1.0
Environment
- CPU: NXP MIMXRT1062
- Display Size: 7 inch
- Display Resolution: 800 x 480 RGB565
- LVGL V8.1.0
- FreeRTOS
Delete this section if you read and applied the mentioned points.
Description
Hi, I’m developing GUI based on LVGL V8.1.0 on my customized MIMXRT1062 board. I found an issue regarding CPU/FPS performance, I put some image and one animation on GUI, and found the CPU will be around 90% and FPS will dramatically drop to only 5 FPS(I set refresh period as 40ms, meaning FPS should be 25).
Then I did some simple test: If I just create a blank widgetContainer with nothing inside, the CPU is only around 5%, and FPS is 25 as expect. But when I put a static image of which size is about 400 x 400 inside the widgetContainer, the CPU will significantly increaed to around 55% and FPS drop to approx. 6.
Could anyone kindly help me on this issue?
Code to reproduce
Add the relevant code snippets here.
Here’s my lvgl_support.c:
#include <lvgl/lvgl.h>
#include "lvgl_support.h"
#include "FreeRTOS.h"
#include "task.h"
#include "fsl_elcdif.h"
#include "fsl_gpio.h"
#ifdef USE_TSC
#include "fsl_lpi2c.h"
#include "fsl_ft5406_rt.h"
#endif
#include "console_support.h"
#include "platform_rtos.h"
#include "platform_utils.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#ifdef USE_TSC
/* Macros for the touch touch controller. */
#define TOUCH_I2C LPI2C1
/* Select USB1 PLL (480 MHz) as master lpi2c clock source */
#define TOUCH_LPI2C_CLOCK_SOURCE_SELECT (0U)
/* Clock divider for master lpi2c clock source */
#define TOUCH_LPI2C_CLOCK_SOURCE_DIVIDER (5U)
#define TOUCH_I2C_CLOCK_FREQ ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (TOUCH_LPI2C_CLOCK_SOURCE_DIVIDER + 1U))
#define TOUCH_I2C_BAUDRATE 100000U
#endif
/* Macros for panel. */
#define LCD_HSW 2
#define LCD_HFP 44
#define LCD_HBP 16
#define LCD_VSW 2
#define LCD_VFP 38
#define LCD_VBP 10
#define LCD_POL_FLAGS \
(kELCDIF_DataEnableActiveHigh | kELCDIF_VsyncActiveLow | kELCDIF_HsyncActiveLow | kELCDIF_DriveDataOnRisingClkEdge)
#define LCD_LCDIF_DATA_BUS kELCDIF_DataBus16Bit
/*******************************************************************************
* Prototypes
******************************************************************************/
static void Board_InitLcd(void);
static void Board_InitLcdClock(void);
static void Board_InitLcdBackLight(void);
static void Board_FlushDisplay(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
/*******************************************************************************
* Variables
******************************************************************************/
#ifdef USE_TSC
static ft5406_rt_handle_t touchHandle;
#endif
static lv_disp_draw_buf_t disp_buf;
AT_NONCACHEABLE_SECTION_ALIGN(static uint8_t s_frameBuffer[2][LCD_WIDTH * LCD_HEIGHT * LCD_FB_BYTE_PER_PIXEL], 64);
static OsMutexHandle_t g_oRefreshLock = 0;
static lv_obj_t* gpLogo = 0;
/*******************************************************************************
* Code
******************************************************************************/
static void lv_port_pre_init(void)
{
g_oRefreshLock = os_mutex_create();
ASSERT(g_oRefreshLock != 0);
lv_disp_draw_buf_init(&disp_buf, s_frameBuffer[0], s_frameBuffer[1], LCD_WIDTH * LCD_HEIGHT); /*Initialize the display buffer*/
}
static void lv_port_disp_init(void)
{
/*-------------------------
* Initialize your display
* -----------------------*/
Board_InitLcd();
/*-----------------------------------
* Register the display in LittlevGL
*----------------------------------*/
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
// extra initialization
disp_drv.hor_res = LCD_WIDTH;
disp_drv.ver_res = LCD_HEIGHT;
disp_drv.full_refresh = 1;
/*Used in buffered mode (LV_VDB_SIZE != 0 in lv_conf.h)*/
disp_drv.flush_cb = Board_FlushDisplay;
/*Set a display buffer*/
disp_drv.draw_buf = &disp_buf;
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
}
void LCDIF_IRQHandler(void)
{
uint32_t intStatus = ELCDIF_GetInterruptStatus(LCDIF);
ELCDIF_ClearInterruptStatus(LCDIF, intStatus);
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
exception return operation might vector to incorrect interrupt */
#if defined __CORTEX_M && (__CORTEX_M == 4U)
__DSB();
#endif
}
static void Board_InitLcdClock(void)
{
extern const clock_video_pll_config_t videoPllConfig_BOARD_BootClockRUN;
CLOCK_InitVideoPll(&videoPllConfig_BOARD_BootClockRUN);
}
static void Board_InitLcdBackLight(void)
{
// controlled by peripheral processor
}
static void Board_InitLcd(void)
{
/* Initialize the display. */
const elcdif_rgb_mode_config_t config = {
.panelWidth = LCD_WIDTH,
.panelHeight = LCD_HEIGHT,
.hsw = LCD_HSW,
.hfp = LCD_HFP,
.hbp = LCD_HBP,
.vsw = LCD_VSW,
.vfp = LCD_VFP,
.vbp = LCD_VBP,
.polarityFlags = LCD_POL_FLAGS,
/* littlevgl starts render in frame buffer 0, so show frame buffer 1 first. */
.bufferAddr = (uint32_t)s_frameBuffer[1],
.pixelFormat = kELCDIF_PixelFormatRGB565,
.dataBus = LCD_LCDIF_DATA_BUS,
};
/* Clear frame buffer. */
memset((void *)s_frameBuffer, 0, sizeof(s_frameBuffer));
/* Init board hardware. */
/* Set the eLCDIF read_qos priority high, to make sure eLCDIF
* can fetch data in time when PXP is used.
*/
*((volatile uint32_t *)0x41044100) = 5;
NVIC_SetPriority(LCDIF_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
Board_InitLcdClock();
ELCDIF_RgbModeInit(LCDIF, &config);
//ELCDIF_EnableInterrupts(LCDIF, kELCDIF_CurFrameDoneInterruptEnable);
//NVIC_EnableIRQ(LCDIF_IRQn);
ELCDIF_RgbModeStart(LCDIF);
Board_InitLcdBackLight();
}
static void Board_FlushDisplay(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
if (!lv_disp_flush_is_last(disp_drv))
return;
ELCDIF_SetNextBufferAddr(LCDIF, (uint32_t)color_p);
/* IMPORTANT!!!
* Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
#ifdef USE_TSC
/*Initialize your touchpad*/
static void Board_InitTouch(void)
{
status_t status;
lpi2c_master_config_t masterConfig = {0};
/*Clock setting for LPI2C*/
CLOCK_SetMux(kCLOCK_Lpi2cMux, TOUCH_LPI2C_CLOCK_SOURCE_SELECT);
CLOCK_SetDiv(kCLOCK_Lpi2cDiv, TOUCH_LPI2C_CLOCK_SOURCE_DIVIDER);
/*
* masterConfig.debugEnable = false;
* masterConfig.ignoreAck = false;
* masterConfig.pinConfig = kLPI2C_2PinOpenDrain;
* masterConfig.baudRate_Hz = 100000U;
* masterConfig.busIdleTimeout_ns = 0;
* masterConfig.pinLowTimeout_ns = 0;
* masterConfig.sdaGlitchFilterWidth_ns = 0;
* masterConfig.sclGlitchFilterWidth_ns = 0;
*/
LPI2C_MasterGetDefaultConfig(&masterConfig);
/* Change the default baudrate configuration */
masterConfig.baudRate_Hz = TOUCH_I2C_BAUDRATE;
/* Initialize the LPI2C master peripheral */
LPI2C_MasterInit(TOUCH_I2C, &masterConfig, TOUCH_I2C_CLOCK_FREQ);
/* Initialize touch panel controller */
status = FT5406_RT_Init(&touchHandle, TOUCH_I2C);
if (status != kStatus_Success)
{
PRINTF("Touch panel init failed\n");
}
}
/* Will be called by the library to read the touchpad */
static bool Board_ReadTouch(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t *data)
{
static int touch_x = 0;
static int touch_y = 0;
data->state = LV_INDEV_STATE_REL;
touch_event_t touch_event;
// swap x and y
if (kStatus_Success == FT5406_RT_GetSingleTouch(&touchHandle, &touch_event, &touch_y, &touch_x))
{
if ((touch_event == kTouch_Down) || (touch_event == kTouch_Contact))
{
data->state = LV_INDEV_STATE_PR;
}
}
/*Set the last pressed coordinates*/
data->point.x = touch_x;
data->point.y = touch_y;
/*Return `false` because we are not buffering and no more data to read*/
return false;
}
#else
OsQueueHandle_t g_LvglKeypadEventQueue;
bool lvgl_keypad_event(Key_Hw_Event_t event)
{
return os_queue_send(g_LvglKeypadEventQueue, &event, 0);
}
void lvgl_keypad_cb(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t *data)
{
Key_Hw_Event_t event;
if (os_queue_receive(g_LvglKeypadEventQueue, &event, 0))
{
if (event.pressed)
{
switch (event.key)
{
case 0x0a:
data->key = LV_KEY_ESC;
break;
case 0x0d:
data->key = LV_KEY_ENTER;
break;
default:
data->key = 0;
break;
}
data->state = LV_INDEV_STATE_PR;
}
else
{
switch (event.key)
{
case 0x0a:
data->key = LV_KEY_ESC;
break;
case 0x0d:
data->key = LV_KEY_ENTER;
break;
default:
data->key = 0;
break;
}
data->state = LV_INDEV_STATE_REL;
}
}
}
#endif
lv_group_t * gInputKeypadGroup;
lv_indev_t * gInputKeypadDev;
OsQueueHandle_t g_LvglPollTaskQueue;
static void lv_port_indev_init(void)
{
/*------------------
* Touchpad
* -----------------*/
#ifdef USE_TSC
static lv_indev_drv_t indev_drv;
Board_InitTouch();
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = Board_ReadTouch;
lv_indev_drv_register(&indev_drv);
#else
// Init and register FMT keyboard device
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_KEYPAD;
indev_drv.read_cb = lvgl_keypad_cb;
gInputKeypadDev = lv_indev_drv_register(&indev_drv);
gInputKeypadGroup = lv_group_create();
lv_indev_set_group(gInputKeypadDev, gInputKeypadGroup);
g_LvglKeypadEventQueue = os_queue_create(2, sizeof(Key_Hw_Event_t));
g_LvglPollTaskQueue = os_queue_create(1, sizeof(uint8_t));
#endif
}
static void lv_poll(uint16_t msDelay)
{
#if !defined (LV_TICK_CUSTOM) || (LV_TICK_CUSTOM == 0)
lv_tick_inc(msDelay);
#endif
lvgl_lock();
lv_task_handler();
lvgl_unlock();
}
static void lv_poll_task(void *pvParameters)
{
uint8_t nEvt;
while (true)
{
os_queue_receive(g_LvglPollTaskQueue, &nEvt, LV_DISP_GIF_REFR_PERIOD);
lv_poll(LV_DISP_GIF_REFR_PERIOD);
}
}
void lvgl_init(void)
{
lv_port_pre_init();
lv_init();
lv_port_disp_init();
lv_port_indev_init();
#ifndef BOOTLOADER
// lvgl_show_sf_logo(100, 193);
#endif
os_task_create(lv_poll_task, 0, "lvgl", 4096, OS_TASK_GUI_PRIORITY);
}
// This LVGL lock/unlock mechanism wouldn't work without FreeRTOS environment
// It is FreeRTOS task context related.
void lvgl_lock(void)
{
if (xGetTaskGUILockRefCount() > 0)
{
// Already locked, just increase the reference count
xTaskGUILockRefInc();
return;
}
// Otherwise, obtain the lock first
if (!os_mutex_lock(g_oRefreshLock, 10000))
{
// Fatal issue. Seems deadlock happened. Restart unit
ASSERT(0);
return; // Shouldn't be here
}
// Now we own the lock, increase the reference count next
xTaskGUILockRefInc();
// It's safe to call any lvgl APIs
return;
}
void lvgl_unlock(void)
{
// Decrease the reference count first
xTaskGUILockRefDec();
if (xGetTaskGUILockRefCount() == 0)
{
// If no context referencing the lock, release it
os_mutex_unlock(g_oRefreshLock);
}
}
And here’re part of my lvgl_conf.h:
/* clang-format off */
#if 1 /*Set it to "1" to enable content*/
#ifndef LV_CONF_H
#define LV_CONF_H
#include <stdint.h>
#include "lvgl_support.h"
/*====================
COLOR SETTINGS
*====================*/
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH 16
/*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/
#define LV_COLOR_16_SWAP 0
/*Enable more complex drawing routines to manage screens transparency.
*Can be used if the UI is above another layer, e.g. an OSD menu or video player.
*Requires `LV_COLOR_DEPTH = 32` colors and the screen's `bg_opa` should be set to non LV_OPA_COVER value*/
#define LV_COLOR_SCREEN_TRANSP 0
/* Adjust color mix functions rounding. GPUs might calculate color mix (blending) differently.
* 0: round down, 64: round up from x.75, 128: round up from half, 192: round up from x.25, 254: round up */
#define LV_COLOR_MIX_ROUND_OFS (LV_COLOR_DEPTH == 32 ? 0: 128)
/*Images pixels with this color will not be drawn if they are chroma keyed)*/
#define LV_COLOR_CHROMA_KEY lv_color_hex(0x00ff00) /*pure green*/
/*=========================
MEMORY SETTINGS
*=========================*/
/*1: use custom malloc/free, 0: use the built-in `lv_mem_alloc()` and `lv_mem_free()`*/
#define LV_MEM_CUSTOM 1
#if LV_MEM_CUSTOM == 0
/*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/
# define LV_MEM_SIZE (32U * 1024U) /*[bytes]*/
/*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/
# define LV_MEM_ADR 0 /*0: unused*/
/*Instead of an address give a memory allocator that will be called to get a memory pool for LVGL. E.g. my_malloc*/
#if LV_MEM_ADR == 0
//#define LV_MEM_POOL_INCLUDE your_alloc_library /* Uncomment if using an external allocator*/
//#define LV_MEM_POOL_ALLOC your_alloc /* Uncomment if using an external allocator*/
#endif
#else /*LV_MEM_CUSTOM*/
# define LV_MEM_CUSTOM_INCLUDE <stdlib.h> /*Header for the dynamic memory function*/
# define LV_MEM_CUSTOM_ALLOC malloc
# define LV_MEM_CUSTOM_FREE free
# define LV_MEM_CUSTOM_REALLOC realloc
#endif /*LV_MEM_CUSTOM*/
/*Number of the intermediate memory buffer used during rendering and other internal processing mechanisms.
*You will see an error log message if there wasn't enough buffers. */
#define LV_MEM_BUF_MAX_NUM 16
/*Use the standard `memcpy` and `memset` instead of LVGL's own functions. (Might or might not be faster).*/
#define LV_MEMCPY_MEMSET_STD 0
/*====================
HAL SETTINGS
*====================*/
/*GIF display refresh period. LVG will redraw changed ares with this period time*/
#define LV_DISP_GIF_REFR_PERIOD 20 /*[ms]*/
/*Default display refresh period. LVG will redraw changed ares with this period time*/
#define LV_DISP_DEF_REFR_PERIOD (LV_DISP_GIF_REFR_PERIOD * 2) /*[ms]*/ //2
/*Input device read period in milliseconds*/
#define LV_INDEV_DEF_READ_PERIOD 30 /*[ms]*/
/*Use a custom tick source that tells the elapsed time in milliseconds.
*It removes the need to manually update the tick with `lv_tick_inc()`)*/
#define LV_TICK_CUSTOM 1
#if LV_TICK_CUSTOM
#define LV_TICK_CUSTOM_INCLUDE "platform_rtos.h" /*Header for the system time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (os_get_sys_tick_count()) /*Expression evaluating to current system time in ms*/
#endif /*LV_TICK_CUSTOM*/
/*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings.
*(Not so important, you can adjust it to modify default sizes and spaces)*/
#define LV_DPI_DEF 130 /*[px/inch]*/
/*=======================
* FEATURE CONFIGURATION
*=======================*/
/*-------------
* Drawing
*-----------*/
/*Enable complex draw engine.
*Required to draw shadow, gradient, rounded corners, circles, arc, skew lines, image transformations or any masks*/
#define LV_DRAW_COMPLEX 1
#if LV_DRAW_COMPLEX != 0
/*Allow buffering some shadow calculation.
*LV_SHADOW_CACHE_SIZE is the max. shadow size to buffer, where shadow size is `shadow_width + radius`
*Caching has LV_SHADOW_CACHE_SIZE^2 RAM cost*/
#define LV_SHADOW_CACHE_SIZE 0
/* Set number of maximally cached circle data.
* The circumference of 1/4 circle are saved for anti-aliasing
* radius * 4 bytes are used per circle (the most often used radiuses are saved)
* 0: to disable caching */
#define LV_CIRCLE_CACHE_SIZE 4
#endif /*LV_DRAW_COMPLEX*/
/*Default image cache size. Image caching keeps the images opened.
*If only the built-in image formats are used there is no real advantage of caching. (I.e. if no new image decoder is added)
*With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images.
*However the opened images might consume additional RAM.
*0: to disable caching*/
#define LV_IMG_CACHE_DEF_SIZE 0
/*Maximum buffer size to allocate for rotation. Only used if software rotation is enabled in the display driver.*/
#define LV_DISP_ROT_MAX_BUF (10*1024)
/*-------------
* GPU
*-----------*/
/*Use STM32's DMA2D (aka Chrom Art) GPU*/
#define LV_USE_GPU_STM32_DMA2D 0
#if LV_USE_GPU_STM32_DMA2D
/*Must be defined to include path of CMSIS header of target processor
e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
#define LV_GPU_DMA2D_CMSIS_INCLUDE
#endif
/*Use NXP's PXP GPU iMX RTxxx platforms*/
#define LV_USE_GPU_NXP_PXP 1
#if LV_USE_GPU_NXP_PXP
/*1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c)
* and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol SDK_OS_FREE_RTOS
* has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected.
*0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init()
*/
#define LV_USE_GPU_NXP_PXP_AUTO_INIT 1
#endif
/*Use NXP's VG-Lite GPU iMX RTxxx platforms*/
#define LV_USE_GPU_NXP_VG_LITE 0
/*Use exnternal renderer*/
#define LV_USE_EXTERNAL_RENDERER 0
/*Use SDL renderer API. Requires LV_USE_EXTERNAL_RENDERER*/
#define LV_USE_GPU_SDL 0
#if LV_USE_GPU_SDL
# define LV_GPU_SDL_INCLUDE_PATH <SDL2/SDL.h>
#endif
/*-------------
* Logging
*-----------*/
/*Enable the log module*/
#define LV_USE_LOG 0
#if LV_USE_LOG
/*How important log should be added:
*LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
*LV_LOG_LEVEL_INFO Log important events
*LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem
*LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
*LV_LOG_LEVEL_USER Only logs added by the user
*LV_LOG_LEVEL_NONE Do not log anything*/
# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN
/*1: Print the log with 'printf';
*0: User need to register a callback with `lv_log_register_print_cb()`*/
# define LV_LOG_PRINTF 0
/*Enable/disable LV_LOG_TRACE in modules that produces a huge number of logs*/
# define LV_LOG_TRACE_MEM 1
# define LV_LOG_TRACE_TIMER 1
# define LV_LOG_TRACE_INDEV 1
# define LV_LOG_TRACE_DISP_REFR 1
# define LV_LOG_TRACE_EVENT 1
# define LV_LOG_TRACE_OBJ_CREATE 1
# define LV_LOG_TRACE_LAYOUT 1
# define LV_LOG_TRACE_ANIM 1
#endif /*LV_USE_LOG*/
/*-------------
* Asserts
*-----------*/
/*Enable asserts if an operation is failed or an invalid data is found.
*If LV_USE_LOG is enabled an error message will be printed on failure*/
#define LV_USE_ASSERT_NULL 1 /*Check if the parameter is NULL. (Very fast, recommended)*/
#define LV_USE_ASSERT_MALLOC 1 /*Checks is the memory is successfully allocated or no. (Very fast, recommended)*/
#define LV_USE_ASSERT_STYLE 0 /*Check if the styles are properly initialized. (Very fast, recommended)*/
#define LV_USE_ASSERT_MEM_INTEGRITY 0 /*Check the integrity of `lv_mem` after critical operations. (Slow)*/
#define LV_USE_ASSERT_OBJ 0 /*Check the object's type and existence (e.g. not deleted). (Slow)*/
/*Add a custom handler when assert happens e.g. to restart the MCU*/
#define LV_ASSERT_HANDLER_INCLUDE <stdint.h>
#define LV_ASSERT_HANDLER while(1); /*Halt by default*/
/*-------------
* Others
*-----------*/
/*1: Show CPU usage and FPS count in the right bottom corner*/
#define LV_USE_PERF_MONITOR 0
#if LV_USE_PERF_MONITOR
#define LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT
#endif
/*1: Show the used memory and the memory fragmentation in the left bottom corner
* Requires LV_MEM_CUSTOM = 0*/
#define LV_USE_MEM_MONITOR 0
#if LV_USE_PERF_MONITOR
#define LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_LEFT
#endif
/*1: Draw random colored rectangles over the redrawn areas*/
#define LV_USE_REFR_DEBUG 0
/*Change the built in (v)snprintf functions*/
#define LV_SPRINTF_CUSTOM 0
#if LV_SPRINTF_CUSTOM
# define LV_SPRINTF_INCLUDE <stdio.h>
# define lv_snprintf snprintf
# define lv_vsnprintf vsnprintf
#else /*LV_SPRINTF_CUSTOM*/
# define LV_SPRINTF_USE_FLOAT 0
#endif /*LV_SPRINTF_CUSTOM*/
#define LV_USE_USER_DATA 1
/*Garbage Collector settings
*Used if lvgl is bound to higher level language and the memory is managed by that language*/
#define LV_ENABLE_GC 0
#if LV_ENABLE_GC != 0
# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/
#endif /*LV_ENABLE_GC*/
/*=====================
* COMPILER SETTINGS
*====================*/
/*For big endian systems set to 1*/
#define LV_BIG_ENDIAN_SYSTEM 0
/*Define a custom attribute to `lv_tick_inc` function*/
#define LV_ATTRIBUTE_TICK_INC
/*Define a custom attribute to `lv_timer_handler` function*/
#define LV_ATTRIBUTE_TIMER_HANDLER
/*Define a custom attribute to `lv_disp_flush_ready` function*/
#define LV_ATTRIBUTE_FLUSH_READY
/*Required alignment size for buffers*/
#define LV_ATTRIBUTE_MEM_ALIGN_SIZE 1
/*Will be added where memories needs to be aligned (with -Os data might not be aligned to boundary by default).
* E.g. __attribute__((aligned(4)))*/
#define LV_ATTRIBUTE_MEM_ALIGN
/*Attribute to mark large constant arrays for example font's bitmaps*/
#define LV_ATTRIBUTE_LARGE_CONST
/*Complier prefix for a big array declaration in RAM*/
#define LV_ATTRIBUTE_LARGE_RAM_ARRAY
/*Place performance critical functions into a faster memory (e.g RAM)*/
#define LV_ATTRIBUTE_FAST_MEM
/*Prefix variables that are used in GPU accelerated operations, often these need to be placed in RAM sections that are DMA accessible*/
#define LV_ATTRIBUTE_DMA
/*Export integer constant to binding. This macro is used with constants in the form of LV_<CONST> that
*should also appear on LVGL binding API such as Micropython.*/
#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning /*The default value just prevents GCC warning*/
/*Extend the default -32k..32k coordinate range to -4M..4M by using int32_t for coordinates instead of int16_t*/
#define LV_USE_LARGE_COORD 0