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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。