LVGL 库提交

This commit is contained in:
2026-08-30 08:57:07 +08:00
parent 26c9098630
commit e2f199c6bf
1056 changed files with 556743 additions and 45 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,46 @@
/**
* @file lv_linux_drm.h
*
*/
#ifndef LV_LINUX_DRM_H
#define LV_LINUX_DRM_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../display/lv_display.h"
#if LV_USE_LINUX_DRM
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_display_t * lv_linux_drm_create(void);
void lv_linux_drm_set_file(lv_display_t * disp, const char * file, int64_t connector_id);
/**********************
* MACROS
**********************/
#endif /* LV_USE_LINUX_DRM */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LV_LINUX_DRM_H */
@@ -0,0 +1,374 @@
/**
* @file lv_linux_fbdev.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_linux_fbdev.h"
#if LV_USE_LINUX_FBDEV
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <time.h>
#if LV_LINUX_FBDEV_BSD
#include <sys/fcntl.h>
#include <sys/consio.h>
#include <sys/fbio.h>
#else
#include <linux/fb.h>
#endif /* LV_LINUX_FBDEV_BSD */
#include "../../../display/lv_display_private.h"
#include "../../../draw/sw/lv_draw_sw.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
struct bsd_fb_var_info {
uint32_t xoffset;
uint32_t yoffset;
uint32_t xres;
uint32_t yres;
int bits_per_pixel;
};
struct bsd_fb_fix_info {
long int line_length;
long int smem_len;
};
typedef struct {
const char * devname;
lv_color_format_t color_format;
#if LV_LINUX_FBDEV_BSD
struct bsd_fb_var_info vinfo;
struct bsd_fb_fix_info finfo;
#else
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
#endif /* LV_LINUX_FBDEV_BSD */
#if LV_LINUX_FBDEV_MMAP
char * fbp;
#endif
uint8_t * rotated_buf;
size_t rotated_buf_size;
long int screensize;
int fbfd;
bool force_refresh;
} lv_linux_fb_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * color_p);
static uint32_t tick_get_cb(void);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
#if LV_LINUX_FBDEV_BSD
#define FBIOBLANK FBIO_BLANK
#endif /* LV_LINUX_FBDEV_BSD */
#ifndef DIV_ROUND_UP
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#endif
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_linux_fbdev_create(void)
{
lv_tick_set_cb(tick_get_cb);
lv_linux_fb_t * dsc = lv_malloc_zeroed(sizeof(lv_linux_fb_t));
LV_ASSERT_MALLOC(dsc);
if(dsc == NULL) return NULL;
lv_display_t * disp = lv_display_create(800, 480);
if(disp == NULL) {
lv_free(dsc);
return NULL;
}
dsc->fbfd = -1;
lv_display_set_driver_data(disp, dsc);
lv_display_set_flush_cb(disp, flush_cb);
return disp;
}
void lv_linux_fbdev_set_file(lv_display_t * disp, const char * file)
{
char * devname = lv_strdup(file);
LV_ASSERT_MALLOC(devname);
if(devname == NULL) return;
lv_linux_fb_t * dsc = lv_display_get_driver_data(disp);
dsc->devname = devname;
if(dsc->fbfd > 0) close(dsc->fbfd);
/* Open the file for reading and writing*/
dsc->fbfd = open(dsc->devname, O_RDWR);
if(dsc->fbfd == -1) {
perror("Error: cannot open framebuffer device");
return;
}
LV_LOG_INFO("The framebuffer device was opened successfully");
/* 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.*/
}
#if LV_LINUX_FBDEV_BSD
struct fbtype fb;
unsigned line_length;
/*Get fb type*/
if(ioctl(dsc->fbfd, FBIOGTYPE, &fb) != 0) {
perror("ioctl(FBIOGTYPE)");
return;
}
/*Get screen width*/
if(ioctl(dsc->fbfd, FBIO_GETLINEWIDTH, &line_length) != 0) {
perror("ioctl(FBIO_GETLINEWIDTH)");
return;
}
dsc->vinfo.xres = (unsigned) fb.fb_width;
dsc->vinfo.yres = (unsigned) fb.fb_height;
dsc->vinfo.bits_per_pixel = fb.fb_depth;
dsc->vinfo.xoffset = 0;
dsc->vinfo.yoffset = 0;
dsc->finfo.line_length = line_length;
dsc->finfo.smem_len = dsc->finfo.line_length * dsc->vinfo.yres;
#else /* LV_LINUX_FBDEV_BSD */
/* Get fixed screen information*/
if(ioctl(dsc->fbfd, FBIOGET_FSCREENINFO, &dsc->finfo) == -1) {
perror("Error reading fixed information");
return;
}
/* Get variable screen information*/
if(ioctl(dsc->fbfd, FBIOGET_VSCREENINFO, &dsc->vinfo) == -1) {
perror("Error reading variable information");
return;
}
#endif /* LV_LINUX_FBDEV_BSD */
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;*/
#if LV_LINUX_FBDEV_MMAP
/* Map the device to memory*/
dsc->fbp = (char *)mmap(0, dsc->screensize, PROT_READ | PROT_WRITE, MAP_SHARED, dsc->fbfd, 0);
if((intptr_t)dsc->fbp == -1) {
perror("Error: failed to map framebuffer device to memory");
return;
}
#endif
/* Don't initialise the memory to retain what's currently displayed / avoid clearing the screen.
* This is important for applications that only draw to a subsection of the full framebuffer.*/
LV_LOG_INFO("The framebuffer device was mapped to memory successfully");
switch(dsc->vinfo.bits_per_pixel) {
case 16:
lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565);
break;
case 24:
lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB888);
break;
case 32:
lv_display_set_color_format(disp, LV_COLOR_FORMAT_XRGB8888);
break;
default:
LV_LOG_WARN("Not supported color format (%d bits)", dsc->vinfo.bits_per_pixel);
return;
}
int32_t hor_res = dsc->vinfo.xres;
int32_t ver_res = dsc->vinfo.yres;
int32_t width = dsc->vinfo.width;
uint32_t draw_buf_size = hor_res * (dsc->vinfo.bits_per_pixel >> 3);
if(LV_LINUX_FBDEV_RENDER_MODE == LV_DISPLAY_RENDER_MODE_PARTIAL) {
draw_buf_size *= LV_LINUX_FBDEV_BUFFER_SIZE;
}
else {
draw_buf_size *= ver_res;
}
uint8_t * draw_buf = NULL;
uint8_t * draw_buf_2 = NULL;
draw_buf = malloc(draw_buf_size);
if(LV_LINUX_FBDEV_BUFFER_COUNT == 2) {
draw_buf_2 = malloc(draw_buf_size);
}
lv_display_set_resolution(disp, hor_res, ver_res);
lv_display_set_buffers(disp, draw_buf, draw_buf_2, draw_buf_size, LV_LINUX_FBDEV_RENDER_MODE);
if(width > 0) {
lv_display_set_dpi(disp, DIV_ROUND_UP(hor_res * 254, width * 10));
}
LV_LOG_INFO("Resolution is set to %" LV_PRId32 "x%" LV_PRId32 " at %" LV_PRId32 "dpi",
hor_res, ver_res, lv_display_get_dpi(disp));
}
void lv_linux_fbdev_set_force_refresh(lv_display_t * disp, bool enabled)
{
lv_linux_fb_t * dsc = lv_display_get_driver_data(disp);
dsc->force_refresh = enabled;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void write_to_fb(lv_linux_fb_t * dsc, uint32_t fb_pos, const void * data, size_t sz)
{
#if LV_LINUX_FBDEV_MMAP
uint8_t * fbp = (uint8_t *)dsc->fbp;
lv_memcpy(&fbp[fb_pos], data, sz);
#else
if(pwrite(dsc->fbfd, data, sz, fb_pos) < 0)
LV_LOG_ERROR("write failed: %d", errno);
#endif
}
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * color_p)
{
lv_linux_fb_t * dsc = lv_display_get_driver_data(disp);
#if LV_LINUX_FBDEV_MMAP
if(dsc->fbp == NULL) {
lv_display_flush_ready(disp);
return;
}
#endif
int32_t w = lv_area_get_width(area);
int32_t h = lv_area_get_height(area);
lv_color_format_t cf = lv_display_get_color_format(disp);
uint32_t px_size = lv_color_format_get_size(cf);
lv_area_t rotated_area;
lv_display_rotation_t rotation = lv_display_get_rotation(disp);
/* Not all framebuffer kernel drivers support hardware rotation, so we need to handle it in software here */
if(rotation != LV_DISPLAY_ROTATION_0 && LV_LINUX_FBDEV_RENDER_MODE == LV_DISPLAY_RENDER_MODE_PARTIAL) {
/* (Re)allocate temporary buffer if needed */
size_t buf_size = w * h * px_size;
if(!dsc->rotated_buf || dsc->rotated_buf_size != buf_size) {
dsc->rotated_buf = realloc(dsc->rotated_buf, buf_size);
dsc->rotated_buf_size = buf_size;
}
/* Rotate the pixel buffer */
uint32_t w_stride = lv_draw_buf_width_to_stride(w, cf);
uint32_t h_stride = lv_draw_buf_width_to_stride(h, cf);
switch(rotation) {
case LV_DISPLAY_ROTATION_0:
break;
case LV_DISPLAY_ROTATION_90:
lv_draw_sw_rotate(color_p, dsc->rotated_buf, w, h, w_stride, h_stride, rotation, cf);
break;
case LV_DISPLAY_ROTATION_180:
lv_draw_sw_rotate(color_p, dsc->rotated_buf, w, h, w_stride, w_stride, rotation, cf);
break;
case LV_DISPLAY_ROTATION_270:
lv_draw_sw_rotate(color_p, dsc->rotated_buf, w, h, w_stride, h_stride, rotation, cf);
break;
}
color_p = dsc->rotated_buf;
/* Rotate the area */
rotated_area = *area;
lv_display_rotate_area(disp, &rotated_area);
area = &rotated_area;
if(rotation != LV_DISPLAY_ROTATION_180) {
w = lv_area_get_width(area);
h = lv_area_get_height(area);
}
}
/* Ensure that we're within the framebuffer's bounds */
if(area->x2 < 0 || area->y2 < 0 || area->x1 > (int32_t)dsc->vinfo.xres - 1 || area->y1 > (int32_t)dsc->vinfo.yres - 1) {
lv_display_flush_ready(disp);
return;
}
uint32_t fb_pos =
(area->x1 + dsc->vinfo.xoffset) * px_size +
(area->y1 + dsc->vinfo.yoffset) * dsc->finfo.line_length;
int32_t y;
if(LV_LINUX_FBDEV_RENDER_MODE == LV_DISPLAY_RENDER_MODE_DIRECT) {
uint32_t color_pos =
area->x1 * px_size +
area->y1 * disp->hor_res * px_size;
for(y = area->y1; y <= area->y2; y++) {
write_to_fb(dsc, fb_pos, &color_p[color_pos], w * px_size);
fb_pos += dsc->finfo.line_length;
color_pos += disp->hor_res * px_size;
}
}
else {
w = lv_area_get_width(area);
for(y = area->y1; y <= area->y2; y++) {
write_to_fb(dsc, fb_pos, color_p, w * px_size);
fb_pos += dsc->finfo.line_length;
color_p += w * px_size;
}
}
if(dsc->force_refresh) {
dsc->vinfo.activate |= FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
if(ioctl(dsc->fbfd, FBIOPUT_VSCREENINFO, &(dsc->vinfo)) == -1) {
perror("Error setting var screen info");
}
}
lv_display_flush_ready(disp);
}
static uint32_t tick_get_cb(void)
{
struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
uint64_t time_ms = t.tv_sec * 1000 + (t.tv_nsec / 1000000);
return time_ms;
}
#endif /*LV_USE_LINUX_FBDEV*/
@@ -0,0 +1,52 @@
/**
* @file lv_linux_fbdev.h
*
*/
#ifndef LV_LINUX_FBDEV_H
#define LV_LINUX_FBDEV_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../display/lv_display.h"
#if LV_USE_LINUX_FBDEV
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_display_t * lv_linux_fbdev_create(void);
void lv_linux_fbdev_set_file(lv_display_t * disp, const char * file);
/**
* Force the display to be refreshed on every change.
* Expected to be used with LV_DISPLAY_RENDER_MODE_DIRECT or LV_DISPLAY_RENDER_MODE_FULL.
*/
void lv_linux_fbdev_set_force_refresh(lv_display_t * disp, bool enabled);
/**********************
* MACROS
**********************/
#endif /* LV_USE_LINUX_FBDEV */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LV_LINUX_FBDEV_H */
@@ -0,0 +1,399 @@
/**
* @file lv_ft81x.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_ft81x.h"
#if LV_USE_FT81X
#include "lv_ft81x_defines.h"
#include "../../../stdlib/lv_mem.h"
#include "../../../stdlib/lv_sprintf.h"
#include "../../../stdlib/lv_string.h"
#include "../../../misc/lv_types.h"
#include "../../../misc/lv_utils.h"
/*********************
* DEFINES
*********************/
/* Increase as functionality is added if needed. */
#define LV_FT81X_CMD_BUF_SIZE 63
/* The PWM value that corresponds to the backlight being "on".
0x80 was found to work on at least two boards but should
be changed as needed. */
#define PWM_DUTY_BACKLIGHT_ON 0x80
/**********************
* TYPEDEFS
**********************/
typedef struct {
lv_ft81x_spi_cb_t spi_cb;
void * user_data;
uint16_t cmd_offset;
} lv_ft81x_driver_data_t;
typedef struct {
uint32_t buf_len;
uint8_t buf[LV_FT81X_CMD_BUF_SIZE];
} lv_ft81x_cmd_list_t;
/**********************
* STATIC PROTOTYPES
**********************/
static lv_result_t initialize(lv_display_t * disp, const lv_ft81x_parameters_t * params);
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map);
static void delete_cb(lv_event_t * e);
static void lv_ft81x_cmd(lv_display_t * disp, uint8_t command, uint8_t parameter);
static uint8_t lv_ft81x_read_8(lv_display_t * disp, uint32_t address);
static uint16_t lv_ft81x_read_16(lv_display_t * disp, uint32_t address);
/* static uint32_t lv_ft81x_read_32(lv_display_t * disp, uint32_t address); */
static void lv_ft81x_write_8(lv_display_t * disp, uint32_t address, uint8_t val);
static void lv_ft81x_write_16(lv_display_t * disp, uint32_t address, uint16_t val);
static void lv_ft81x_write_32(lv_display_t * disp, uint32_t address, uint32_t val);
static void lv_ft81x_cmd_list_init(lv_display_t * disp, lv_ft81x_cmd_list_t * cmd_list);
static void lv_ft81x_cmd_list_add_16(lv_display_t * disp, lv_ft81x_cmd_list_t * cmd_list, uint16_t value);
static void lv_ft81x_cmd_list_add_32(lv_display_t * disp, lv_ft81x_cmd_list_t * cmd_list, uint32_t value);
static void lv_ft81x_cmd_list_send(lv_display_t * disp, lv_ft81x_cmd_list_t * cmd_list);
static void lv_ft81x_encode_read_address(void * dst_4_bytes, uint32_t address);
static void lv_ft81x_encode_write_address(void * dst_3_bytes, uint32_t address);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
#if LV_BIG_ENDIAN_SYSTEM
#define BE_TO_OR_FROM_NATIVE_32(x) ((uint32_t)(x))
#define BE_TO_OR_FROM_NATIVE_16(x) ((uint16_t)(x))
#define LE_TO_OR_FROM_NATIVE_32(x) lv_swap_bytes_32(x)
#define LE_TO_OR_FROM_NATIVE_16(x) lv_swap_bytes_16(x)
#else
#define BE_TO_OR_FROM_NATIVE_32(x) lv_swap_bytes_32(x)
#define BE_TO_OR_FROM_NATIVE_16(x) lv_swap_bytes_16(x)
#define LE_TO_OR_FROM_NATIVE_32(x) ((uint32_t)(x))
#define LE_TO_OR_FROM_NATIVE_16(x) ((uint16_t)(x))
#endif
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_ft81x_create(const lv_ft81x_parameters_t * params, void * partial_buf, uint32_t buf_size,
lv_ft81x_spi_cb_t spi_cb, void * user_data)
{
LV_ASSERT_NULL(spi_cb);
lv_display_t * disp = lv_display_create(params->hor_res, params->ver_res);
lv_ft81x_driver_data_t * drv = lv_malloc_zeroed(sizeof(lv_ft81x_driver_data_t));
LV_ASSERT_MALLOC(drv);
drv->spi_cb = spi_cb;
drv->user_data = user_data;
drv->cmd_offset = 0;
lv_display_set_driver_data(disp, drv);
lv_display_set_flush_cb(disp, flush_cb);
lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565);
lv_display_set_buffers(disp, partial_buf, NULL, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
lv_display_add_event_cb(disp, delete_cb, LV_EVENT_DELETE, NULL);
lv_result_t init_res = initialize(disp, params);
if(init_res != LV_RESULT_OK) {
lv_display_delete(disp);
return NULL;
}
return disp;
}
void * lv_ft81x_get_user_data(lv_display_t * disp)
{
lv_ft81x_driver_data_t * drv = lv_display_get_driver_data(disp);
return drv->user_data;
}
/**********************
* STATIC FUNCTIONS
**********************/
static lv_result_t initialize(lv_display_t * disp, const lv_ft81x_parameters_t * params)
{
lv_ft81x_cmd(disp, params->has_crystal ? EVE_CLKEXT : EVE_CLKINT, 0);
if(params->is_bt81x) lv_ft81x_cmd(disp, EVE_CLKSEL, 0x46);
lv_ft81x_cmd(disp, EVE_ACTIVE, 0);
/* at least 40 ms is needed for EVE to become ready. */
lv_delay_ms(40);
uint32_t start_millis = lv_tick_get();
while(lv_ft81x_read_8(disp, REG_ID) != 0x7c) {
if(lv_tick_get() - start_millis > 1000) {
LV_LOG_ERROR("failed to read 0x7C from the ID register 1000 ms after activation.");
return LV_RESULT_INVALID;
}
lv_delay_ms(1);
};
start_millis = lv_tick_get();
while(lv_ft81x_read_8(disp, REG_CPURESET) & 0x03) {
if(lv_tick_get() - start_millis > 1000) {
LV_LOG_ERROR("CPURESET register coprocessor and touch engines not in \"working status\" 1000 ms after activation.");
return LV_RESULT_INVALID;
}
lv_delay_ms(1);
};
if(params->is_bt81x) lv_ft81x_write_32(disp, REG_FREQUENCY, 72000000);
lv_ft81x_write_8(disp, REG_PWM_DUTY, PWM_DUTY_BACKLIGHT_ON);
lv_ft81x_write_16(disp, REG_HSIZE, params->hor_res); /* active display width */
lv_ft81x_write_16(disp, REG_HCYCLE, params->hcycle); /* total number of clocks per line, incl front/back porch */
lv_ft81x_write_16(disp, REG_HOFFSET, params->hoffset); /* start of active line */
lv_ft81x_write_16(disp, REG_HSYNC0, params->hsync0); /* start of horizontal sync pulse */
lv_ft81x_write_16(disp, REG_HSYNC1, params->hsync1); /* end of horizontal sync pulse */
lv_ft81x_write_16(disp, REG_VSIZE, params->ver_res); /* active display height */
lv_ft81x_write_16(disp, REG_VCYCLE, params->vcycle); /* total number of lines per screen, including pre/post */
lv_ft81x_write_16(disp, REG_VOFFSET, params->voffset); /* start of active screen */
lv_ft81x_write_16(disp, REG_VSYNC0, params->vsync0); /* start of vertical sync pulse */
lv_ft81x_write_16(disp, REG_VSYNC1, params->vsync1); /* end of vertical sync pulse */
lv_ft81x_write_8(disp, REG_SWIZZLE, params->swizzle); /* FT8xx output to LCD - pin order */
lv_ft81x_write_8(disp, REG_PCLK_POL, params->pclkpol); /* LCD data is clocked in on this PCLK edge */
lv_ft81x_write_8(disp, REG_CSPREAD,
params->cspread); /* helps with noise, when set to 1 fewer signals are changed simultaneously, reset-default: 1 */
/* write a basic display-list to get things started */
lv_ft81x_write_32(disp, EVE_RAM_DL, DL_CLEAR_RGB);
lv_ft81x_write_32(disp, EVE_RAM_DL + 4, (DL_CLEAR | CLR_COL | CLR_STN | CLR_TAG));
lv_ft81x_write_32(disp, EVE_RAM_DL + 8, DL_DISPLAY); /* end of display list */
lv_ft81x_write_32(disp, REG_DLSWAP, EVE_DLSWAP_FRAME);
/* nothing is being displayed yet... the pixel clock is still 0x00 */
lv_ft81x_write_8(disp, REG_GPIO,
0x80); /* enable the DISP signal to the LCD panel, it is set to output in REG_GPIO_DIR by default */
lv_ft81x_write_8(disp, REG_PCLK, params->pclk); /* now start clocking data to the LCD panel */
LV_ASSERT(lv_ft81x_read_16(disp, REG_CMD_READ) != 0xfff);
LV_ASSERT(0 == lv_ft81x_read_16(disp, REG_CMD_WRITE));
lv_ft81x_cmd_list_t cmd_list;
lv_ft81x_cmd_list_init(disp, &cmd_list);
lv_ft81x_cmd_list_add_32(disp, &cmd_list, CMD_MEMSET);
lv_ft81x_cmd_list_add_32(disp, &cmd_list, 0); /* address */
lv_ft81x_cmd_list_add_32(disp, &cmd_list, 0x00); /* val */
lv_ft81x_cmd_list_add_32(disp, &cmd_list, 2 * params->hor_res * params->ver_res); /* count */
lv_ft81x_cmd_list_send(disp, &cmd_list);
lv_ft81x_cmd_list_init(disp, &cmd_list);
lv_ft81x_cmd_list_add_32(disp, &cmd_list, CMD_DLSTART);
lv_ft81x_cmd_list_add_32(disp, &cmd_list, DL_CLEAR_RGB | 0); /* clear to black */
lv_ft81x_cmd_list_add_32(disp, &cmd_list, DL_CLEAR | CLR_COL | CLR_STN | CLR_TAG);
lv_ft81x_cmd_list_add_32(disp, &cmd_list, TAG(0));
lv_ft81x_cmd_list_add_32(disp, &cmd_list, TAG(20));
lv_ft81x_cmd_list_add_32(disp, &cmd_list, CMD_SETBITMAP);
lv_ft81x_cmd_list_add_32(disp, &cmd_list, 0); /* address */
lv_ft81x_cmd_list_add_16(disp, &cmd_list, EVE_RGB565);
lv_ft81x_cmd_list_add_16(disp, &cmd_list, params->hor_res);
lv_ft81x_cmd_list_add_16(disp, &cmd_list, params->ver_res);
lv_ft81x_cmd_list_add_16(disp, &cmd_list, 0);
lv_ft81x_cmd_list_add_32(disp, &cmd_list, DL_BEGIN | EVE_BITMAPS);
lv_ft81x_cmd_list_add_32(disp, &cmd_list, VERTEX2F(0, 0));
lv_ft81x_cmd_list_add_32(disp, &cmd_list, DL_END);
lv_ft81x_cmd_list_add_32(disp, &cmd_list, TAG(0));
lv_ft81x_cmd_list_add_32(disp, &cmd_list, DL_DISPLAY);
lv_ft81x_cmd_list_add_32(disp, &cmd_list, CMD_SWAP);
lv_ft81x_cmd_list_send(disp, &cmd_list);
return LV_RESULT_OK;
}
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
{
lv_ft81x_driver_data_t * drv = lv_display_get_driver_data(disp);
if(drv->spi_cb == NULL) {
LV_LOG_ERROR("The SPI callback is NULL.");
return;
}
int32_t hor_res = lv_display_get_horizontal_resolution(disp);
uint32_t disp_row_bytes = hor_res * 2;
uint32_t address = disp_row_bytes * area->y1 + area->x1 * 2;
uint8_t encoded_address[3];
if(lv_area_get_width(area) == hor_res) {
lv_ft81x_encode_write_address(encoded_address, address);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_ASSERT, NULL, 0);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_SEND, encoded_address, sizeof(encoded_address));
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_SEND, px_map, lv_area_get_size(area) * 2);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_DEASSERT, NULL, 0);
}
else {
uint32_t area_height = lv_area_get_height(area);
uint32_t area_row_bytes = lv_area_get_width(area) * 2;
for(uint32_t i = 0; i < area_height; i++) {
lv_ft81x_encode_write_address(encoded_address, address);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_ASSERT, NULL, 0);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_SEND, encoded_address, sizeof(encoded_address));
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_SEND, px_map, area_row_bytes);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_DEASSERT, NULL, 0);
address += disp_row_bytes;
px_map += area_row_bytes;
}
}
lv_display_flush_ready(disp);
}
static void delete_cb(lv_event_t * e)
{
lv_display_t * disp = lv_event_get_target(e);
lv_ft81x_driver_data_t * drv = lv_display_get_driver_data(disp);
lv_free(drv);
}
static void lv_ft81x_cmd(lv_display_t * disp, uint8_t command, uint8_t parameter)
{
lv_ft81x_driver_data_t * drv = lv_display_get_driver_data(disp);
uint8_t data[3] = {command, parameter, 0x00};
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_ASSERT, NULL, 0);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_SEND, data, sizeof(data));
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_DEASSERT, NULL, 0);
}
static uint8_t lv_ft81x_read_8(lv_display_t * disp, uint32_t address)
{
lv_ft81x_driver_data_t * drv = lv_display_get_driver_data(disp);
lv_ft81x_encode_read_address(&address, address);
uint8_t val;
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_ASSERT, NULL, 0);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_SEND, &address, sizeof(address));
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_RECEIVE, &val, sizeof(val));
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_DEASSERT, NULL, 0);
return val;
}
static uint16_t lv_ft81x_read_16(lv_display_t * disp, uint32_t address)
{
lv_ft81x_driver_data_t * drv = lv_display_get_driver_data(disp);
lv_ft81x_encode_read_address(&address, address);
uint16_t val;
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_ASSERT, NULL, 0);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_SEND, &address, sizeof(address));
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_RECEIVE, &val, sizeof(val));
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_DEASSERT, NULL, 0);
val = LE_TO_OR_FROM_NATIVE_16(val);
return val;
}
static void lv_ft81x_write_8(lv_display_t * disp, uint32_t address, uint8_t val)
{
lv_ft81x_driver_data_t * drv = lv_display_get_driver_data(disp);
uint8_t data[4];
lv_ft81x_encode_write_address(data, address);
data[3] = val;
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_ASSERT, NULL, 0);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_SEND, data, sizeof(data));
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_DEASSERT, NULL, 0);
}
static void lv_ft81x_write_16(lv_display_t * disp, uint32_t address, uint16_t val)
{
lv_ft81x_driver_data_t * drv = lv_display_get_driver_data(disp);
val = LE_TO_OR_FROM_NATIVE_16(val);
uint8_t data[5];
lv_ft81x_encode_write_address(data, address);
lv_memcpy(data + 3, &val, 2);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_ASSERT, NULL, 0);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_SEND, data, sizeof(data));
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_DEASSERT, NULL, 0);
}
static void lv_ft81x_write_32(lv_display_t * disp, uint32_t address, uint32_t val)
{
lv_ft81x_driver_data_t * drv = lv_display_get_driver_data(disp);
val = LE_TO_OR_FROM_NATIVE_32(val);
uint8_t data[7];
lv_ft81x_encode_write_address(data, address);
lv_memcpy(data + 3, &val, 4);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_ASSERT, NULL, 0);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_SEND, data, sizeof(data));
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_DEASSERT, NULL, 0);
}
static void lv_ft81x_cmd_list_init(lv_display_t * disp, lv_ft81x_cmd_list_t * cmd_list)
{
lv_ft81x_driver_data_t * drv = lv_display_get_driver_data(disp);
LV_ASSERT_MSG(LV_FT81X_CMD_BUF_SIZE >= 3, "increase LV_FT81X_CMD_BUF_SIZE as needed");
lv_ft81x_encode_write_address(cmd_list->buf, EVE_RAM_CMD + drv->cmd_offset);
cmd_list->buf_len = 3;
}
static void lv_ft81x_cmd_list_add_16(lv_display_t * disp, lv_ft81x_cmd_list_t * cmd_list, uint16_t value)
{
lv_ft81x_driver_data_t * drv = lv_display_get_driver_data(disp);
uint8_t * buf_dst = &cmd_list->buf[cmd_list->buf_len];
cmd_list->buf_len += 2;
LV_ASSERT_MSG(cmd_list->buf_len <= LV_FT81X_CMD_BUF_SIZE, "increase LV_FT81X_CMD_BUF_SIZE as needed");
value = LE_TO_OR_FROM_NATIVE_16(value);
lv_memcpy(buf_dst, &value, 2);
drv->cmd_offset = (drv->cmd_offset + 2) & 0xfff; /* circular */
}
static void lv_ft81x_cmd_list_add_32(lv_display_t * disp, lv_ft81x_cmd_list_t * cmd_list, uint32_t value)
{
lv_ft81x_driver_data_t * drv = lv_display_get_driver_data(disp);
uint8_t * buf_dst = &cmd_list->buf[cmd_list->buf_len];
cmd_list->buf_len += 4;
LV_ASSERT_MSG(cmd_list->buf_len <= LV_FT81X_CMD_BUF_SIZE, "increase LV_FT81X_CMD_BUF_SIZE as needed");
value = LE_TO_OR_FROM_NATIVE_32(value);
lv_memcpy(buf_dst, &value, 4);
drv->cmd_offset = (drv->cmd_offset + 4) & 0xfff; /* circular */
}
static void lv_ft81x_cmd_list_send(lv_display_t * disp, lv_ft81x_cmd_list_t * cmd_list)
{
lv_ft81x_driver_data_t * drv = lv_display_get_driver_data(disp);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_ASSERT, NULL, 0);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_SEND, cmd_list->buf, cmd_list->buf_len);
drv->spi_cb(disp, LV_FT81X_SPI_OPERATION_CS_DEASSERT, NULL, 0);
lv_ft81x_write_16(disp, REG_CMD_WRITE, drv->cmd_offset);
}
static void lv_ft81x_encode_read_address(void * dst_4_bytes, uint32_t address)
{
address = BE_TO_OR_FROM_NATIVE_32(address << 8);
lv_memcpy(dst_4_bytes, &address, 4);
}
static void lv_ft81x_encode_write_address(void * dst_3_bytes, uint32_t address)
{
address = BE_TO_OR_FROM_NATIVE_32((address | 0x800000) << 8);
lv_memcpy(dst_3_bytes, &address, 3);
}
#endif /*LV_USE_FT81X*/
@@ -0,0 +1,93 @@
/**
* @file lv_ft81x.h
*
*/
#ifndef LV_FT81X_H
#define LV_FT81X_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_FT81X
#include "../../../display/lv_display.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
uint16_t hor_res;
uint16_t ver_res;
uint16_t hcycle;
uint16_t hoffset;
uint16_t hsync0;
uint16_t hsync1;
uint16_t vcycle;
uint16_t voffset;
uint16_t vsync0;
uint16_t vsync1;
uint8_t swizzle;
uint8_t pclkpol;
uint8_t cspread;
uint8_t pclk;
bool has_crystal;
bool is_bt81x;
} lv_ft81x_parameters_t;
typedef enum {
LV_FT81X_SPI_OPERATION_CS_ASSERT,
LV_FT81X_SPI_OPERATION_CS_DEASSERT,
LV_FT81X_SPI_OPERATION_SEND,
LV_FT81X_SPI_OPERATION_RECEIVE
} lv_ft81x_spi_operation;
typedef void (*lv_ft81x_spi_cb_t)(lv_display_t * disp, lv_ft81x_spi_operation operation, void * data, uint32_t length);
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a framebuffer-based ft81x driver display.
* @param params pointer to a struct of display panel properties. does not need to be static.
* @param partial_buf a single partial buffer
* @param buf_size size of the partial buffer
* @param spi_cb a callback called by the driver to perform SPI operations
* @param user_data use `lv_ft81x_get_user_data` to get this pointer inside the SPI callback
* @return pointer to the display
*/
lv_display_t * lv_ft81x_create(const lv_ft81x_parameters_t * params, void * partial_buf, uint32_t buf_size,
lv_ft81x_spi_cb_t spi_cb, void * user_data);
/**
* Get the `user_data` parameter that was passed to `lv_ft81x_create`. Useful in the SPI callback.
* @param disp pointer to the ft81x display
* @return the `user_data` pointer
*/
void * lv_ft81x_get_user_data(lv_display_t * disp);
/**********************
* MACROS
**********************/
#endif /*LV_USE_FT81X*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_FT81X_H*/
@@ -0,0 +1,846 @@
/**
* @file lv_ft81x_defines.h
*
* Copied from https://github.com/lvgl/lvgl_esp32_drivers/blob/9fed1cc47b5a45fec6bae08b55d2147d3b50260c/lvgl_tft/EVE.h
*/
#ifndef LV_FT81X_DEFINES_H
#define LV_FT81X_DEFINES_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/* ft81x and ft80x each define exclusive
* definitions. Define ft81x for now.
*
* bt81x is a superset of ft81x and ft80x.
* Don't define it since its special
* definitions are not required to use it.
*/
#define FT81X_ENABLE
/* #define BT81X_ENABLE */
#define DL_CLEAR 0x26000000UL /* requires OR'd arguments */
#define DL_CLEAR_RGB 0x02000000UL /* requires OR'd arguments */
#define DL_COLOR_RGB 0x04000000UL /* requires OR'd arguments */
#define DL_POINT_SIZE 0x0D000000UL /* requires OR'd arguments */
#define DL_END 0x21000000UL
#define DL_BEGIN 0x1F000000UL /* requires OR'd arguments */
#define DL_DISPLAY 0x00000000UL
#define CLR_COL 0x4
#define CLR_STN 0x2
#define CLR_TAG 0x1
/* SPI SIO/DIO/QIO tranfer widths */
#define SPI_WIDTH_SIO 0x0
#define SPI_WIDTH_DIO 0x1
#define SPI_WIDTH_QIO 0x2
/* Host commands */
#define EVE_ACTIVE 0x00 /* place FT8xx in active state */
#define EVE_STANDBY 0x41 /* place FT8xx in Standby (clk running) */
#define EVE_SLEEP 0x42 /* place FT8xx in Sleep (clk off) */
#define EVE_PWRDOWN 0x50 /* place FT8xx in Power Down (core off) */
#define EVE_CLKEXT 0x44 /* select external clock source */
#define EVE_CLKINT 0x48 /* select internal clock source */
#define EVE_CORERST 0x68 /* reset core - all registers default and processors reset */
#define EVE_CLK48M 0x62 /* select 48MHz PLL output */
#define EVE_CLK36M 0x61 /* select 36MHz PLL output */
/* defines used for graphics commands */
#define EVE_NEVER 0UL
#define EVE_LESS 1UL
#define EVE_LEQUAL 2UL
#define EVE_GREATER 3UL
#define EVE_GEQUAL 4UL
#define EVE_EQUAL 5UL
#define EVE_NOTEQUAL 6UL
#define EVE_ALWAYS 7UL
/* Bitmap formats */
#define EVE_ARGB1555 0UL
#define EVE_L1 1UL
#define EVE_L4 2UL
#define EVE_L8 3UL
#define EVE_RGB332 4UL
#define EVE_ARGB2 5UL
#define EVE_ARGB4 6UL
#define EVE_RGB565 7UL
#define EVE_PALETTED 8UL
#define EVE_TEXT8X8 9UL
#define EVE_TEXTVGA 10UL
#define EVE_BARGRAPH 11UL
/* Bitmap filter types */
#define EVE_NEAREST 0UL
#define EVE_BILINEAR 1UL
/* Bitmap wrap types */
#define EVE_BORDER 0UL
#define EVE_REPEAT 1UL
/* Stencil defines */
#define EVE_KEEP 1UL
#define EVE_REPLACE 2UL
#define EVE_INCR 3UL
#define EVE_DECR 4UL
#define EVE_INVERT 5UL
/* Graphics display list swap defines */
#define EVE_DLSWAP_DONE 0UL
#define EVE_DLSWAP_LINE 1UL
#define EVE_DLSWAP_FRAME 2UL
/* Interrupt bits */
#define EVE_INT_SWAP 0x01
#define EVE_INT_TOUCH 0x02
#define EVE_INT_TAG 0x04
#define EVE_INT_SOUND 0x08
#define EVE_INT_PLAYBACK 0x10
#define EVE_INT_CMDEMPTY 0x20
#define EVE_INT_CMDFLAG 0x40
#define EVE_INT_CONVCOMPLETE 0x80
/* Touch mode */
#define EVE_TMODE_OFF 0
#define EVE_TMODE_ONESHOT 1
#define EVE_TMODE_FRAME 2
#define EVE_TMODE_CONTINUOUS 3
/* Alpha blending */
#define EVE_ZERO 0UL
#define EVE_ONE 1UL
#define EVE_SRC_ALPHA 2UL
#define EVE_DST_ALPHA 3UL
#define EVE_ONE_MINUS_SRC_ALPHA 4UL
#define EVE_ONE_MINUS_DST_ALPHA 5UL
/* Graphics primitives */
#define EVE_BITMAPS 1UL
#define EVE_POINTS 2UL
#define EVE_LINES 3UL
#define EVE_LINE_STRIP 4UL
#define EVE_EDGE_STRIP_R 5UL
#define EVE_EDGE_STRIP_L 6UL
#define EVE_EDGE_STRIP_A 7UL
#define EVE_EDGE_STRIP_B 8UL
#define EVE_RECTS 9UL
/* Widget command */
#define EVE_OPT_MONO 1
#define EVE_OPT_NODL 2
#define EVE_OPT_FLAT 256
#define EVE_OPT_CENTERX 512
#define EVE_OPT_CENTERY 1024
#define EVE_OPT_CENTER (EVE_OPT_CENTERX | EVE_OPT_CENTERY)
#define EVE_OPT_NOBACK 4096
#define EVE_OPT_NOTICKS 8192
#define EVE_OPT_NOHM 16384
#define EVE_OPT_NOPOINTER 16384
#define EVE_OPT_NOSECS 32768
#define EVE_OPT_NOHANDS 49152
#define EVE_OPT_RIGHTX 2048
#define EVE_OPT_SIGNED 256
/* Defines related to inbuilt font */
#define EVE_NUMCHAR_PERFONT (128L) /* number of font characters per bitmap handle */
#define EVE_FONT_TABLE_SIZE (148L) /* size of the font table - utilized for loopup by the graphics engine */
#define EVE_FONT_TABLE_POINTER (0xFFFFCUL) /* pointer to the inbuilt font tables starting from bitmap handle 16 */
/* Audio sample type defines */
#define EVE_LINEAR_SAMPLES 0UL /* 8bit signed samples */
#define EVE_ULAW_SAMPLES 1UL /* 8bit ulaw samples */
#define EVE_ADPCM_SAMPLES 2UL /* 4bit ima adpcm samples */
/* Synthesized sound */
#define EVE_SILENCE 0x00
#define EVE_SQUAREWAVE 0x01
#define EVE_SINEWAVE 0x02
#define EVE_SAWTOOTH 0x03
#define EVE_TRIANGLE 0x04
#define EVE_BEEPING 0x05
#define EVE_ALARM 0x06
#define EVE_WARBLE 0x07
#define EVE_CAROUSEL 0x08
#define EVE_PIPS(n) (0x0F + (n))
#define EVE_HARP 0x40
#define EVE_XYLOPHONE 0x41
#define EVE_TUBA 0x42
#define EVE_GLOCKENSPIEL 0x43
#define EVE_ORGAN 0x44
#define EVE_TRUMPET 0x45
#define EVE_PIANO 0x46
#define EVE_CHIMES 0x47
#define EVE_MUSICBOX 0x48
#define EVE_BELL 0x49
#define EVE_CLICK 0x50
#define EVE_SWITCH 0x51
#define EVE_COWBELL 0x52
#define EVE_NOTCH 0x53
#define EVE_HIHAT 0x54
#define EVE_KICKDRUM 0x55
#define EVE_POP 0x56
#define EVE_CLACK 0x57
#define EVE_CHACK 0x58
#define EVE_MUTE 0x60
#define EVE_UNMUTE 0x61
/* Synthesized sound frequencies, midi note */
#define EVE_MIDI_A0 21
#define EVE_MIDI_A_0 22
#define EVE_MIDI_B0 23
#define EVE_MIDI_C1 24
#define EVE_MIDI_C_1 25
#define EVE_MIDI_D1 26
#define EVE_MIDI_D_1 27
#define EVE_MIDI_E1 28
#define EVE_MIDI_F1 29
#define EVE_MIDI_F_1 30
#define EVE_MIDI_G1 31
#define EVE_MIDI_G_1 32
#define EVE_MIDI_A1 33
#define EVE_MIDI_A_1 34
#define EVE_MIDI_B1 35
#define EVE_MIDI_C2 36
#define EVE_MIDI_C_2 37
#define EVE_MIDI_D2 38
#define EVE_MIDI_D_2 39
#define EVE_MIDI_E2 40
#define EVE_MIDI_F2 41
#define EVE_MIDI_F_2 42
#define EVE_MIDI_G2 43
#define EVE_MIDI_G_2 44
#define EVE_MIDI_A2 45
#define EVE_MIDI_A_2 46
#define EVE_MIDI_B2 47
#define EVE_MIDI_C3 48
#define EVE_MIDI_C_3 49
#define EVE_MIDI_D3 50
#define EVE_MIDI_D_3 51
#define EVE_MIDI_E3 52
#define EVE_MIDI_F3 53
#define EVE_MIDI_F_3 54
#define EVE_MIDI_G3 55
#define EVE_MIDI_G_3 56
#define EVE_MIDI_A3 57
#define EVE_MIDI_A_3 58
#define EVE_MIDI_B3 59
#define EVE_MIDI_C4 60
#define EVE_MIDI_C_4 61
#define EVE_MIDI_D4 62
#define EVE_MIDI_D_4 63
#define EVE_MIDI_E4 64
#define EVE_MIDI_F4 65
#define EVE_MIDI_F_4 66
#define EVE_MIDI_G4 67
#define EVE_MIDI_G_4 68
#define EVE_MIDI_A4 69
#define EVE_MIDI_A_4 70
#define EVE_MIDI_B4 71
#define EVE_MIDI_C5 72
#define EVE_MIDI_C_5 73
#define EVE_MIDI_D5 74
#define EVE_MIDI_D_5 75
#define EVE_MIDI_E5 76
#define EVE_MIDI_F5 77
#define EVE_MIDI_F_5 78
#define EVE_MIDI_G5 79
#define EVE_MIDI_G_5 80
#define EVE_MIDI_A5 81
#define EVE_MIDI_A_5 82
#define EVE_MIDI_B5 83
#define EVE_MIDI_C6 84
#define EVE_MIDI_C_6 85
#define EVE_MIDI_D6 86
#define EVE_MIDI_D_6 87
#define EVE_MIDI_E6 88
#define EVE_MIDI_F6 89
#define EVE_MIDI_F_6 90
#define EVE_MIDI_G6 91
#define EVE_MIDI_G_6 92
#define EVE_MIDI_A6 93
#define EVE_MIDI_A_6 94
#define EVE_MIDI_B6 95
#define EVE_MIDI_C7 96
#define EVE_MIDI_C_7 97
#define EVE_MIDI_D7 98
#define EVE_MIDI_D_7 99
#define EVE_MIDI_E7 100
#define EVE_MIDI_F7 101
#define EVE_MIDI_F_7 102
#define EVE_MIDI_G7 103
#define EVE_MIDI_G_7 104
#define EVE_MIDI_A7 105
#define EVE_MIDI_A_7 106
#define EVE_MIDI_B7 107
#define EVE_MIDI_C8 108
/* GPIO bits */
#define EVE_GPIO0 0
#define EVE_GPIO1 1 /* default gpio pin for audio shutdown, 1 - enable, 0 - disable */
#define EVE_GPIO7 7 /* default gpio pin for display enable, 1 - enable, 0 - disable */
/* Display rotation */
#define EVE_DISPLAY_0 0 /* 0 degrees rotation */
#define EVE_DISPLAY_180 1 /* 180 degrees rotation */
/* commands common to EVE/EVE2/EVE3 */
#define CMD_APPEND 0xFFFFFF1E
#define CMD_BGCOLOR 0xFFFFFF09
#define CMD_BUTTON 0xFFFFFF0D
#define CMD_CALIBRATE 0xFFFFFF15
#define CMD_CLOCK 0xFFFFFF14
#define CMD_COLDSTART 0xFFFFFF32
#define CMD_DIAL 0xFFFFFF2D
#define CMD_DLSTART 0xFFFFFF00
#define CMD_FGCOLOR 0xFFFFFF0A
#define CMD_GAUGE 0xFFFFFF13
#define CMD_GETMATRIX 0xFFFFFF33
#define CMD_GETPROPS 0xFFFFFF25
#define CMD_GETPTR 0xFFFFFF23
#define CMD_GRADCOLOR 0xFFFFFF34
#define CMD_GRADIENT 0xFFFFFF0B
#define CMD_INFLATE 0xFFFFFF22
#define CMD_INTERRUPT 0xFFFFFF02
#define CMD_KEYS 0xFFFFFF0E
#define CMD_LOADIDENTITY 0xFFFFFF26
#define CMD_LOADIMAGE 0xFFFFFF24
#define CMD_LOGO 0xFFFFFF31
#define CMD_MEMCPY 0xFFFFFF1D
#define CMD_MEMCRC 0xFFFFFF18
#define CMD_MEMSET 0xFFFFFF1B
#define CMD_MEMWRITE 0xFFFFFF1A
#define CMD_MEMZERO 0xFFFFFF1C
#define CMD_NUMBER 0xFFFFFF2E
#define CMD_PROGRESS 0xFFFFFF0F
#define CMD_REGREAD 0xFFFFFF19
#define CMD_ROTATE 0xFFFFFF29
#define CMD_SCALE 0xFFFFFF28
#define CMD_SCREENSAVER 0xFFFFFF2F
#define CMD_SCROLLBAR 0xFFFFFF11
#define CMD_SETFONT 0xFFFFFF2B
#define CMD_SETMATRIX 0xFFFFFF2A
#define CMD_SKETCH 0xFFFFFF30
#define CMD_SLIDER 0xFFFFFF10
#define CMD_SNAPSHOT 0xFFFFFF1F
#define CMD_SPINNER 0xFFFFFF16
#define CMD_STOP 0xFFFFFF17
#define CMD_SWAP 0xFFFFFF01
#define CMD_TEXT 0xFFFFFF0C
#define CMD_TOGGLE 0xFFFFFF12
#define CMD_TRACK 0xFFFFFF2C
#define CMD_TRANSLATE 0xFFFFFF27
/* the following are undocumented commands that therefore should not be used */
#if 0
#define CMD_CRC 0xFFFFFF03
#define CMD_HAMMERAUX 0xFFFFFF04
#define CMD_MARCH 0xFFFFFF05
#define CMD_IDCT 0xFFFFFF06
#define CMD_EXECUTE 0xFFFFFF07
#define CMD_GETPOINT 0xFFFFFF08
#define CMD_TOUCH_TRANSFORM 0xFFFFFF20
#endif
/* FT8xx graphics engine specific macros useful for static display list generation */
#define ALPHA_FUNC(func,ref) ((9UL<<24)|(((func)&7UL)<<8)|(((ref)&255UL)<<0))
#define BEGIN(prim) ((31UL<<24)|(((prim)&15UL)<<0))
#define BITMAP_HANDLE(handle) ((5UL<<24)|(((handle)&31UL)<<0))
#define BITMAP_LAYOUT(format,linestride,height) ((7UL<<24)|(((format)&31UL)<<19)|(((linestride)&1023UL)<<9)|(((height)&511UL)<<0))
#define BITMAP_SIZE(filter,wrapx,wrapy,width,height) ((8UL<<24)|(((filter)&1UL)<<20)|(((wrapx)&1UL)<<19)|(((wrapy)&1UL)<<18)|(((width)&511UL)<<9)|(((height)&511UL)<<0))
#define BITMAP_TRANSFORM_A(a) ((21UL<<24)|(((a)&131071UL)<<0))
#define BITMAP_TRANSFORM_B(b) ((22UL<<24)|(((b)&131071UL)<<0))
#define BITMAP_TRANSFORM_C(c) ((23UL<<24)|(((c)&16777215UL)<<0))
#define BITMAP_TRANSFORM_D(d) ((24UL<<24)|(((d)&131071UL)<<0))
#define BITMAP_TRANSFORM_E(e) ((25UL<<24)|(((e)&131071UL)<<0))
#define BITMAP_TRANSFORM_F(f) ((26UL<<24)|(((f)&16777215UL)<<0))
#define BLEND_FUNC(src,dst) ((11UL<<24)|(((src)&7UL)<<3)|(((dst)&7UL)<<0))
#define CALL(dest) ((29UL<<24)|(((dest)&65535UL)<<0))
#define CELL(cell) ((6UL<<24)|(((cell)&127UL)<<0))
#define CLEAR(c,s,t) ((38UL<<24)|(((c)&1UL)<<2)|(((s)&1UL)<<1)|(((t)&1UL)<<0))
#define CLEAR_COLOR_A(alpha) ((15UL<<24)|(((alpha)&255UL)<<0))
#define CLEAR_COLOR_RGB(red,green,blue) ((2UL<<24)|(((red)&255UL)<<16)|(((green)&255UL)<<8)|(((blue)&255UL)<<0))
#define CLEAR_STENCIL(s) ((17UL<<24)|(((s)&255UL)<<0))
#define CLEAR_TAG(s) ((18UL<<24)|(((s)&255UL)<<0))
#define COLOR_A(alpha) ((16UL<<24)|(((alpha)&255UL)<<0))
#define COLOR_MASK(r,g,b,a) ((32UL<<24)|(((r)&1UL)<<3)|(((g)&1UL)<<2)|(((b)&1UL)<<1)|(((a)&1UL)<<0))
#define COLOR_RGB(red,green,blue) ((4UL<<24)|(((red)&255UL)<<16)|(((green)&255UL)<<8)|(((blue)&255UL)<<0))
/* #define DISPLAY() ((0UL<<24)) */
#define END() ((33UL<<24))
#define JUMP(dest) ((30UL<<24)|(((dest)&65535UL)<<0))
#define LINE_WIDTH(width) ((14UL<<24)|(((width)&4095UL)<<0))
#define MACRO(m) ((37UL<<24)|(((m)&1UL)<<0))
#define POINT_SIZE(size) ((13UL<<24)|(((size)&8191UL)<<0))
#define RESTORE_CONTEXT() ((35UL<<24))
#define RETURN() ((36UL<<24))
#define SAVE_CONTEXT() ((34UL<<24))
#define STENCIL_FUNC(func,ref,mask) ((10UL<<24)|(((func)&7UL)<<16)|(((ref)&255UL)<<8)|(((mask)&255UL)<<0))
#define STENCIL_MASK(mask) ((19UL<<24)|(((mask)&255UL)<<0))
#define STENCIL_OP(sfail,spass) ((12UL<<24)|(((sfail)&7UL)<<3)|(((spass)&7UL)<<0))
#define TAG(s) ((3UL<<24)|(((s)&255UL)<<0))
#define TAG_MASK(mask) ((20UL<<24)|(((mask)&1UL)<<0))
#define VERTEX2F(x,y) ((1UL<<30)|(((x)&32767UL)<<15)|(((y)&32767UL)<<0))
#define VERTEX2II(x,y,handle,cell) ((2UL<<30)|(((x)&511UL)<<21)|(((y)&511UL)<<12)|(((handle)&31UL)<<7)|(((cell)&127UL)<<0))
/* ----------------- BT81x exclusive definitions -----------------*/
#if defined (BT81X_ENABLE)
#define EVE_GLFORMAT 31UL /* used with BITMAP_LAYOUT to indicate bitmap-format is specified by BITMAP_EXT_FORMAT */
#define DL_BITMAP_EXT_FORMAT 0x2E000000 /* requires OR'd arguments */
/* extended Bitmap formats */
#define EVE_COMPRESSED_RGBA_ASTC_4x4_KHR 37808UL
#define EVE_COMPRESSED_RGBA_ASTC_5x4_KHR 37809UL
#define EVE_COMPRESSED_RGBA_ASTC_5x5_KHR 37810UL
#define EVE_COMPRESSED_RGBA_ASTC_6x5_KHR 37811UL
#define EVE_COMPRESSED_RGBA_ASTC_6x6_KHR 37812UL
#define EVE_COMPRESSED_RGBA_ASTC_8x5_KHR 37813UL
#define EVE_COMPRESSED_RGBA_ASTC_8x6_KHR 37814UL
#define EVE_COMPRESSED_RGBA_ASTC_8x8_KHR 37815UL
#define EVE_COMPRESSED_RGBA_ASTC_10x5_KHR 37816UL
#define EVE_COMPRESSED_RGBA_ASTC_10x6_KHR 37817UL
#define EVE_COMPRESSED_RGBA_ASTC_10x8_KHR 37818UL
#define EVE_COMPRESSED_RGBA_ASTC_10x10_KHR 37819UL
#define EVE_COMPRESSED_RGBA_ASTC_12x10_KHR 37820UL
#define EVE_COMPRESSED_RGBA_ASTC_12x12_KHR 37821UL
#define EVE_RAM_ERR_REPORT 0x309800UL /* max 128 bytes null terminated string */
#define EVE_RAM_FLASH 0x800000UL
#define EVE_RAM_FLASH_POSTBLOB 0x801000UL
#define EVE_OPT_FLASH 64UL
#define EVE_OPT_FORMAT 4096UL
#define EVE_OPT_FILL 8192UL
/* additional commands for BT81x */
#define CMD_BITMAP_TRANSFORM 0xFFFFFF21
#define CMD_SYNC 0xFFFFFF42 /* does not need a dedicated function, just use EVE_cmd_dl(CMD_SYNC) */
#define CMD_FLASHERASE 0xFFFFFF44 /* does not need a dedicated function, just use EVE_cmd_dl(CMD_FLASHERASE) */
#define CMD_FLASHWRITE 0xFFFFFF45
#define CMD_FLASHREAD 0xFFFFFF46
#define CMD_FLASHUPDATE 0xFFFFFF47
#define CMD_FLASHDETACH 0xFFFFFF48 /* does not need a dedicated function, just use EVE_cmd_dl(CMD_FLASHDETACH) */
#define CMD_FLASHATTACH 0xFFFFFF49 /* does not need a dedicated function, just use EVE_cmd_dl(CMD_FLASHATTACH) */
#define CMD_FLASHFAST 0xFFFFFF4A
#define CMD_FLASHSPIDESEL 0xFFFFFF4B /* does not need a dedicated function, just use EVE_cmd_dl(CMD_FLASHSPIDESEL) */
#define CMD_FLASHSPITX 0xFFFFFF4C
#define CMD_FLASHSPIRX 0xFFFFFF4D
#define CMD_FLASHSOURCE 0xFFFFFF4E
#define CMD_CLEARCACHE 0xFFFFFF4F /* does not need a dedicated function, just use EVE_cmd_dl(CMD_CLEARCACHE) */
#define CMD_INFLATE2 0xFFFFFF50
#define CMD_ROTATEAROUND 0xFFFFFF51
#define CMD_RESETFONTS 0xFFFFFF52 /* does not need a dedicated function, just use EVE_cmd_dl(CMD_RESETFONTS) */
#define CMD_ANIMSTART 0xFFFFFF53
#define CMD_ANIMSTOP 0xFFFFFF54
#define CMD_ANIMXY 0xFFFFFF55
#define CMD_ANIMDRAW 0xFFFFFF56
#define CMD_GRADIENTA 0xFFFFFF57
#define CMD_FILLWIDTH 0xFFFFFF58
#define CMD_APPENDF 0xFFFFFF59
#define CMD_ANIMFRAME 0xFFFFFF5A
#define CMD_VIDEOSTARTF 0xFFFFFF5F /* does not need a dedicated function, just use EVE_cmd_dl(CMD_VIDEOSTARTF) */
#if 0
/* some undocumented commands for BT81x */
#define CMD_NOP 0xFFFFFF5B
#define CMD_SHA1 0xFFFFFF5C
#define CMD_HMAC 0xFFFFFF5D
#define CMD_LAST_ 0xFFFFFF5E
#endif
/* additional registers for BT81x */
#define REG_ADAPTIVE_FRAMERATE 0x30257cUL
#define REG_PLAYBACK_PAUSE 0x3025ecUL
#define REG_FLASH_STATUS 0x3025f0UL
#define REG_FLASH_SIZE 0x309024UL
#define REG_PLAY_CONTROL 0x30914eUL
#define REG_COPRO_PATCH_DTR 0x309162UL
/* BT81x graphics engine specific macros */
#define BITMAP_EXT_FORMAT(format) ((46UL<<24)|(((format)&65535UL)<<0))
#define BITMAP_SWIZZLE(r,g,b,a) ((47UL<<24)|(((r)&7UL)<<9)|(((g)&7UL)<<6)|(((b)&7UL)<<3)|(((a)&7UL)<<0))
#define BITMAP_SOURCE2(flash_or_ram, addr) ((1UL<<24)|((flash_or_ram) << 23)|(((addr)&8388607UL)<<0))
#define INT_FRR() ((48UL<<24))
#undef BITMAP_TRANSFORM_A
#undef BITMAP_TRANSFORM_B
#undef BITMAP_TRANSFORM_D
#undef BITMAP_TRANSFORM_E
#define BITMAP_TRANSFORM_A_EXT(p,v) ((21UL<<24)|(((p)&1UL)<<17)|(((v)&131071UL)<<0))
#define BITMAP_TRANSFORM_B_EXT(p,v) ((22UL<<24)|(((p)&1UL)<<17)|(((v)&131071UL)<<0))
#define BITMAP_TRANSFORM_D_EXT(p,v) ((24UL<<24)|(((p)&1UL)<<17)|(((v)&131071UL)<<0))
#define BITMAP_TRANSFORM_E_EXT(p,v) ((25UL<<24)|(((p)&1UL)<<17)|(((v)&131071UL)<<0))
#define BITMAP_TRANSFORM_A(a) BITMAP_TRANSFORM_A_EXT(0,a)
#define BITMAP_TRANSFORM_B(b) BITMAP_TRANSFORM_B_EXT(0,b)
#define BITMAP_TRANSFORM_D(d) BITMAP_TRANSFORM_D_EXT(0,d)
#define BITMAP_TRANSFORM_E(e) BITMAP_TRANSFORM_E_EXT(0,e)
#endif
/* ----------------- FT81x / BT81x exclusive definitions -----------------*/
#if defined (FT81X_ENABLE)
/* Host commands */
#define EVE_CLKSEL 0x61 /* configure system clock */
#define EVE_RST_PULSE 0x68 /* reset core - all registers default and processors reset */
#define EVE_PINDRIVE 0x70 /* setup drive strength for various pins */
#define EVE_PIN_PD_STATE 0x71 /* setup how pins behave during power down */
/* Memory definitions */
#define EVE_RAM_G 0x000000UL
#define EVE_ROM_CHIPID 0x0C0000UL
#define EVE_ROM_FONT 0x1E0000UL
#define EVE_ROM_FONT_ADDR 0x2FFFFCUL
#define EVE_RAM_DL 0x300000UL
#define EVE_RAM_REG 0x302000UL
#define EVE_RAM_CMD 0x308000UL
/* Memory buffer sizes */
#define EVE_RAM_G_SIZE 1024*1024L
#define EVE_CMDFIFO_SIZE 4*1024L
#define EVE_RAM_DL_SIZE 8*1024L
/* various additional defines for FT81x */
#define EVE_ADC_DIFFERENTIAL 1UL
#define EVE_ADC_SINGLE_ENDED 0UL
#define EVE_INT_G8 18UL
#define EVE_INT_L8C 12UL
#define EVE_INT_VGA 13UL
#define EVE_OPT_MEDIAFIFO 16UL
#define EVE_OPT_FULLSCREEN 8UL
#define EVE_OPT_NOTEAR 4UL
#define EVE_OPT_SOUND 32UL
#define EVE_PALETTED565 14UL
#define EVE_PALETTED4444 15UL
#define EVE_PALETTED8 16UL
#define EVE_L2 17UL
/* additional commands for FT81x */
#define CMD_MEDIAFIFO 0xFFFFFF39
#define CMD_PLAYVIDEO 0xFFFFFF3A
#define CMD_ROMFONT 0xFFFFFF3F
#define CMD_SETBASE 0xFFFFFF38
#define CMD_SETBITMAP 0xFFFFFF43
#define CMD_SETFONT2 0xFFFFFF3B
#define CMD_SETROTATE 0xFFFFFF36
#define CMD_SETSCRATCH 0xFFFFFF3C
#define CMD_SNAPSHOT2 0xFFFFFF37
#define CMD_VIDEOFRAME 0xFFFFFF41
#define CMD_VIDEOSTART 0xFFFFFF40
/* the following are undocumented commands that therefore should not be used */
#if 0
#define CMD_CSKETCH 0xFFFFFF35
#define CMD_INT_RAMSHARED 0xFFFFFF3D
#define CMD_INT_SWLOADIMAGE 0xFFFFFF3E
#endif
/* Register definitions */
#define REG_ANA_COMP 0x302184UL /* only listed in datasheet */
#define REG_BIST_EN 0x302174UL /* only listed in datasheet */
#define REG_CLOCK 0x302008UL
#define REG_CMDB_SPACE 0x302574UL
#define REG_CMDB_WRITE 0x302578UL
#define REG_CMD_DL 0x302100UL
#define REG_CMD_READ 0x3020f8UL
#define REG_CMD_WRITE 0x3020fcUL
#define REG_CPURESET 0x302020UL
#define REG_CSPREAD 0x302068UL
#define REG_CTOUCH_EXTENDED 0x302108UL
#define REG_CTOUCH_TOUCH0_XY 0x302124UL /* only listed in datasheet */
#define REG_CTOUCH_TOUCH4_X 0x30216cUL
#define REG_CTOUCH_TOUCH4_Y 0x302120UL
#define REG_CTOUCH_TOUCH1_XY 0x30211cUL
#define REG_CTOUCH_TOUCH2_XY 0x30218cUL
#define REG_CTOUCH_TOUCH3_XY 0x302190UL
#define REG_TOUCH_CONFIG 0x302168UL
#define REG_DATESTAMP 0x302564UL /* only listed in datasheet */
#define REG_DITHER 0x302060UL
#define REG_DLSWAP 0x302054UL
#define REG_FRAMES 0x302004UL
#define REG_FREQUENCY 0x30200cUL
#define REG_GPIO 0x302094UL
#define REG_GPIOX 0x30209cUL
#define REG_GPIOX_DIR 0x302098UL
#define REG_GPIO_DIR 0x302090UL
#define REG_HCYCLE 0x30202cUL
#define REG_HOFFSET 0x302030UL
#define REG_HSIZE 0x302034UL
#define REG_HSYNC0 0x302038UL
#define REG_HSYNC1 0x30203cUL
#define REG_ID 0x302000UL
#define REG_INT_EN 0x3020acUL
#define REG_INT_FLAGS 0x3020a8UL
#define REG_INT_MASK 0x3020b0UL
#define REG_MACRO_0 0x3020d8UL
#define REG_MACRO_1 0x3020dcUL
#define REG_MEDIAFIFO_READ 0x309014UL /* only listed in programmers guide */
#define REG_MEDIAFIFO_WRITE 0x309018UL /* only listed in programmers guide */
#define REG_OUTBITS 0x30205cUL
#define REG_PCLK 0x302070UL
#define REG_PCLK_POL 0x30206cUL
#define REG_PLAY 0x30208cUL
#define REG_PLAYBACK_FORMAT 0x3020c4UL
#define REG_PLAYBACK_FREQ 0x3020c0UL
#define REG_PLAYBACK_LENGTH 0x3020b8UL
#define REG_PLAYBACK_LOOP 0x3020c8UL
#define REG_PLAYBACK_PLAY 0x3020ccUL
#define REG_PLAYBACK_READPTR 0x3020bcUL
#define REG_PLAYBACK_START 0x3020b4UL
#define REG_PWM_DUTY 0x3020d4UL
#define REG_PWM_HZ 0x3020d0UL
#define REG_RENDERMODE 0x302010UL /* only listed in datasheet */
#define REG_ROTATE 0x302058UL
#define REG_SNAPFORMAT 0x30201cUL /* only listed in datasheet */
#define REG_SNAPSHOT 0x302018UL /* only listed in datasheet */
#define REG_SNAPY 0x302014UL /* only listed in datasheet */
#define REG_SOUND 0x302088UL
#define REG_SPI_WIDTH 0x302188UL /* listed with false offset in programmers guide V1.1 */
#define REG_SWIZZLE 0x302064UL
#define REG_TAG 0x30207cUL
#define REG_TAG_X 0x302074UL
#define REG_TAG_Y 0x302078UL
#define REG_TAP_CRC 0x302024UL /* only listed in datasheet */
#define REG_TAP_MASK 0x302028UL /* only listed in datasheet */
#define REG_TOUCH_ADC_MODE 0x302108UL
#define REG_TOUCH_CHARGE 0x30210cUL
#define REG_TOUCH_DIRECT_XY 0x30218cUL
#define REG_TOUCH_DIRECT_Z1Z2 0x302190UL
#define REG_TOUCH_MODE 0x302104UL
#define REG_TOUCH_OVERSAMPLE 0x302114UL
#define REG_TOUCH_RAW_XY 0x30211cUL
#define REG_TOUCH_RZ 0x302120UL
#define REG_TOUCH_RZTHRESH 0x302118UL
#define REG_TOUCH_SCREEN_XY 0x302124UL
#define REG_TOUCH_SETTLE 0x302110UL
#define REG_TOUCH_TAG 0x30212cUL
#define REG_TOUCH_TAG1 0x302134UL /* only listed in datasheet */
#define REG_TOUCH_TAG1_XY 0x302130UL /* only listed in datasheet */
#define REG_TOUCH_TAG2 0x30213cUL /* only listed in datasheet */
#define REG_TOUCH_TAG2_XY 0x302138UL /* only listed in datasheet */
#define REG_TOUCH_TAG3 0x302144UL /* only listed in datasheet */
#define REG_TOUCH_TAG3_XY 0x302140UL /* only listed in datasheet */
#define REG_TOUCH_TAG4 0x30214cUL /* only listed in datasheet */
#define REG_TOUCH_TAG4_XY 0x302148UL /* only listed in datasheet */
#define REG_TOUCH_TAG_XY 0x302128UL
#define REG_TOUCH_TRANSFORM_A 0x302150UL
#define REG_TOUCH_TRANSFORM_B 0x302154UL
#define REG_TOUCH_TRANSFORM_C 0x302158UL
#define REG_TOUCH_TRANSFORM_D 0x30215cUL
#define REG_TOUCH_TRANSFORM_E 0x302160UL
#define REG_TOUCH_TRANSFORM_F 0x302164UL
#define REG_TRACKER 0x309000UL /* only listed in programmers guide */
#define REG_TRACKER_1 0x309004UL /* only listed in programmers guide */
#define REG_TRACKER_2 0x309008UL /* only listed in programmers guide */
#define REG_TRACKER_3 0x30900cUL /* only listed in programmers guide */
#define REG_TRACKER_4 0x309010UL /* only listed in programmers guide */
#define REG_TRIM 0x302180UL
#define REG_VCYCLE 0x302040UL
#define REG_VOFFSET 0x302044UL
#define REG_VOL_PB 0x302080UL
#define REG_VOL_SOUND 0x302084UL
#define REG_VSIZE 0x302048UL
#define REG_VSYNC0 0x30204cUL
#define REG_VSYNC1 0x302050UL
#if 0
#define REG_BUSYBITS 0x3020e8UL /* only listed as "reserved" in datasheet */
#define REG_CRC 0x302178UL /* only listed as "reserved" in datasheet */
#define REG_SPI_EARLY_TX 0x30217cUL /* only listed as "reserved" in datasheet */
#define REG_ROMSUB_SEL 0x3020f0UL /* only listed as "reserved" in datasheet */
#define REG_TOUCH_FAULT 0x302170UL /* only listed as "reserved" in datasheet */
#endif
/* FT81x graphics engine specific macros useful for static display list generation */
/* beware, these are different to FTDIs implementation as these take the original values as parameters and not only the upper bits */
#define BITMAP_LAYOUT_H(linestride,height) ((40UL<<24)|((((linestride&0xC00)>>10)&3UL)<<2)|((((height&0x600)>>9)&3UL)<<0))
#define BITMAP_SIZE_H(width,height) ((41UL<<24)|((((width&0x600)>>9)&3UL)<<2)|((((height&0x600)>>9)&3UL)<<0))
#define BITMAP_SOURCE(addr) ((1UL<<24)|(((addr)&4194303UL)<<0))
//#define NOP() ((45UL<<24))
#define PALETTE_SOURCE(addr) ((42UL<<24)|(((addr)&4194303UL)<<0))
#define SCISSOR_SIZE(width,height) ((28UL<<24)|(((width)&4095UL)<<12)|(((height)&4095UL)<<0))
#define SCISSOR_XY(x,y) ((27UL<<24)|(((x)&2047UL)<<11)|(((y)&2047UL)<<0))
#define VERTEX_FORMAT(frac) ((39UL<<24)|(((frac)&7UL)<<0))
#define VERTEX_TRANSLATE_X(x) ((43UL<<24)|(((x)&131071UL)<<0))
#define VERTEX_TRANSLATE_Y(y) ((44UL<<24)|(((y)&131071UL)<<0))
/* ----------------- FT80x exclusive definitions -----------------*/
#else
/* Memory definitions */
#define EVE_RAM_G 0x000000UL
#define EVE_ROM_CHIPID 0x0C0000UL
#define EVE_ROM_FONT 0x0BB23CUL
#define EVE_ROM_FONT_ADDR 0x0FFFFCUL
#define EVE_RAM_DL 0x100000UL
#define EVE_RAM_PAL 0x102000UL
#define EVE_RAM_CMD 0x108000UL
#define EVE_RAM_SCREENSHOT 0x1C2000UL
/* Memory buffer sizes */
#define EVE_RAM_G_SIZE 256*1024L
#define EVE_CMDFIFO_SIZE 4*1024L
#define EVE_RAM_DL_SIZE 8*1024L
#define EVE_RAM_PAL_SIZE 1*1024L
/* Register definitions */
#define REG_ID 0x102400UL
#define REG_FRAMES 0x102404UL
#define REG_CLOCK 0x102408UL
#define REG_FREQUENCY 0x10240CUL
#define REG_SCREENSHOT_EN 0x102410UL
#define REG_SCREENSHOT_Y 0x102414UL
#define REG_SCREENSHOT_START 0x102418UL
#define REG_CPURESET 0x10241CUL
#define REG_TAP_CRC 0x102420UL
#define REG_TAP_MASK 0x102424UL
#define REG_HCYCLE 0x102428UL
#define REG_HOFFSET 0x10242CUL
#define REG_HSIZE 0x102430UL
#define REG_HSYNC0 0x102434UL
#define REG_HSYNC1 0x102438UL
#define REG_VCYCLE 0x10243CUL
#define REG_VOFFSET 0x102440UL
#define REG_VSIZE 0x102444UL
#define REG_VSYNC0 0x102448UL
#define REG_VSYNC1 0x10244CUL
#define REG_DLSWAP 0x102450UL
#define REG_ROTATE 0x102454UL
#define REG_OUTBITS 0x102458UL
#define REG_DITHER 0x10245CUL
#define REG_SWIZZLE 0x102460UL
#define REG_CSPREAD 0x102464UL
#define REG_PCLK_POL 0x102468UL
#define REG_PCLK 0x10246CUL
#define REG_TAG_X 0x102470UL
#define REG_TAG_Y 0x102474UL
#define REG_TAG 0x102478UL
#define REG_VOL_PB 0x10247CUL
#define REG_VOL_SOUND 0x102480UL
#define REG_SOUND 0x102484UL
#define REG_PLAY 0x102488UL
#define REG_GPIO_DIR 0x10248CUL
#define REG_GPIO 0x102490UL
#define REG_INT_FLAGS 0x102498UL
#define REG_INT_EN 0x10249CUL
#define REG_INT_MASK 0x1024A0UL
#define REG_PLAYBACK_START 0x1024A4UL
#define REG_PLAYBACK_LENGTH 0x1024A8UL
#define REG_PLAYBACK_READPTR 0x1024ACUL
#define REG_PLAYBACK_FREQ 0x1024B0UL
#define REG_PLAYBACK_FORMAT 0x1024B4UL
#define REG_PLAYBACK_LOOP 0x1024B8UL
#define REG_PLAYBACK_PLAY 0x1024BCUL
#define REG_PWM_HZ 0x1024C0UL
#define REG_PWM_DUTY 0x1024C4UL
#define REG_MACRO_0 0x1024C8UL
#define REG_MACRO_1 0x1024CCUL
#define REG_SCREENSHOT_BUSY 0x1024D8UL
#define REG_CMD_READ 0x1024E4UL
#define REG_CMD_WRITE 0x1024E8UL
#define REG_CMD_DL 0x1024ECUL
#define REG_TOUCH_MODE 0x1024F0UL
#define REG_TOUCH_ADC_MODE 0x1024F4UL
#define REG_TOUCH_CHARGE 0x1024F8UL
#define REG_TOUCH_SETTLE 0x1024FCUL
#define REG_TOUCH_OVERSAMPLE 0x102500UL
#define REG_TOUCH_RZTHRESH 0x102504UL
#define REG_TOUCH_RAW_XY 0x102508UL
#define REG_TOUCH_RZ 0x10250CUL
#define REG_TOUCH_SCREEN_XY 0x102510UL
#define REG_TOUCH_TAG_XY 0x102514UL
#define REG_TOUCH_TAG 0x102518UL
#define REG_TOUCH_TRANSFORM_A 0x10251CUL
#define REG_TOUCH_TRANSFORM_B 0x102520UL
#define REG_TOUCH_TRANSFORM_C 0x102524UL
#define REG_TOUCH_TRANSFORM_D 0x102528UL
#define REG_TOUCH_TRANSFORM_E 0x10252CUL
#define REG_TOUCH_TRANSFORM_F 0x102530UL
#define REG_SCREENSHOT_READ 0x102554UL
#define REG_TRIM 0x10256CUL
#define REG_TOUCH_DIRECT_XY 0x102574UL
#define REG_TOUCH_DIRECT_Z1Z2 0x102578UL
#define REG_TRACKER 0x109000UL
/* FT80x graphics engine specific macros useful for static display list generation */
#define BITMAP_SOURCE(addr) ((1UL<<24)|(((addr)&1048575UL)<<0))
#define SCISSOR_SIZE(width,height) ((28UL<<24)|(((width)&1023UL)<<10)|(((height)&1023UL)<<0))
#define SCISSOR_XY(x,y) ((27UL<<24)|(((x)&511UL)<<9)|(((y)&511UL)<<0))
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_FT81X_DEFINES_H*/
@@ -0,0 +1,117 @@
/**
* @file lv_ili9341.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_ili9341.h"
#if LV_USE_ILI9341
/*********************
* DEFINES
*********************/
#define CMD_FRMCTR1 0xB1 /* Frame Rate Control (In Normal Mode/Full Colors) */
#define CMD_FRMCTR2 0xB2 /* Frame Rate Control (In Idle Mode/8 colors) */
#define CMD_FRMCTR3 0xB3 /* Frame Rate control (In Partial Mode/Full Colors) */
#define CMD_INVCTR 0xB4 /* Display Inversion Control */
#define CMD_DFUNCTR 0xB6 /* Display Function Control */
#define CMD_PWCTR1 0xC0 /* Power Control 1 */
#define CMD_PWCTR2 0xC1 /* Power Control 2 */
#define CMD_VMCTR1 0xC5 /* VCOM Control 1 */
#define CMD_VMCTR2 0xC7 /* VCOM Control 2 */
#define CMD_PWCTRA 0xCB /* Power Control A */
#define CMD_PWCTRB 0xCF /* Power Control B */
#define CMD_GMCTRP1 0xE0 /* Positive Gamma Correction */
#define CMD_GMCTRN1 0xE1 /* Negative Gamma Correction */
#define CMD_DTCTRA 0xE8 /* Driver timing control A */
#define CMD_DTCTRB 0xEA /* Driver timing control B */
#define CMD_PONSEQ 0xED /* Power On Sequence */
#define CMD_RDINDEX 0xD9 /* ili9341 */
#define CMD_IDXRD 0xDD /* ILI9341 only, indexed control register read */
#define CMD_ENA3G 0xF2 /* Enable 3 Gamma control */
#define CMD_IFCTR 0xF6 /* Interface Control */
#define CMD_PRCTR 0xF7 /* Pump ratio control */
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC CONSTANTS
**********************/
/* init commands based on LovyanGFX ILI9341 driver */
static const uint8_t init_cmd_list[] = {
CMD_PWCTRB, 3, 0x00, 0xC1, 0x30,
CMD_PONSEQ, 4, 0x64, 0x03, 0x12, 0x81,
CMD_DTCTRA, 3, 0x85, 0x00, 0x78,
CMD_PWCTRA, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
CMD_PRCTR, 1, 0x20,
CMD_DTCTRB, 2, 0x00, 0x00,
CMD_PWCTR1, 1, 0x23,
CMD_PWCTR2, 1, 0x10,
CMD_VMCTR1, 2, 0x3e, 0x28,
CMD_VMCTR2, 1, 0x86,
CMD_FRMCTR1, 2, 0x00, 0x13,
CMD_DFUNCTR, 2, 0x0A, 0xA2,
CMD_IFCTR, 3, 0x09, 0x30, 0x00,
CMD_ENA3G, 1, 0x00,
LV_LCD_CMD_SET_GAMMA_CURVE, 1, 0x01,
CMD_GMCTRP1, 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
CMD_GMCTRN1, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
LV_LCD_CMD_DELAY_MS, LV_LCD_CMD_EOF
};
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_ili9341_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_ili9341_send_cmd_cb_t send_cmd_cb, lv_ili9341_send_color_cb_t send_color_cb)
{
lv_display_t * disp = lv_lcd_generic_mipi_create(hor_res, ver_res, flags, send_cmd_cb, send_color_cb);
lv_lcd_generic_mipi_send_cmd_list(disp, init_cmd_list);
return disp;
}
void lv_ili9341_set_gap(lv_display_t * disp, uint16_t x, uint16_t y)
{
lv_lcd_generic_mipi_set_gap(disp, x, y);
}
void lv_ili9341_set_invert(lv_display_t * disp, bool invert)
{
lv_lcd_generic_mipi_set_invert(disp, invert);
}
void lv_ili9341_set_gamma_curve(lv_display_t * disp, uint8_t gamma)
{
lv_lcd_generic_mipi_set_gamma_curve(disp, gamma);
}
void lv_ili9341_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list)
{
lv_lcd_generic_mipi_send_cmd_list(disp, cmd_list);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_ILI9341*/
@@ -0,0 +1,94 @@
/**
* @file lv_ili9341.h
*
* This driver is just a wrapper around the generic MIPI compatible LCD controller driver
*
*/
#ifndef LV_ILI9341_H
#define LV_ILI9341_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lcd/lv_lcd_generic_mipi.h"
#if LV_USE_ILI9341
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef lv_lcd_send_cmd_cb_t lv_ili9341_send_cmd_cb_t;
typedef lv_lcd_send_color_cb_t lv_ili9341_send_color_cb_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create an LCD display with ILI9341 driver
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
* @return pointer to the created display
*/
lv_display_t * lv_ili9341_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_ili9341_send_cmd_cb_t send_cmd_cb, lv_ili9341_send_color_cb_t send_color_cb);
/**
* Set gap, i.e., the offset of the (0,0) pixel in the VRAM
* @param disp display object
* @param x x offset
* @param y y offset
*/
void lv_ili9341_set_gap(lv_display_t * disp, uint16_t x, uint16_t y);
/**
* Set color inversion
* @param disp display object
* @param invert false: normal, true: invert
*/
void lv_ili9341_set_invert(lv_display_t * disp, bool invert);
/**
* Set gamma curve
* @param disp display object
* @param gamma gamma curve
*/
void lv_ili9341_set_gamma_curve(lv_display_t * disp, uint8_t gamma);
/**
* Send list of commands.
* @param disp display object
* @param cmd_list controller and panel-specific commands
*/
void lv_ili9341_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list);
/**********************
* OTHERS
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_ILI9341*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_ILI9341_H*/
@@ -0,0 +1,341 @@
/**
* @file lv_lcd_generic_mipi.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_lcd_generic_mipi.h"
#if LV_USE_GENERIC_MIPI
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void send_cmd(lv_lcd_generic_mipi_driver_t * drv, uint8_t cmd, uint8_t * param, size_t param_size);
static void send_color(lv_lcd_generic_mipi_driver_t * drv, uint8_t cmd, uint8_t * param, size_t param_size);
static void init(lv_lcd_generic_mipi_driver_t * drv, lv_lcd_flag_t flags);
static void set_mirror(lv_lcd_generic_mipi_driver_t * drv, bool mirror_x, bool mirror_y);
static void set_swap_xy(lv_lcd_generic_mipi_driver_t * drv, bool swap);
static void set_rotation(lv_lcd_generic_mipi_driver_t * drv, lv_display_rotation_t rot);
static void res_chg_event_cb(lv_event_t * e);
static lv_lcd_generic_mipi_driver_t * get_driver(lv_display_t * disp);
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_lcd_generic_mipi_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_lcd_send_cmd_cb_t send_cmd_cb, lv_lcd_send_color_cb_t send_color_cb)
{
lv_display_t * disp = lv_display_create(hor_res, ver_res);
if(disp == NULL) {
return NULL;
}
lv_lcd_generic_mipi_driver_t * drv = (lv_lcd_generic_mipi_driver_t *)lv_malloc(sizeof(lv_lcd_generic_mipi_driver_t));
if(drv == NULL) {
lv_display_delete(disp);
return NULL;
}
/* init driver struct */
drv->disp = disp;
drv->send_cmd = send_cmd_cb;
drv->send_color = send_color_cb;
lv_display_set_driver_data(disp, (void *)drv);
/* init controller */
init(drv, flags);
/* register resolution change callback (NOTE: this handles screen rotation as well) */
lv_display_add_event_cb(disp, res_chg_event_cb, LV_EVENT_RESOLUTION_CHANGED, NULL);
/* register flush callback */
lv_display_set_flush_cb(disp, flush_cb);
return disp;
}
void lv_lcd_generic_mipi_set_gap(lv_display_t * disp, uint16_t x, uint16_t y)
{
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
drv->x_gap = x;
drv->y_gap = y;
}
void lv_lcd_generic_mipi_set_invert(lv_display_t * disp, bool invert)
{
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
send_cmd(drv, invert ? LV_LCD_CMD_ENTER_INVERT_MODE : LV_LCD_CMD_EXIT_INVERT_MODE, NULL, 0);
}
void lv_lcd_generic_mipi_set_address_mode(lv_display_t * disp, bool mirror_x, bool mirror_y, bool swap_xy, bool bgr)
{
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
uint8_t mad = drv->madctl_reg & ~(LV_LCD_MASK_RGB_ORDER);
if(bgr) {
mad |= LV_LCD_BIT_RGB_ORDER__BGR;
}
drv->madctl_reg = mad;
drv->mirror_x = mirror_x;
drv->mirror_y = mirror_y;
drv->swap_xy = swap_xy;
set_rotation(drv, lv_display_get_rotation(disp)); /* update screen */
}
void lv_lcd_generic_mipi_set_gamma_curve(lv_display_t * disp, uint8_t gamma)
{
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
send_cmd(drv, LV_LCD_CMD_SET_GAMMA_CURVE, (uint8_t[]) {
gamma,
}, 1);
}
void lv_lcd_generic_mipi_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list)
{
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
while(1) {
uint8_t cmd = *cmd_list++;
uint8_t num = *cmd_list++;
if(cmd == LV_LCD_CMD_DELAY_MS) {
if(num == LV_LCD_CMD_EOF) /* end of list */
break;
else { /* delay in 10 ms units*/
lv_delay_ms((uint32_t)(num) * 10);
}
}
else {
drv->send_cmd(drv->disp, &cmd, 1, cmd_list, num);
cmd_list += num;
}
}
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Helper function to call the user-supplied 'send_cmd' function
* @param drv LCD driver object
* @param cmd command byte
* @param param parameter buffer
* @param param_size number of bytes of the parameters
*/
static void send_cmd(lv_lcd_generic_mipi_driver_t * drv, uint8_t cmd, uint8_t * param, size_t param_size)
{
uint8_t cmdbuf = cmd; /* MIPI uses 8 bit commands */
drv->send_cmd(drv->disp, &cmdbuf, 1, param, param_size);
}
/**
* Helper function to call the user-supplied 'send_color' function
* @param drv LCD driver object
* @param cmd command byte
* @param param parameter buffer
* @param param_size number of bytes of the parameters
*/
static void send_color(lv_lcd_generic_mipi_driver_t * drv, uint8_t cmd, uint8_t * param, size_t param_size)
{
uint8_t cmdbuf = cmd; /* MIPI uses 8 bit commands */
drv->send_color(drv->disp, &cmdbuf, 1, param, param_size);
/* note: LVGL waits for your callback to call `lv_display_flush_ready` to know when the transfer has finished. */
}
/**
* Initialize LCD driver after a hard reset
* @param drv LCD driver object
*/
static void init(lv_lcd_generic_mipi_driver_t * drv, lv_lcd_flag_t flags)
{
drv->x_gap = 0;
drv->y_gap = 0;
/* init color mode and RGB order */
drv->madctl_reg = flags & LV_LCD_FLAG_BGR ? LV_LCD_BIT_RGB_ORDER__BGR : LV_LCD_BIT_RGB_ORDER__RGB;
drv->colmod_reg = flags & LV_LCD_FLAG_RGB666 ? LV_LCD_PIXEL_FORMAT_RGB666 : LV_LCD_PIXEL_FORMAT_RGB565;
/* init orientation */
drv->mirror_x = flags & LV_LCD_FLAG_MIRROR_X;
drv->mirror_y = flags & LV_LCD_FLAG_MIRROR_Y;
drv->swap_xy = false;
/* update madctl_reg */
set_swap_xy(drv, drv->swap_xy);
set_mirror(drv, drv->mirror_x, drv->mirror_y);
/* enter sleep mode first */
send_cmd(drv, LV_LCD_CMD_ENTER_SLEEP_MODE, NULL, 0);
lv_delay_ms(10);
/* perform software reset */
send_cmd(drv, LV_LCD_CMD_SOFT_RESET, NULL, 0);
lv_delay_ms(200);
/* LCD goes into sleep mode and display will be turned off after power on reset, exit sleep mode first */
send_cmd(drv, LV_LCD_CMD_EXIT_SLEEP_MODE, NULL, 0);
lv_delay_ms(300);
send_cmd(drv, LV_LCD_CMD_ENTER_NORMAL_MODE, NULL, 0);
send_cmd(drv, LV_LCD_CMD_SET_ADDRESS_MODE, (uint8_t[]) {
drv->madctl_reg,
}, 1);
send_cmd(drv, LV_LCD_CMD_SET_PIXEL_FORMAT, (uint8_t[]) {
drv->colmod_reg,
}, 1);
send_cmd(drv, LV_LCD_CMD_SET_DISPLAY_ON, NULL, 0);
}
/**
* Set readout directions (used for rotating the display)
* @param drv LCD driver object
* @param mirror_x false: normal, true: mirrored
* @param mirror_y false: normal, true: mirrored
*/
static void set_mirror(lv_lcd_generic_mipi_driver_t * drv, bool mirror_x, bool mirror_y)
{
uint8_t mad = drv->madctl_reg & ~(LV_LCD_MASK_COLUMN_ADDRESS_ORDER | LV_LCD_MASK_PAGE_ADDRESS_ORDER);
if(mirror_x) {
mad |= LV_LCD_BIT_COLUMN_ADDRESS_ORDER__RTOL;
}
if(mirror_y) {
mad |= LV_LCD_BIT_PAGE_ADDRESS_ORDER__BTOT;
}
drv->madctl_reg = mad;
}
/**
* Swap horizontal and vertical readout (used for rotating the display)
* @param drv LCD driver object
* @param swap false: normal, true: swapped
*/
static void set_swap_xy(lv_lcd_generic_mipi_driver_t * drv, bool swap)
{
uint8_t mad = drv->madctl_reg & ~(LV_LCD_MASK_PAGE_COLUMN_ORDER);
if(swap) {
mad |= LV_LCD_BIT_PAGE_COLUMN_ORDER__REVERSE;
}
drv->madctl_reg = mad;
}
/**
* Flush display buffer to the LCD
* @param disp display object
* @param hor_res horizontal resolution
* @param area area stored in the buffer
* @param px_map buffer containing pixel data
* @note transfers pixel data to the LCD controller using the callbacks 'send_cmd' and 'send_color', which were
* passed to the 'lv_st7789_create()' function
*/
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
{
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
int32_t x_start = area->x1;
int32_t x_end = area->x2 + 1;
int32_t y_start = area->y1;
int32_t y_end = area->y2 + 1;
LV_ASSERT((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position");
x_start += drv->x_gap;
x_end += drv->x_gap;
y_start += drv->y_gap;
y_end += drv->y_gap;
/* define an area of frame memory where MCU can access */
send_cmd(drv, LV_LCD_CMD_SET_COLUMN_ADDRESS, (uint8_t[]) {
(x_start >> 8) & 0xFF,
x_start & 0xFF,
((x_end - 1) >> 8) & 0xFF,
(x_end - 1) & 0xFF,
}, 4);
send_cmd(drv, LV_LCD_CMD_SET_PAGE_ADDRESS, (uint8_t[]) {
(y_start >> 8) & 0xFF,
y_start & 0xFF,
((y_end - 1) >> 8) & 0xFF,
(y_end - 1) & 0xFF,
}, 4);
/* transfer frame buffer */
size_t len = (x_end - x_start) * (y_end - y_start) * lv_color_format_get_size(lv_display_get_color_format(disp));
send_color(drv, LV_LCD_CMD_WRITE_MEMORY_START, px_map, len);
}
/**
* Set rotation taking into account the current mirror and swap settings
* @param drv LCD driver object
* @param rot rotation
*/
static void set_rotation(lv_lcd_generic_mipi_driver_t * drv, lv_display_rotation_t rot)
{
switch(rot) {
case LV_DISPLAY_ROTATION_0:
set_swap_xy(drv, drv->swap_xy);
set_mirror(drv, drv->mirror_x, drv->mirror_y);
break;
case LV_DISPLAY_ROTATION_90:
set_swap_xy(drv, !drv->swap_xy);
set_mirror(drv, drv->mirror_x, !drv->mirror_y);
break;
case LV_DISPLAY_ROTATION_180:
set_swap_xy(drv, drv->swap_xy);
set_mirror(drv, !drv->mirror_x, !drv->mirror_y);
break;
case LV_DISPLAY_ROTATION_270:
set_swap_xy(drv, !drv->swap_xy);
set_mirror(drv, !drv->mirror_x, drv->mirror_y);
break;
}
send_cmd(drv, LV_LCD_CMD_SET_ADDRESS_MODE, (uint8_t[]) {
drv->madctl_reg
}, 1);
}
/**
* Handle LV_EVENT_RESOLUTION_CHANGED event (handles both resolution and rotation change)
* @param e LV_EVENT_RESOLUTION_CHANGED event
*/
static void res_chg_event_cb(lv_event_t * e)
{
lv_display_t * disp = lv_event_get_current_target(e);
lv_lcd_generic_mipi_driver_t * drv = get_driver(disp);
uint16_t hor_res = lv_display_get_horizontal_resolution(disp);
uint16_t ver_res = lv_display_get_vertical_resolution(disp);
lv_display_rotation_t rot = lv_display_get_rotation(disp);
/* TODO: implement resolution change */
LV_UNUSED(hor_res);
LV_UNUSED(ver_res);
/* handle rotation */
set_rotation(drv, rot);
}
static lv_lcd_generic_mipi_driver_t * get_driver(lv_display_t * disp)
{
return (lv_lcd_generic_mipi_driver_t *)lv_display_get_driver_data(disp);
}
#endif /*LV_USE_GENERIC_MIPI*/
@@ -0,0 +1,243 @@
/**
* @file lv_lcd_generic_mipi.h
*
* Generic driver for controllers adhering to the MIPI DBI/DCS specification
*
* Works with:
*
* ST7735
* ST7789
* ST7796
* ILI9341
* ILI9488 (NOTE: in SPI mode ILI9488 only supports RGB666 mode, which is currently not supported)
*
* any probably many more
*
*/
#ifndef LV_LCD_GENERIC_MIPI_H
#define LV_LCD_GENERIC_MIPI_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../display/lv_display.h"
#if LV_USE_GENERIC_MIPI
/*********************
* DEFINES
*********************/
/* MIPI DCS (Display Command Set) v1.02.00 User Command Set */
#define LV_LCD_CMD_NOP 0x00 /* No Operation */
#define LV_LCD_CMD_SOFT_RESET 0x01 /* Software Reset */
#define LV_LCD_CMD_GET_POWER_MODE 0x0A /* Get the current power mode */
#define LV_LCD_CMD_GET_ADDRESS_MODE 0x0B /* Get the data order for transfers from the Host to the display module and from the frame memory to the display device */
#define LV_LCD_CMD_GET_PIXEL_FORMAT 0x0C /* Get the current pixel format */
#define LV_LCD_CMD_GET_DISPLAY_MODE 0x0D /* Get the current display mode from the peripheral */
#define LV_LCD_CMD_GET_SIGNAL_MODE 0x0E /* Get display module signaling mode */
#define LV_LCD_CMD_GET_DIAGNOSTIC_RESULT 0x0F /* Get Peripheral Self-Diagnostic Result */
#define LV_LCD_CMD_ENTER_SLEEP_MODE 0x10 /* Power for the display panel is off */
#define LV_LCD_CMD_EXIT_SLEEP_MODE 0x11 /* Power for the display panel is on */
#define LV_LCD_CMD_ENTER_PARTIAL_MODE 0x12 /* Part of the display area is used for image display */
#define LV_LCD_CMD_ENTER_NORMAL_MODE 0x13 /* The whole display area is used for image display */
#define LV_LCD_CMD_EXIT_INVERT_MODE 0x20 /* Displayed image colors are not inverted */
#define LV_LCD_CMD_ENTER_INVERT_MODE 0x21 /* Displayed image colors are inverted */
#define LV_LCD_CMD_SET_GAMMA_CURVE 0x26 /* Selects the gamma curve used by the display device */
#define LV_LCD_CMD_SET_DISPLAY_OFF 0x28 /* Blanks the display device */
#define LV_LCD_CMD_SET_DISPLAY_ON 0x29 /* Show the image on the display device */
#define LV_LCD_CMD_SET_COLUMN_ADDRESS 0x2A /* Set the column extent */
#define LV_LCD_CMD_SET_PAGE_ADDRESS 0x2B /* Set the page extent */
#define LV_LCD_CMD_WRITE_MEMORY_START 0x2C /* Transfer image data from the Host Processor to the peripheral starting at the location provided by set_column_address and set_page_address */
#define LV_LCD_CMD_READ_MEMORY_START 0x2E /* Transfer image data from the peripheral to the Host Processor interface starting at the location provided by set_column_address and set_page_address */
#define LV_LCD_CMD_SET_PARTIAL_ROWS 0x30 /* Defines the number of rows in the partial display area on the display device */
#define LV_LCD_CMD_SET_PARTIAL_COLUMNS 0x31 /* Defines the number of columns in the partial display area on the display device */
#define LV_LCD_CMD_SET_SCROLL_AREA 0x33 /* Defines the vertical scrolling and fixed area on display device */
#define LV_LCD_CMD_SET_TEAR_OFF 0x34 /* Synchronization information is not sent from the display module to the host processor */
#define LV_LCD_CMD_SET_TEAR_ON 0x35 /* Synchronization information is sent from the display module to the host processor at the start of VFP */
#define LV_LCD_CMD_SET_ADDRESS_MODE 0x36 /* Set the data order for transfers from the Host to the display module and from the frame memory to the display device */
#define LV_LCD_CMD_SET_SCROLL_START 0x37 /* Defines the vertical scrolling starting point */
#define LV_LCD_CMD_EXIT_IDLE_MODE 0x38 /* Full color depth is used on the display panel */
#define LV_LCD_CMD_ENTER_IDLE_MODE 0x39 /* Reduced color depth is used on the display panel */
#define LV_LCD_CMD_SET_PIXEL_FORMAT 0x3A /* Defines how many bits per pixel are used in the interface */
#define LV_LCD_CMD_WRITE_MEMORY_CONTINUE 0x3C /* Transfer image information from the Host Processor interface to the peripheral from the last written location */
#define LV_LCD_CMD_READ_MEMORY_CONTINUE 0x3E /* Read image data from the peripheral continuing after the last read_memory_continue or read_memory_start */
#define LV_LCD_CMD_SET_TEAR_SCANLINE 0x44 /* Synchronization information is sent from the display module to the host processor when the display device refresh reaches the provided scanline */
#define LV_LCD_CMD_GET_SCANLINE 0x45 /* Get the current scanline */
#define LV_LCD_CMD_READ_DDB_CONTINUE 0xA8 /* Continue reading the DDB from the last read location */
#define LV_LCD_CMD_READ_DDB_START 0xA1 /* Read the DDB from the provided location */
/* address mode flag masks */
#define LV_LCD_MASK_FLIP_VERTICAL (1 << 0) /* This bit flips the image shown on the display device top to bottom. No change is made to the frame memory */
#define LV_LCD_MASK_FLIP_HORIZONTAL (1 << 1) /* This bit flips the image shown on the display device left to right. No change is made to the frame memory */
#define LV_LCD_MASK_DATA_LATCH_DATA_ORDER (1 << 2) /* Display Data Latch Order */
#define LV_LCD_MASK_RGB_ORDER (1 << 3) /* RGB/BGR Order */
#define LV_LCD_MASK_LINE_ADDRESS_ORDER (1 << 4) /* Line Address Order */
#define LV_LCD_MASK_PAGE_COLUMN_ORDER (1 << 5) /* Page/Column Order */
#define LV_LCD_MASK_COLUMN_ADDRESS_ORDER (1 << 6) /* Column Address Order */
#define LV_LCD_MASK_PAGE_ADDRESS_ORDER (1 << 7) /* Page Address Order */
#define LV_LCD_BIT_FLIP_VERTICAL__NOT_FLIPPED 0
#define LV_LCD_BIT_FLIP_VERTICAL__FLIPPED LV_LCD_MASK_FLIP_VERTICAL /* This bit flips the image shown on the display device top to bottom. No change is made to the frame memory */
#define LV_LCD_BIT_FLIP_HORIZONTAL__NOT_FLIPPED 0
#define LV_LCD_BIT_FLIP_HORIZONTAL__FLIPPED LV_LCD_MASK_FLIP_HORIZONTAL /* This bit flips the image shown on the display device left to right. No change is made to the frame memory */
#define LV_LCD_BIT_DATA_LATCH_DATA_ORDER__LTOR 0 /* Display Data Latch Order: LCD Refresh Left to Right */
#define LV_LCD_BIT_DATA_LATCH_DATA_ORDER__RTOL LV_LCD_MASK_DATA_LATCH_DATA_ORDER /* Display Data Latch Order: LCD Refresh Right to Left */
#define LV_LCD_BIT_RGB_ORDER__RGB 0 /* RGB/BGR Order: RGB */
#define LV_LCD_BIT_RGB_ORDER__BGR LV_LCD_MASK_RGB_ORDER /* RGB/BGR Order: BGR */
#define LV_LCD_BIT_LINE_ADDRESS_ORDER__TTOB 0 /* Line Address Order: LCD Refresh Top to Bottom */
#define LV_LCD_BIT_LINE_ADDRESS_ORDER__BTOT LV_LCD_MASK_LINE_ADDRESS_ORDER /* Line Address Order: LCD Refresh Bottom to Top */
#define LV_LCD_BIT_PAGE_COLUMN_ORDER__NORMAL 0 /* Page/Column Order: Normal Mode */
#define LV_LCD_BIT_PAGE_COLUMN_ORDER__REVERSE LV_LCD_MASK_PAGE_COLUMN_ORDER /* Page/Column Order: Reverse Mode */
#define LV_LCD_BIT_COLUMN_ADDRESS_ORDER__LTOR 0 /* Column Address Order: Left to Right */
#define LV_LCD_BIT_COLUMN_ADDRESS_ORDER__RTOL LV_LCD_MASK_COLUMN_ADDRESS_ORDER /* Column Address Order: Right to Left */
#define LV_LCD_BIT_PAGE_ADDRESS_ORDER__TTOB 0 /* Page Address Order: Top to Bottom */
#define LV_LCD_BIT_PAGE_ADDRESS_ORDER__BTOT LV_LCD_MASK_PAGE_ADDRESS_ORDER /* Page Address Order: Bottom to Top */
/* predefined gamma curves */
#define LV_LCD_GAMMA_2_2 0x01 /* 2.2 */
#define LV_LCD_GAMMA_1_8 0x02 /* 1.8 */
#define LV_LCD_GAMMA_2_5 0x04 /* 2.5 */
#define LV_LCD_GAMMA_1_0 0x08 /* 1.0 */
/* common pixel formats */
#define LV_LCD_PIXEL_FORMAT_RGB565 0x55 /* bus: 16 bits, pixel: 16 bits */
#define LV_LCD_PIXEL_FORMAT_RGB666 0x66 /* bus: 18 bits, pixel: 18 bits */
/* flags for lv_lcd_xxx_create() */
#define LV_LCD_FLAG_NONE 0x00000000UL
#define LV_LCD_FLAG_MIRROR_X 0x00000001UL
#define LV_LCD_FLAG_MIRROR_Y 0x00000002UL
#define LV_LCD_FLAG_BGR 0x00000008UL
#define LV_LCD_FLAG_RGB666 0x00000010UL
/* command list */
#define LV_LCD_CMD_DELAY_MS 0xff
#define LV_LCD_CMD_EOF 0xff
/**********************
* TYPEDEFS
**********************/
/**
* Configuration flags for lv_lcd_xxx_create()
*
*/
typedef uint32_t lv_lcd_flag_t;
/**
* Prototype of a platform-dependent callback to transfer commands and data to the LCD controller.
* @param disp display object
* @param cmd command buffer (can handle 16 bit commands as well)
* @param cmd_size number of bytes of the command
* @param param parameter buffer
* @param param_size number of bytes of the parameters
*/
typedef void (*lv_lcd_send_cmd_cb_t)(lv_display_t * disp, const uint8_t * cmd, size_t cmd_size, const uint8_t * param,
size_t param_size);
/**
* Prototype of a platform-dependent callback to transfer pixel data to the LCD controller.
* @param disp display object
* @param cmd command buffer (can handle 16 bit commands as well)
* @param cmd_size number of bytes of the command
* @param param parameter buffer
* @param param_size number of bytes of the parameters
*/
typedef void (*lv_lcd_send_color_cb_t)(lv_display_t * disp, const uint8_t * cmd, size_t cmd_size, uint8_t * param,
size_t param_size);
/**
* Generic MIPI compatible LCD driver
*/
typedef struct {
lv_display_t * disp; /* the associated LVGL display object */
lv_lcd_send_cmd_cb_t send_cmd; /* platform-specific implementation to send a command to the LCD controller */
lv_lcd_send_color_cb_t send_color; /* platform-specific implementation to send pixel data to the LCD controller */
uint16_t x_gap; /* x offset of the (0,0) pixel in VRAM */
uint16_t y_gap; /* y offset of the (0,0) pixel in VRAM */
uint8_t madctl_reg; /* current value of MADCTL register */
uint8_t colmod_reg; /* current value of COLMOD register */
bool mirror_x;
bool mirror_y;
bool swap_xy;
} lv_lcd_generic_mipi_driver_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a MIPI DCS compatible LCD display
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer).
* `lv_display_flush_ready` must be called after the transfer has finished.
* @return pointer to the created display
*/
lv_display_t * lv_lcd_generic_mipi_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_lcd_send_cmd_cb_t send_cmd_cb, lv_lcd_send_color_cb_t send_color_cb);
/**
* Set gap, i.e., the offset of the (0,0) pixel in the VRAM
* @param disp display object
* @param x x offset
* @param y y offset
*/
void lv_lcd_generic_mipi_set_gap(lv_display_t * disp, uint16_t x, uint16_t y);
/**
* Set color inversion
* @param disp display object
* @param invert false: normal, true: invert
*/
void lv_lcd_generic_mipi_set_invert(lv_display_t * disp, bool invert);
/**
* Set address mode
* @param disp display object
* @param mirror_x horizontal mirror (false: normal, true: mirrored)
* @param mirror_y vertical mirror (false: normal, true: mirrored)
* @param swap_xy swap axes (false: normal, true: swap)
* @param bgr RGB/BGR order (false: RGB, true: BGR)
*/
void lv_lcd_generic_mipi_set_address_mode(lv_display_t * disp, bool mirror_x, bool mirror_y, bool swap_xy, bool bgr);
/**
* Set gamma curve
* @param disp display object
* @param gamma gamma curve
*/
void lv_lcd_generic_mipi_set_gamma_curve(lv_display_t * disp, uint8_t gamma);
/**
* Send list of commands.
* @param disp display object
* @param cmd_list controller and panel-specific commands
*/
void lv_lcd_generic_mipi_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list);
/**********************
* OTHERS
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_GENERIC_MIPI*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_LCD_GENERIC_MIPI_H*/
@@ -0,0 +1,361 @@
/**
* @file lv_renesas_glcdc.c
*
*/
/*********************
*PLATFORM ABSTRACTION
*********************/
#ifdef _RENESAS_RA_
#define USE_FREE_RTOS (BSP_CFG_RTOS == 2)
#else // RX with SMC code generation
#ifndef _RENESAS_RX_
#define _RENESAS_RX_ 1
#endif
#define USE_FREE_RTOS 1
#define DISPLAY_HSIZE_INPUT0 LCD_CH0_IN_GR2_HSIZE
#define DISPLAY_VSIZE_INPUT0 LCD_CH0_IN_GR2_VSIZE
#define DISPLAY_BUFFER_STRIDE_BYTES_INPUT0 LCD_CH0_IN_GR2_LINEOFFSET
#endif /*_RENESAS_RA_*/
/*********************
* INCLUDES
*********************/
#include "lv_renesas_glcdc.h"
#if LV_USE_RENESAS_GLCDC
#ifdef _RENESAS_RA_
#include "LVGL_thread.h"
#else /* RX */
#include "hal_data.h"
#include "platform.h"
#include "r_glcdc_rx_if.h"
#include "r_glcdc_rx_pinset.h"
#endif /*_RENESAS_RA_*/
#include <stdbool.h>
#include "../../../display/lv_display_private.h"
#include "../../../draw/sw/lv_draw_sw.h"
/*********************
* DEFINES
*********************/
#define BYTES_PER_PIXEL 2
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static lv_display_t * glcdc_create(void * buf1, void * buf2, uint32_t buf_size, lv_display_render_mode_t render_mode);
static void glcdc_init(void);
static void give_vsync_sem_and_yield(void);
static void flush_direct(lv_display_t * display, const lv_area_t * area, uint8_t * px_map);
static void flush_partial(lv_display_t * display, const lv_area_t * area, uint8_t * px_map);
static void flush_wait_direct(lv_display_t * display);
static void flush_wait_partial(lv_display_t * display);
#ifdef _RENESAS_RX_
static void enable_dave2d_drw_interrupt(void);
#endif /*_RENESAS_RX_*/
/**********************
* STATIC VARIABLES
**********************/
#ifdef _RENESAS_RX_
static uint8_t fb_background[2][LCD_CH0_IN_GR2_HSIZE * LCD_CH0_IN_GR2_VSIZE * BYTES_PER_PIXEL]__attribute__((
section(".framebuffer"), aligned(64), used));
static SemaphoreHandle_t _SemaphoreVsync = NULL;
static glcdc_cfg_t g_config;
static glcdc_runtime_cfg_t g_layer_change;
/* A global variable that Dave 2D driver relies on. (Being auto generated on RA platforms)*/
display_t g_display0_cfg;
#endif /*_RENESAS_RX_*/
static void * rotation_buffer = NULL;
static uint32_t partial_buffer_size = 0;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_renesas_glcdc_direct_create(void)
{
return glcdc_create(&fb_background[0][0], &fb_background[1][0], sizeof(fb_background[0]),
LV_DISPLAY_RENDER_MODE_DIRECT);
}
lv_display_t * lv_renesas_glcdc_partial_create(void * buf1, void * buf2, size_t buf_size)
{
partial_buffer_size = buf_size;
return glcdc_create(buf1, buf2, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
}
/*This function is declared in and being used by FSP generated code modules*/
#ifdef _RENESAS_RA_
void glcdc_callback(display_callback_args_t * p_args)
{
if(DISPLAY_EVENT_LINE_DETECTION == p_args->event) {
give_vsync_sem_and_yield();
}
else if(DISPLAY_EVENT_GR1_UNDERFLOW == p_args->event) {
__BKPT(0); /*Layer 1 Underrun*/
}
else if(DISPLAY_EVENT_GR2_UNDERFLOW == p_args->event) {
__BKPT(0); /*Layer 2 Underrun*/
}
else { /*DISPLAY_EVENT_FRAME_END*/
__BKPT(0);
}
}
#else /* RX */
void glcdc_callback(glcdc_callback_args_t * p_args)
{
if(GLCDC_EVENT_LINE_DETECTION == p_args->event) {
give_vsync_sem_and_yield();
}
else if(GLCDC_EVENT_GR1_UNDERFLOW == p_args->event) {
while(1); /*Layer 1 Underrun*/
}
else if(GLCDC_EVENT_GR2_UNDERFLOW == p_args->event) {
while(1); /*Layer 2 Underrun*/
}
else {/*DISPLAY_EVENT_FRAME_END*/
while(1);
}
}
#endif /*_RENESAS_RA_*/
/**********************
* STATIC FUNCTIONS
**********************/
static lv_display_t * glcdc_create(void * buf1, void * buf2, uint32_t buf_size, lv_display_render_mode_t render_mode)
{
#ifdef _RENESAS_RA_
glcdc_init();
#else
g_display0_cfg.input->format = LCD_CH0_IN_GR2_FORMAT;
_SemaphoreVsync = xSemaphoreCreateBinary();
glcdc_init();
enable_dave2d_drw_interrupt();
#endif /*_RENESAS_RA_*/
lv_display_t * display = lv_display_create(DISPLAY_HSIZE_INPUT0, DISPLAY_VSIZE_INPUT0);
if(render_mode == LV_DISPLAY_RENDER_MODE_DIRECT) {
lv_display_set_flush_cb(display, flush_direct);
lv_display_set_flush_wait_cb(display, flush_wait_direct);
}
else if(render_mode == LV_DISPLAY_RENDER_MODE_PARTIAL) {
lv_display_set_flush_cb(display, flush_partial);
lv_display_set_flush_wait_cb(display, flush_wait_partial);
}
else {
LV_ASSERT(0);
}
lv_display_set_buffers_with_stride(display, buf1, buf2, buf_size, DISPLAY_BUFFER_STRIDE_BYTES_INPUT0, render_mode);
return display;
}
static void give_vsync_sem_and_yield(void)
{
#if USE_FREE_RTOS
BaseType_t context_switch;
/*Set Vsync semaphore*/
xSemaphoreGiveFromISR(_SemaphoreVsync, &context_switch);
/*Return to the highest priority available task*/
portYIELD_FROM_ISR(context_switch);
#else
#endif /*USE_FREE_RTOS*/
}
static void glcdc_init(void)
{
/* Fill the Frame buffer with black colour (0x0000 in RGB565), for a clean start after previous runs */
lv_memzero(fb_background, sizeof(fb_background));
#ifdef _RENESAS_RA_
/* Initialize GLCDC driver */
uint8_t * p_fb = &fb_background[1][0];
fsp_err_t err;
err = R_GLCDC_Open(&g_display0_ctrl, &g_display0_cfg);
if(FSP_SUCCESS != err) {
__BKPT(0);
}
err = R_GLCDC_Start(&g_display0_ctrl);
if(FSP_SUCCESS != err) {
__BKPT(0);
}
do {
err =
R_GLCDC_BufferChange(&g_display0_ctrl,
(uint8_t *) p_fb,
(display_frame_layer_t) 0);
} while(FSP_ERR_INVALID_UPDATE_TIMING == err);
#else /* RX */
glcdc_err_t err;
glcdc_runtime_cfg_t layer_change;
R_GLCDC_PinSet();
err = R_GLCDC_Open(&g_config);
if(GLCDC_SUCCESS != err) {
while(1);
}
err = R_GLCDC_Control(GLCDC_CMD_START_DISPLAY, &g_config);
if(GLCDC_SUCCESS != err) {
while(1);
}
g_layer_change.input = g_config.input[GLCDC_FRAME_LAYER_2];
g_layer_change.chromakey = g_config.chromakey[GLCDC_FRAME_LAYER_2];
g_layer_change.blend = g_config.blend[GLCDC_FRAME_LAYER_2];
layer_change.input.p_base = (uint32_t *)&fb_background[1][0];
do {
err = R_GLCDC_LayerChange(GLCDC_FRAME_LAYER_2, &g_layer_change);
} while(GLCDC_ERR_INVALID_UPDATE_TIMING == err);
#endif /*_RENESAS_RA_*/
}
static void flush_direct(lv_display_t * display, const lv_area_t * area, uint8_t * px_map)
{
FSP_PARAMETER_NOT_USED(area);
/*Display the frame buffer pointed by px_map*/
if(!lv_display_flush_is_last(display)) return;
#if defined(RENESAS_CORTEX_M85) && (BSP_CFG_DCACHE_ENABLED)
/* Invalidate cache - so the HW can access any data written by the CPU */
SCB_CleanInvalidateDCache_by_Addr(px_map, sizeof(fb_background[0]));
#endif
#ifdef _RENESAS_RA_
R_GLCDC_BufferChange(&g_display0_ctrl,
(uint8_t *) px_map,
(display_frame_layer_t) 0);
#else /* RX */
glcdc_err_t err;
g_layer_change.input.p_base = (uint32_t *)px_map;
do {
err = R_GLCDC_LayerChange(GLCDC_FRAME_LAYER_2, &g_layer_change);
} while(GLCDC_ERR_INVALID_UPDATE_TIMING == err);
#endif /*_RENESAS_RA_*/
}
static void flush_wait_direct(lv_display_t * display)
{
if(!lv_display_flush_is_last(display)) return;
#if USE_FREE_RTOS
/*If Vsync semaphore has already been set, clear it then wait to avoid tearing*/
if(uxSemaphoreGetCount(_SemaphoreVsync)) {
xSemaphoreTake(_SemaphoreVsync, 10);
}
xSemaphoreTake(_SemaphoreVsync, portMAX_DELAY);
#endif /*USE_FREE_RTOS*/
}
static void flush_partial(lv_display_t * display, const lv_area_t * area, uint8_t * px_map)
{
uint16_t * img = (uint16_t *)px_map;
lv_area_t rotated_area;
lv_color_format_t cf = lv_display_get_color_format(display);
lv_display_rotation_t rotation = lv_display_get_rotation(display);
if(rotation != LV_DISPLAY_ROTATION_0) {
int32_t w = lv_area_get_width(area);
int32_t h = lv_area_get_height(area);
uint32_t w_stride = lv_draw_buf_width_to_stride(w, cf);
uint32_t h_stride = lv_draw_buf_width_to_stride(h, cf);
// only allocate if rotation is actually being used
if(!rotation_buffer) {
rotation_buffer = lv_malloc(partial_buffer_size);
LV_ASSERT_MALLOC(rotation_buffer);
}
if(rotation == LV_DISPLAY_ROTATION_180)
lv_draw_sw_rotate(img, rotation_buffer, w, h, w_stride, w_stride, rotation, cf);
else /* 90 or 270 */
lv_draw_sw_rotate(img, rotation_buffer, w, h, w_stride, h_stride, rotation, cf);
img = rotation_buffer;
rotated_area = *area;
lv_display_rotate_area(display, &rotated_area);
area = &rotated_area;
}
int32_t w = lv_area_get_width(area);
int32_t h = lv_area_get_height(area);
uint16_t * fb = (uint16_t *)fb_background[1];
fb = fb + area->y1 * DISPLAY_HSIZE_INPUT0;
fb = fb + area->x1;
int32_t i;
for(i = 0; i < h; i++) {
lv_memcpy(fb, img, w * BYTES_PER_PIXEL);
#if defined(RENESAS_CORTEX_M85) && (BSP_CFG_DCACHE_ENABLED)
SCB_CleanInvalidateDCache_by_Addr(fb, w * BYTES_PER_PIXEL);
#endif
fb += DISPLAY_HSIZE_INPUT0;
img += w;
}
}
static void flush_wait_partial(lv_display_t * display)
{
LV_UNUSED(display);
return;
}
#ifdef _RENESAS_RX_
extern void drw_int_isr(void);
static void enable_dave2d_drw_interrupt(void)
{
bsp_int_ctrl_t grpal1;
/* Specify the priority of the group interrupt. */
grpal1.ipl = 5;
/* Use the BSP API to register the interrupt handler for DRW2D. */
R_BSP_InterruptWrite(BSP_INT_SRC_AL1_DRW2D_DRW_IRQ, (bsp_int_cb_t)drw_int_isr);
/* Use the BSP API to enable the group interrupt. */
R_BSP_InterruptControl(BSP_INT_SRC_AL1_DRW2D_DRW_IRQ, BSP_INT_CMD_GROUP_INTERRUPT_ENABLE, (void *)&grpal1);
}
#endif /*_RENESAS_RX_*/
#endif /*LV_USE_RENESAS_GLCDC*/
@@ -0,0 +1,57 @@
/**
* @file lv_renesas_glcdc.h
*
*/
#ifndef LV_RENESAS_GLCDC_H
#define LV_RENESAS_GLCDC_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../display/lv_display.h"
#if LV_USE_RENESAS_GLCDC
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a display using Renesas' GLCDC peripheral in DIRECT render mode
* @return pointer to the created display
*/
lv_display_t * lv_renesas_glcdc_direct_create(void);
/**
* Create a display using Renesas' GLCDC peripheral in PARTIAL render mode
* @param buf1 first buffer
* @param buf2 second buffer (can be `NULL`)
* @param buf_size buffer size in byte
* @return pointer to the created display
*/
lv_display_t * lv_renesas_glcdc_partial_create(void * buf1, void * buf2, size_t buf_size);
/**********************
* MACROS
**********************/
#endif /* LV_USE_RENESAS_GLCDC */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LV_RENESAS_GLCDC_H */
@@ -0,0 +1,113 @@
/**
* @file lv_st7735.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_st7735.h"
#if LV_USE_ST7735
/*********************
* DEFINES
*********************/
#define CMD_GAMSET 0x26
#define CMD_FRMCTR1 0xB1
#define CMD_FRMCTR2 0xB2
#define CMD_FRMCTR3 0xB3
#define CMD_INVCTR 0xB4
#define CMD_DISSET5 0xB6
#define CMD_PWCTR1 0xC0
#define CMD_PWCTR2 0xC1
#define CMD_PWCTR3 0xC2
#define CMD_PWCTR4 0xC3
#define CMD_PWCTR5 0xC4
#define CMD_VMCTR1 0xC5
#define CMD_VMOFCTR 0xC7
#define CMD_NVFCTR1 0xD9
#define CMD_GMCTRP1 0xE0
#define CMD_GMCTRN1 0xE1
#define CMD_PWCTR6 0xFC
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC CONSTANTS
**********************/
/* init commands for buydisplay.com ER-TFTM018-3 */
static const uint8_t init_cmd_list[] = {
0xB1, 3, 0x05, 0x3C, 0x3C,
0xB2, 3, 0x05, 0x3C, 0x3C,
0xB3, 6, 0x05, 0x3C, 0x3C, 0x05, 0x3C, 0x3C,
0xB4, 1, 0x03,
0xC0, 3, 0x28, 0x08, 0x04,
0xC1, 1, 0XC0,
0xC2, 2, 0x0D, 0x00,
0xC3, 2, 0x8D, 0x2A,
0xC4, 2, 0x8D, 0xEE,
0xC5, 1, 0x10,
0xE0, 16, 0x04, 0x22, 0x07, 0x0A, 0x2E, 0x30, 0x25, 0x2A, 0x28, 0x26, 0x2E, 0x3A, 0x00, 0x01, 0x03, 0x13,
0xE1, 16, 0x04, 0x16, 0x06, 0x0D, 0x2D, 0x26, 0x23, 0x27, 0x27, 0x25, 0x2D, 0x3B, 0x00, 0x01, 0x04, 0x13,
LV_LCD_CMD_DELAY_MS, LV_LCD_CMD_EOF
};
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_st7735_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7735_send_cmd_cb_t send_cmd_cb, lv_st7735_send_color_cb_t send_color_cb)
{
lv_display_t * disp = lv_lcd_generic_mipi_create(hor_res, ver_res, flags, send_cmd_cb, send_color_cb);
lv_lcd_generic_mipi_send_cmd_list(disp, init_cmd_list);
return disp;
}
void lv_st7735_set_gap(lv_display_t * disp, uint16_t x, uint16_t y)
{
lv_lcd_generic_mipi_set_gap(disp, x, y);
}
void lv_st7735_set_invert(lv_display_t * disp, bool invert)
{
lv_lcd_generic_mipi_set_invert(disp, invert);
}
void lv_st7735_set_gamma_curve(lv_display_t * disp, uint8_t gamma)
{
lv_lcd_generic_mipi_set_gamma_curve(disp, gamma);
}
void lv_st7735_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list)
{
lv_lcd_generic_mipi_send_cmd_list(disp, cmd_list);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_ST7735*/
@@ -0,0 +1,93 @@
/**
* @file lv_st7735.h
*
* This driver is just a wrapper around the generic MIPI compatible LCD controller driver
*
*/
#ifndef LV_ST7735_H
#define LV_ST7735_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lcd/lv_lcd_generic_mipi.h"
#if LV_USE_ST7735
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef lv_lcd_send_cmd_cb_t lv_st7735_send_cmd_cb_t;
typedef lv_lcd_send_color_cb_t lv_st7735_send_color_cb_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create an LCD display with ST7735 driver
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
* @return pointer to the created display
*/
lv_display_t * lv_st7735_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7735_send_cmd_cb_t send_cmd_cb, lv_st7735_send_color_cb_t send_color_cb);
/**
* Set gap, i.e., the offset of the (0,0) pixel in the VRAM
* @param disp display object
* @param x x offset
* @param y y offset
*/
void lv_st7735_set_gap(lv_display_t * disp, uint16_t x, uint16_t y);
/**
* Set color inversion
* @param disp display object
* @param invert false: normal, true: invert
*/
void lv_st7735_set_invert(lv_display_t * disp, bool invert);
/**
* Set gamma curve
* @param disp display object
* @param gamma gamma curve
*/
void lv_st7735_set_gamma_curve(lv_display_t * disp, uint8_t gamma);
/**
* Send list of commands.
* @param disp display object
* @param cmd_list controller and panel-specific commands
*/
void lv_st7735_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list);
/**********************
* OTHERS
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_ST7735*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_ST7735_H*/
@@ -0,0 +1,116 @@
/**
* @file lv_st7789.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_st7789.h"
#if LV_USE_ST7789
/*********************
* DEFINES
*********************/
#define CMD_FRMCTR1 0xB1
#define CMD_FRMCTR2 0xB2
#define CMD_FRMCTR3 0xB3
#define CMD_INVCTR 0xB4
#define CMD_DFUNCTR 0xB6
#define CMD_ETMOD 0xB7
#define CMD_PWCTR1 0xC0
#define CMD_PWCTR2 0xC1
#define CMD_PWCTR3 0xC2
#define CMD_PWCTR4 0xC3
#define CMD_PWCTR5 0xC4
#define CMD_VMCTR 0xC5
#define CMD_GMCTRP1 0xE0
#define CMD_GMCTRN1 0xE1
#define CMD_DOCA 0xE8
#define CMD_CSCON 0xF0
#define CMD_RAMCTRL 0xB0
#define CMD_PORCTRL 0xB2 /* Porch control */
#define CMD_GCTRL 0xB7 /* Gate control */
#define CMD_VCOMS 0xBB /* VCOMS setting */
#define CMD_LCMCTRL 0xC0 /* LCM control */
#define CMD_VDVVRHEN 0xC2 /* VDV and VRH command enable */
#define CMD_VRHS 0xC3 /* VRH set */
#define CMD_VDVSET 0xC4 /* VDV setting */
#define CMD_FRCTR2 0xC6 /* FR Control 2 */
#define CMD_PWCTRL1 0xD0 /* Power control 1 */
#define CMD_PVGAMCTRL 0xE0 /* Positive Gamma Correction */
#define CMD_NVGAMCTRL 0xE1 /* Negative Gamma Correction */
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC CONSTANTS
**********************/
/* init commands based on LovyanGFX ST7789 driver */
static const uint8_t init_cmd_list[] = {
CMD_GCTRL, 1, 0x44, /* GCTRL -- panel dependent */
CMD_VCOMS, 1, 0x24, /* VCOMS -- panel dependent */
CMD_VRHS, 1, 0x13, /* VRHS - panel dependent */
CMD_PWCTRL1, 2, 0xa4, 0xa1,
CMD_RAMCTRL, 2, 0x00, 0xC0, /* controls mapping of RGB565 to RGB666 */
CMD_PVGAMCTRL, 14, 0xd0, 0x00, 0x02, 0x07, 0x0a, 0x28, 0x32, 0x44, 0x42, 0x06, 0x0e, 0x12, 0x14, 0x17,
CMD_NVGAMCTRL, 14, 0xd0, 0x00, 0x02, 0x07, 0x0a, 0x28, 0x31, 0x54, 0x47, 0x0e, 0x1c, 0x17, 0x1b, 0x1e,
LV_LCD_CMD_SET_GAMMA_CURVE, 1, 0x01,
LV_LCD_CMD_DELAY_MS, LV_LCD_CMD_EOF
};
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_st7789_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7789_send_cmd_cb_t send_cmd_cb, lv_st7789_send_color_cb_t send_color_cb)
{
lv_display_t * disp = lv_lcd_generic_mipi_create(hor_res, ver_res, flags, send_cmd_cb, send_color_cb);
lv_lcd_generic_mipi_send_cmd_list(disp, init_cmd_list);
return disp;
}
void lv_st7789_set_gap(lv_display_t * disp, uint16_t x, uint16_t y)
{
lv_lcd_generic_mipi_set_gap(disp, x, y);
}
void lv_st7789_set_invert(lv_display_t * disp, bool invert)
{
lv_lcd_generic_mipi_set_invert(disp, invert);
}
void lv_st7789_set_gamma_curve(lv_display_t * disp, uint8_t gamma)
{
lv_lcd_generic_mipi_set_gamma_curve(disp, gamma);
}
void lv_st7789_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list)
{
lv_lcd_generic_mipi_send_cmd_list(disp, cmd_list);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_ST7789*/
@@ -0,0 +1,94 @@
/**
* @file lv_st7789.h
*
* This driver is just a wrapper around the generic MIPI compatible LCD controller driver
*
*/
#ifndef LV_ST7789_H
#define LV_ST7789_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lcd/lv_lcd_generic_mipi.h"
#if LV_USE_ST7789
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef lv_lcd_send_cmd_cb_t lv_st7789_send_cmd_cb_t;
typedef lv_lcd_send_color_cb_t lv_st7789_send_color_cb_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create an LCD display with ST7789 driver
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
* @return pointer to the created display
*/
lv_display_t * lv_st7789_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7789_send_cmd_cb_t send_cmd_cb, lv_st7789_send_color_cb_t send_color_cb);
/**
* Set gap, i.e., the offset of the (0,0) pixel in the VRAM
* @param disp display object
* @param x x offset
* @param y y offset
*/
void lv_st7789_set_gap(lv_display_t * disp, uint16_t x, uint16_t y);
/**
* Set color inversion
* @param disp display object
* @param invert false: normal, true: invert
*/
void lv_st7789_set_invert(lv_display_t * disp, bool invert);
/**
* Set gamma curve
* @param disp display object
* @param gamma gamma curve
*/
void lv_st7789_set_gamma_curve(lv_display_t * disp, uint8_t gamma);
/**
* Send list of commands.
* @param disp display object
* @param cmd_list controller and panel-specific commands
*/
void lv_st7789_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list);
/**********************
* OTHERS
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_ST7789*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_ST7789_H*/
@@ -0,0 +1,121 @@
/**
* @file lv_st7796.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_st7796.h"
#if LV_USE_ST7796
/*********************
* DEFINES
*********************/
#define CMD_FRMCTR1 0xB1
#define CMD_FRMCTR2 0xB2
#define CMD_FRMCTR3 0xB3
#define CMD_INVCTR 0xB4
#define CMD_DFUNCTR 0xB6
#define CMD_ETMOD 0xB7
#define CMD_PWCTR1 0xC0
#define CMD_PWCTR2 0xC1
#define CMD_PWCTR3 0xC2
#define CMD_PWCTR4 0xC3
#define CMD_PWCTR5 0xC4
#define CMD_VMCTR 0xC5
#define CMD_GMCTRP1 0xE0
#define CMD_GMCTRN1 0xE1
#define CMD_DOCA 0xE8
#define CMD_CSCON 0xF0
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC CONSTANTS
**********************/
/* init commands based on LovyanGFX */
static const uint8_t init_cmd_list[] = {
CMD_CSCON, 1, 0xC3, /* Enable extension command 2 partI */
CMD_CSCON, 1, 0x96, /* Enable extension command 2 partII */
CMD_INVCTR, 1, 0x01, /* 1-dot inversion */
CMD_DFUNCTR, 3, 0x80, /* Display Function Control: Bypass */
0x22, /* Source Output Scan from S1 to S960, Gate Output scan from G1 to G480, scan cycle = 2 */
0x3B, /* LCD Drive Line = 8 * (59 + 1) */
CMD_DOCA, 8, 0x40, 0x8A, 0x00, 0x00,
0x29, /* Source equalizing period time = 22.5 us */
0x19, /* Timing for "Gate start" = 25 (Tclk) */
0xA5, /* Timing for "Gate End" = 37 (Tclk), Gate driver EQ function ON */
0x33,
CMD_PWCTR2, 1, 0x06, /* Power control2: VAP(GVDD) = 3.85 + (vcom + vcom offset), VAN(GVCL) = -3.85 + (vcom + vcom offset) */
CMD_PWCTR3, 1, 0xA7, /* Power control 3: Source driving current level = low, Gamma driving current level = High */
CMD_VMCTR, 1, 0x18, /* VCOM Control: VCOM = 0.9 */
LV_LCD_CMD_DELAY_MS, 12, /* delay 120 ms */
CMD_GMCTRP1, 14, /* Gamma */
0xF0, 0x09, 0x0B, 0x06, 0x04, 0x15, 0x2F,
0x54, 0x42, 0x3C, 0x17, 0x14, 0x18, 0x1B,
CMD_GMCTRN1, 14,
0xE0, 0x09, 0x0B, 0x06, 0x04, 0x03, 0x2B,
0x43, 0x42, 0x3B, 0x16, 0x14, 0x17, 0x1B,
LV_LCD_CMD_DELAY_MS, 12, /* delay 120 ms */
CMD_CSCON, 1, 0x3C, /* Disable extension command 2 partI */
CMD_CSCON, 1, 0x69, /* Disable extension command 2 partII */
LV_LCD_CMD_DELAY_MS, LV_LCD_CMD_EOF
};
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_st7796_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7796_send_cmd_cb_t send_cmd_cb, lv_st7796_send_color_cb_t send_color_cb)
{
lv_display_t * disp = lv_lcd_generic_mipi_create(hor_res, ver_res, flags, send_cmd_cb, send_color_cb);
lv_lcd_generic_mipi_send_cmd_list(disp, init_cmd_list);
return disp;
}
void lv_st7796_set_gap(lv_display_t * disp, uint16_t x, uint16_t y)
{
lv_lcd_generic_mipi_set_gap(disp, x, y);
}
void lv_st7796_set_invert(lv_display_t * disp, bool invert)
{
lv_lcd_generic_mipi_set_invert(disp, invert);
}
void lv_st7796_set_gamma_curve(lv_display_t * disp, uint8_t gamma)
{
/* NOTE: the generic method is not supported on ST7796, TODO: implement gamma tables */
LV_UNUSED(disp);
LV_UNUSED(gamma);
}
void lv_st7796_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list)
{
lv_lcd_generic_mipi_send_cmd_list(disp, cmd_list);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_ST7796*/
@@ -0,0 +1,93 @@
/**
* @file lv_st7796.h
*
* This driver is just a wrapper around the generic MIPI compatible LCD controller driver
*
*/
#ifndef LV_ST7796_H
#define LV_ST7796_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lcd/lv_lcd_generic_mipi.h"
#if LV_USE_ST7796
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef lv_lcd_send_cmd_cb_t lv_st7796_send_cmd_cb_t;
typedef lv_lcd_send_color_cb_t lv_st7796_send_color_cb_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create an LCD display with ST7796 driver
* @param hor_res horizontal resolution
* @param ver_res vertical resolution
* @param flags default configuration settings (mirror, RGB ordering, etc.)
* @param send_cmd platform-dependent function to send a command to the LCD controller (usually uses polling transfer)
* @param send_color platform-dependent function to send pixel data to the LCD controller (usually uses DMA transfer: must implement a 'ready' callback)
* @return pointer to the created display
*/
lv_display_t * lv_st7796_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags,
lv_st7796_send_cmd_cb_t send_cmd_cb, lv_st7796_send_color_cb_t send_color_cb);
/**
* Set gap, i.e., the offset of the (0,0) pixel in the VRAM
* @param disp display object
* @param x x offset
* @param y y offset
*/
void lv_st7796_set_gap(lv_display_t * disp, uint16_t x, uint16_t y);
/**
* Set color inversion
* @param disp display object
* @param invert false: normal, true: invert
*/
void lv_st7796_set_invert(lv_display_t * disp, bool invert);
/**
* Set gamma curve
* @param disp display object
* @param gamma gamma curve
*/
void lv_st7796_set_gamma_curve(lv_display_t * disp, uint8_t gamma);
/**
* Send list of commands.
* @param disp display object
* @param cmd_list controller and panel-specific commands
*/
void lv_st7796_send_cmd_list(lv_display_t * disp, const uint8_t * cmd_list);
/**********************
* OTHERS
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_ST7796*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_ST7796_H*/
@@ -0,0 +1,290 @@
/**
* @file lv_st_ltdc.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_ST_LTDC
#include "lv_st_ltdc.h"
#include "../../../display/lv_display_private.h"
#include "../../../draw/sw/lv_draw_sw.h"
#include "ltdc.h"
#if LV_ST_LTDC_USE_DMA2D_FLUSH
#if LV_USE_DRAW_DMA2D
#error cannot use LV_ST_LTDC_USE_DMA2D_FLUSH with LV_USE_DRAW_DMA2D
#endif /*LV_USE_DRAW_DMA2D*/
#include "dma2d.h"
#endif /*LV_ST_LTDC_USE_DMA2D_FLUSH*/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
#if LV_USE_OS != LV_OS_NONE
typedef lv_thread_sync_t sync_t;
#else
typedef volatile bool sync_t;
#endif
/**********************
* STATIC PROTOTYPES
**********************/
static lv_display_t * create(void * buf1, void * buf2, uint32_t buf_size, uint32_t layer_idx,
lv_display_render_mode_t mode);
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map);
static void flush_wait_cb(lv_display_t * disp);
static lv_color_format_t get_lv_cf_from_layer_cf(uint32_t cf);
static void reload_event_callback(LTDC_HandleTypeDef * hltdc);
#if LV_ST_LTDC_USE_DMA2D_FLUSH
static void transfer_complete_callback(DMA2D_HandleTypeDef * hdma2d);
static uint32_t get_dma2d_output_cf_from_layer_cf(uint32_t cf);
static uint32_t get_dma2d_input_cf_from_lv_cf(uint32_t cf);
#endif
/**********************
* STATIC VARIABLES
**********************/
static struct {
bool disp_flushed_in_flush_cb[MAX_LAYER];
sync_t sync[MAX_LAYER];
volatile bool layer_interrupt_is_owned[MAX_LAYER];
#if LV_ST_LTDC_USE_DMA2D_FLUSH
volatile uint32_t dma2d_interrupt_owner; /*layer_idx + 1, or 0 for none*/
#endif
} g_data;
/**********************
* MACROS
**********************/
#if LV_USE_OS != LV_OS_NONE
#define SYNC_INIT(layer_idx) lv_thread_sync_init(&g_data.sync[layer_idx])
#define SYNC_WAIT(layer_idx) lv_thread_sync_wait(&g_data.sync[layer_idx])
#define SYNC_SIGNAL_ISR(layer_idx) lv_thread_sync_signal_isr(&g_data.sync[layer_idx])
#else
#define SYNC_INIT(layer_idx) do { g_data.sync[layer_idx] = false; } while(0)
#define SYNC_WAIT(layer_idx) do { while(!g_data.sync[layer_idx]); g_data.sync[layer_idx] = false; } while(0)
#define SYNC_SIGNAL_ISR(layer_idx) do { g_data.sync[layer_idx] = true; } while(0)
#endif
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_st_ltdc_create_direct(void * fb_adr_1, void * fb_adr_2, uint32_t layer_idx)
{
return create(fb_adr_1, fb_adr_2, 0, layer_idx, LV_DISPLAY_RENDER_MODE_DIRECT);
}
lv_display_t * lv_st_ltdc_create_partial(void * render_buf_1, void * render_buf_2, uint32_t buf_size,
uint32_t layer_idx)
{
return create(render_buf_1, render_buf_2, buf_size, layer_idx, LV_DISPLAY_RENDER_MODE_PARTIAL);
}
/**********************
* STATIC FUNCTIONS
**********************/
static lv_display_t * create(void * buf1, void * buf2, uint32_t buf_size, uint32_t layer_idx,
lv_display_render_mode_t mode)
{
LTDC_LayerCfgTypeDef * layer_cfg = &hltdc.LayerCfg[layer_idx];
uint32_t layer_width = layer_cfg->ImageWidth;
uint32_t layer_height = layer_cfg->ImageHeight;
uint32_t layer_cf = layer_cfg->PixelFormat;
lv_color_format_t cf = get_lv_cf_from_layer_cf(layer_cf);
lv_display_t * disp = lv_display_create(layer_width, layer_height);
lv_display_set_color_format(disp, cf);
lv_display_set_flush_cb(disp, flush_cb);
lv_display_set_flush_wait_cb(disp, flush_wait_cb);
lv_display_set_driver_data(disp, (void *)(uintptr_t)layer_idx);
if(mode == LV_DISPLAY_RENDER_MODE_DIRECT) {
uint32_t cf_size = lv_color_format_get_size(cf);
lv_display_set_buffers(disp, buf1, buf2, layer_width * layer_height * cf_size, LV_DISPLAY_RENDER_MODE_DIRECT);
if(buf1 != NULL && buf2 != NULL) {
HAL_LTDC_RegisterCallback(&hltdc, HAL_LTDC_RELOAD_EVENT_CB_ID, reload_event_callback);
SYNC_INIT(layer_idx);
}
}
else {
lv_display_set_buffers(disp, buf1, buf2, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
#if LV_ST_LTDC_USE_DMA2D_FLUSH
hdma2d.XferCpltCallback = transfer_complete_callback;
SYNC_INIT(layer_idx);
#endif
}
return disp;
}
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
{
uint32_t layer_idx = (uint32_t)(uintptr_t)lv_display_get_driver_data(disp);
g_data.disp_flushed_in_flush_cb[layer_idx] = false;
if(disp->render_mode == LV_DISPLAY_RENDER_MODE_DIRECT) {
if(lv_display_is_double_buffered(disp) && lv_display_flush_is_last(disp)) {
HAL_LTDC_SetAddress_NoReload(&hltdc, (uint32_t)px_map, layer_idx);
g_data.layer_interrupt_is_owned[layer_idx] = true;
HAL_LTDC_Reload(&hltdc, LTDC_RELOAD_VERTICAL_BLANKING);
}
else {
g_data.disp_flushed_in_flush_cb[layer_idx] = true;
}
}
else {
LTDC_LayerCfgTypeDef * layer_cfg = &hltdc.LayerCfg[layer_idx];
lv_color_format_t cf = lv_display_get_color_format(disp);
int32_t disp_width = disp->hor_res;
uint8_t * fb = (uint8_t *) layer_cfg->FBStartAdress;
uint32_t px_size = lv_color_format_get_size(cf);
uint32_t fb_stride = px_size * disp_width;
lv_area_t rotated_area = *area;
lv_display_rotate_area(disp, &rotated_area);
uint8_t * first_pixel = fb + fb_stride * rotated_area.y1 + px_size * rotated_area.x1;
int32_t area_width = lv_area_get_width(area);
int32_t area_height = lv_area_get_height(area);
lv_display_rotation_t rotation = lv_display_get_rotation(disp);
if(rotation == LV_DISPLAY_ROTATION_0) {
#if LV_ST_LTDC_USE_DMA2D_FLUSH
uint32_t dma2d_input_cf = get_dma2d_input_cf_from_lv_cf(cf);
uint32_t dma2d_output_cf = get_dma2d_output_cf_from_layer_cf(layer_cfg->PixelFormat);
while(DMA2D->CR & DMA2D_CR_START);
DMA2D->FGPFCCR = dma2d_input_cf;
DMA2D->FGMAR = (uint32_t)px_map;
DMA2D->FGOR = 0;
DMA2D->OPFCCR = dma2d_output_cf;
DMA2D->OMAR = (uint32_t)first_pixel;
DMA2D->OOR = disp_width - area_width;
DMA2D->NLR = (area_width << DMA2D_NLR_PL_Pos) | (area_height << DMA2D_NLR_NL_Pos);
g_data.dma2d_interrupt_owner = layer_idx + 1;
DMA2D->CR = DMA2D_CR_START | DMA2D_CR_TCIE | (0x1U << DMA2D_CR_MODE_Pos); /* memory-to-memory with PFC */
#else
uint32_t area_stride = px_size * area_width;
uint8_t * fb_p = first_pixel;
uint8_t * px_map_p = px_map;
for(int i = 0; i < area_height; i++) {
lv_memcpy(fb_p, px_map_p, area_stride);
fb_p += fb_stride;
px_map_p += area_stride;
}
g_data.disp_flushed_in_flush_cb[layer_idx] = true;
#endif
}
else {
uint32_t area_stride = px_size * area_width;
lv_draw_sw_rotate(px_map, first_pixel, area_width, area_height, area_stride, fb_stride, rotation, cf);
g_data.disp_flushed_in_flush_cb[layer_idx] = true;
}
}
}
static void flush_wait_cb(lv_display_t * disp)
{
uint32_t layer_idx = (uint32_t)(uintptr_t)lv_display_get_driver_data(disp);
if(!g_data.disp_flushed_in_flush_cb[layer_idx]) {
SYNC_WAIT(layer_idx);
}
}
static lv_color_format_t get_lv_cf_from_layer_cf(uint32_t cf)
{
switch(cf) {
case LTDC_PIXEL_FORMAT_ARGB8888:
return LV_COLOR_FORMAT_ARGB8888;
case LTDC_PIXEL_FORMAT_RGB888:
return LV_COLOR_FORMAT_RGB888;
case LTDC_PIXEL_FORMAT_RGB565:
return LV_COLOR_FORMAT_RGB565;
case LTDC_PIXEL_FORMAT_L8:
return LV_COLOR_FORMAT_L8;
case LTDC_PIXEL_FORMAT_AL88:
return LV_COLOR_FORMAT_AL88;
default:
LV_ASSERT_MSG(0, "the LTDC color format is not supported");
}
}
static void reload_event_callback(LTDC_HandleTypeDef * hltdc)
{
uint32_t i;
for(i = 0; i < MAX_LAYER; i++) {
if(g_data.layer_interrupt_is_owned[i]) {
g_data.layer_interrupt_is_owned[i] = false;
SYNC_SIGNAL_ISR(i);
}
}
}
#if LV_ST_LTDC_USE_DMA2D_FLUSH
static void transfer_complete_callback(DMA2D_HandleTypeDef * hdma2d)
{
DMA2D->IFCR = 0x3FU;
uint32_t owner = g_data.dma2d_interrupt_owner;
if(owner) {
g_data.dma2d_interrupt_owner = 0;
owner -= 1;
SYNC_SIGNAL_ISR(owner);
}
}
static uint32_t get_dma2d_output_cf_from_layer_cf(uint32_t cf)
{
switch(cf) {
case LTDC_PIXEL_FORMAT_ARGB8888:
return DMA2D_OUTPUT_ARGB8888;
case LTDC_PIXEL_FORMAT_RGB888:
return DMA2D_OUTPUT_RGB888;
case LTDC_PIXEL_FORMAT_RGB565:
return DMA2D_OUTPUT_RGB565;
default:
LV_ASSERT_MSG(0, "DMA2D cannot output to the LTDC color format");
}
}
static uint32_t get_dma2d_input_cf_from_lv_cf(uint32_t cf)
{
switch(cf) {
case LV_COLOR_FORMAT_ARGB8888:
return DMA2D_INPUT_ARGB8888;
case LV_COLOR_FORMAT_RGB888:
return DMA2D_INPUT_RGB888;
case LV_COLOR_FORMAT_RGB565:
return DMA2D_INPUT_RGB565;
case LV_COLOR_FORMAT_L8:
return DMA2D_INPUT_L8;
case LV_COLOR_FORMAT_AL88:
return DMA2D_INPUT_AL88;
case LV_COLOR_FORMAT_A8:
return DMA2D_INPUT_A8;
default:
LV_ASSERT_MSG(0, "the LVGL color format is not a DMA2D input color format");
}
}
#endif /*LV_ST_LTDC_USE_DMA2D_FLUSH*/
#endif /*LV_USE_ST_LTDC*/
@@ -0,0 +1,65 @@
/**
* @file lv_st_ltdc.h
*
*/
#ifndef LV_ST_LTDC_H
#define LV_ST_LTDC_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_ST_LTDC
#include "../../../display/lv_display.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a direct render mode display bound to a LTDC layer.
* @param fb_adr_1 The LTDC layer's framebuffer memory address.
* @param fb_adr_2 An additional framebuffer-sized buffer to use for double buffering, or `NULL`.
* @param layer_idx The LTDC layer number to bind the display to. Typically 0 or 1.
* @return The display.
*/
lv_display_t * lv_st_ltdc_create_direct(void * fb_adr_1, void * fb_adr_2, uint32_t layer_idx);
/**
* Create a partial render mode display bound to a LTDC layer. The layer's framebuffer is flushed to internally.
* Enable `LV_ST_LTDC_USE_DMA2D_FLUSH` for parallel flushing.
* @param render_buf_1 A render buffer.
* @param render_buf_2 An additional render buffer for double-buffering, or `NULL`.
* @param buf_size The size of the buffer(s) in bytes.
* @param layer_idx The LTDC layer number to bind the display to. Typically 0 or 1.
* @return The display.
*/
lv_display_t * lv_st_ltdc_create_partial(void * render_buf_1, void * render_buf_2, uint32_t buf_size,
uint32_t layer_idx);
/**********************
* MACROS
**********************/
#endif /*LV_USE_ST_LTDC*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_ST_LTDC_H*/
@@ -0,0 +1,110 @@
/**
* @file lv_tft_espi.cpp
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_tft_espi.h"
#if LV_USE_TFT_ESPI
#include <TFT_eSPI.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
TFT_eSPI * tft;
} lv_tft_espi_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map);
static void resolution_changed_event_cb(lv_event_t * e);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_tft_espi_create(uint32_t hor_res, uint32_t ver_res, void * buf, uint32_t buf_size_bytes)
{
lv_tft_espi_t * dsc = (lv_tft_espi_t *)lv_malloc_zeroed(sizeof(lv_tft_espi_t));
LV_ASSERT_MALLOC(dsc);
if(dsc == NULL) return NULL;
lv_display_t * disp = lv_display_create(hor_res, ver_res);
if(disp == NULL) {
lv_free(dsc);
return NULL;
}
dsc->tft = new TFT_eSPI(hor_res, ver_res);
dsc->tft->begin(); /* TFT init */
dsc->tft->setRotation(0);
lv_display_set_driver_data(disp, (void *)dsc);
lv_display_set_flush_cb(disp, flush_cb);
lv_display_add_event_cb(disp, resolution_changed_event_cb, LV_EVENT_RESOLUTION_CHANGED, NULL);
lv_display_set_buffers(disp, (void *)buf, NULL, buf_size_bytes, LV_DISPLAY_RENDER_MODE_PARTIAL);
return disp;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
{
lv_tft_espi_t * dsc = (lv_tft_espi_t *)lv_display_get_driver_data(disp);
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
dsc->tft->startWrite();
dsc->tft->setAddrWindow(area->x1, area->y1, w, h);
dsc->tft->pushColors((uint16_t *)px_map, w * h, true);
dsc->tft->endWrite();
lv_display_flush_ready(disp);
}
static void resolution_changed_event_cb(lv_event_t * e)
{
lv_display_t * disp = (lv_display_t *)lv_event_get_target(e);
lv_tft_espi_t * dsc = (lv_tft_espi_t *)lv_display_get_driver_data(disp);
int32_t hor_res = lv_display_get_horizontal_resolution(disp);
int32_t ver_res = lv_display_get_vertical_resolution(disp);
lv_display_rotation_t rot = lv_display_get_rotation(disp);
/* handle rotation */
switch(rot) {
case LV_DISPLAY_ROTATION_0:
dsc->tft->setRotation(0); /* Portrait orientation */
break;
case LV_DISPLAY_ROTATION_90:
dsc->tft->setRotation(1); /* Landscape orientation */
break;
case LV_DISPLAY_ROTATION_180:
dsc->tft->setRotation(2); /* Portrait orientation, flipped */
break;
case LV_DISPLAY_ROTATION_270:
dsc->tft->setRotation(3); /* Landscape orientation, flipped */
break;
}
}
#endif /*LV_USE_TFT_ESPI*/
@@ -0,0 +1,43 @@
/**
* @file lv_tft_espi.h
*
*/
#ifndef LV_TFT_ESPI_H
#define LV_TFT_ESPI_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../display/lv_display.h"
#if LV_USE_TFT_ESPI
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_display_t * lv_tft_espi_create(uint32_t hor_res, uint32_t ver_res, void * buf, uint32_t buf_size_bytes);
/**********************
* MACROS
**********************/
#endif /* LV_USE_TFT_ESPI */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LV_TFT_ESPI_H */