From 2cdd41345afb5e0dc44a354a2c6141ceaee6f353 Mon Sep 17 00:00:00 2001 From: Peter Bee Date: Mon, 17 Jul 2023 14:03:33 +0800 Subject: [PATCH] feat(dev): add nuttx lcd driver (#4377) Signed-off-by: Peter Bee --- Kconfig | 32 +++++ lv_conf_template.h | 7 ++ lvgl.h | 1 + src/dev/disp/lcd/lv_nuttx_lcd.c | 204 ++++++++++++++++++++++++++++++++ src/dev/disp/lcd/lv_nuttx_lcd.h | 45 +++++++ src/lv_conf_internal.h | 25 ++++ 6 files changed, 314 insertions(+) create mode 100644 src/dev/disp/lcd/lv_nuttx_lcd.c create mode 100644 src/dev/disp/lcd/lv_nuttx_lcd.h diff --git a/Kconfig b/Kconfig index 0ba81bd47..703013c95 100644 --- a/Kconfig +++ b/Kconfig @@ -1220,6 +1220,38 @@ menu "LVGL configuration" depends on LV_USE_LINUX_FBDEV && LV_LINUX_FBDEV_CUSTOM_BUFFER default 60 + config LV_USE_NUTTX_LCD + bool "Use NuttX LCD device" + default n + + choice + prompt "NuttX LCD buffer size" + depends on LV_USE_NUTTX_LCD + default LV_NUTTX_LCD_SINGLE_BUFFER + + config LV_NUTTX_LCD_SINGLE_BUFFER + bool "One screen-sized buffer" + + config LV_NUTTX_LCD_DOUBLE_BUFFER + bool "Two screen-sized buffer" + + config LV_NUTTX_LCD_CUSTOM_BUFFER + bool "Custom-sized buffer" + + endchoice + + config LV_NUTTX_LCD_BUFFER_COUNT + int + depends on LV_USE_NUTTX_LCD + default 0 if LV_NUTTX_LCD_CUSTOM_BUFFER + default 1 if LV_NUTTX_LCD_SINGLE_BUFFER + default 2 if LV_NUTTX_LCD_DOUBLE_BUFFER + + config LV_NUTTX_LCD_BUFFER_SIZE + int "Custom partial buffer size (in number of rows)" + depends on LV_USE_NUTTX_LCD && LV_NUTTX_LCD_CUSTOM_BUFFER + default 60 + config LV_USE_LINUX_DRM bool "Use Linux DRM device" default n diff --git a/lv_conf_template.h b/lv_conf_template.h index b9e894bc9..5be703abe 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -726,6 +726,13 @@ #define LV_LINUX_FBDEV_BUFFER_SIZE 60 #endif +/*Driver for /dev/lcd*/ +#define LV_USE_NUTTX_LCD 0 +#if LV_USE_NUTTX_LCD + #define LV_NUTTX_LCD_BUFFER_COUNT 0 + #define LV_NUTTX_LCD_BUFFER_SIZE 60 +#endif + /*Driver for /dev/dri/card*/ #define LV_USE_LINUX_DRM 0 diff --git a/lvgl.h b/lvgl.h index dc35aeecc..b0751b7a3 100644 --- a/lvgl.h +++ b/lvgl.h @@ -115,6 +115,7 @@ extern "C" { #include "src/dev/disp/drm/lv_linux_drm.h" #include "src/dev/disp/fb/lv_linux_fbdev.h" +#include "src/dev/disp/lcd/lv_nuttx_lcd.h" #include "src/dev/input/touchscreen/lv_nuttx_touchscreen.h" diff --git a/src/dev/disp/lcd/lv_nuttx_lcd.c b/src/dev/disp/lcd/lv_nuttx_lcd.c new file mode 100644 index 000000000..9279cd29f --- /dev/null +++ b/src/dev/disp/lcd/lv_nuttx_lcd.c @@ -0,0 +1,204 @@ +/** + * @file lv_nuttx_lcd.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_nuttx_lcd.h" +#if LV_USE_NUTTX_LCD + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../../../lvgl_private.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + int fd; + lv_disp_t * disp; + struct lcddev_area_s area; + struct lcddev_area_align_s align_info; +} lv_nuttx_lcd_t; + +/********************** + * STATIC PROTOTYPES + **********************/ + +static lv_coord_t align_round_up(lv_coord_t v, uint16_t align); +static void rounder_cb(lv_event_t * e); +static void flush_cb(lv_disp_t * disp, const lv_area_t * area_p, + uint8_t * color_p); +static lv_disp_t * lcd_init(int fd, int hor_res, int ver_res); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_disp_t * lv_nuttx_lcd_create(const char * dev_path) +{ + struct fb_videoinfo_s vinfo; + struct lcd_planeinfo_s pinfo; + lv_disp_t * disp; + int fd; + int ret; + + LV_ASSERT_NULL(dev_path); + + LV_LOG_INFO("lcd %s opening", dev_path); + fd = open(dev_path, 0); + if(fd < 0) { + perror("Error: cannot open lcd device"); + return NULL; + } + + LV_LOG_INFO("lcd %s open success", dev_path); + + ret = ioctl(fd, LCDDEVIO_GETVIDEOINFO, + (unsigned long)((uintptr_t)&vinfo)); + if(ret < 0) { + perror("Error: ioctl(LCDDEVIO_GETVIDEOINFO) failed"); + close(fd); + return NULL; + } + + ret = ioctl(fd, LCDDEVIO_GETPLANEINFO, + (unsigned long)((uintptr_t)&pinfo)); + if(ret < 0) { + perror("ERROR: ioctl(LCDDEVIO_GETPLANEINFO) failed"); + close(fd); + return NULL; + } + + disp = lcd_init(fd, vinfo.xres, vinfo.yres); + if(disp == NULL) { + close(fd); + } + + return disp; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static lv_coord_t align_round_up(lv_coord_t v, uint16_t align) +{ + return (v + align - 1) & ~(align - 1); +} + + +static void rounder_cb(lv_event_t * e) +{ + lv_nuttx_lcd_t * lcd = lv_event_get_user_data(e); + lv_area_t * area = lv_event_get_param(e); + struct lcddev_area_align_s * align_info = &lcd->align_info; + lv_coord_t w; + lv_coord_t h; + + area->x1 &= ~(align_info->col_start_align - 1); + area->y1 &= ~(align_info->row_start_align - 1); + + w = align_round_up(lv_area_get_width(area), align_info->width_align); + h = align_round_up(lv_area_get_height(area), align_info->height_align); + + area->x2 = area->x1 + w - 1; + area->y2 = area->y1 + h - 1; +} + +static void flush_cb(lv_disp_t * disp, const lv_area_t * area_p, + uint8_t * color_p) +{ + lv_nuttx_lcd_t * lcd = disp->user_data; + + lcd->area.row_start = area_p->y1; + lcd->area.row_end = area_p->y2; + lcd->area.col_start = area_p->x1; + lcd->area.col_end = area_p->x2; + lcd->area.data = (uint8_t *)color_p; + ioctl(lcd->fd, LCDDEVIO_PUTAREA, (unsigned long) & (lcd->area)); + lv_disp_flush_ready(disp); +} + +static lv_disp_t * lcd_init(int fd, int hor_res, int ver_res) +{ + lv_color_t * draw_buf = NULL; + lv_color_t * draw_buf_2 = NULL; + lv_nuttx_lcd_t * lcd = lv_malloc(sizeof(lv_nuttx_lcd_t)); + LV_ASSERT_MALLOC(lcd); + if(lcd == NULL) { + LV_LOG_ERROR("lv_nuttx_lcd_t malloc failed"); + return NULL; + } + lv_memzero(lcd, sizeof(lv_nuttx_lcd_t)); + + lv_disp_t * disp = lv_disp_create(hor_res, ver_res); + if(disp == NULL) { + lv_free(lcd); + return NULL; + } + +#if LV_NUTTX_LCD_BUFFER_COUNT > 0 + uint32_t buf_size = hor_res * ver_res * sizeof(lv_color_t); + lv_disp_render_mode_t render_mode = LV_DISP_RENDER_MODE_FULL; +#else + uint32_t buf_size = hor_res * LV_NUTTX_LCD_BUFFER_SIZE * sizeof(lv_color_t); + lv_disp_render_mode_t render_mode = LV_DISP_RENDER_MODE_PARTIAL; +#endif + + draw_buf = lv_malloc(buf_size); + if(draw_buf == NULL) { + LV_LOG_ERROR("display draw_buf malloc failed"); + lv_free(lcd); + return NULL; + } + +#if LV_NUTTX_LCD_BUFFER_COUNT == 2 + draw_buf_2 = lv_malloc(buf_size); + if(draw_buf_2 == NULL) { + LV_LOG_ERROR("display draw_buf_2 malloc failed"); + lv_free(lcd); + lv_free(draw_buf); + return NULL; + } +#endif + + lcd->fd = fd; + if(ioctl(fd, LCDDEVIO_GETAREAALIGN, &lcd->align_info) < 0) { + perror("Error: ioctl(LCDDEVIO_GETAREAALIGN) failed"); + } + + lcd->disp = disp; + lv_disp_set_draw_buffers(lcd->disp, draw_buf, draw_buf_2, buf_size, render_mode); + lv_disp_set_flush_cb(lcd->disp, flush_cb); + lv_event_add(&lcd->disp->event_list, rounder_cb, LV_EVENT_INVALIDATE_AREA, lcd); + lcd->disp->user_data = lcd; + + return lcd->disp; +} + +#endif /*LV_USE_NUTTX_LCD*/ diff --git a/src/dev/disp/lcd/lv_nuttx_lcd.h b/src/dev/disp/lcd/lv_nuttx_lcd.h new file mode 100644 index 000000000..685e86164 --- /dev/null +++ b/src/dev/disp/lcd/lv_nuttx_lcd.h @@ -0,0 +1,45 @@ +/** + * @file lv_nuttx_lcd.h + * + */ + +#ifndef LV_NUTTX_LCD_H +#define LV_NUTTX_LCD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "../../../disp/lv_disp.h" + +#if LV_USE_NUTTX_LCD + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +lv_disp_t * lv_nuttx_lcd_create(const char * dev_path); + +/********************** + * MACROS + **********************/ + +#endif /* LV_USE_NUTTX_LCD */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LV_NUTTX_LCD_H */ diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 619858e56..cfc3b6eed 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -2358,6 +2358,31 @@ #endif #endif +/*Driver for /dev/lcd*/ +#ifndef LV_USE_NUTTX_LCD + #ifdef CONFIG_LV_USE_NUTTX_LCD + #define LV_USE_NUTTX_LCD CONFIG_LV_USE_NUTTX_LCD + #else + #define LV_USE_NUTTX_LCD 0 + #endif +#endif +#if LV_USE_NUTTX_LCD + #ifndef LV_NUTTX_LCD_BUFFER_COUNT + #ifdef CONFIG_LV_NUTTX_LCD_BUFFER_COUNT + #define LV_NUTTX_LCD_BUFFER_COUNT CONFIG_LV_NUTTX_LCD_BUFFER_COUNT + #else + #define LV_NUTTX_LCD_BUFFER_COUNT 0 + #endif + #endif + #ifndef LV_NUTTX_LCD_BUFFER_SIZE + #ifdef CONFIG_LV_NUTTX_LCD_BUFFER_SIZE + #define LV_NUTTX_LCD_BUFFER_SIZE CONFIG_LV_NUTTX_LCD_BUFFER_SIZE + #else + #define LV_NUTTX_LCD_BUFFER_SIZE 60 + #endif + #endif +#endif + /*Driver for /dev/dri/card*/ #ifndef LV_USE_LINUX_DRM #ifdef CONFIG_LV_USE_LINUX_DRM