【随笔记】Littlevgl 8.x 踩过的坑
阅读原文时间:2023年07月09日阅读:2

在多线程并发使用的时候,总是在运行过程中莫名其妙的 crash,后面才意识到 LVGL 本身不支持并发,加了互斥锁解决了。

在引入矢量字库时(freetype),又有启动时会概率性 crash 的问题,每次 crash 的地方还不一样,这个坑爬了好久,甚至都怀疑是不是 freetype 有问题,还好总算找到方法解决了,不过还不清楚具体原因,先记录。

以下以 linux 平台下 C++ 语言的方式举例说明,理解方法即可。

一、多线程并发使用

多线程并发使用时,需要在以下两种情况加上互斥锁:

1. 移植时在调用 lv_tick_inc(1) 和 lv_task_handler() 时上锁

// 线程函数
void LvglDrive::prvLvTickTask(LvglDrive *context)
{
    while(context->th_tasktick_runing)
    {
        context->m_lvmutex.lock();
        lv_tick_inc(1);
        context->m_lvmutex.unlock();
        usleep(1 * 1000);
    }
    return ;
}

// 线程函数
void LvglDrive::prvLvHandlerTask(LvglDrive *context)
{
    while(context->th_tasktick_runing)
    {
        context->m_lvmutex.lock();
        lv_task_handler();
        context->m_lvmutex.unlock();
        usleep(5 * 1000);
    }
    return ;
}

2. 操作控件时上锁

void GuiManager::toast_show(const char *str, unsigned int timeout)
{
    LvglDrive::getInstance()->lock();
    lv_timer_reset(lv_timer_toast);
    lv_timer_pause(lv_timer_toast);
    if(timeout){
        lv_timer_set_period(lv_timer_toast, timeout);
        lv_timer_resume(lv_timer_toast);
    }
    lv_label_set_text(lv_obj_toast, str);
    lv_obj_set_style_pad_top(lv_obj_toast, 5, 0);
    lv_obj_set_style_pad_left(lv_obj_toast, 15, 0);
    lv_obj_set_style_pad_right(lv_obj_toast, 15, 0);
    lv_obj_set_style_pad_bottom(lv_obj_toast, 8, 0);
    LvglDrive::getInstance()->unlock();
    return ;
}

void GuiManager::toast_hide()
{
    LvglDrive::getInstance()->lock();
    lv_timer_reset(lv_timer_toast);
    lv_timer_pause(lv_timer_toast);
    lv_label_set_text(lv_obj_toast, "");
    lv_obj_set_style_pad_top(lv_obj_toast, 0, 0);
    lv_obj_set_style_pad_left(lv_obj_toast, 0, 0);
    lv_obj_set_style_pad_right(lv_obj_toast, 0, 0);
    lv_obj_set_style_pad_bottom(lv_obj_toast, 0, 0);
    LvglDrive::getInstance()->unlock();
    return ;
}

二、引入矢量字库(freetype)

需要先把所有需要用到的 UI 控件都创建和初始化完成之后,再去创建两个线程去调用 lv_tick_inc(1) 和 lv_task_handler(),顺序如下:

1、初始化 framebuffer、lv_init()、lv_freetype_init()、lv_port_disp_init()

2、初始化所需要的 UI 控件

3、创建线程调用  lv_task_handler() 、lv_tick_inc(1)

4、按需要设置 UI 控件

bool GuiManager::running()
{
    // 初始化 framebuffer、lv_init()、lv_freetype_init()、lv_port_disp_init()
    if(LvglDrive::getInstance()->init() == false){
        eprintf("lvgl driver running failed!!!\n");
        return false;
    }

    ...

    static lv_ft_info_t ft_info_18;
    ft_info_18.name = RES_FONT_PATH;
    ft_info_18.weight = 18;
    ft_info_18.style = FT_FONT_STYLE_NORMAL | FT_FONT_STYLE_BOLD;
    lv_ft_font_init(&ft_info_18);

    static lv_style_t style_18;
    lv_style_init(&style_18);
    lv_style_set_text_font(&style_18, ft_info_18.font);
    lv_style_set_radius(&style_18, LV_RADIUS_CIRCLE);

    lv_obj_toast = lv_label_create(lv_layer_sys());
    lv_obj_add_style(lv_obj_toast, &style_18, 0);
    lv_obj_set_style_bg_opa(lv_obj_toast, LV_OPA_30, 0);
    lv_obj_set_style_bg_color(lv_obj_toast, lv_color_black(), 0);
    lv_obj_set_style_text_color(lv_obj_toast, lv_color_white(), 0);
    lv_label_set_text(lv_obj_toast, "");
    lv_obj_set_style_pad_top(lv_obj_toast, 0, 0);
    lv_obj_set_style_pad_left(lv_obj_toast, 0, 0);
    lv_obj_set_style_pad_right(lv_obj_toast, 0, 0);
    lv_obj_set_style_pad_bottom(lv_obj_toast, 0, 0);
    lv_obj_align(lv_obj_toast, LV_ALIGN_CENTER, 0, 50);

    lv_timer_toast = lv_timer_create(on_timer_lv_toast_refresh, 500, this);
    lv_timer_pause(lv_timer_toast);

    ...

    // 创建线程:prvLvTickTask()、prvLvHandlerTask()
    LvglDrive::getInstance()->run();
    return true;
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章