/** * @file lv_port_disp_templ.c * */ /*Copy this file as "lv_port_disp.c" and set this value to "1" to enable content*/ #if 1 /********************* * INCLUDES *********************/ #include "lv_port_disp.h" #include "ltdc.h" #include "lcd.h" #include /********************* * DEFINES *********************/ #ifndef MY_DISP_HOR_RES #warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen width, default value 320 is used for now. #define MY_DISP_HOR_RES 1024 #endif #ifndef MY_DISP_VER_RES #warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen height, default value 240 is used for now. #define MY_DISP_VER_RES 600 #endif /********************** * TYPEDEFS **********************/ #define DBG_TAG "LVGLd" #define DBG_LVL DBG_INFO #include /********************** * STATIC PROTOTYPES **********************/ static void disp_init(void); static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); //static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width, // const lv_area_t * fill_area, lv_color_t color); /********************** * STATIC VARIABLES **********************/ /********************** * MACROS **********************/ static lv_disp_draw_buf_t draw_buf_dsc_1; static lv_disp_draw_buf_t draw_buf_dsc_2; static lv_disp_draw_buf_t draw_buf_dsc_3; static lv_color_t *buf_1 = RT_NULL; static lv_color_t *buf_2_1 = RT_NULL; static lv_color_t *buf_2_2 = RT_NULL; static lv_color_t *buf_3_1 = RT_NULL; static lv_color_t *buf_3_2 = RT_NULL; /********************** * GLOBAL FUNCTIONS **********************/ extern struct rt_memheap sdram_heap; // void lv_port_disp_init(void) { /*------------------------- * Initialize your display * -----------------------*/ disp_init(); /*----------------------------- * Create a buffer for drawing *----------------------------*/ /** * LVGL requires a buffer where it internally draws the widgets. * Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display. * The buffer has to be greater than 1 display row * * There are 3 buffering configurations: * 1. Create ONE buffer: * LVGL will draw the display's content here and writes it to your display * * 2. Create TWO buffer: * LVGL will draw the display's content to a buffer and writes it your display. * You should use DMA to write the buffer's content to the display. * It will enable LVGL to draw the next part of the screen to the other buffer while * the data is being sent form the first buffer. It makes rendering and flushing parallel. * * 3. Double buffering * Set 2 screens sized buffers and set disp_drv.full_refresh = 1. * This way LVGL will always provide the whole rendered screen in `flush_cb` * and you only need to change the frame buffer's address. */ /* Example for 1) */ //static lv_disp_draw_buf_t draw_buf_dsc_1 __attribute__((aligned(8))); //static lv_color_t *buf_1 __attribute__((aligned(8))) = RT_NULL; //static lv_color_t buf_1[MY_DISP_HOR_RES * 10] __attribute__((section(".sdram"))); /*A buffer for 10 rows*/ //buf_1 = (lv_color_t *)rt_memheap_alloc(&sdram_heap, sizeof(lv_color_t) * MY_DISP_HOR_RES * 10); //lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/ /* Example for 2) */ //static lv_disp_draw_buf_t draw_buf_dsc_2 __attribute__((aligned(8))); //static lv_color_t *buf_2_1 __attribute__((aligned(8)))= RT_NULL; //static lv_color_t *buf_2_2 __attribute__((aligned(8)))= RT_NULL; //static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10] __attribute__((section(".sdram"))); /*A buffer for 10 rows*/ //static lv_color_t buf_2_2[MY_DISP_HOR_RES * 10] __attribute__((section(".sdram"))); /*An other buffer for 10 rows*/ //buf_2_1 = (lv_color_t *)rt_memheap_alloc(&sdram_heap, sizeof(lv_color_t) * MY_DISP_HOR_RES * 10); //buf_2_2 = (lv_color_t *)rt_memheap_alloc(&sdram_heap, sizeof(lv_color_t) * MY_DISP_HOR_RES * 10); //lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/ /* Example for 3) also set disp_drv.full_refresh = 1 below*/ //static lv_disp_draw_buf_t draw_buf_dsc_3 __attribute__((aligned(8))); //static lv_color_t *buf_3_1 __attribute__((aligned(8)))= RT_NULL; //static lv_color_t *buf_3_2 __attribute__((aligned(8)))= RT_NULL; //static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES] __attribute__((section(".sdram"))); /*A screen sized buffer*/ //static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES] __attribute__((section(".sdram"))); /*Another screen sized buffer*/ //buf_3_1 = (lv_color_t *)rt_memheap_alloc(&sdram_heap, sizeof(lv_color_t) * MY_DISP_VER_RES * 10); //buf_3_2 = (lv_color_t *)rt_memheap_alloc(&sdram_heap, sizeof(lv_color_t) * MY_DISP_VER_RES * 10); //lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2, MY_DISP_HOR_RES * MY_DISP_VER_RES ); /*Initialize the display buffer*/ // 使用对齐分配函数 buf_1 = (lv_color_t *)rt_memheap_alloc_align(&sdram_heap, sizeof(lv_color_t) * MY_DISP_HOR_RES * 10, 4); // ← 关键:对齐到 4 字节 buf_2_1 = (lv_color_t *)rt_memheap_alloc_align(&sdram_heap, sizeof(lv_color_t) * MY_DISP_HOR_RES * 10, 4); buf_2_2 = (lv_color_t *)rt_memheap_alloc_align(&sdram_heap, sizeof(lv_color_t) * MY_DISP_HOR_RES * 10, 4); buf_3_1 = (lv_color_t *)rt_memheap_alloc_align(&sdram_heap, sizeof(lv_color_t) * MY_DISP_HOR_RES * MY_DISP_VER_RES, 4); buf_3_2 = (lv_color_t *)rt_memheap_alloc_align(&sdram_heap, sizeof(lv_color_t) * MY_DISP_HOR_RES * MY_DISP_VER_RES, 4); if (!buf_1 || !buf_2_1 || !buf_2_2 || !buf_3_1 || !buf_3_2) { LOG_E("Failed to alloc aligned draw buffers"); } // 初始化 draw buffer lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10); lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10); lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2, MY_DISP_HOR_RES * MY_DISP_VER_RES); /*----------------------------------- * Register the display in LVGL *----------------------------------*/ static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ lv_disp_drv_init(&disp_drv); /*Basic initialization*/ /*Set up the functions to access to your display*/ /*Set the resolution of the display*/ disp_drv.hor_res = MY_DISP_HOR_RES; disp_drv.ver_res = MY_DISP_VER_RES; /*Used to copy the buffer's content to the display*/ disp_drv.flush_cb = disp_flush; /*Set a display buffer*/ disp_drv.draw_buf = &draw_buf_dsc_3; /*Required for Example 3)*/ //disp_drv.full_refresh = 1; /* Fill a memory array with a color if you have GPU. * Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL. * But if you have a different GPU you can use with this callback.*/ //disp_drv.gpu_fill_cb = gpu_fill; /*Finally register the driver*/ lv_disp_drv_register(&disp_drv); } /********************** * STATIC FUNCTIONS **********************/ /*Initialize your display and the required peripherals.*/ static void disp_init(void) { /*You code here*/ } volatile bool disp_flush_enabled = true; /* Enable updating the screen (the flushing process) when disp_flush() is called by LVGL */ void disp_enable_update(void) { disp_flush_enabled = true; } /* Disable updating the screen (the flushing process) when disp_flush() is called by LVGL */ void disp_disable_update(void) { disp_flush_enabled = false; } /*Flush the content of the internal buffer the specific area on the display *You can use DMA or any hardware acceleration to do this operation in the background but *'lv_disp_flush_ready()' has to be called when finished.*/ static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { // if(disp_flush_enabled){ // ltdc_color_fill(area->x1,area->y1,area->x2,area->y2,(uint16_t*)color_p); // } if(!RGB_DIR) /*竖屏*/ { int32_t x; int32_t y; for(y = area->y1; y <= area->y2; y++) { for(x = area->x1; x <= area->x2; x++) { #if LTDC_PIXFORMAT == LTDC_PIXFORMAT_ARGB8888 ltdc_draw_point(x, y, *(uint32_t *)(uint32_t*)color_p); #elif LTDC_PIXFORMAT_RGB565 ltdc_draw_point(x, y, *(uint16_t *)(uint32_t*)color_p); #endif color_p++; } } } else /*横屏*/ { ltdc_color_fill(area->x1,area->y1,area->x2,area->y2,(uint16_t*)color_p); } /*IMPORTANT!!! *Inform the graphics library that you are ready with the flushing*/ lv_disp_flush_ready(disp_drv); } /*OPTIONAL: GPU INTERFACE*/ /*If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color*/ //static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width, // const lv_area_t * fill_area, lv_color_t color) //{ // /*It's an example code which should be done by your GPU*/ // int32_t x, y; // dest_buf += dest_width * fill_area->y1; /*Go to the first line*/ // // for(y = fill_area->y1; y <= fill_area->y2; y++) { // for(x = fill_area->x1; x <= fill_area->x2; x++) { // dest_buf[x] = color; // } // dest_buf+=dest_width; /*Go to the next line*/ // } //} #else /*Enable this file at the top*/ /*This dummy typedef exists purely to silence -Wpedantic.*/ typedef int keep_pedantic_happy; #endif