263|2

70

帖子

0

资源

一粒金砂(中级)

【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实际上是分片的。
SRAM-手册.png

keil上面也是默认分成两个区

SRAM-MDK.png
经过试验,单个缓冲似乎不能跨区,粗略测试过后,最大的缓冲区就是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 的主页有这么一点:
堆栈.png
仔细一看,startup文件下默认配置的栈堆都只有0x400,都改成0x2000后就能成功运行了。

 

(五)效果

LittleVGL.jpg 现在显示出来了,后面移植触摸驱动

 

工程: lvdisplay.rar (12.02 MB, 下载次数: 0)


回复

1万

帖子

133

资源

管理员

个人签名

玩板看这里:

http://bbs.eeworld.com.cn/elecplay.html

EEWorld测评频道众多好板等你来玩,还可以来频道许愿树许愿说说你想要玩的板子,我们都在努力为大家实现!


回复

327

帖子

0

资源

一粒金砂(中级)

期待楼主后续评测


回复
您需要登录后才可以回帖 登录 | 注册

关闭
站长推荐上一条 1/5 下一条

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表