feat(driver): add NuttX fbdev and touchscreen support (#4360)

This commit is contained in:
Peter Bee
2023-07-14 02:31:33 +08:00
committed by GitHub
parent 4f0e5c8970
commit 0aa856aeb7
8 changed files with 407 additions and 23 deletions

105
Kconfig
View File

@@ -156,6 +156,13 @@ menu "LVGL configuration"
help
Required to draw anything on the screen.
config LV_DRAW_SW_DRAW_UNIT_CNT
int "Number of draw units"
default 1
help
> 1 requires an operating system enabled in `LV_USE_OS`
> 1 means multply threads will render the screen in parallel
config LV_DRAW_SW_COMPLEX
bool "Enable complex draw engine"
default y
@@ -1128,6 +1135,104 @@ menu "LVGL configuration"
This can save some memory, but not much. After the quick access bar is created, it can be hidden by clicking the button at the top left corner of the browsing area, which is very useful for small screen devices.
endmenu
menu "Devices"
config LV_USE_SDL
bool "Use SDL to open window on PC and handle mouse and keyboard"
default n
config LV_SDL_INCLUDE_PATH
string "SDL include path"
depends on LV_USE_SDL
default "SDL/SDL2.h"
config LV_SDL_PARTIAL_MODE
bool "SDL partial mode"
depends on LV_USE_SDL
default n
config LV_SDL_FULLSCREEN
bool "SDL fullscreen"
depends on LV_USE_SDL
default n
config LV_SDL_DIRECT_EXIT
bool "Exit the application when all SDL widows are closed"
depends on LV_USE_SDL
default y
config LV_USE_LINUX_FBDEV
bool "Use Linux framebuffer device"
default n
config LV_LINUX_FBDEV_BSD
bool "Use BSD flavored framebuffer device"
depends on LV_USE_LINUX_FBDEV
default n
config LV_LINUX_FBDEV_NUTTX
bool "Use NuttX flavored framebuffer device"
depends on LV_USE_LINUX_FBDEV
default n
choice
prompt "Framebuffer device render mode"
depends on LV_USE_LINUX_FBDEV
default LV_LINUX_FBDEV_RENDER_MODE_PARTIAL
config LV_LINUX_FBDEV_RENDER_MODE_PARTIAL
bool "Partial mode"
help
Use the buffer(s) to render the screen is smaller parts. This way the buffers can be smaller then the display to save RAM. At least 1/10 screen size buffer(s) are recommended.
config LV_LINUX_FBDEV_RENDER_MODE_DIRECT
bool "Direct mode"
help
The buffer(s) has to be screen sized and LVGL will render into the correct location of the buffer. This way the buffer always contain the whole image. Only the changed ares will be updated. With 2 buffers the buffers' content are kept in sync automatically and in flush_cb only address change is required.
config LV_LINUX_FBDEV_RENDER_MODE_FULL
bool "Full mode"
help
Always redraw the whole screen even if only one pixel has been changed. With 2 buffers in flush_cb only and address change is required.
endchoice
choice
prompt "Framebuffer size"
depends on LV_USE_LINUX_FBDEV
default LV_LINUX_FBDEV_SINGLE_BUFFER
config LV_LINUX_FBDEV_SINGLE_BUFFER
bool "One screen-sized buffer"
config LV_LINUX_FBDEV_DOUBLE_BUFFER
bool "Two screen-sized buffer"
depends on !LV_LINUX_FBDEV_RENDER_MODE_PARTIAL
config LV_LINUX_FBDEV_CUSTOM_BUFFER
bool "Custom-sized buffer"
depends on LV_LINUX_FBDEV_RENDER_MODE_PARTIAL
endchoice
config LV_LINUX_FBDEV_BUFFER_COUNT
int
depends on LV_USE_LINUX_FBDEV
default 0 if LV_LINUX_FBDEV_CUSTOM_BUFFER
default 1 if LV_LINUX_FBDEV_SINGLE_BUFFER
default 2 if LV_LINUX_FBDEV_DOUBLE_BUFFER
config LV_LINUX_FBDEV_BUFFER_SIZE
int "Custom partial buffer size (in number of rows)"
depends on LV_USE_LINUX_FBDEV && LV_LINUX_FBDEV_CUSTOM_BUFFER
default 60
config LV_USE_LINUX_DRM
bool "Use Linux DRM device"
default n
config LV_USE_TFT_ESPI
bool "Use TFT_eSPI driver"
default n
config LV_USE_NUTTX_TOUCHSCREEN
bool "Use NuttX touchscreen driver"
default n
endmenu
menu "Examples"
config LV_BUILD_EXAMPLES
bool "Enable the examples to be built"

View File

@@ -720,6 +720,10 @@
#define LV_USE_LINUX_FBDEV 0
#if LV_USE_LINUX_FBDEV
#define LV_LINUX_FBDEV_BSD 0
#define LV_LINUX_FBDEV_NUTTX 0
#define LV_LINUX_FBDEV_RENDER_MODE LV_DISP_RENDER_MODE_PARTIAL
#define LV_LINUX_FBDEV_BUFFER_COUNT 0
#define LV_LINUX_FBDEV_BUFFER_SIZE 60
#endif
/*Driver for /dev/dri/card*/
@@ -728,6 +732,9 @@
/*Interface for TFT_eSPI*/
#define LV_USE_TFT_ESPI 0
/*Driver for /dev/input*/
#define LV_USE_NUTTX_TOUCHSCREEN 0
/*==================
* EXAMPLES
*==================*/

2
lvgl.h
View File

@@ -116,6 +116,8 @@ extern "C" {
#include "src/dev/disp/drm/lv_linux_drm.h"
#include "src/dev/disp/fb/lv_linux_fbdev.h"
#include "src/dev/input/touchscreen/lv_nuttx_touchscreen.h"
/*********************
* DEFINES
*********************/

View File

@@ -22,11 +22,13 @@
#include <sys/time.h>
#include <sys/consio.h>
#include <sys/fbio.h>
#else /* LV_LINUX_FBDEV_BSD */
#elif LV_LINUX_FBDEV_NUTTX
#include <nuttx/video/fb.h>
#else
#include <linux/fb.h>
#endif /* LV_LINUX_FBDEV_BSD */
#include "../../../stdlib/lv_string.h"
#include <lvgl/lvgl.h>
/*********************
* DEFINES
@@ -48,7 +50,6 @@ struct bsd_fb_fix_info {
long int smem_len;
};
typedef struct {
const char * devname;
lv_color_format_t color_format;
@@ -67,6 +68,7 @@ typedef struct {
/**********************
* STATIC PROTOTYPES
**********************/
static void flush_cb(lv_disp_t * disp, const lv_area_t * area, uint8_t * color_p);
/**********************
@@ -76,6 +78,7 @@ static void flush_cb(lv_disp_t * disp, const lv_area_t * area, uint8_t * color_p
/**********************
* MACROS
**********************/
#if LV_LINUX_FBDEV_BSD
#define FBIOBLANK FBIO_BLANK
#endif /* LV_LINUX_FBDEV_BSD */
@@ -127,11 +130,13 @@ void lv_linux_fbdev_set_file(lv_disp_t * disp, const char * file)
}
LV_LOG_INFO("The framebuffer device was opened successfully");
#if !LV_LINUX_FBDEV_NUTTX
// Make sure that the display is on.
if(ioctl(dsc->fbfd, FBIOBLANK, FB_BLANK_UNBLANK) != 0) {
perror("ioctl(FBIOBLANK)");
// Don't return. Some framebuffer drivers like efifb or simplefb don't implement FBIOBLANK.
}
#endif /* !LV_LINUX_FBDEV_NUTTX */
#if LV_LINUX_FBDEV_BSD
struct fbtype fb;
@@ -171,7 +176,7 @@ void lv_linux_fbdev_set_file(lv_disp_t * disp, const char * file)
}
#endif /* LV_LINUX_FBDEV_BSD */
LV_LOG_INFO("%dx%d, %dbpp", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
LV_LOG_INFO("%dx%d, %dbpp", dsc->vinfo.xres, dsc->vinfo.yres, dsc->vinfo.bits_per_pixel);
// Figure out the size of the screen in bytes
dsc->screensize = dsc->finfo.smem_len; //finfo.line_length * vinfo.yres;
@@ -191,10 +196,20 @@ void lv_linux_fbdev_set_file(lv_disp_t * disp, const char * file)
lv_coord_t hor_res = dsc->vinfo.xres;
lv_coord_t ver_res = dsc->vinfo.yres;
lv_coord_t width = dsc->vinfo.width;
uint32_t draw_buf_size = hor_res * dsc->vinfo.bits_per_pixel >> 3;
if(LV_LINUX_FBDEV_BUFFER_COUNT < 1) {
draw_buf_size *= LV_LINUX_FBDEV_BUFFER_SIZE;
}
else {
draw_buf_size *= ver_res;
}
uint32_t draw_buf_size = hor_res * ver_res / 4; /*1/4 screen sized buffer has the same performance */
lv_color_t * draw_buf = malloc(draw_buf_size * sizeof(lv_color_t));
lv_disp_set_draw_buffers(disp, draw_buf, NULL, draw_buf_size, LV_DISP_RENDER_MODE_PARTIAL);
lv_color_t * draw_buf = lv_malloc(draw_buf_size);
lv_color_t * draw_buf_2 = NULL;
if(LV_LINUX_FBDEV_BUFFER_COUNT == 2) {
draw_buf_2 = lv_malloc(draw_buf_size);
}
lv_disp_set_draw_buffers(disp, draw_buf, draw_buf_2, draw_buf_size, LV_LINUX_FBDEV_RENDER_MODE);
lv_disp_set_res(disp, hor_res, ver_res);
if(width) {
@@ -220,19 +235,36 @@ static void flush_cb(lv_disp_t * disp, const lv_area_t * area, uint8_t * color_p
}
lv_coord_t w = lv_area_get_width(area);
long int location = 0;
uint32_t px_size = lv_color_format_get_size(lv_disp_get_color_format(disp));
uint32_t color_pos = (area->x1 + dsc->vinfo.xoffset) * px_size + area->y1 * dsc->finfo.line_length;
uint32_t fb_pos = color_pos + dsc->vinfo.yoffset * dsc->finfo.line_length;
uint8_t * fbp = (uint8_t *)dsc->fbp;
int32_t y;
if(LV_LINUX_FBDEV_RENDER_MODE == LV_DISP_RENDER_MODE_DIRECT) {
for(y = area->y1; y <= area->y2; y++) {
location = (area->x1 + dsc->vinfo.xoffset) + (y + dsc->vinfo.yoffset) * dsc->finfo.line_length;
lv_memcpy(&fbp[location], (uint32_t *)color_p, w * px_size);
lv_memcpy(&fbp[fb_pos], &color_p[color_pos], w * px_size);
fb_pos += dsc->finfo.line_length;
color_pos += dsc->finfo.line_length;
}
}
else {
for(y = area->y1; y <= area->y2; y++) {
lv_memcpy(&fbp[fb_pos], color_p, w * px_size);
fb_pos += dsc->finfo.line_length;
color_p += w * px_size;
}
}
#if LV_LINUX_FBDEV_NUTTX && defined(CONFIG_FB_UPDATE)
//May be some direct update command is required
//ret = ioctl(state->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)rect));
struct fb_area_s fb_area;
fb_area.x = area->x1;
fb_area.y = area->y1;
fb_area.w = lv_area_get_width(area);
fb_area.h = lv_area_get_height(area);
ioctl(dsc->fbfd, FBIO_UPDATE, (unsigned long)((uintptr_t)&fb_area));
#endif
lv_disp_flush_ready(disp);
}

View File

@@ -0,0 +1,140 @@
/**
* @file lv_nuttx_touchscreen.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_nuttx_touchscreen.h"
#if LV_USE_NUTTX_TOUCHSCREEN
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <debug.h>
#include <errno.h>
#include <fcntl.h>
#include <nuttx/input/touchscreen.h>
#include "../../../lvgl_private.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
int fd;
lv_indev_state_t last_state;
lv_indev_t * indev_drv;
} lv_nuttx_touchscreen_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void touchscreen_read(lv_indev_t * drv, lv_indev_data_t * data);
static lv_indev_t * touchscreen_init(int fd);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_indev_t * lv_nuttx_touchscreen_create(const char * dev_path)
{
lv_indev_t * indev;
int fd;
LV_ASSERT_NULL(dev_path);
LV_LOG_INFO("touchscreen %s opening", dev_path);
fd = open(dev_path, O_RDONLY | O_NONBLOCK);
if(fd < 0) {
perror("Error: cannot open touchscreen device");
return NULL;
}
LV_LOG_INFO("touchscreen %s open success", dev_path);
indev = touchscreen_init(fd);
if(indev == NULL) {
close(fd);
}
return indev;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void touchscreen_read(lv_indev_t * drv, lv_indev_data_t * data)
{
lv_nuttx_touchscreen_t * touchscreen = drv->user_data;
struct touch_sample_s sample;
/* Read one sample */
int nbytes = read(touchscreen->fd, &sample,
sizeof(struct touch_sample_s));
/* Handle unexpected return values */
if(nbytes == sizeof(struct touch_sample_s)) {
uint8_t touch_flags = sample.point[0].flags;
if(touch_flags & TOUCH_DOWN || touch_flags & TOUCH_MOVE) {
const lv_disp_t * disp_drv = drv->disp;
lv_coord_t ver_max = disp_drv->ver_res - 1;
lv_coord_t hor_max = disp_drv->hor_res - 1;
data->point.x = LV_CLAMP(0, sample.point[0].x, hor_max);
data->point.y = LV_CLAMP(0, sample.point[0].y, ver_max);
touchscreen->last_state = LV_INDEV_STATE_PRESSED;
}
else if(touch_flags & TOUCH_UP) {
touchscreen->last_state = LV_INDEV_STATE_RELEASED;
}
/* Read until the last point */
data->continue_reading = true;
}
data->state = touchscreen->last_state;
}
static lv_indev_t * touchscreen_init(int fd)
{
lv_nuttx_touchscreen_t * touchscreen;
touchscreen = malloc(sizeof(lv_nuttx_touchscreen_t));
if(touchscreen == NULL) {
LV_LOG_ERROR("touchscreen_s malloc failed");
return NULL;
}
touchscreen->fd = fd;
touchscreen->last_state = LV_INDEV_STATE_RELEASED;
touchscreen->indev_drv = lv_indev_create();
touchscreen->indev_drv->type = LV_INDEV_TYPE_POINTER;
touchscreen->indev_drv->read_cb = touchscreen_read;
touchscreen->indev_drv->user_data = touchscreen;
return touchscreen->indev_drv;
}
#endif /*LV_USE_NUTTX_SCREEN*/

View File

@@ -0,0 +1,49 @@
/**
* @file lv_nuttx_touchscreen.h
*
*/
/*********************
* INCLUDES
*********************/
#ifndef LV_NUTTX_TOUCHSCREEN_H
#define LV_NUTTX_TOUCHSCREEN_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../indev/lv_indev.h"
#if LV_USE_NUTTX_TOUCHSCREEN
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_indev_t * lv_nuttx_touchscreen_create(const char * dev_path);
/**********************
* MACROS
**********************/
#endif /* LV_USE_LINUX_FBDEV */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LV_NUTTX_TOUCHSCREEN_H */

View File

@@ -2328,6 +2328,34 @@
#define LV_LINUX_FBDEV_BSD 0
#endif
#endif
#ifndef LV_LINUX_FBDEV_NUTTX
#ifdef CONFIG_LV_LINUX_FBDEV_NUTTX
#define LV_LINUX_FBDEV_NUTTX CONFIG_LV_LINUX_FBDEV_NUTTX
#else
#define LV_LINUX_FBDEV_NUTTX 0
#endif
#endif
#ifndef LV_LINUX_FBDEV_RENDER_MODE
#ifdef CONFIG_LV_LINUX_FBDEV_RENDER_MODE
#define LV_LINUX_FBDEV_RENDER_MODE CONFIG_LV_LINUX_FBDEV_RENDER_MODE
#else
#define LV_LINUX_FBDEV_RENDER_MODE LV_DISP_RENDER_MODE_PARTIAL
#endif
#endif
#ifndef LV_LINUX_FBDEV_BUFFER_COUNT
#ifdef CONFIG_LV_LINUX_FBDEV_BUFFER_COUNT
#define LV_LINUX_FBDEV_BUFFER_COUNT CONFIG_LV_LINUX_FBDEV_BUFFER_COUNT
#else
#define LV_LINUX_FBDEV_BUFFER_COUNT 0
#endif
#endif
#ifndef LV_LINUX_FBDEV_BUFFER_SIZE
#ifdef CONFIG_LV_LINUX_FBDEV_BUFFER_SIZE
#define LV_LINUX_FBDEV_BUFFER_SIZE CONFIG_LV_LINUX_FBDEV_BUFFER_SIZE
#else
#define LV_LINUX_FBDEV_BUFFER_SIZE 60
#endif
#endif
#endif
/*Driver for /dev/dri/card*/
@@ -2348,6 +2376,15 @@
#endif
#endif
/*Driver for /dev/input*/
#ifndef LV_USE_NUTTX_TOUCHSCREEN
#ifdef CONFIG_LV_USE_NUTTX_TOUCHSCREEN
#define LV_USE_NUTTX_TOUCHSCREEN CONFIG_LV_USE_NUTTX_TOUCHSCREEN
#else
#define LV_USE_NUTTX_TOUCHSCREEN 0
#endif
#endif
/*==================
* EXAMPLES
*==================*/

View File

@@ -37,7 +37,7 @@ extern "C" {
* LV_USE_STDLIB_MALLOC
*******************/
#if defined(CONFIG_LV_USE_BUILTIN_MALLOC)
#ifdef CONFIG_LV_USE_BUILTIN_MALLOC
# define CONFIG_LV_USE_STDLIB_MALLOC LV_STDLIB_BUILTIN
#elif defined(CONFIG_LV_USE_CLIB_MALLOC)
# define CONFIG_LV_USE_STDLIB_MALLOC LV_STDLIB_CLIB
@@ -49,7 +49,7 @@ extern "C" {
* LV_USE_STDLIB_STRING
*******************/
#if defined(CONFIG_LV_USE_BUILTIN_STRING)
#ifdef CONFIG_LV_USE_BUILTIN_STRING
# define CONFIG_LV_USE_STDLIB_STRING LV_STDLIB_BUILTIN
#elif defined(CONFIG_LV_USE_CLIB_STRING)
# define CONFIG_LV_USE_STDLIB_STRING LV_STDLIB_CLIB
@@ -61,7 +61,7 @@ extern "C" {
* LV_USE_STDLIB_SPRINTF
*******************/
#if defined(CONFIG_LV_USE_BUILTIN_SPRINTF)
#ifdef CONFIG_LV_USE_BUILTIN_SPRINTF
# define CONFIG_LV_USE_STDLIB_SPRINTF LV_STDLIB_BUILTIN
#elif defined(CONFIG_LV_USE_CLIB_SPRINTF)
# define CONFIG_LV_USE_STDLIB_SPRINTF LV_STDLIB_CLIB
@@ -211,12 +211,24 @@ extern "C" {
* BIDI DIRECTION
*-----------------*/
#ifdef CONFIG_LV_BASE_DIR_LTR
// #ifdef CONFIG_LV_BASE_DIR_LTR
# define CONFIG_LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_LTR
#elif defined(CONFIG_LV_BASE_DIR_RTL)
# define CONFIG_LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_RTL
#elif defined(CONFIG_LV_BASE_DIR_AUTO)
# define CONFIG_LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO
// #elif defined(CONFIG_LV_BASE_DIR_RTL)
// # define CONFIG_LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_RTL
// #elif defined(CONFIG_LV_BASE_DIR_AUTO)
// # define CONFIG_LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO
// #endif
/*------------------
* LINUX FBDEV
*-----------------*/
#ifdef CONFIG_LV_LINUX_FBDEV_RENDER_MODE_PARTIAL
# define CONFIG_LV_LINUX_FBDEV_RENDER_MODE LV_DISP_RENDER_MODE_PARTIAL
#elif defined(CONFIG_LV_LINUX_FBDEV_RENDER_MODE_DIRECT)
# define CONFIG_LV_LINUX_FBDEV_RENDER_MODE LV_DISP_RENDER_MODE_DIRECT
#elif defined(CONFIG_LV_LINUX_FBDEV_RENDER_MODE_FULL)
# define CONFIG_LV_LINUX_FBDEV_RENDER_MODE LV_DISP_RENDER_MODE_FULL
#endif
#ifdef __cplusplus