以下是以Gd官方代码为例
1 /*! 2 \brief main program 3 \param[in] none 4 \param[out] none 5 \retval none 6 */ 7 int main(void) 8 { 9 /* configure Systick and LCD */ 10 systick_config(); 11 lcd_config(); 12 lcd_init(); 13 lcd_layer_init(LCD_LAYER_BACKGROUND); 14 lcd_layer_enable(LCD_LAYER_BACKGROUND); 15 16 lcd_layer_set(LCD_LAYER_BACKGROUND); 17 lcd_transparency_set(255); 18 19 SPI_Touch_GPIO_Configuration(); 20 Touch_PenIRQ_Initializtion(); 21 22 lv_init(); 23 lv_port_disp_init(); 24 lv_port_indev_init(); 25 26 lv_demo_widgets(); 27 lv_demo_benchmark(); 28 29 while(1){ 30 delay_1ms(5); 31 lv_task_handler(); 32 } 33 }
这里只初始化了layer 0 做为背景层。为什么不初始化layer 1?
首先layer 1是可以覆盖layer 0的。而官方demo里,只将layer 0给lvgl用于LCD的显示图层。而lvgl有两个兵乓buf用于轮流使用,一个写数据,一个搬运数据。
这么看的话似乎一个图层就够了, 因为同一时期或者一个总线速度下,搬运数据是有限制的,而同一时期只能用于一个图层的显示。先这么理解吧。。
LVGL的两个buf按照正点原子的方法是下面这么定义的,而且最好比实际大小大点。
1 /*官方Demo*/ 2 void lv_port_disp_init(void) 3 { 4 /*------------------------- 5 * Initialize your display 6 * -----------------------*/ 7 disp_init(); 8 9 /*----------------------------- 10 * Create a buffer for drawing 11 *----------------------------*/ 12 13 static lv_disp_buf_t draw_buf_dsc_2; 14 static lv_color_t draw_buf_2_1[COLOR_BUF_SIZE] __attribute__((at(0xC0080000))); 15 static lv_color_t draw_buf_2_2[COLOR_BUF_SIZE] __attribute__((at(0xC0100000))); 16 lv_disp_buf_init(&draw_buf_dsc_2, draw_buf_2_1, draw_buf_2_2, COLOR_BUF_SIZE); /*Initialize the display buffer*/ 17 18 /*----------------------------------- 19 * Register the display in LVGL 20 *----------------------------------*/ 21 22 lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ 23 lv_disp_drv_init(&disp_drv); /*Basic initialization*/ 24 25 /*Set up the functions to access to your display*/ 26 27 /*Set the resolution of the display*/ 28 disp_drv.hor_res = LV_HOR_RES_MAX; 29 disp_drv.ver_res = LV_VER_RES_MAX; 30 31 /*Used to copy the buffer's content to the display*/ 32 disp_drv.flush_cb = disp_flush; 33 34 /*Set a display buffer*/ 35 disp_drv.buffer = &draw_buf_dsc_2; 36 37 rcu_periph_clock_enable(RCU_IPA); 38 39 #if LV_USE_GPU 40 /*Optionally add functions to access the GPU. (Only in buffered mode, LV_VDB_SIZE != 0)*/ 41 42 /*Blend two color array using opacity*/ 43 disp_drv.gpu_blend_cb = gpu_blend; 44 45 /*Fill a memory array with a color*/ 46 disp_drv.gpu_fill_cb = gpu_fill; 47 #endif 48 49 /*Finally register the driver*/ 50 lv_disp_drv_register(&disp_drv); 51 }
lvgl的显示接口初始化函数没什么好说的,照着配置就行了。重点是disp_flush()
1 /* Flush the content of the internal buffer the specific area on the display 2 * You can use DMA or any hardware acceleration to do this operation in the background but 3 * 'lv_disp_flush_ready()' has to be called when finished. */ 4 static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) 5 { 6 uint32_t time_out; 7 uint16_t offline; 8 offline = LV_HOR_RES_MAX - (area->x2 - area->x1 + 1); 9 10 IPA_CTL = 0x0; 11 IPA_FMADDR = (uint32_t)color_p; 12 IPA_DMADDR = (uint32_t)(uint32_t)LCD_FRAME_BUFFER + 2*(LV_HOR_RES_MAX*area->y1+area->x1); 13 IPA_FLOFF = 0; 14 IPA_DLOFF = offline; 15 IPA_FPCTL = FOREGROUND_PPF_RGB565; 16 IPA_IMS = (uint32_t)((area->x2 - area->x1 + 1) << 16) | (uint16_t)(area->y2 - area->y1 + 1); 17 18 IPA_CTL |= IPA_CTL_TEN; 19 20 while (IPA_CTL & IPA_CTL_TEN) 21 { 22 if(time_out++ >= 0XFFFFFFFF) break; 23 } 24 25 lv_disp_flush_ready(disp_drv); 26 }
IPA 和STM32的DMA2D是一个东西,只是被GD给取了个别名而已。
在LCD初始化的时候,在SDRAM里给layer 0分配了一块地址,然后又给LVGL分配了两个buf用于双缓存使用。