LVGL在rt-thread上的移植是怎样的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
首先按照rt-thread的lcd驱动框架完成驱动的编写,可参考如下结构体,完成相关函数的实现。
struct rt_device_graphic_ops { void (*set_pixel) (const char *pixel, int x, int y); void (*get_pixel) (char *pixel, int x, int y); void (*draw_hline)(const char *pixel, int x1, int x2, int y); void (*draw_vline)(const char *pixel, int x, int y1, int y2); void (*blit_line) (const char *pixel, int x, int y, rt_size_t size); };
在完成函数编写后,进行操作结构体的定义。
struct rt_device_graphic_ops fsmc_lcd_ops = { LCD_DrawPoint, LCD_ReadPoint, LCD_HLine, RT_NULL, LCD_BlitLine, };
然后,按照显示屏设备的具体信息进行填写,并将设备挂载到设备驱动列表。
int drv_lcd_hw_init(void) { rt_err_t result = RT_EOK; struct rt_device *device = &_lcd.parent; /* memset _lcd to zero */ memset(&_lcd, 0x00, sizeof(_lcd)); _lcd.lcd_info.bits_per_pixel = 16; _lcd.lcd_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565; device->type = RT_Device_Class_Graphic; #ifdef RT_USING_DEVICE_OPS device->ops = &lcd_ops; #else device->init = drv_lcd_init; device->control = drv_lcd_control; #endif device->user_data = &fsmc_lcd_ops; rt_device_register(device, "lcd", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE); return result; } INIT_DEVICE_EXPORT(drv_lcd_hw_init);
关于lvgl的相关参数设备及移植的详细说明见 官方移植说明,在此不做过多说明。
此部分对接主要针对lv_port_disp.c文件中lvgl显示驱动和rt-thread驱动接口的对接部分做下介绍。
此部分主要完成显示设备的查找和打开操作。
/* Initialize your display and the required peripherals. */ static void disp_init(void) { /*You code here*/ lcd_device = rt_device_find("lcd"); if (!lcd_device) { LOG_E("find %s failed!", "lcd"); return; } rt_device_open(lcd_device, RT_DEVICE_FLAG_RDWR); }
该部分需要完成指定区域的显示像素内容的写入,可以进行像素点操作或行列操作,可以结合自己显示屏的特性进行调整,此部分刷入的方案也是会影响显示的刷新率,需要尽可以选择刷新速度最快的方案。
/* Flush the content of the internal buffer the specific area on the display * You can use DMA or any hardware acceleration to do this operation in the background but * 'lv_disp_flush_ready()' has to be called when finished. */ static void disp_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) { /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/ // int32_t x; // int32_t y; // for (y = area->y1; y <= area->y2; y++) // { // for (x = area->x1; x <= area->x2; x++) // { // /* Put a pixel to the display. For example: */ // /* put_px(x, y, *color_p)*/ // rt_graphix_ops(lcd_device)->set_pixel((const char *)&color_p->full, x, y); // color_p++; // } // } int32_t y; int32_t width; for (y = area->y1; y <= area->y2; y++) { width = (area->x2 - area->x1 + 1); rt_graphix_ops(lcd_device)->blit_line((const char *)&color_p->full, area->x1, y, width); color_p += width; } /* IMPORTANT!!! * Inform the graphics library that you are ready with the flushing*/ lv_disp_flush_ready(disp_drv); }
在lvgl中有两个函数是依赖于系统的调用:lv_tick_inc和lv_task_handler(),注意这两个函数不能放到一个线程中,就避免相关事件响应机制出错。 我们可以创建一个软件定时器和一个任务分别来处理lvgl的系统调用。
rt_thread_t tid; tid = rt_thread_create("lvgl_task", lvgl_task, RT_NULL, 4096, 20, 4); if (tid != RT_NULL) rt_thread_startup(tid); rt_timer_t timer1 = rt_timer_create("timer1", lvgl_tick, RT_NULL, 10, RT_TIMER_FLAG_PERIODIC); if (timer1 != RT_NULL) rt_timer_start(timer1);
在lvgl_task中,我们周期调用lv_task_handler()函数即可。
static void lvgl_task(void *parameter) { while (true) { rt_thread_delay(10); lv_task_handler(); } }
相应的,在软定时器中,我们根据软件定时器的间隔,在超时处理中对lv_tick_inc注入时间间隔即可。
static void lvgl_tick(void *parameter) { lv_tick_inc(10); }
至此,已经完成rt-thread与lvgl的移植对接工作,可以进行应用层代码的编写。
关于LVGL在rt-thread上的移植是怎样的问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。