diff --git a/.clang-format b/.clang-format index 1e81119..072b4e4 100644 --- a/.clang-format +++ b/.clang-format @@ -3,6 +3,7 @@ IndentWidth: 4 AlignConsecutiveMacros: Consecutive AlignConsecutiveDeclarations: true AlignConsecutiveAssignments: true +AllowShortFunctionsOnASingleLine: false BreakBeforeBraces: Custom BraceWrapping: AfterEnum: false diff --git a/.gitmodules b/.gitmodules index c8e2b7b..7a3227d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,9 @@ [submodule "lib/FatFS/fatfs"] path = lib/FatFS url = https://git.minori.work/Embedded_SDK/FatFS.git +[submodule "lib/LCD"] + path = lib/LCD + url = https://github.com/imi415/epd-spi.git +[submodule "lib/LVGL"] + path = lib/LVGL + url = https://github.com/lvgl/lvgl.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 20b5ca6..362d22f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,14 +65,20 @@ set(TARGET_SOURCES "lib/LwIP/port/sys_arch.c" "src/ethernetif.c" "src/fatfs_diskio.c" + "src/fatfs_system.c" "src/freertos_helpers.c" "src/fsl_phy.c" + "src/fs_helpers.c" "src/httpd_helpers.c" "src/ip_stack_helpers.c" + "src/lcd_impl.c" + "src/lvgl_helpers.c" "src/main.c" "src/sdhc_host.c" "src/syscalls.c" "src/system_utilities.c" + "src/ui/ui.c" + "src/ui/ui_standby.c" ) set(TARGET_C_DEFINES @@ -94,10 +100,12 @@ set(TARGET_C_INCLUDES # Shared libraries linked with application set(TARGET_LIBS + "epd-spi" + "fatfs" "freertos_kernel" + "lvgl" "lwip" "mbedtls" - "fatfs" ) # Shared library and linker script search paths @@ -110,9 +118,9 @@ set(TARGET_CFLAGS_HARDWARE "-mcpu=cortex-m4 -mthumb -mfloat-abi=soft") # Conditional flags # DEBUG -set(CMAKE_C_FLAGS_DEBUG "-DDEBUG -O0 -g") -set(CMAKE_CXX_FLAGS_DEBUG "-DDEBUG -O0 -g") -set(CMAKE_ASM_FLAGS_DEBUG "-DDEBUG -O0 -g") +set(CMAKE_C_FLAGS_DEBUG "-DDEBUG -O1 -g") +set(CMAKE_CXX_FLAGS_DEBUG "-DDEBUG -O1 -g") +set(CMAKE_ASM_FLAGS_DEBUG "-DDEBUG -O1 -g") # RELEASE set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O2 -flto") @@ -139,6 +147,11 @@ add_subdirectory(lib/MbedTLS) set(FATFS_CONFIG_DIRECTORY "${CMAKE_SOURCE_DIR}/include" CACHE STRING "") add_subdirectory(lib/FatFS) +add_subdirectory(lib/LCD) + +set(LV_CONF_PATH "${CMAKE_SOURCE_DIR}/include/lv_conf.h" CACHE STRING "" FORCE) +add_subdirectory(lib/LVGL) + # Shared sources, includes and definitions add_compile_definitions(${TARGET_C_DEFINES}) include_directories(${TARGET_C_INCLUDES}) diff --git a/MK60DN512xxx10.mex b/MK60DN512xxx10.mex index 332bf66..c37025c 100644 --- a/MK60DN512xxx10.mex +++ b/MK60DN512xxx10.mex @@ -26,6 +26,8 @@ 11.0.1 + + @@ -168,6 +170,18 @@ + + + + + + + + + + + + @@ -231,10 +245,10 @@ - + - + @@ -258,8 +272,8 @@ - - + + @@ -578,11 +592,11 @@ - + - + diff --git a/MK60DN512xxx10_flash_sram.ld b/MK60DN512xxx10_flash_sram.ld index 58e9af1..f7d9e78 100644 --- a/MK60DN512xxx10_flash_sram.ld +++ b/MK60DN512xxx10_flash_sram.ld @@ -256,6 +256,10 @@ SECTIONS . = ALIGN(8); *(.lwip_pool) *(.lwip_pool*) + *(.lvgl_workmem) + *(.lvgl_workmem*) + *(.lvgl_buffer) + *(.lvgl_buffer*) . = ALIGN(8); } > m_fb_sram diff --git a/board/board.c b/board/board.c index 8e3a178..5ffae95 100644 --- a/board/board.c +++ b/board/board.c @@ -29,11 +29,20 @@ */ #include + +/* Device Drivers */ #include "fsl_common.h" +#include "fsl_dmamux.h" +#include "fsl_edma.h" #include "fsl_rtc.h" #include "fsl_sysmpu.h" + +/* Debug Console */ #include "fsl_debug_console.h" + +/* Board */ #include "board.h" +#include "pin_mux.h" /******************************************************************************* * Variables @@ -43,14 +52,12 @@ * Code ******************************************************************************/ /* Initialize debug console. */ -void BOARD_InitDebugConsole(void) -{ +void BOARD_InitDebugConsole(void) { uint32_t uartClkSrcFreq = BOARD_DEBUG_UART_CLK_FREQ; DbgConsole_Init(BOARD_DEBUG_UART_BASEADDR, BOARD_DEBUG_UART_BAUDRATE, BOARD_DEBUG_UART_TYPE, uartClkSrcFreq); } - void BOARD_EnableRTC(void) { rtc_config_t rtc_config; @@ -61,6 +68,21 @@ void BOARD_EnableRTC(void) { RTC->SR |= RTC_SR_TCE_MASK; } +void BOARD_EnableLCD(void) { + GPIO_WritePinOutput(BOARD_INITPINS_TFT_RESET_GPIO, BOARD_INITPINS_TFT_RESET_PIN, 1U); + GPIO_WritePinOutput(BOARD_INITPINS_TFT_BL_GPIO, BOARD_INITPINS_TFT_BL_PIN, 1U); +} + void BOARD_DisableSYSMPU(void) { SYSMPU_Enable(SYSMPU, false); +} + +void BOARD_EnableEDMA(void) { + edma_config_t cfg; + EDMA_GetDefaultConfig(&cfg); + EDMA_Init(DMA0, &cfg); + + DMAMUX_Init(DMAMUX0); + + NVIC_SetPriority(DMA0_IRQn, 5); } \ No newline at end of file diff --git a/board/board.h b/board/board.h index a6df629..67d6d09 100644 --- a/board/board.h +++ b/board/board.h @@ -186,6 +186,8 @@ void BOARD_InitDebugConsole(void); void BOARD_EnableRTC(void); void BOARD_DisableSYSMPU(void); +void BOARD_EnableLCD(void); +void BOARD_EnableEDMA(void); #if defined(__cplusplus) } diff --git a/board/clock_config.c b/board/clock_config.c index c78a493..38e51f8 100644 --- a/board/clock_config.c +++ b/board/clock_config.c @@ -131,10 +131,10 @@ void BOARD_InitBootClocks(void) name: BOARD_BootClockRUN called_from_default_init: true outputs: -- {id: Bus_clock.outFreq, value: 12.5 MHz} +- {id: Bus_clock.outFreq, value: 50 MHz} - {id: Core_clock.outFreq, value: 100 MHz} - {id: Flash_clock.outFreq, value: 12.5 MHz} -- {id: FlexBus_clock.outFreq, value: 12.5 MHz} +- {id: FlexBus_clock.outFreq, value: 50 MHz} - {id: LPO_clock.outFreq, value: 1 kHz} - {id: MCGFFCLK.outFreq, value: 39.0625 kHz} - {id: OSCERCLK.outFreq, value: 50 MHz} @@ -157,8 +157,8 @@ settings: - {id: RTC_CR_OSC_CAP_LOAD_CFG, value: SC12PF} - {id: SDHCClkConfig, value: 'yes'} - {id: SIM.OUTDIV1.scale, value: '1', locked: true} -- {id: SIM.OUTDIV2.scale, value: '8'} -- {id: SIM.OUTDIV3.scale, value: '8'} +- {id: SIM.OUTDIV2.scale, value: '2'} +- {id: SIM.OUTDIV3.scale, value: '2'} - {id: SIM.OUTDIV4.scale, value: '8'} - {id: SIM.SDHCSRCSEL.sel, value: OSC.OSCERCLK} sources: @@ -191,7 +191,7 @@ const sim_clock_config_t simConfig_BOARD_BootClockRUN = { .pllFllSel = SIM_PLLFLLSEL_MCGFLLCLK_CLK, /* PLLFLL select: MCGFLLCLK clock */ .er32kSrc = SIM_OSC32KSEL_OSC32KCLK_CLK, /* OSC32KSEL select: OSC32KCLK clock */ - .clkdiv1 = 0x7770000U, /* SIM_CLKDIV1 - OUTDIV1: /1, OUTDIV2: /8, OUTDIV3: /8, OUTDIV4: /8 */ + .clkdiv1 = 0x1170000U, /* SIM_CLKDIV1 - OUTDIV1: /1, OUTDIV2: /2, OUTDIV3: /2, OUTDIV4: /8 */ }; const osc_config_t oscConfig_BOARD_BootClockRUN = { diff --git a/board/peripherals.c b/board/peripherals.c index b37c6d3..ae06d9b 100644 --- a/board/peripherals.c +++ b/board/peripherals.c @@ -105,11 +105,11 @@ instance: - autoAcknowledge: 'true' - extendTransferAddress: 'false' - byteLaneShift: 'kFLEXBUS_NotShifted' - - portSize: 'kFLEXBUS_1Byte' + - portSize: 'kFLEXBUS_2Bytes' - writeAddressHold: 'kFLEXBUS_Hold1Cycle' - readAddressHold: 'kFLEXBUS_Hold1Or0Cycles' - addressSetup: 'kFLEXBUS_FirstRisingEdge' - - waitStates: '0' + - waitStates: '6' - burstWrite: 'false' - burstRead: 'false' - writeProtect: 'false' @@ -149,11 +149,11 @@ flexbus_config_t FB_LCD_config = { .autoAcknowledge = true, .extendTransferAddress = false, .byteLaneShift = kFLEXBUS_NotShifted, - .portSize = kFLEXBUS_1Byte, + .portSize = kFLEXBUS_2Bytes, .writeAddressHold = kFLEXBUS_Hold1Cycle, .readAddressHold = kFLEXBUS_Hold1Or0Cycles, .addressSetup = kFLEXBUS_FirstRisingEdge, - .waitStates = 0U, + .waitStates = 6U, .secondaryWaitStates = false, .burstWrite = false, .burstRead = false, diff --git a/board/pin_mux.c b/board/pin_mux.c index 218bd0a..de75d10 100644 --- a/board/pin_mux.c +++ b/board/pin_mux.c @@ -14,6 +14,8 @@ mcu_data: ksdk2_0 processor_version: 11.0.1 pin_labels: - {pin_num: '58', pin_signal: PTA6/FTM0_CH3/TRACE_CLKOUT, label: BUZZER, identifier: BUZZER} +- {pin_num: '106', pin_signal: CMP1_IN1/PTC3/LLWU_P7/SPI0_PCS1/UART1_RX/FTM0_CH2/CLKOUT/I2S0_TX_BCLK, label: TFT_BL, identifier: TFT_BL} +- {pin_num: '126', pin_signal: PTC19/UART3_CTS_b/ENET0_1588_TMR3/FB_CS3_b/FB_BE7_0_b/FB_TA_b, label: TFT_RESET, identifier: TFT_RESET} * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** */ /* clang-format on */ @@ -100,6 +102,8 @@ BOARD_InitPins: - {pin_num: '7', peripheral: SDHC, signal: 'D, 3', pin_signal: PTE4/LLWU_P2/SPI1_PCS0/UART3_TX/SDHC0_D3, pull_select: up, pull_enable: enable} - {pin_num: '8', peripheral: SDHC, signal: 'D, 2', pin_signal: PTE5/SPI1_PCS2/UART3_RX/SDHC0_D2, pull_select: up, pull_enable: enable} - {pin_num: '3', peripheral: SDHC, signal: DCLK, pin_signal: ADC1_SE6a/PTE2/LLWU_P1/SPI1_SCK/UART1_CTS_b/SDHC0_DCLK, pull_select: up, pull_enable: enable} + - {pin_num: '106', peripheral: GPIOC, signal: 'GPIO, 3', pin_signal: CMP1_IN1/PTC3/LLWU_P7/SPI0_PCS1/UART1_RX/FTM0_CH2/CLKOUT/I2S0_TX_BCLK, direction: OUTPUT, gpio_init_state: 'true'} + - {pin_num: '126', peripheral: GPIOC, signal: 'GPIO, 19', pin_signal: PTC19/UART3_CTS_b/ENET0_1588_TMR3/FB_CS3_b/FB_BE7_0_b/FB_TA_b, direction: OUTPUT, gpio_init_state: 'true'} * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** */ /* clang-format on */ @@ -130,6 +134,20 @@ void BOARD_InitPins(void) /* Initialize GPIO functionality on pin PTA6 (pin 58) */ GPIO_PinInit(BOARD_INITPINS_BUZZER_GPIO, BOARD_INITPINS_BUZZER_PIN, &BUZZER_config); + gpio_pin_config_t TFT_BL_config = { + .pinDirection = kGPIO_DigitalOutput, + .outputLogic = 1U + }; + /* Initialize GPIO functionality on pin PTC3 (pin 106) */ + GPIO_PinInit(BOARD_INITPINS_TFT_BL_GPIO, BOARD_INITPINS_TFT_BL_PIN, &TFT_BL_config); + + gpio_pin_config_t TFT_RESET_config = { + .pinDirection = kGPIO_DigitalOutput, + .outputLogic = 1U + }; + /* Initialize GPIO functionality on pin PTC19 (pin 126) */ + GPIO_PinInit(BOARD_INITPINS_TFT_RESET_GPIO, BOARD_INITPINS_TFT_RESET_PIN, &TFT_RESET_config); + /* PORTA12 (pin 64) is configured as RMII0_RXD1 */ PORT_SetPinMux(PORTA, 12U, kPORT_MuxAlt4); @@ -238,9 +256,15 @@ void BOARD_InitPins(void) /* PORTC17 (pin 124) is configured as FB_CS4_b */ PORT_SetPinMux(PORTC, 17U, kPORT_MuxAlt5); + /* PORTC19 (pin 126) is configured as PTC19 */ + PORT_SetPinMux(BOARD_INITPINS_TFT_RESET_PORT, BOARD_INITPINS_TFT_RESET_PIN, kPORT_MuxAsGpio); + /* PORTC2 (pin 105) is configured as FB_AD12 */ PORT_SetPinMux(PORTC, 2U, kPORT_MuxAlt5); + /* PORTC3 (pin 106) is configured as PTC3 */ + PORT_SetPinMux(BOARD_INITPINS_TFT_BL_PORT, BOARD_INITPINS_TFT_BL_PIN, kPORT_MuxAsGpio); + /* PORTC4 (pin 109) is configured as FB_AD11 */ PORT_SetPinMux(PORTC, 4U, kPORT_MuxAlt5); diff --git a/board/pin_mux.h b/board/pin_mux.h index c594838..eba5d8e 100644 --- a/board/pin_mux.h +++ b/board/pin_mux.h @@ -42,6 +42,32 @@ void BOARD_InitBootPins(void); #define BOARD_INITPINS_BUZZER_PIN_MASK (1U << 6U) /*!<@brief PORT pin mask */ /* @} */ +/*! @name PORTC3 (number 106), TFT_BL + @{ */ + +/* Symbols to be used with GPIO driver */ +#define BOARD_INITPINS_TFT_BL_GPIO GPIOC /*!<@brief GPIO peripheral base pointer */ +#define BOARD_INITPINS_TFT_BL_GPIO_PIN_MASK (1U << 3U) /*!<@brief GPIO pin mask */ + +/* Symbols to be used with PORT driver */ +#define BOARD_INITPINS_TFT_BL_PORT PORTC /*!<@brief PORT peripheral base pointer */ +#define BOARD_INITPINS_TFT_BL_PIN 3U /*!<@brief PORT pin number */ +#define BOARD_INITPINS_TFT_BL_PIN_MASK (1U << 3U) /*!<@brief PORT pin mask */ + /* @} */ + +/*! @name PORTC19 (number 126), TFT_RESET + @{ */ + +/* Symbols to be used with GPIO driver */ +#define BOARD_INITPINS_TFT_RESET_GPIO GPIOC /*!<@brief GPIO peripheral base pointer */ +#define BOARD_INITPINS_TFT_RESET_GPIO_PIN_MASK (1U << 19U) /*!<@brief GPIO pin mask */ + +/* Symbols to be used with PORT driver */ +#define BOARD_INITPINS_TFT_RESET_PORT PORTC /*!<@brief PORT peripheral base pointer */ +#define BOARD_INITPINS_TFT_RESET_PIN 19U /*!<@brief PORT pin number */ +#define BOARD_INITPINS_TFT_RESET_PIN_MASK (1U << 19U) /*!<@brief PORT pin mask */ + /* @} */ + /*! * @brief Configures pin routing and optionally pin electrical features. * diff --git a/include/ffconf.h b/include/ffconf.h index bee39ff..fb6433e 100644 --- a/include/ffconf.h +++ b/include/ffconf.h @@ -113,7 +113,7 @@ */ -#define FF_USE_LFN 2 +#define FF_USE_LFN 3 #define FF_MAX_LFN 255 /* The FF_USE_LFN switches the support for LFN (long file name). / @@ -276,9 +276,9 @@ /* #include // O/S definitions */ -#define FF_FS_REENTRANT 0 +#define FF_FS_REENTRANT 1 #define FF_FS_TIMEOUT 1000 -#define FF_SYNC_t HANDLE +#define FF_SYNC_t void * /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() diff --git a/include/fs_helpers.h b/include/fs_helpers.h new file mode 100644 index 0000000..6d4eb19 --- /dev/null +++ b/include/fs_helpers.h @@ -0,0 +1,6 @@ +#ifndef FS_HELPERS_H +#define FS_HELPERS_H + +int fs_mount(void); + +#endif \ No newline at end of file diff --git a/include/lcd_impl.h b/include/lcd_impl.h new file mode 100644 index 0000000..fdd54bb --- /dev/null +++ b/include/lcd_impl.h @@ -0,0 +1,22 @@ +#ifndef LCD_IMPL_H +#define LCD_IMPL_H + +/* FreeRTOS */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* Device Drivers */ +#include "fsl_edma.h" + +typedef struct { + SemaphoreHandle_t dma_semphr; + edma_handle_t dma_handle; +} lcd_impl_t; + +epd_ret_t epd_impl_init(void *handle); +epd_ret_t epd_impl_write_command(void *handle, uint8_t *command, uint32_t len); +epd_ret_t epd_impl_write_data(void *handle, uint8_t *data, uint32_t len); +epd_ret_t epd_impl_reset(void *handle); + +#endif \ No newline at end of file diff --git a/include/lv_conf.h b/include/lv_conf.h new file mode 100644 index 0000000..d78e9c7 --- /dev/null +++ b/include/lv_conf.h @@ -0,0 +1,700 @@ +/** + * @file lv_conf.h + * Configuration file for v8.2.0 + */ + +/* + * Copy this file as `lv_conf.h` + * 1. simply next to the `lvgl` folder + * 2. or any other places and + * - define `LV_CONF_INCLUDE_SIMPLE` + * - add the path as include path + */ + +/* clang-format off */ +#if 1 /*Set it to "1" to enable content*/ + +#ifndef LV_CONF_H +#define LV_CONF_H + +#include + +/*==================== + COLOR SETTINGS + *====================*/ + +/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/ +#define LV_COLOR_DEPTH 32 + +/*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 0 +#if LV_MEM_CUSTOM == 0 + /*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/ + #define LV_MEM_SIZE (128U * 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 /* FB SRAM */ + /*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 /*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 + *====================*/ + +/*Default display refresh period. LVG will redraw changed areas with this period time*/ +#define LV_DISP_DEF_REFR_PERIOD 30 /*[ms]*/ + +/*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 "lvgl_helpers.h" /*Header for the system time function*/ + #define LV_TICK_CUSTOM_SYS_TIME_EXPR (lvgl_millis()) /*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 + +/*Number of stops allowed per gradient. Increase this to allow more stops. + *This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/ +#define LV_GRADIENT_MAX_STOPS 2 + +/*Default gradient buffer size. + *When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again. + *LV_GRAD_CACHE_DEF_SIZE sets the size of this cache in bytes. + *If the cache is too small the map will be allocated only while it's required for the drawing. + *0 mean no caching.*/ +#define LV_GRAD_CACHE_DEF_SIZE 0 + +/*Allow dithering the gradients (to achieve visual smooth color gradients on limited color depth display) + *LV_DITHER_GRADIENT implies allocating one or two more lines of the object's rendering surface + *The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */ +#define LV_DITHER_GRADIENT 0 +#if LV_DITHER_GRADIENT + /*Add support for error diffusion dithering. + *Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing. + *The increase in memory consumption is (24 bits * object's width)*/ + #define LV_DITHER_ERROR_DIFFUSION 0 +#endif + +/*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 0 +#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 0 +#endif + +/*Use NXP's VG-Lite GPU iMX RTxxx platforms*/ +#define LV_USE_GPU_NXP_VG_LITE 0 + +/*Use SDL renderer API*/ +#define LV_USE_GPU_SDL 0 +#if LV_USE_GPU_SDL + #define LV_GPU_SDL_INCLUDE_PATH + /*Texture cache size, 8MB by default*/ + #define LV_GPU_SDL_LRU_SIZE (1024 * 1024 * 8) + /*Custom blend mode for mask drawing, disable if you need to link with older SDL2 lib*/ + #define LV_GPU_SDL_CUSTOM_BLEND_MODE (SDL_VERSION_ATLEAST(2, 0, 6)) +#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 +#define LV_ASSERT_HANDLER while(1); /*Halt by default*/ + +/*------------- + * Others + *-----------*/ + +/*1: Show CPU usage and FPS count*/ +#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 + * Requires LV_MEM_CUSTOM = 0*/ +#define LV_USE_MEM_MONITOR 0 +#if LV_USE_MEM_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 + #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 + +/*Compiler prefix for a big array declaration in RAM*/ +#define LV_ATTRIBUTE_LARGE_RAM_ARRAY __attribute((section(".lvgl_workmem"))) + +/*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_ 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 + +/*================== + * FONT USAGE + *===================*/ + +/*Montserrat fonts with ASCII range and some symbols using bpp = 4 + *https://fonts.google.com/specimen/Montserrat*/ +#define LV_FONT_MONTSERRAT_8 0 +#define LV_FONT_MONTSERRAT_10 0 +#define LV_FONT_MONTSERRAT_12 0 +#define LV_FONT_MONTSERRAT_14 0 +#define LV_FONT_MONTSERRAT_16 0 +#define LV_FONT_MONTSERRAT_18 0 +#define LV_FONT_MONTSERRAT_20 0 +#define LV_FONT_MONTSERRAT_22 0 +#define LV_FONT_MONTSERRAT_24 0 +#define LV_FONT_MONTSERRAT_26 0 +#define LV_FONT_MONTSERRAT_28 0 +#define LV_FONT_MONTSERRAT_30 0 +#define LV_FONT_MONTSERRAT_32 0 +#define LV_FONT_MONTSERRAT_34 0 +#define LV_FONT_MONTSERRAT_36 0 +#define LV_FONT_MONTSERRAT_38 0 +#define LV_FONT_MONTSERRAT_40 0 +#define LV_FONT_MONTSERRAT_42 0 +#define LV_FONT_MONTSERRAT_44 0 +#define LV_FONT_MONTSERRAT_46 0 +#define LV_FONT_MONTSERRAT_48 0 + +/*Demonstrate special features*/ +#define LV_FONT_MONTSERRAT_12_SUBPX 0 +#define LV_FONT_MONTSERRAT_28_COMPRESSED 0 /*bpp = 3*/ +#define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 /*Hebrew, Arabic, Persian letters and all their forms*/ +#define LV_FONT_SIMSUN_16_CJK 0 /*1000 most common CJK radicals*/ + +/*Pixel perfect monospace fonts*/ +#define LV_FONT_UNSCII_8 1 +#define LV_FONT_UNSCII_16 0 + +/*Optionally declare custom fonts here. + *You can use these fonts as default font too and they will be available globally. + *E.g. #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) LV_FONT_DECLARE(my_font_2)*/ +#define LV_FONT_CUSTOM_DECLARE + +/*Always set a default font*/ +#define LV_FONT_DEFAULT &lv_font_unscii_8 + +/*Enable handling large font and/or fonts with a lot of characters. + *The limit depends on the font size, font face and bpp. + *Compiler error will be triggered if a font needs it.*/ +#define LV_FONT_FMT_TXT_LARGE 0 + +/*Enables/disables support for compressed fonts.*/ +#define LV_USE_FONT_COMPRESSED 1 + +/*Enable subpixel rendering*/ +#define LV_USE_FONT_SUBPX 1 +#if LV_USE_FONT_SUBPX + /*Set the pixel order of the display. Physical order of RGB channels. Doesn't matter with "normal" fonts.*/ + #define LV_FONT_SUBPX_BGR 1 /*0: RGB; 1:BGR order*/ +#endif + +/*================= + * TEXT SETTINGS + *=================*/ + +/** + * Select a character encoding for strings. + * Your IDE or editor should have the same character encoding + * - LV_TXT_ENC_UTF8 + * - LV_TXT_ENC_ASCII + */ +#define LV_TXT_ENC LV_TXT_ENC_UTF8 + +/*Can break (wrap) texts on these chars*/ +#define LV_TXT_BREAK_CHARS " ,.;:-_" + +/*If a word is at least this long, will break wherever "prettiest" + *To disable, set to a value <= 0*/ +#define LV_TXT_LINE_BREAK_LONG_LEN 0 + +/*Minimum number of characters in a long word to put on a line before a break. + *Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/ +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 + +/*Minimum number of characters in a long word to put on a line after a break. + *Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/ +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 + +/*The control character to use for signalling text recoloring.*/ +#define LV_TXT_COLOR_CMD "#" + +/*Support bidirectional texts. Allows mixing Left-to-Right and Right-to-Left texts. + *The direction will be processed according to the Unicode Bidirectional Algorithm: + *https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/ +#define LV_USE_BIDI 0 +#if LV_USE_BIDI + /*Set the default direction. Supported values: + *`LV_BASE_DIR_LTR` Left-to-Right + *`LV_BASE_DIR_RTL` Right-to-Left + *`LV_BASE_DIR_AUTO` detect texts base direction*/ + #define LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO +#endif + +/*Enable Arabic/Persian processing + *In these languages characters should be replaced with an other form based on their position in the text*/ +#define LV_USE_ARABIC_PERSIAN_CHARS 0 + +/*================== + * WIDGET USAGE + *================*/ + +/*Documentation of the widgets: https://docs.lvgl.io/latest/en/html/widgets/index.html*/ + +#define LV_USE_ARC 1 + +#define LV_USE_ANIMIMG 1 + +#define LV_USE_BAR 1 + +#define LV_USE_BTN 1 + +#define LV_USE_BTNMATRIX 1 + +#define LV_USE_CANVAS 1 + +#define LV_USE_CHECKBOX 1 + +#define LV_USE_DROPDOWN 1 /*Requires: lv_label*/ + +#define LV_USE_IMG 1 /*Requires: lv_label*/ + +#define LV_USE_LABEL 1 +#if LV_USE_LABEL + #define LV_LABEL_TEXT_SELECTION 1 /*Enable selecting text of the label*/ + #define LV_LABEL_LONG_TXT_HINT 1 /*Store some extra info in labels to speed up drawing of very long texts*/ +#endif + +#define LV_USE_LINE 1 + +#define LV_USE_ROLLER 1 /*Requires: lv_label*/ +#if LV_USE_ROLLER + #define LV_ROLLER_INF_PAGES 7 /*Number of extra "pages" when the roller is infinite*/ +#endif + +#define LV_USE_SLIDER 1 /*Requires: lv_bar*/ + +#define LV_USE_SWITCH 1 + +#define LV_USE_TEXTAREA 1 /*Requires: lv_label*/ +#if LV_USE_TEXTAREA != 0 + #define LV_TEXTAREA_DEF_PWD_SHOW_TIME 1500 /*ms*/ +#endif + +#define LV_USE_TABLE 1 + +/*================== + * EXTRA COMPONENTS + *==================*/ + +/*----------- + * Widgets + *----------*/ +#define LV_USE_CALENDAR 1 +#if LV_USE_CALENDAR + #define LV_CALENDAR_WEEK_STARTS_MONDAY 0 + #if LV_CALENDAR_WEEK_STARTS_MONDAY + #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"} + #else + #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"} + #endif + + #define LV_CALENDAR_DEFAULT_MONTH_NAMES {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} + #define LV_USE_CALENDAR_HEADER_ARROW 1 + #define LV_USE_CALENDAR_HEADER_DROPDOWN 1 +#endif /*LV_USE_CALENDAR*/ + +#define LV_USE_CHART 1 + +#define LV_USE_COLORWHEEL 1 + +#define LV_USE_IMGBTN 1 + +#define LV_USE_KEYBOARD 1 + +#define LV_USE_LED 1 + +#define LV_USE_LIST 1 + +#define LV_USE_MENU 1 + +#define LV_USE_METER 1 + +#define LV_USE_MSGBOX 1 + +#define LV_USE_SPINBOX 1 + +#define LV_USE_SPINNER 1 + +#define LV_USE_TABVIEW 1 + +#define LV_USE_TILEVIEW 1 + +#define LV_USE_WIN 1 + +#define LV_USE_SPAN 1 +#if LV_USE_SPAN + /*A line text can contain maximum num of span descriptor */ + #define LV_SPAN_SNIPPET_STACK_SIZE 64 +#endif + +/*----------- + * Themes + *----------*/ + +/*A simple, impressive and very complete theme*/ +#define LV_USE_THEME_DEFAULT 1 +#if LV_USE_THEME_DEFAULT + + /*0: Light mode; 1: Dark mode*/ + #define LV_THEME_DEFAULT_DARK 0 + + /*1: Enable grow on press*/ + #define LV_THEME_DEFAULT_GROW 1 + + /*Default transition time in [ms]*/ + #define LV_THEME_DEFAULT_TRANSITION_TIME 80 +#endif /*LV_USE_THEME_DEFAULT*/ + +/*A very simple theme that is a good starting point for a custom theme*/ +#define LV_USE_THEME_BASIC 1 + +/*A theme designed for monochrome displays*/ +#define LV_USE_THEME_MONO 1 + +/*----------- + * Layouts + *----------*/ + +/*A layout similar to Flexbox in CSS.*/ +#define LV_USE_FLEX 1 + +/*A layout similar to Grid in CSS.*/ +#define LV_USE_GRID 1 + +/*--------------------- + * 3rd party libraries + *--------------------*/ + +/*File system interfaces for common APIs */ + +/*API for fopen, fread, etc*/ +#define LV_USE_FS_STDIO 0 +#if LV_USE_FS_STDIO + #define LV_FS_STDIO_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_STDIO_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ + #define LV_FS_STDIO_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ +#endif + +/*API for open, read, etc*/ +#define LV_USE_FS_POSIX 0 +#if LV_USE_FS_POSIX + #define LV_FS_POSIX_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_POSIX_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ + #define LV_FS_POSIX_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ +#endif + +/*API for CreateFile, ReadFile, etc*/ +#define LV_USE_FS_WIN32 0 +#if LV_USE_FS_WIN32 + #define LV_FS_WIN32_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_WIN32_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ + #define LV_FS_WIN32_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ +#endif + +/*API for FATFS (needs to be added separately). Uses f_open, f_read, etc*/ +#define LV_USE_FS_FATFS 0 +#if LV_USE_FS_FATFS + #define LV_FS_FATFS_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_FATFS_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ +#endif + +/*PNG decoder library*/ +#define LV_USE_PNG 0 + +/*BMP decoder library*/ +#define LV_USE_BMP 0 + +/* JPG + split JPG decoder library. + * Split JPG is a custom format optimized for embedded systems. */ +#define LV_USE_SJPG 0 + +/*GIF decoder library*/ +#define LV_USE_GIF 0 + +/*QR code library*/ +#define LV_USE_QRCODE 0 + +/*FreeType library*/ +#define LV_USE_FREETYPE 0 +#if LV_USE_FREETYPE + /*Memory used by FreeType to cache characters [bytes] (-1: no caching)*/ + #define LV_FREETYPE_CACHE_SIZE (16 * 1024) + #if LV_FREETYPE_CACHE_SIZE >= 0 + /* 1: bitmap cache use the sbit cache, 0:bitmap cache use the image cache. */ + /* sbit cache:it is much more memory efficient for small bitmaps(font size < 256) */ + /* if font size >= 256, must be configured as image cache */ + #define LV_FREETYPE_SBIT_CACHE 0 + /* Maximum number of opened FT_Face/FT_Size objects managed by this cache instance. */ + /* (0:use system defaults) */ + #define LV_FREETYPE_CACHE_FT_FACES 0 + #define LV_FREETYPE_CACHE_FT_SIZES 0 + #endif +#endif + +/*Rlottie library*/ +#define LV_USE_RLOTTIE 0 + +/*FFmpeg library for image decoding and playing videos + *Supports all major image formats so do not enable other image decoder with it*/ +#define LV_USE_FFMPEG 0 +#if LV_USE_FFMPEG + /*Dump input information to stderr*/ + #define LV_FFMPEG_AV_DUMP_FORMAT 0 +#endif + +/*----------- + * Others + *----------*/ + +/*1: Enable API to take snapshot for object*/ +#define LV_USE_SNAPSHOT 0 + +/*1: Enable Monkey test*/ +#define LV_USE_MONKEY 0 + +/*1: Enable grid navigation*/ +#define LV_USE_GRIDNAV 0 + +/*================== +* EXAMPLES +*==================*/ + +/*Enable the examples to be built with the library*/ +#define LV_BUILD_EXAMPLES 1 + +/*=================== + * DEMO USAGE + ====================*/ + +/*Show some widget. It might be required to increase `LV_MEM_SIZE` */ +#define LV_USE_DEMO_WIDGETS 0 +#if LV_USE_DEMO_WIDGETS +#define LV_DEMO_WIDGETS_SLIDESHOW 0 +#endif + +/*Demonstrate the usage of encoder and keyboard*/ +#define LV_USE_DEMO_KEYPAD_AND_ENCODER 0 + +/*Benchmark your system*/ +#define LV_USE_DEMO_BENCHMARK 0 + +/*Stress test for LVGL*/ +#define LV_USE_DEMO_STRESS 0 + +/*Music player demo*/ +#define LV_USE_DEMO_MUSIC 0 +#if LV_USE_DEMO_MUSIC +# define LV_DEMO_MUSIC_SQUARE 0 +# define LV_DEMO_MUSIC_LANDSCAPE 0 +# define LV_DEMO_MUSIC_ROUND 0 +# define LV_DEMO_MUSIC_LARGE 0 +# define LV_DEMO_MUSIC_AUTO_PLAY 0 +#endif + +/*--END OF LV_CONF_H--*/ + +#endif /*LV_CONF_H*/ + +#endif /*End of "Content enable"*/ diff --git a/include/lvgl_helpers.h b/include/lvgl_helpers.h new file mode 100644 index 0000000..51de889 --- /dev/null +++ b/include/lvgl_helpers.h @@ -0,0 +1,7 @@ +#ifndef LVGL_HELPERS_H +#define LVGL_HELPERS_H + +int lvgl_setup(void); +uint32_t lvgl_millis(void); + +#endif \ No newline at end of file diff --git a/include/ui_helpers.h b/include/ui_helpers.h new file mode 100644 index 0000000..4c2ffc0 --- /dev/null +++ b/include/ui_helpers.h @@ -0,0 +1,21 @@ +#ifndef UI_HELPERS_H +#define UI_HELPERS_H + +#include "FreeRTOS.h" +#include "semphr.h" + +typedef enum { + UI_STANDBY_CMD_UPDATE_TIME, +} ui_standby_queue_cmd_t; + +typedef struct { + ui_standby_queue_cmd_t cmd; + void *payload; +} ui_standby_queue_t; + +extern SemaphoreHandle_t g_lvgl_semphr; +extern QueueHandle_t g_ui_standby_queue; + +int ui_setup(void); + +#endif \ No newline at end of file diff --git a/lib/LCD b/lib/LCD new file mode 160000 index 0000000..42c8727 --- /dev/null +++ b/lib/LCD @@ -0,0 +1 @@ +Subproject commit 42c8727a321e6667dfabe85c7bb508a6f7a39e67 diff --git a/lib/LVGL b/lib/LVGL new file mode 160000 index 0000000..0b5a1d4 --- /dev/null +++ b/lib/LVGL @@ -0,0 +1 @@ +Subproject commit 0b5a1d4b23975b920ff841ea9cd038802f51711b diff --git a/src/fatfs_system.c b/src/fatfs_system.c new file mode 100644 index 0000000..14582ab --- /dev/null +++ b/src/fatfs_system.c @@ -0,0 +1,33 @@ +/* FreeRTOS */ +#include "FreeRTOS.h" +#include "semphr.h" +#include "task.h" + +/* FatFS */ +#include "ff.h" + +void *ff_memalloc(UINT msize) { + return pvPortMalloc(msize); +} + +void ff_memfree(void *mblock) { + vPortFree(mblock); +} + +int ff_cre_syncobj(BYTE vol, FF_SYNC_t *sobj) { + *sobj = xSemaphoreCreateMutex(); + return (int)(*sobj != NULL); +} + +int ff_del_syncobj(FF_SYNC_t sobj) { + vSemaphoreDelete(sobj); + return 1; +} + +int ff_req_grant(FF_SYNC_t sobj) { + return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); +} + +void ff_rel_grant(FF_SYNC_t sobj) { + xSemaphoreGive(sobj); +} \ No newline at end of file diff --git a/src/fs_helpers.c b/src/fs_helpers.c new file mode 100644 index 0000000..b849390 --- /dev/null +++ b/src/fs_helpers.c @@ -0,0 +1,20 @@ +#include "ff.h" + +FATFS g_fs; /* File system object */ + +int fs_mount(void) { + if (f_mount(&g_fs, "0:/", 1U)) { + return -1; + } + + FRESULT error = f_mkdir(_T("0:/TMP")); + + if (error) { + if (error == FR_EXIST) { + } else { + return -2; + } + } + + return 0; +} \ No newline at end of file diff --git a/src/lcd_impl.c b/src/lcd_impl.c new file mode 100644 index 0000000..f0fa887 --- /dev/null +++ b/src/lcd_impl.c @@ -0,0 +1,105 @@ +/* Drivers */ +#include "fsl_clock.h" +#include "fsl_common.h" +#include "fsl_dmamux.h" +#include "fsl_edma.h" +#include "fsl_gpio.h" + +/* Board */ +#include "peripherals.h" +#include "pin_mux.h" +/* LCD panel */ +#include "epd-spi/panel/lcd_generic_ssd1289.h" + +/* Private header */ +#include "lcd_impl.h" + +#define IMPL_LCD_DMA_INSTANCE DMA0 +#define IMPL_LCD_DMAMUX_INSTANCE DMAMUX0 +#define IMPL_LCD_DMA_CHANNEL 0 +#define IMPL_LCD_DMA_REQUEST 63 /* Always On Request */ + +#define IMPL_LCD_COMMAND_BASE ((uint16_t *)0x70000000) +#define IMPL_LCD_DATA_BASE ((uint16_t *)0x78000000) + +static void epd_impl_edma_callback(edma_handle_t *handle, void *userData, bool transferDone, uint32_t tcds) { + lcd_impl_t *impl = userData; + BaseType_t xHigherPriorityTaskWoken; + + xSemaphoreGiveFromISR(impl->dma_semphr, &xHigherPriorityTaskWoken); + + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + +epd_ret_t epd_impl_init(void *handle) { + lcd_impl_t *impl = handle; + + impl->dma_semphr = xSemaphoreCreateBinary(); + if (impl->dma_semphr == NULL) { + return EPD_FAIL; + } + + /* Async flush */ + xSemaphoreGive(impl->dma_semphr); + + DMAMUX_SetSource(IMPL_LCD_DMAMUX_INSTANCE, IMPL_LCD_DMA_CHANNEL, IMPL_LCD_DMA_REQUEST); + DMAMUX_EnableChannel(IMPL_LCD_DMAMUX_INSTANCE, IMPL_LCD_DMA_CHANNEL); + EDMA_CreateHandle(&impl->dma_handle, IMPL_LCD_DMA_INSTANCE, IMPL_LCD_DMA_CHANNEL); + EDMA_SetCallback(&impl->dma_handle, epd_impl_edma_callback, impl); + + return EPD_OK; +} + +epd_ret_t epd_impl_write_command(void *handle, uint8_t *command, uint32_t len) { + uint32_t param_len = (len - 1) / 2; + + *IMPL_LCD_COMMAND_BASE = command[0]; + + for (uint32_t i = 0; i < param_len; i++) { + uint16_t le_param = (command[2 * i + 1] << 8) | command[2 * i + 2]; + *IMPL_LCD_DATA_BASE = le_param; + } + + return EPD_OK; +} + +epd_ret_t epd_impl_write_data(void *handle, uint8_t *data, uint32_t len) { + lcd_impl_t *impl = handle; + + uint32_t data_len = (len / 2); + + edma_transfer_config_t cfg = { + .srcAddr = (uint32_t)data, + .srcTransferSize = kEDMA_TransferSize2Bytes, + .srcOffset = 2U, + .destAddr = (uint32_t)IMPL_LCD_DATA_BASE, + .destTransferSize = kEDMA_TransferSize2Bytes, + .destOffset = 0U, /* Destination is not self-incrementing */ + .majorLoopCounts = data_len, + .minorLoopBytes = 2, + }; + + /* Wait for DMA transfer complete. */ + if (xSemaphoreTake(impl->dma_semphr, portMAX_DELAY) != pdPASS) { + return EPD_FAIL; + } + + EDMA_SubmitTransfer(&impl->dma_handle, &cfg); + EDMA_StartTransfer(&impl->dma_handle); + + return EPD_OK; +} + +epd_ret_t epd_impl_reset(void *handle) { + uint32_t delay = CLOCK_GetCoreSysClkFreq() / 50; /* 20 msec */ + + GPIO_WritePinOutput(BOARD_INITPINS_TFT_RESET_GPIO, BOARD_INITPINS_TFT_RESET_PIN, 0U); + + for (uint32_t i = 0; i < delay; i++) { + asm("nop"); + } + + GPIO_WritePinOutput(BOARD_INITPINS_TFT_RESET_GPIO, BOARD_INITPINS_TFT_RESET_PIN, 1U); + + return EPD_OK; +} \ No newline at end of file diff --git a/src/lvgl_helpers.c b/src/lvgl_helpers.c new file mode 100644 index 0000000..bf50ad6 --- /dev/null +++ b/src/lvgl_helpers.c @@ -0,0 +1,207 @@ +#include + +/* LVGL */ +#include "lvgl.h" + +/* FreeRTOS */ +#include "FreeRTOS.h" +#include "event_groups.h" +#include "semphr.h" +#include "task.h" + +/* FatFS */ +#include "ff.h" + +/* LCD */ +#include "epd-spi/panel/lcd_generic_ssd1289.h" +#include "lcd_impl.h" + +#define LVGL_FS_BASE "0:/LV_ROOT/" + +#define LVGL_RES_HOR 240 +#define LVGL_RES_VER 320 + +SemaphoreHandle_t g_lvgl_semphr; +EventGroupHandle_t g_lvgl_event_group; + +static lv_disp_draw_buf_t s_lvgl_disp_buf; +static lv_disp_drv_t s_lvgl_disp_drv; +static lv_fs_drv_t s_lvgl_fs_drv; + +static lcd_impl_t s_lcd_impl; + +static lcd_generic_ssd1289_t s_lcd = { + .cb = + { + .reset_cb = epd_impl_reset, + .write_command_cb = epd_impl_write_command, + .write_data_cb = epd_impl_write_data, + }, + .dir = LCD_GENERIC_SSD1289_DIR_VERTICAL, + .mode = LCD_GENERIC_SSD1289_MODE_XBRG8888, + .user_data = &s_lcd_impl, +}; + +__attribute((section(".lvgl_buffer"))) static lv_color_t s_lvgl_buf_1[LVGL_RES_HOR * 20]; +__attribute((section(".lvgl_buffer"))) static lv_color_t s_lvgl_buf_2[LVGL_RES_HOR * 20]; + +void lvgl_task(void *pvParameters); + +static void lvgl_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) { + lcd_generic_ssd1289_t *lcd = disp_drv->user_data; + + epd_coord_t coord = { + .x_start = area->x1, + .x_end = area->x2, + .y_start = area->y1, + .y_end = area->y2, + }; + + lcd_generic_ssd1289_upload(lcd, &coord, (uint8_t *)color_p); + + lv_disp_flush_ready(disp_drv); +} + +static void lvgl_set_px_cb(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, + lv_color_t color, lv_opa_t opa) { + /* 4 bytes per pixel. */ + uint32_t *px = (uint32_t *)&buf[(y * buf_w + x) * 4]; + + /* Set color */ + *px = color.ch.green & 0xFFU; + *px |= (color.ch.red & 0xFFU) << 8U; + *px |= (color.ch.blue & 0xFFU) << 16U; +} + +static void *lvgl_fs_open_cb(lv_fs_drv_t *drv, const char *path, lv_fs_mode_t mode) { + FIL *fp = pvPortMalloc(sizeof(FIL)); + if (fp == NULL) { + return NULL; + } + + char *ff_path = pvPortMalloc(255); + if (ff_path == NULL) { + vPortFree(fp); + return NULL; + } + + snprintf(ff_path, 255, LVGL_FS_BASE "%s", path); + FRESULT res = f_open(fp, ff_path, FA_READ); + if (res != FR_OK) { + vPortFree(ff_path); + vPortFree(fp); + + return NULL; + } + + vPortFree(ff_path); + + return fp; +} + +static lv_fs_res_t lvgl_fs_close_cb(lv_fs_drv_t *drv, void *file_p) { + FIL *fp = file_p; + + FRESULT res = f_close(fp); + + vPortFree(fp); + + if (res != FR_OK) { + return LV_FS_RES_FS_ERR; + } + + return LV_FS_RES_OK; +} + +static lv_fs_res_t lvgl_fs_read_cb(lv_fs_drv_t *drv, void *file_p, void *buf, uint32_t btr, uint32_t *br) { + FIL *fp = file_p; + + FRESULT res = f_read(fp, buf, btr, (unsigned int *)br); + if (res != FR_OK) { + return LV_FS_RES_FS_ERR; + } + + return LV_FS_RES_OK; +} + +static lv_fs_res_t lvgl_fs_seek_cb(lv_fs_drv_t *drv, void *file_p, uint32_t pos, lv_fs_whence_t whence) { + FRESULT res; + + FIL *fp = file_p; + + uint32_t size = f_size(fp); + + if (whence != LV_FS_SEEK_CUR) { + res = f_rewind(fp); + + if (res != FR_OK) { + return LV_FS_RES_FS_ERR; + } + } + + if (whence == LV_FS_SEEK_END) { + pos = (size - 1) - pos; + } + + res = f_lseek(fp, pos); + if (res != FR_OK) { + return LV_FS_RES_FS_ERR; + } + + return LV_FS_RES_OK; +} + +int lvgl_setup(void) { + lv_init(); + + lv_disp_draw_buf_init(&s_lvgl_disp_buf, s_lvgl_buf_1, s_lvgl_buf_2, LVGL_RES_HOR * 10); + + epd_impl_init(&s_lcd_impl); + lcd_generic_ssd1289_init(&s_lcd); + + lv_disp_drv_init(&s_lvgl_disp_drv); + s_lvgl_disp_drv.draw_buf = &s_lvgl_disp_buf; + s_lvgl_disp_drv.user_data = &s_lcd; + s_lvgl_disp_drv.flush_cb = lvgl_flush_cb; + s_lvgl_disp_drv.set_px_cb = lvgl_set_px_cb; + s_lvgl_disp_drv.hor_res = LVGL_RES_HOR; + s_lvgl_disp_drv.ver_res = LVGL_RES_VER; + + lv_disp_drv_register(&s_lvgl_disp_drv); + + lv_fs_drv_init(&s_lvgl_fs_drv); + s_lvgl_fs_drv.letter = 'A'; + s_lvgl_fs_drv.open_cb = lvgl_fs_open_cb; + s_lvgl_fs_drv.close_cb = lvgl_fs_close_cb; + s_lvgl_fs_drv.read_cb = lvgl_fs_read_cb; + s_lvgl_fs_drv.seek_cb = lvgl_fs_seek_cb; + + lv_fs_drv_register(&s_lvgl_fs_drv); + + g_lvgl_semphr = xSemaphoreCreateBinary(); + if (g_lvgl_semphr == NULL) { + return -1; + } + + xSemaphoreGive(g_lvgl_semphr); + + if (xTaskCreate(lvgl_task, "LVTASK", 2048, NULL, 32, NULL) != pdPASS) { + return -3; + } + + return 0; +} + +uint32_t lvgl_millis(void) { + return xTaskGetTickCount(); +} + +void lvgl_task(void *pvParameters) { + for (;;) { + if (xSemaphoreTake(g_lvgl_semphr, pdMS_TO_TICKS(150)) == pdTRUE) { + lv_timer_handler(); + xSemaphoreGive(g_lvgl_semphr); + } + vTaskDelay(pdMS_TO_TICKS(15)); + } +} diff --git a/src/main.c b/src/main.c index fbde210..0975551 100644 --- a/src/main.c +++ b/src/main.c @@ -22,7 +22,13 @@ #include "task.h" /* FatFS */ -#include "ff.h" +#include "fs_helpers.h" + +/* LVGL */ +#include "lvgl_helpers.h" + +/* UI */ +#include "ui_helpers.h" /* MbedTLS */ #include "mbedtls/aes.h" @@ -31,8 +37,6 @@ #include "mbedtls/sha256.h" #include "mbedtls/sha512.h" -FATFS g_fs; /* File system object */ - static void vTaskHello(void *pvParameters); static void mtls_selftests(int verbose); @@ -43,6 +47,8 @@ int main(void) { BOARD_DisableSYSMPU(); BOARD_EnableRTC(); + BOARD_EnableLCD(); + BOARD_EnableEDMA(); BOARD_InitDebugConsole(); @@ -61,20 +67,16 @@ int main(void) { } static void vTaskHello(void *pvParameters) { - if (f_mount(&g_fs, "0:/", 1U)) { - PRINTF("Mount volume failed.\r\n"); - vTaskDelete(NULL); + while (fs_mount() < 0) { + vTaskDelay(pdMS_TO_TICKS(5000)); } - FRESULT error = f_mkdir(_T("0:/dir_1")); + if (lvgl_setup() < 0) { + vTaskSuspend(NULL); + } - if (error) { - if (error == FR_EXIST) { - PRINTF("Directory exists.\r\n"); - } else { - PRINTF("Make directory failed.\r\n"); - vTaskDelete(NULL); - } + if (ui_setup() < 0) { + vTaskSuspend(NULL); } ip_stack_setup(); @@ -86,6 +88,22 @@ static void vTaskHello(void *pvParameters) { t = time(NULL); cur_tm = localtime(&t); + cur_tm->tm_hour += 8U; + cur_tm->tm_isdst = 0; + + mktime(cur_tm); + + char *time_str = pvPortMalloc(7); + + ui_standby_queue_t cmd = { + .cmd = UI_STANDBY_CMD_UPDATE_TIME, + .payload = time_str, + }; + + strftime(time_str, 7, "%H:%M", cur_tm); + + xQueueSend(g_ui_standby_queue, &cmd, 0); + printf("Current time: %04d-%02d-%02d %02d:%02d:%02d\r\n", cur_tm->tm_year + 1900, cur_tm->tm_mon + 1, cur_tm->tm_mday, cur_tm->tm_hour, cur_tm->tm_min, cur_tm->tm_sec); } diff --git a/src/ui/ui.c b/src/ui/ui.c new file mode 100644 index 0000000..025e88d --- /dev/null +++ b/src/ui/ui.c @@ -0,0 +1,18 @@ +#include "ui_helpers.h" + +QueueHandle_t g_ui_standby_queue; + +void ui_standby_task(void *pvParameters); + +int ui_setup(void) { + g_ui_standby_queue = xQueueCreate(2, sizeof(ui_standby_queue_t)); + if(g_ui_standby_queue == NULL) { + return -1; + } + + if(xTaskCreate(ui_standby_task, "U_STBY", 256, NULL, 33, NULL) != pdPASS) { + return -2; + } + + return 0; +} \ No newline at end of file diff --git a/src/ui/ui_standby.c b/src/ui/ui_standby.c new file mode 100644 index 0000000..d4fe224 --- /dev/null +++ b/src/ui/ui_standby.c @@ -0,0 +1,59 @@ +/* FreeRTOS */ +#include "FreeRTOS.h" +#include "task.h" + +/* LVGL */ +#include "lvgl.h" + +/* UI */ +#include "ui_helpers.h" + +void ui_standby_task(void *pvParameters) { + lv_obj_t *img_background = NULL; + lv_font_t *font_noto_sans_bold_72 = NULL; + lv_style_t style_label_time; + lv_obj_t *label_time = NULL; + + if (xSemaphoreTake(g_lvgl_semphr, portMAX_DELAY) == pdTRUE) { + img_background = lv_img_create(lv_scr_act()); + lv_img_set_src(img_background, "A:/resources/images/bg_image_1.bin"); + + font_noto_sans_bold_72 = lv_font_load("A:/resources/fonts/noto-sans_bold_72.bin"); + + lv_style_init(&style_label_time); + lv_style_set_text_font(&style_label_time, font_noto_sans_bold_72); + lv_style_set_text_color(&style_label_time, lv_color_make(181, 27, 58)); + + label_time = lv_label_create(lv_scr_act()); + lv_obj_add_style(label_time, &style_label_time, 0); + lv_obj_set_width(label_time, 240); + lv_obj_set_height(label_time, 80); + lv_obj_align(label_time, LV_ALIGN_CENTER, 0, -40); + lv_obj_set_style_text_align(label_time, LV_TEXT_ALIGN_CENTER, 0); + lv_label_set_text(label_time, "--:--"); + + xSemaphoreGive(g_lvgl_semphr); + } + + ui_standby_queue_t cmd; + + for (;;) { + if (xQueueReceive(g_ui_standby_queue, &cmd, portMAX_DELAY) == pdPASS) { + switch (cmd.cmd) { + case UI_STANDBY_CMD_UPDATE_TIME: { + if (xSemaphoreTake(g_lvgl_semphr, portMAX_DELAY) == pdTRUE) { + lv_label_set_text(label_time, (char *)cmd.payload); + + xSemaphoreGive(g_lvgl_semphr); + } + + vPortFree(cmd.payload); + + break; + } + default: + break; + } + } + } +} \ No newline at end of file