STM32F1,LVGL简易DEMO移植

简介

尝试过在ESP32上移植LVGL之后,再在STM32上面LVGL,确认下是不是可以用
虽然STM32F103ZE的ROM及RAM都没有ESP32丰富,便对应于LVGL的最低配置要求,应该也可以正常运行的。不过也只能移植简单的
按键显示,像复杂一些DEMO,在STM32F1不用了,资源不够,导致编译不通过。

LVGL

LVGL是一款比较流行的致力于MCU与MPU创建漂亮UI的嵌入式图形库,免费且开源。

最低要求

ROM > 64KB
RAM > 2K
STACK > 2K
HEAP > 2K

移植步骤

LVGL移植总的步骤主要是如下几步
1.调用lv_init();
2.初始化驱动
3.注册显示与输入驱动,显存的配置,显示响应回调函数的响应
4.lv_tick_inc(x) 在中断中定时更新,x设定取决于lv_tick_inc的调用频率
5.lv_timer_handler,定时调用,完成LVGL的响应(更新LVGL的响应)

具体示例

使用的是正点原子STM32F103ZE开发板

拷贝一个LCD可以正常驱动的工程

拷贝LVGL源码至工程

这里使用的是V8.3.0
拷贝完之后需要将源码添加至工程,并添加相应的include路径,STM32的添加LVGL的文件相对ESP32来说,就麻烦很多
需要每个文件都添加进工程
主要包括lvgl/src, lvgl/exmaples/porting(这个路径也可以不添加,在自己定义的移植文件路径添加即可)

如果一次没成功,也没事,可以根据提示的编译错误慢慢添加
重命令lv_conf.h,并使能#if 0 改为#if 1
LVGL需要编译器支持C99模式,不然无法编译通过
因为将lv_conf.h独立于LVGL的源码,需要添加预定义LV_CONF_INCLUDE_SIMPLE,没加的话,编译会提示这个错误,加上就可以正常编译
在INCLUDE的路径下添加LVGL源码路径
lvgl/example/porting目录下的移植文件拷贝到工程目录下,lv_port_disp_template与lv_port_indev_template并重命名为lv_port_disp.h, lv_port_disp.c, lv_port_indev.h, lv_port_indev.c
因为改变了路径,文件不放在LVGL源码的路径下, 直接include "lvgl.h"即可,并使能两个文件#if 0 改为 #if 1

屏幕驱动

分配好显存,移植LCD区域点阵更新操作

void lv_port_disp_init(void)
{
    /*-------------------------
     * Initialize your display
     * -----------------------*/
    disp_init();

    /* Example for 1) */
    lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10);   /*Initialize the display buffer*/

    /*-----------------------------------
     * 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_1;


    ///*Finally register the driver*/
    lv_disp_drv_register(&disp_drv);
}

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
	LCD_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);
}

输入驱动

这里以电阻触摸屏为例,给到LVGL的触点信息必须是和屏幕位置相对应的
校准具体模拟值与感应像素点的位置的操作,应该在BSP层里面做好,最后传给LVGL是像素逻辑位置

void lv_port_indev_init(void)
{
    static lv_indev_drv_t indev_drv;
    touchpad_init();

    /*Register a touchpad input device*/
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touchpad_read;
    indev_touchpad = lv_indev_drv_register(&indev_drv);
}

/*Initialize your touchpad*/
static void touchpad_init(void)
{
    /*Your code comes here*/
}

/*Will be called by the library to read the touchpad*/
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    static lv_coord_t last_x = 0;
    static lv_coord_t last_y = 0;

    /*Save the pressed coordinates and the state*/
    if(touchpad_is_pressed()) {
        touchpad_get_xy(&last_x, &last_y);
        data->state = LV_INDEV_STATE_PR;
    }
    else {
        data->state = LV_INDEV_STATE_REL;
    }

    /*Set the last pressed coordinates*/
    data->point.x = last_x;
    data->point.y = last_y;
}

/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
    /*Your code comes here*/
	tp_dev.scan(0);
	if(tp_dev.sta&TP_PRES_DOWN)
		return true;
	else
    	return false;
}

/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
    /*Your code comes here*/
    (*x) = tp_dev.x[0];
    (*y) = tp_dev.y[0];
}

初始化及调用

在SYSTICK中断函数里,将LVGL计时增加

void SysTick_Handler(void)
{
    HAL_IncTick();
	lv_tick_inc(1);
}

初始化并调用

    lv_init();
	lv_port_disp_init();
	lv_port_indev_init();
	lv_example_btn_1();
	
  	while(1) 
	{		
		lv_timer_handler();
		delay_ms(3);
	} 

存在问题

编译通过后,烧录到硬件,发现只显示部分就卡死了
单步调试时,发生HardFault错误
原因是默认的STACK深度不够,导致跑LVGL的栈溢出了,整个程序就出错了
需要修改默认的栈深度,针对按钮测试DEMO,暂改为0x800的大小

Stack_Size      EQU     0x00000800

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size

显示图片

其他

使用片上SRAM可以使用LVGL,使用外部的SRAM也可以正常使用LVGL

总结

这里只是验证了,LVGL在STM32F1上面是可以跑起来的,具体的使用及细节还是需要在实际用到的项目去了解及深入

posted @ 2024-10-19 16:32  cau_par  阅读(24)  评论(0编辑  收藏  举报