【GD32450I-EVAL】LittleVGL显示部分移植
[复制链接]
本帖最后由 tinnu 于 2020-9-13 23:30 编辑
(一)Littlevgl
Littlevgl是目前最火的开源嵌入式GUI之一,相比于emwin,其界面更加柔和,基于MIT协议,这个协议非常宽松,可以商用闭源,而emwin商用则是需要付费,并且源码也是封闭的。另外,在移植的便利性上Littlevgl也远比emwin更有优势。
LittleVGL最新已经更新到V7系列,我这次就移植最新的这个版本。
Littlevgl下载地址:https://gitee.com/mirrors/lvgl?_from=gitee_search
WIKI(里面有API手册下载地址):https://docs.lvgl.io/v7/en/html/
(二)基本移植
1-把原本的littlevgl文件夹删掉,把Git下来的src里面的文件全部拷进去
#define LV_HOR_RES_MAX (LCD_WIDTH)
#define LV_VER_RES_MAX (LCD_HEIGHT)
其中 LCD_WIDTH 的值在后面的驱动文件里面定义。
2-把GPU禁用掉:
/* 1: Enable GPU interface*/
#define LV_USE_GPU 0 /*Only enables `gpu_fill_cb` and `gpu_blend_cb` in the disp. drv- */
#define LV_USE_GPU_STM32_DMA2D 0
/*If enabling LV_USE_GPU_STM32_DMA2D, LV_GPU_DMA2D_CMSIS_INCLUDE 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
3-添加宏
LV_CONF_INCLUDE_SIMPLE=1
4-添加一个 littlevgl_support.c 文件
添加显示刷新函数:
void lv_port_disp_init(void)
{
/*-------------------------
* Initialize your display
* -----------------------*/
tli_gpio_config();
tli_config_twolayout();
tli_layer_enable(LAYER0);
tli_reload_config(TLI_REQUEST_RELOAD_EN);
tli_enable();
/*-----------------------------------
* Register the display in LittlevGL
*----------------------------------*/
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*/
static lv_disp_buf_t disp_buf_2;
lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LCD_WIDTH * LCD_HEIGHT * LCD_FB_BYTE_PER_PIXEL); /*Initialize the display buffer*/
disp_drv.buffer = &disp_buf_2;
disp_drv.hor_res = LCD_WIDTH;
disp_drv.ver_res = LCD_HEIGHT;
/*Used in buffered mode (LV_VDB_SIZE != 0 in lv_conf.h)*/
disp_drv.flush_cb = DEMO_FlushDisplay;
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
}
(三)平台驱动移植
1-缓存设置
Littlevgl一般设置双缓冲,按照480*272*4=510K这个大小来说,本芯片IK结尾,只有256K SRAM肯定是不够了,如果是II结尾的那颗或许还可以。
如果按照256K理论上也可以设置双240*240*2大小的缓冲区,但这256K实际上是分片的。
keil上面也是默认分成两个区
经过试验,单个缓冲似乎不能跨区,粗略测试过后,最大的缓冲区就是270*180*2*2了。
因此在 littlevgl_support.h 文件中添加:
#define LCD_WIDTH 270
#define LCD_HEIGHT 180
#define LCD_FB_BYTE_PER_PIXEL 1
在 littlevgl_support.c 文件中添加全局变量:
static lv_color_t buf2_1[LCD_WIDTH * LCD_HEIGHT * LCD_FB_BYTE_PER_PIXEL]; /*A buffer for 10 rows*/
static lv_color_t buf2_2[LCD_WIDTH * LCD_HEIGHT * LCD_FB_BYTE_PER_PIXEL]; /*An other buffer for 10 rows*/
如果是用memset方式在开辟,则需要设置LCD_WIDTH * LCD_HEIGHT * LCD_FB_BYTE_PER_PIXEL*2大小,因为现在使用的是RGB565格式,每位需要16位2字节空间。
2-初始化
gpio的初始化见上一贴: 【GD32450I-EVAL】TLI-RGB屏幕驱动初探
tli的初始化需要根据缓冲区做一点改变,刚好设置为 LCD_WIDTH * LCD_HEIGHT 的显示范围:
static void tli_config_twolayout(void)
{
tli_parameter_struct tli_init_struct;
tli_layer_parameter_struct tli_layer_init_struct;
rcu_periph_clock_enable(RCU_TLI);
tli_gpio_config();
/* configure PLLSAI to generate TLI clock */
if(ERROR == rcu_pllsai_config(192, 2, 3)){
while(1);
}
rcu_tli_clock_div_config(RCU_PLLSAIR_DIV8);
rcu_osci_on(RCU_PLLSAI_CK);
if(ERROR == rcu_osci_stab_wait(RCU_PLLSAI_CK)){
while(1);
}
/* configure TLI parameter struct */
tli_init_struct.signalpolarity_hs = TLI_HSYN_ACTLIVE_LOW;
tli_init_struct.signalpolarity_vs = TLI_VSYN_ACTLIVE_LOW;
tli_init_struct.signalpolarity_de = TLI_DE_ACTLIVE_LOW;
tli_init_struct.signalpolarity_pixelck = TLI_PIXEL_CLOCK_TLI;
/* LCD display timing configuration */
tli_init_struct.synpsz_hpsz = HORIZONTAL_SYNCHRONOUS_PULSE - 1;
tli_init_struct.synpsz_vpsz = VERTICAL_SYNCHRONOUS_PULSE - 1;
tli_init_struct.backpsz_hbpsz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH - 1;
tli_init_struct.backpsz_vbpsz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH - 1;
tli_init_struct.activesz_hasz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH + ACTIVE_WIDTH - 1;
tli_init_struct.activesz_vasz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH + ACTIVE_HEIGHT - 1;
tli_init_struct.totalsz_htsz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH + ACTIVE_WIDTH + HORIZONTAL_FRONT_PORCH - 1;
tli_init_struct.totalsz_vtsz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH + ACTIVE_HEIGHT + VERTICAL_FRONT_PORCH - 1;
/* configure LCD background R,G,B values */
tli_init_struct.backcolor_red = 0xFF;
tli_init_struct.backcolor_green = 0xFF;
tli_init_struct.backcolor_blue = 0xFF;
tli_init(&tli_init_struct);
/* TLI layer1 configuration */
/* TLI window size configuration */
tli_layer_init_struct.layer_window_leftpos = 20 + HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH;
tli_layer_init_struct.layer_window_rightpos = (20 + LCD_WIDTH + HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH - 1);
tli_layer_init_struct.layer_window_toppos = 30 + VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH;
tli_layer_init_struct.layer_window_bottompos = (30 + LCD_HEIGHT + VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH - 1);
/* TLI window pixel format configuration */
tli_layer_init_struct.layer_ppf = LAYER_PPF_RGB565;
/* TLI window specified alpha configuration */
tli_layer_init_struct.layer_sa = 255;
/* TLI window blend configuration */
tli_layer_init_struct.layer_acf1 = LAYER_ACF1_PASA;
tli_layer_init_struct.layer_acf2 = LAYER_ACF2_PASA;
/* TLI layer default alpha R,G,B value configuration */
tli_layer_init_struct.layer_default_alpha = 0;
tli_layer_init_struct.layer_default_blue = 0xFF;
tli_layer_init_struct.layer_default_green = 0xFF;
tli_layer_init_struct.layer_default_red = 0xFF;
/* TLI layer frame buffer base address configuration */
tli_layer_init_struct.layer_frame_bufaddr = (uint32_t)buf2_1;
tli_layer_init_struct.layer_frame_line_length = ((LCD_WIDTH * 2) + 3);
tli_layer_init_struct.layer_frame_buf_stride_offset = (LCD_WIDTH * 2);
tli_layer_init_struct.layer_frame_total_line_number = LCD_HEIGHT;
tli_layer_init(LAYER1, &tli_layer_init_struct);
/* TLI layer0 configuration */
tli_layer_init_struct.layer_window_leftpos = 20 + HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH;
tli_layer_init_struct.layer_window_rightpos = (20 + LCD_WIDTH + HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH - 1);
tli_layer_init_struct.layer_window_toppos = 40 + VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH;
tli_layer_init_struct.layer_window_bottompos = (40 + LCD_HEIGHT + VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH - 1);
tli_layer_init_struct.layer_ppf = LAYER_PPF_RGB565;
/* TLI window specified alpha configuration */
tli_layer_init_struct.layer_sa = 255;
/* TLI layer default alpha R,G,B value configuration */
tli_layer_init_struct.layer_default_blue = 0xFF;
tli_layer_init_struct.layer_default_green = 0xFF;
tli_layer_init_struct.layer_default_red = 0xFF;
tli_layer_init_struct.layer_default_alpha = 0xFF;
/* TLI window blend configuration */
tli_layer_init_struct.layer_acf1 = LAYER_ACF1_PASA;
tli_layer_init_struct.layer_acf2 = LAYER_ACF2_PASA;
/* TLI layer frame buffer base address configuration */
tli_layer_init_struct.layer_frame_bufaddr = (uint32_t)buf2_2;
tli_layer_init_struct.layer_frame_line_length = ((LCD_WIDTH * 2) + 3);
tli_layer_init_struct.layer_frame_buf_stride_offset = (LCD_WIDTH * 2);
tli_layer_init_struct.layer_frame_total_line_number = LCD_HEIGHT;
tli_layer_init(LAYER0, &tli_layer_init_struct);
tli_dither_config(TLI_DITHER_ENABLE);
}
3-每帧回调刷新,通过显示不同的层实现
static void DEMO_FlushDisplay(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
if (color_p == buf2_1)
{
tli_layer_disable(LAYER0);
tli_layer_enable(LAYER1);
tli_reload_config(TLI_REQUEST_RELOAD_EN);
}
else if (color_p == buf2_2)
{
tli_layer_disable(LAYER1);
tli_layer_enable(LAYER0);
tli_reload_config(TLI_REQUEST_RELOAD_EN);
}
/* IMPORTANT!!!
* Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
4-显示的图像,创建一个居中的进度条
//例程入口
void lvAdd_sliderTest()
{
lv_obj_t * slider = lv_slider_create(lv_scr_act(), NULL);
lv_obj_set_width(slider, LV_DPI*1.5);
lv_obj_align(slider, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_event_cb(slider, cb_sliderTest);
lv_slider_set_range(slider, 0, 50);
// Create a label below the slider
slider_label = lv_label_create(lv_scr_act(), NULL);
lv_label_set_text(slider_label, "0");
lv_obj_set_auto_realign(slider_label, true);
lv_obj_align(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
}
5-主函数调用
int main(void)
{
static __IO uint32_t timingdelaylocal = 0U;
gd_eval_led_init(LED1);
systick_config();
lv_init();
lv_port_disp_init();
lv_port_indev_init();
lvAdd_sliderTest();
while(1){
delay_ms(10);
lv_tick_inc(10);
lv_task_handler();
}
}
(四)堆栈问题
第一次编译通过之后,在板子上运行始终卡死在初始化阶段,具体是卡死在theme的初始化配置上:
lv_theme_t * th = LV_THEME_DEFAULT_INIT(LV_THEME_DEFAULT_COLOR_PRIMARY, LV_THEME_DEFAULT_COLOR_SECONDARY,
LV_THEME_DEFAULT_FLAG,
LV_THEME_DEFAULT_FONT_SMALL, LV_THEME_DEFAULT_FONT_NORMAL, LV_THEME_DEFAULT_FONT_SUBTITLE, LV_THEME_DEFAULT_FONT_TITLE);
这个问题困扰了很久没能解决,非常郁闷,之前也曾经成功地移植过LittleVGL到其他平台,但都是基于eclipse的开发环境,很多配置并不相同,在修改过编译选项无果后,偶然之下发现LittleVGL 的主页有这么一点:
仔细一看,startup文件下默认配置的栈堆都只有0x400,都改成0x2000后就能成功运行了。
(五)效果
现在显示出来了,后面移植触摸驱动
工程:
lvdisplay.rar
(12.02 MB, 下载次数: 261)
|