硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1757|回复: 12
收起左侧

[RTOS] lvgl 摄像头刷新canvas控件问题

[复制链接]

4

主题

19

回帖

31

积分

新手上路

QM

积分
31
QQ
发表于 2024-11-4 01:38:42 来自手机 | 显示全部楼层 |阅读模式
freertos下,初始为主界面,按下按钮触发页面切换,并启动摄像头采集并输出到lvgl的canvas控件上,大小为640x480,再次点击关闭摄像头并返回。
主要的转换逻辑都在lvgl的事件回调内实现,摄像头图像通过dcmi的framecallback发送事件来触发更新。
两种思路,一种是类似guix例程那样,不额外开新的任务,摄像头采集刷新和lvgl任务放在一起,但这个方法,返回主页面的时候会直接爆掉,通过调试定位到lveventsend函数,但不知道该怎么改,如果改lv库的话需要改个写权限;另一种方法是额外开个新任务,任务初始vtasksuspend,点击按钮来resume启动摄像头。但试了试发现需要这个任务比lvgl优先级低,否则点击返回一定会进硬件错误,尝试定位问题每次找到的位置都不一样,特地调整lvgl的优先级也会在camera任务刷新过快而概率性爆掉。
而且两种方式的图像输出都只有从上到下的2/3部分。
脑子笨,求教论坛大佬们。
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117563
QQ
发表于 2024-11-4 08:27:56 | 显示全部楼层
1、注意LVGL不支持多任务,后来出的新版本不知道新增加没。
2、我做的emWin刷新和GUIX摄像头案例,摄像头采集完毕后,给GUI任务刷新即可,GUI任务本来就是干这个的,不要再一个任务又去处理摄像头,累赘。比如你弄个实体按键处理GUI,处理触摸,处理ADC波形展示,都要单独开一个任务,显然不用。数据准备好了,直接处理即可。
回复

使用道具 举报

4

主题

19

回帖

31

积分

新手上路

QM

积分
31
QQ
 楼主| 发表于 2024-11-4 09:51:42 | 显示全部楼层
没有在其他任务里调用过gui函数也不可以吗,页面切换这边将摄像头相关全部注释掉再试的话,是可以正常切换的。
不过说到这个,新版本倒是提供了多线程调用的支持,但是我目前用的8.3.10是没有的。gui guider也只支持到8.3.10
void lv_lock(void)
Lock LVGL's general mutex. LVGL is not thread safe, so a mutex is used to avoid executing multiple LVGL functions at the same time from different threads. It shall be called when calling LVGL functions from threads different than lv_timer_handler's thread. It doesn't need to be called in LVGL events because they are called from lv_timer_handler(). It is called internally in lv_timer_handler().
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117563
QQ
发表于 2024-11-4 09:59:08 | 显示全部楼层
qingming2333 发表于 2024-11-4 09:51
没有在其他任务里调用过gui函数也不可以吗,页面切换这边将摄像头相关全部注释掉再试的话,是可以正常切换 ...
没有在其他任务里调用过gui函数也不可以吗


可以,但没必要,因为你的DCMI DMA已经把数据准备好,就等GUI刷新了。直接发消息通信让GUI任务刷新即可,无需多开任务来怎么设计复杂性。
回复

使用道具 举报

0

主题

40

回帖

40

积分

新手上路

积分
40
发表于 2024-11-4 10:20:33 | 显示全部楼层
这种比较简单,如果内存足够的话,就多级缓冲,然后LVGL,定时刷新即可,跟播放音频一样的做法
回复

使用道具 举报

4

主题

19

回帖

31

积分

新手上路

QM

积分
31
QQ
 楼主| 发表于 2024-11-4 10:30:00 | 显示全部楼层
主要还是想解决摄像头传递图像不正确、完整,以及返回时的硬件错误问题。lvgl任务栈和lvgl memsize都设置的挺大的,应该不会是它们的问题
单任务和多任务都有这个问题,单任务甚至百分百触发。
void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
{
        CAM_Stop();
        g_tCam.CaptureOk = 1;                /* 表示DMA传输结束 */
        lv_event_send(guider_ui.screen_1_canvas_1, LV_EVENT_VALUE_CHANGED, NULL);
}
static void screen_1_btn_1_event_handler (lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);
    switch (code) {
    case LV_EVENT_CLICKED:
    {
                osMutexAcquire(LVGLMutex,0);
        ui_load_scr_animation(&guider_ui, &guider_ui.screen, guider_ui.screen_del, &guider_ui.screen_1_del, setup_scr_screen, LV_SCR_LOAD_ANIM_NONE, 200, 200, true, true);
                lv_timer_resume(lv_timer_dclock);//返回主页面,拉起时钟
                lv_timer_resume(lv_timer_update);
                #if        ANOTHERTASK
                        vTaskSuspend(ThreadCAMERA);
                #else
                        flag =1;
                #endif
                osMutexRelease(LVGLMutex);
        break;
    }
    default:
        break;
    }
}
static void screen_btn_2_event_handler (lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);
    switch (code) {
    case LV_EVENT_CLICKED:
    {
                osMutexAcquire(LVGLMutex,0);
        ui_load_scr_animation(&guider_ui, &guider_ui.screen_1, guider_ui.screen_1_del, &guider_ui.screen_del, setup_scr_screen_1, LV_SCR_LOAD_ANIM_NONE, 200, 200, true, true);
                lv_timer_pause(lv_timer_dclock); //进入摄像头页面,关闭时钟
                lv_timer_pause(lv_timer_update);
                #if        ANOTHERTASK
                        vTaskResume(ThreadCAMERA);
                #else
                        flag =0;
                        CAM_Start1(SDRAM_CAMERA); //刷新一次,以让canvas控件左脚踩右脚
                #endif
                osMutexRelease(LVGLMutex);
        break;
    }
    default:
        break;
    }
}
static void screen_1_canvas_1_event_handler (lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);
       
    switch (code) {
               
    case LV_EVENT_VALUE_CHANGED:
    {
                osMutexAcquire(LVGLMutex,0);
                #if        ANOTHERTASK
                        lv_obj_invalidate(guider_ui.screen_1_canvas_1);
                #else
                        if(!flag)
                        {
                                lv_obj_invalidate(guider_ui.screen_1_canvas_1);
                                CAM_Start1(SDRAM_CAMERA);
                        }
                #endif
                osMutexRelease(LVGLMutex);
//                printf("flush once!\r\n ");
        break;
    }
    default:
        break;
    }
}
static void screen_1_canvas_1_event_handler (lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);
       
    switch (code) {
               
    case LV_EVENT_VALUE_CHANGED:
    {
                osMutexAcquire(LVGLMutex,0);
                #if        ANOTHERTASK
                        lv_obj_invalidate(guider_ui.screen_1_canvas_1);
                #else
                        if(!flag)
                        {
                                lv_obj_invalidate(guider_ui.screen_1_canvas_1);
                                CAM_Start1(SDRAM_CAMERA);
                        }
                #endif
                osMutexRelease(LVGLMutex);
//                printf("flush once!\r\n ");
        break;
    }
    default:
        break;
    }
}

分别是我的回调以及两个按钮触发页面更换,以及canvas控件刷新的逻辑,Anothertask是我昨晚测试两种方法时定义的宏,flag是我临时拿出来给单任务的全局标志。
互斥量感觉没什么意义,是刚刚才加上的。硬汉哥或者其他搞过的大佬能不能帮忙看下
回复

使用道具 举报

4

主题

19

回帖

31

积分

新手上路

QM

积分
31
QQ
 楼主| 发表于 2024-11-4 10:57:44 | 显示全部楼层
a13421364618 发表于 2024-11-4 10:20
这种比较简单,如果内存足够的话,就多级缓冲,然后LVGL,定时刷新即可,跟播放音频一样的做法

感谢,我去看看怎么搞
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117563
QQ
发表于 2024-11-4 13:38:00 | 显示全部楼层
qingming2333 发表于 2024-11-4 10:30
主要还是想解决摄像头传递图像不正确、完整,以及返回时的硬件错误问题。lvgl任务栈和lvgl memsize都设置的 ...

这个可以对比下我分享的GUIX和emWn的摄像头案例。
回复

使用道具 举报

0

主题

290

回帖

290

积分

高级会员

积分
290
发表于 2024-11-4 13:42:25 | 显示全部楼层
qingming2333 发表于 2024-11-4 10:57
感谢,我去看看怎么搞

在tap或者sys层创建canvas试试看。不用的时候隐藏,用的时候显示,不销毁
回复

使用道具 举报

4

主题

19

回帖

31

积分

新手上路

QM

积分
31
QQ
 楼主| 发表于 2024-11-5 01:46:17 | 显示全部楼层
regbbs 发表于 2024-11-4 13:42
在tap或者sys层创建canvas试试看。不用的时候隐藏,用的时候显示,不销毁

谢谢,可行,至少不会再进硬件错误,目前的问题似乎出在canvas 颜色格式设置上,用的OV7060的摄像头,应该跟guix里一样给canvas配置LV_IMG_CF_RGB565,但设置完会显示没有数据;
如果设置为LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED,会显示几帧之后不再刷新,可能问题出在其他地方,我明天再检查检查。
回复

使用道具 举报

692

主题

3576

回帖

5677

积分

论坛元老

积分
5677
发表于 2024-11-5 09:20:57 | 显示全部楼层
本帖最后由 hpdell 于 2024-11-5 10:09 编辑
qingming2333 发表于 2024-11-5 01:46
谢谢,可行,至少不会再进硬件错误,目前的问题似乎出在canvas 颜色格式设置上,用的OV7060的摄像头,应 ...

把 camera 输出的图像当作一个图片来处理就可以了,

我就是这么干的,目前camera 输出的 图像在 页面显示,保存都是没有问题的

当然如果使用 lvgl 画布 来显示也是可以的

图片配置:

lv_img_dsc_t camera_img = {
        .header.cf = LV_IMG_CF_TRUE_COLOR,  // ok
        .header.always_zero = 0,
        .header.reserved = 0,
        .header.w = CAMERA_Display_Width,
        .header.h = CAMERA_Display_Height,
        .data_size = CAMERA_DMA_BUFF_SIZE,

        .data = 0,  // 这个在需要显示的地方重新指向 camera 数据地址即可
};





回复

使用道具 举报

4

主题

19

回帖

31

积分

新手上路

QM

积分
31
QQ
 楼主| 发表于 2024-11-5 13:05:41 | 显示全部楼层
hpdell 发表于 2024-11-5 09:20
把 camera 输出的图像当作一个图片来处理就可以了,

我就是这么干的,目前camera 输出的 图像在 页面 ...

好的好的,晚上回去试试
回复

使用道具 举报

4

主题

19

回帖

31

积分

新手上路

QM

积分
31
QQ
 楼主| 发表于 2024-11-5 23:05:29 | 显示全部楼层
ok,目前能刷个60帧,偶尔因为任务调度和非线程安全问题会自己停止刷新,其他都还好。
谢谢大伙
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-14 16:18 , Processed in 0.057539 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表