diff --git a/examples/lvgldemo/Kconfig b/examples/lvgldemo/Kconfig index 2e6e2fa39..b62abf6d5 100644 --- a/examples/lvgldemo/Kconfig +++ b/examples/lvgldemo/Kconfig @@ -22,6 +22,13 @@ config EXAMPLES_LVGLDEMO_BUFF_SIZE int "Display buffer size (in line)" default 20 +config EXAMPLES_LVGLDEMO_ASYNC_FLUSH + bool "Flush the display buffer asynchronously" + default n + ---help--- + Enable this option to perform an asynchronous write of the buffer + contents to the display device. + choice prompt "Select a demo application" default EXAMPLES_LVGLDEMO_WIDGETS diff --git a/examples/lvgldemo/fbdev.c b/examples/lvgldemo/fbdev.c index 1b6c00dec..0a4f8b929 100644 --- a/examples/lvgldemo/fbdev.c +++ b/examples/lvgldemo/fbdev.c @@ -39,8 +39,14 @@ #include "fbdev.h" +#include #include +#ifdef CONFIG_EXAMPLES_LVGLDEMO_ASYNC_FLUSH +#include +#include +#endif + #include #include #include @@ -79,30 +85,62 @@ struct fb_state_s struct fb_state_s state; +#ifdef CONFIG_EXAMPLES_LVGLDEMO_ASYNC_FLUSH +static pthread_t fb_write_thread; +static sem_t flush_sem; +static sem_t wait_sem; + +static lv_area_t lv_area; +static lv_color_t *lv_color_p; +#endif + /**************************************************************************** - * Public Functions + * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: fbdev_flush + * Name: fbdev_wait * * Description: - * Flush a buffer to the marked area + * Wait for the flushing operation conclusion to notify LVGL. * * Input Parameters: - * x1 - Left coordinate - * y1 - Top coordinate - * x2 - Right coordinate - * y2 - Bottom coordinate - * color_p - A n array of colors + * disp_drv - LVGL driver interface * * Returned Value: * None * ****************************************************************************/ -static void fbdev_flush(struct _disp_drv_t *disp_drv, const lv_area_t *area, - lv_color_t *color_p) +#ifdef CONFIG_EXAMPLES_LVGLDEMO_ASYNC_FLUSH + +static void fbdev_wait(lv_disp_drv_t *disp_drv) +{ + sem_wait(&wait_sem); + + /* Tell the flushing is ready */ + + lv_disp_flush_ready(disp_drv); +} + +#endif + +/**************************************************************************** + * Name: fbdev_flush_internal + * + * Description: + * Write the buffer to Framebuffer interface. + * + * Input Parameters: + * area - Area of the screen to be flushed + * color_p - A n array of colors + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int fbdev_flush_internal(const lv_area_t *area, lv_color_t *color_p) { #ifdef CONFIG_FB_UPDATE struct fb_area_s fb_area; @@ -119,29 +157,29 @@ static void fbdev_flush(struct _disp_drv_t *disp_drv, const lv_area_t *area, if (state.fbmem == NULL) { - return; + return ERROR; } /* Return if the area is out the screen */ if (x2 < 0) { - return; + return ERROR; } if (y2 < 0) { - return; + return ERROR; } if (x1 > state.vinfo.xres - 1) { - return; + return ERROR; } if (y1 > state.vinfo.yres - 1) { - return; + return ERROR; } /* Truncate the area to the screen */ @@ -216,11 +254,112 @@ static void fbdev_flush(struct _disp_drv_t *disp_drv, const lv_area_t *area, ioctl(state.fd, FBIO_UPDATE, (unsigned long)((uintptr_t)&fb_area)); #endif + return OK; +} + +/**************************************************************************** + * Name: fbdev_async_flush + * + * Description: + * Flush a buffer to the marked area asynchronously. + * + * Input Parameters: + * disp_drv - LVGL driver interface + * area - Area of the screen to be flushed + * color_p - A n array of colors + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_LVGLDEMO_ASYNC_FLUSH + +static void fbdev_async_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, + lv_color_t *color_p) +{ + UNUSED(disp_drv); + + lv_area.y1 = area->y1; + lv_area.y2 = area->y2; + lv_area.x1 = area->x1; + lv_area.x2 = area->x2; + + lv_color_p = color_p; + + sem_post(&flush_sem); +} + +#endif + +/**************************************************************************** + * Name: fbdev_sync_flush + * + * Description: + * Flush a buffer to the marked area synchronously. + * + * Input Parameters: + * disp_drv - LVGL driver interface + * area - Area of the screen to be flushed + * color_p - A n array of colors + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_EXAMPLES_LVGLDEMO_ASYNC_FLUSH + +static void fbdev_sync_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, + lv_color_t *color_p) +{ + fbdev_flush_internal(area, color_p); + /* Tell the flushing is ready */ lv_disp_flush_ready(disp_drv); } +#endif + +/**************************************************************************** + * Name: fbdev_write + * + * Description: + * Thread for writing the buffer to Framebuffer interface. + * + * Input Parameters: + * arg - Context data from the parent thread + * + * Returned Value: + * Context data to the parent thread + * + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_LVGLDEMO_ASYNC_FLUSH + +static pthread_addr_t fbdev_write(pthread_addr_t arg) +{ + int ret = OK; + + UNUSED(arg); + + while (ret == OK) + { + sem_wait(&flush_sem); + + ret = fbdev_flush_internal(&lv_area, lv_color_p); + + sem_post(&wait_sem); + } + + gerr("Failed to write buffer contents to display device\n"); + + return NULL; +} + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -249,7 +388,7 @@ int fbdev_init(lv_disp_drv_t *lv_drvr) if (state.fd < 0) { int errcode = errno; - gerr("ERROR: Failed to open %s: %d\n", fbdev, errcode); + gerr("Failed to open %s: %d\n", fbdev, errcode); return EXIT_FAILURE; } @@ -261,7 +400,7 @@ int fbdev_init(lv_disp_drv_t *lv_drvr) { int errcode = errno; - gerr("ERROR: ioctl(FBIOGET_VIDEOINFO) failed: %d\n", errcode); + gerr("ioctl(FBIOGET_VIDEOINFO) failed: %d\n", errcode); close(state.fd); state.fd = -1; return EXIT_FAILURE; @@ -276,7 +415,7 @@ int fbdev_init(lv_disp_drv_t *lv_drvr) if (ret < 0) { int errcode = errno; - gerr("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n", errcode); + gerr("ioctl(FBIOGET_PLANEINFO) failed: %d\n", errcode); close(state.fd); state.fd = -1; return EXIT_FAILURE; @@ -290,7 +429,21 @@ int fbdev_init(lv_disp_drv_t *lv_drvr) lv_drvr->hor_res = state.vinfo.xres; lv_drvr->ver_res = state.vinfo.yres; - lv_drvr->flush_cb = fbdev_flush; +#ifndef CONFIG_EXAMPLES_LVGLDEMO_ASYNC_FLUSH + lv_drvr->flush_cb = fbdev_sync_flush; +#else + lv_drvr->flush_cb = fbdev_async_flush; + lv_drvr->wait_cb = fbdev_wait; + + /* Initialize the mutexes for buffer flushing synchronization */ + + sem_init(&flush_sem, 0, 0); + sem_init(&wait_sem, 0, 0); + + /* Initialize the buffer flushing thread */ + + pthread_create(&fb_write_thread, NULL, fbdev_write, NULL); +#endif /* Only these pixel depths are supported. viinfo.fmt is ignored, only * certain color formats are supported. @@ -299,7 +452,7 @@ int fbdev_init(lv_disp_drv_t *lv_drvr) if (state.pinfo.bpp != 32 && state.pinfo.bpp != 16 && state.pinfo.bpp != 8 && state.pinfo.bpp != 1) { - gerr("ERROR: bpp=%u not supported\n", state.pinfo.bpp); + gerr("bpp=%u not supported\n", state.pinfo.bpp); close(state.fd); state.fd = -1; return EXIT_FAILURE; @@ -319,8 +472,7 @@ int fbdev_init(lv_disp_drv_t *lv_drvr) if (state.fbmem == MAP_FAILED) { int errcode = errno; - gerr("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n", - errcode); + gerr("ioctl(FBIOGET_PLANEINFO) failed: %d\n", errcode); close(state.fd); state.fd = -1; return EXIT_FAILURE; diff --git a/examples/lvgldemo/lcddev.c b/examples/lvgldemo/lcddev.c index 9b5e47e50..092410c09 100644 --- a/examples/lvgldemo/lcddev.c +++ b/examples/lvgldemo/lcddev.c @@ -24,9 +24,15 @@ #include "lcddev.h" +#include #include #include +#ifdef CONFIG_EXAMPLES_LVGLDEMO_ASYNC_FLUSH +#include +#include +#endif + #include #include #include @@ -62,10 +68,44 @@ struct lcd_state_s static struct lcd_state_s state; +#ifdef CONFIG_EXAMPLES_LVGLDEMO_ASYNC_FLUSH +static pthread_t lcd_write_thread; +static sem_t flush_sem; +static sem_t wait_sem; +static struct lcddev_area_s lcd_area; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: lcddev_wait + * + * Description: + * Wait for the flushing operation conclusion to notify LVGL. + * + * Input Parameters: + * disp_drv - LVGL driver interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_LVGLDEMO_ASYNC_FLUSH + +static void lcddev_wait(lv_disp_drv_t *disp_drv) +{ + sem_wait(&wait_sem); + + /* Tell the flushing is ready */ + + lv_disp_flush_ready(disp_drv); +} + +#endif + /**************************************************************************** * Name: lcddev_flush * @@ -82,8 +122,28 @@ static struct lcd_state_s state; * ****************************************************************************/ -static void lcddev_flush(struct _disp_drv_t *disp_drv, const lv_area_t *area, - lv_color_t *color_p) +#ifdef CONFIG_EXAMPLES_LVGLDEMO_ASYNC_FLUSH + +static void lcddev_async_flush(lv_disp_drv_t *disp_drv, + const lv_area_t *area, + lv_color_t *color_p) +{ + UNUSED(disp_drv); + + lcd_area.row_start = area->y1; + lcd_area.row_end = area->y2; + lcd_area.col_start = area->x1; + lcd_area.col_end = area->x2; + + lcd_area.data = (uint8_t *)color_p; + + sem_post(&flush_sem); +} + +#else + +static void lcddev_sync_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, + lv_color_t *color_p) { int ret; struct lcddev_area_s lcd_area; @@ -102,8 +162,7 @@ static void lcddev_flush(struct _disp_drv_t *disp_drv, const lv_area_t *area, { int errcode = errno; - gerr("ERROR: ioctl(LCDDEVIO_PUTAREA) failed: %d\n", - errcode); + gerr("ioctl(LCDDEVIO_PUTAREA) failed: %d\n", errcode); close(state.fd); return; } @@ -113,6 +172,53 @@ static void lcddev_flush(struct _disp_drv_t *disp_drv, const lv_area_t *area, lv_disp_flush_ready(disp_drv); } +#endif + +/**************************************************************************** + * Name: lcddev_write + * + * Description: + * Write the buffer to LCD interface. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_LVGLDEMO_ASYNC_FLUSH + +static pthread_addr_t lcddev_write(pthread_addr_t addr) +{ + int ret = OK; + int errcode; + + while (ret == OK) + { + sem_wait(&flush_sem); + ret = ioctl(state.fd, LCDDEVIO_PUTAREA, (unsigned long)&lcd_area); + if (ret < 0) + { + errcode = errno; + } + + sem_post(&wait_sem); + } + + if (ret != OK) + { + gerr("ioctl(LCDDEVIO_PUTAREA) failed: %d\n", errcode); + close(state.fd); + state.fd = -1; + } + + return NULL; +} + +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -142,7 +248,7 @@ int lcddev_init(lv_disp_drv_t *lv_drvr) if (state.fd < 0) { int errcode = errno; - gerr("ERROR: Failed to open %s: %d\n", state.fd, errcode); + gerr("Failed to open %s: %d\n", state.fd, errcode); return EXIT_FAILURE; } @@ -154,7 +260,7 @@ int lcddev_init(lv_disp_drv_t *lv_drvr) { int errcode = errno; - gerr("ERROR: ioctl(LCDDEVIO_GETVIDEOINFO) failed: %d\n", errcode); + gerr("ioctl(LCDDEVIO_GETVIDEOINFO) failed: %d\n", errcode); close(state.fd); state.fd = -1; return EXIT_FAILURE; @@ -169,7 +275,7 @@ int lcddev_init(lv_disp_drv_t *lv_drvr) if (ret < 0) { int errcode = errno; - gerr("ERROR: ioctl(LCDDEVIO_GETPLANEINFO) failed: %d\n", errcode); + gerr("ioctl(LCDDEVIO_GETPLANEINFO) failed: %d\n", errcode); close(state.fd); state.fd = -1; return EXIT_FAILURE; @@ -183,15 +289,27 @@ int lcddev_init(lv_disp_drv_t *lv_drvr) * so fail to initialize. */ - gerr( - "ERROR: Display bpp (%u) did not match CONFIG_LV_COLOR_DEPTH (%u)\n", - state.pinfo.bpp, - CONFIG_LV_COLOR_DEPTH); + gerr("Display bpp (%u) did not match CONFIG_LV_COLOR_DEPTH (%u)\n", + state.pinfo.bpp, CONFIG_LV_COLOR_DEPTH); } lv_drvr->hor_res = state.vinfo.xres; lv_drvr->ver_res = state.vinfo.yres; - lv_drvr->flush_cb = lcddev_flush; +#ifndef CONFIG_EXAMPLES_LVGLDEMO_ASYNC_FLUSH + lv_drvr->flush_cb = lcddev_sync_flush; +#else + lv_drvr->flush_cb = lcddev_async_flush; + lv_drvr->wait_cb = lcddev_wait; + + /* Initialize the mutexes for buffer flushing synchronization */ + + sem_init(&flush_sem, 0, 0); + sem_init(&wait_sem, 0, 0); + + /* Initialize the buffer flushing thread */ + + pthread_create(&lcd_write_thread, NULL, lcddev_write, NULL); +#endif return EXIT_SUCCESS; }