sdk例程:原子rgb屏从头开始移植lvgl完整流程 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
- 基于原子zynq例程的《D:\FPGA\Atom\ZYNQ_SDK_7020\34_touch_draw_lcd》,该例程显示是rgb888
- 一般来说,调通了显示和触摸后,移植lvgl很容易
- 基于lvgl 8.2,从官网下载和裁剪。这个过程前面其它例程有,这里不再重复了。
- main.c中需要增加如下头文件
#include "ACZ702_Lib/COMMON.h"
#include "lvgl/lvgl.h"
#include "lvgl/examples/porting/lv_port_disp_template.h"
#include "lvgl/examples/porting/lv_port_indev_template.h"
#include "lvgl/demos/lv_demos.h"
#include "xil_mmu.h"
-
不要使用Xil_DCacheDisable(), 否则刷频速度慢20倍,这通过lv_demo_benchmark()测试出来的。要使用mmu的配置,只将frame_buffer设置为NORM_NONCACHE
-
lv_conf.h文件
想跑哪些demo,把相应的宏打开
- lv_port_disp_template.c文件
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
uint32_t frame_buffer_addr = (XPAR_PS7_DDR_0_S_AXI_BASEADDR + 0x6000000);
uint8_t *p_frame=(uint8_t *)frame_buffer_addr;
int32_t x;
int32_t y;
uint32_t stride=800*3;
uint32_t curr_line_addr = area->y1 * stride ;
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
/*Put a pixel to the display. For example:*/
/*put_px(x, y, *color_p)*/
p_frame[curr_line_addr + x*3 + 0] = color_p->ch.blue;
p_frame[curr_line_addr + x*3 + 1] = color_p->ch.green;
p_frame[curr_line_addr + x*3 + 2] = color_p->ch.red;
color_p++;
}
curr_line_addr += stride;
}
xil_printf("x0=%d, x1=%d, y0=%d, y1=%d\r\n", area->x1,area->x2,area->y1,area->y2);
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
- lv_port_indev_template.c文件
- 添加打印函数,方便debug
- 因为有API函数,所以使用很方便。但需要touch的坐标,与lvgl的失配按图中3的公式。这是经过大约1个小时的测试,找到的,这样才是合适的。
//****************************************Copyright (c)***********************************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name: main.c
// Last modified Date: 2019/07/26 15:59:46
// Last Version: V1.0
// Descriptions: VDMA驱动LCD示例
//----------------------------------------------------------------------------------------
// Created by: 正点原子
// Created date: 2019/07/26 15:59:52
// Version: V1.0
// Descriptions: The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xil_types.h"
#include "xil_cache.h"
#include "xparameters.h"
#include "xgpio.h"
#include "xaxivdma.h"
#include "xaxivdma_i.h"
#include "display_ctrl/display_ctrl.h"
#include "emio_iic_cfg/emio_iic_cfg.h"
#include "vdma_api/vdma_api.h"
#include "APP/delay.h"
#include "TOUCH/touch.h"
#include "main.h"
#include "ACZ702_Lib/COMMON.h"
#include "lvgl/lvgl.h"
#include "lvgl/examples/porting/lv_port_disp_template.h"
#include "lvgl/examples/porting/lv_port_indev_template.h"
#include "lvgl/demos/lv_demos.h"
#include "xil_mmu.h"
//宏定义
#define BYTES_PIXEL 3 //像素字节数,RGB888占3个字节
#define FRAME_BUFFER_NUM 3 //帧缓存个数3
#define DYNCLK_BASEADDR XPAR_AXI_DYNCLK_0_BASEADDR //动态时钟基地址
#define VDMA_ID XPAR_AXIVDMA_0_DEVICE_ID //VDMA器件ID
#define DISP_VTC_ID XPAR_VTC_0_DEVICE_ID //VTC器件ID
#define AXI_GPIO_0_ID XPAR_AXI_GPIO_0_DEVICE_ID //PL端 AXI GPIO 0(lcd_id)器件ID
#define AXI_GPIO_0_CHANEL 1 //PL按键使用AXI GPIO(lcd_id)通道1
//函数声明
void Load_Drow_Dialog(void); //清空屏幕并在右上角显示"RST"
void gui_draw_hline(u16 x0, u16 y0, u16 len, u16 color); //画水平线
void gui_fill_circle(u16 x0, u16 y0, u16 r, u16 color); //画实心圆
void ctp_test(void); //电容触摸屏测试函数
void lcd_draw_bline(u16 x1, u16 y1, u16 x2, u16 y2, u8 size, u16 color); //画线函数
void frame_data_fill(u8 *frame, u16 sx, u16 sy, u16 ex, u16 ey, u16 color, u32 stride);
//10个触控点的颜色(电容触摸屏用)
const u16 POINT_COLOR_TBL[10] = {
MLCD_RED, MLCD_GREEN, MLCD_BLUE, MLCD_BROWN, MLCD_GRED,
MLCD_BRED, MLCD_GBLUE, MLCD_LIGHTBLUE, MLCD_BRRED, MLCD_GRAY
};
//全局变量
XAxiVdma vdma;
DisplayCtrl dispCtrl;
XGpio axi_gpio_inst; //PL端 AXI GPIO 驱动实例
VideoMode vd_mode;
//frame buffer的起始地址
unsigned int const frame_buffer_addr = (XPAR_PS7_DDR_0_S_AXI_BASEADDR + 0x6000000);
unsigned int lcd_id=0; //LCD ID
void ScuTimer_IRQ_Handler(void *CallBackRef)
{
/* ↓↓↓用户处理↓↓↓ */
lv_tick_inc(1);
//xil_printf("tick\r\n");
/* ↑↑↑结束处理↑↑↑ */
XScuTimer_ClearInterruptStatus(&ScuTimer);
}
int main(void)
{
//获取LCD的ID
XGpio_Initialize(&axi_gpio_inst,AXI_GPIO_0_ID);
XGpio_SetDataDirection(&axi_gpio_inst,AXI_GPIO_0_CHANEL,0x07); //设置AXI GPIO为输入
lcd_id = LTDC_PanelID_Read(&axi_gpio_inst,AXI_GPIO_0_CHANEL);
XGpio_SetDataDirection(&axi_gpio_inst,AXI_GPIO_0_CHANEL,0x00); //设置AXI GPIO为输出
xil_printf("LCD ID: %x\r\n",lcd_id);
//根据获取的LCD的ID号来进行video参数的选择
switch(lcd_id){
case 0x4342 : vd_mode = VMODE_480x272; break; //4.3寸屏,480*272分辨率
case 0x4384 : vd_mode = VMODE_800x480; break; //4.3寸屏,800*480分辨率
case 0x7084 : vd_mode = VMODE_800x480; break; //7寸屏,800*480分辨率
case 0x7016 : vd_mode = VMODE_1024x600; break; //7寸屏,1024*600分辨率
case 0x1018 : vd_mode = VMODE_1280x800; break; //10.1寸屏,1280*800分辨率
default : vd_mode = VMODE_800x480; break;
}
emio_init();
//配置VDMA
run_vdma_frame_buffer(&vdma, VDMA_ID, vd_mode.width, vd_mode.height,
frame_buffer_addr,0, 0,ONLY_READ);
//清空DDR3帧缓存空间
memset(frame_buffer_addr,0xFF,vd_mode.height*vd_mode.width*FRAME_BUFFER_NUM*BYTES_PIXEL);
memset((_PTR)LV_MEM_ADR, 0x0, LV_MEM_SIZE); // LVGL堆内存清零
//Xil_DCacheDisable(); //关闭cache,否则由于对Frame Buffer的写入延时比较大,画板的效果会很慢
Xil_MemMap(frame_buffer_addr, vd_mode.height*vd_mode.width*FRAME_BUFFER_NUM*BYTES_PIXEL, NORM_NONCACHE);
//用Xil_MemMap设置MMU,效果非常好!速度比Xil_DCacheDisable快20倍!
//初始化Display controller
DisplayInitialize(&dispCtrl, DISP_VTC_ID, DYNCLK_BASEADDR);
//设置VideoMode
DisplaySetMode(&dispCtrl, &vd_mode);
DisplayStart(&dispCtrl);
tp_dev.init(); //触摸屏初始化
/* 私有定时器初始化 */
ScuGic_Init();
ScuTimer_Int_Init(1000);
/* lvgl初始化 */
lv_init();
lv_port_disp_init();
lv_port_indev_init();
/* 创建demo */
// lv_demo_printer();
// lv_demo_keypad_encoder();
// lv_demo_widgets();
// lv_demo_stress();
// lv_demo_benchmark();
lv_demo_music();
/* 死循环 */
for ( ; ; ) {
lv_task_handler();
usleep(5 * 1000);
}
// if (tp_dev.touchtype & 0X80) //如果是电容屏
// {
// u8 t = 0;
// u8 i = 0;
// u16 lastpos[10][2]; //最后一次的数据
// u8 maxp = 5; //最大触摸点数
// if (lcd_id == 0X1018)
// maxp = 10;
// while(1)
// {
// //扫描当前触摸屏的触摸状态
// tp_dev.scan();
//
// //对每个触摸点进行处理
// for (t = 0; t < maxp; t++)
// {
// if( (tp_dev.sta) & (1 << t) ) //如果有触摸
// {
// //如果当前触摸点的坐标在LCD的宽度和高度范围内
// if( (tp_dev.x[t] < vd_mode.height) && (tp_dev.y[t] < vd_mode.width) )
// {
// if (lastpos[t][0] == 0XFFFF)
// {
// lastpos[t][0] = tp_dev.x[t];
// lastpos[t][1] = tp_dev.y[t];
// }
// lcd_draw_bline( lastpos[t][0] , lastpos[t][1],
// tp_dev.x[t] , tp_dev.y[t],
// 2 , POINT_COLOR_TBL[t]
// ); //画线
// lastpos[t][0] = tp_dev.x[t];
// lastpos[t][1] = tp_dev.y[t];
//
// if( (tp_dev.x[t] < 30) && (tp_dev.y[t] < 30) )
// {
// //清空DDR3帧缓存空间
// memset(frame_buffer_addr,0xFF,vd_mode.height*vd_mode.width*FRAME_BUFFER_NUM*BYTES_PIXEL);
// }
// }
// }
// //如果无触摸
// else
// lastpos[t][0] = 0XFFFF;
// }
// delay_ms(5);
// i++;
// }
// }
return 0;
}
//画一条粗线
//(x1,y1),(x2,y2):线条的起始坐标
//size:线条的粗细程度
//color:线条的颜色
void lcd_draw_bline(u16 x1, u16 y1, u16 x2, u16 y2, u8 size, u16 color)
{
u16 t;
int xerr = 0, yerr = 0, delta_x, delta_y, distance;
int incx, incy, uRow, uCol;
if ( (x1 < size) || (x2 < size) || (y1 < size) || (y2 < size) )
return;
delta_x = x2 - x1; //计算坐标增量
delta_y = y2 - y1;
uRow = x1;
uCol = y1;
if (delta_x > 0)
incx = 1; //设置单步方向
else if (delta_x == 0)
incx = 0; //垂直线
else
{
incx = -1;
delta_x = -delta_x;
}
if (delta_y > 0)
incy = 1;
else if (delta_y == 0)
incy = 0; //水平线
else
{
incy = -1;
delta_y = -delta_y;
}
if (delta_x > delta_y)
distance = delta_x; //选取基本增量坐标轴
else
distance = delta_y;
for (t = 0; t <= distance + 1; t++) //画线输出
{
gui_fill_circle(uRow, uCol, size, color); //画点
xerr += delta_x;
yerr += delta_y;
if (xerr > distance)
{
xerr -= distance;
uRow += incx;
}
if (yerr > distance)
{
yerr -= distance;
uCol += incy;
}
}
}
//画实心圆
//x0,y0:坐标
//r:半径
//color:颜色
void gui_fill_circle(u16 x0, u16 y0, u16 r, u16 color) {
u32 i;
u32 imax = ((u32) r * 707) / 1000 + 1;
u32 sqmax = (u32) r * (u32) r + (u32) r / 2;
u32 x = r;
gui_draw_hline(x0 - r, y0, 2 * r, color);
for (i = 1; i <= imax; i++)
{
if ((i * i + x * x) > sqmax) // draw lines from outside
{
if (x > imax)
{
gui_draw_hline(x0 - i + 1, y0 + x, 2 * (i - 1), color);
gui_draw_hline(x0 - i + 1, y0 - x, 2 * (i - 1), color);
}
x--;
}
// draw lines from inside (center)
gui_draw_hline(x0 - x, y0 + i, 2 * x, color);
gui_draw_hline(x0 - x, y0 - i, 2 * x, color);
}
}
//画水平线
//x0,y0:坐标
//len:线长度
//color:颜色
void gui_draw_hline(u16 x0, u16 y0, u16 len, u16 color)
{
if (len == 0)
return;
if( (x0 + len - 1) >= vd_mode.height )
x0 = vd_mode.height - len - 1; //限制坐标范围
x0 = vd_mode.height - x0;
if(y0 >= vd_mode.width)
y0 = vd_mode.width - 1; //限制坐标范围
frame_data_fill( (u8 *)frame_buffer_addr, y0 , x0, y0 , x0 + len - 1, color, vd_mode.width*BYTES_PIXEL );
}
// sx sy ex ey 都是像素点的形式坐标
// color 是RGB565数据,要转换成RGB888
// stride :frame buffer一行的字节数
void frame_data_fill(u8 *frame, u16 sx, u16 sy, u16 ex, u16 ey, u16 color, u32 stride)
{
u32 curr_line_addr ; //当前行的起始字节在frame buffer中的地址
u32 x_pos ; //像素点的X方向的形式坐标
u16 y_pos ; //像素点的Y方向的形式坐标
u8 rgb_r, rgb_g, rgb_b ;
rgb_r = (color >> 11) << 3 ; //最高5位就是Red
rgb_g = ( (color >> 5) & 0x003F ) << 2 ; //中间6位是Green,右移5位,并且将原先RGB565中的5位的Red清零
rgb_b = (color & 0x001F) << 3 ; //低5位就是Blue
curr_line_addr = sy * stride ;
//逐行赋值像素数据
for( y_pos = sy; y_pos <= ey; y_pos++ )
{
//在每一行中从左至右依次赋值像素数据
for( x_pos = sx; x_pos <= ex; x_pos++ )
{
frame[curr_line_addr + x_pos*BYTES_PIXEL + 0] = rgb_b;
frame[curr_line_addr + x_pos*BYTES_PIXEL + 1] = rgb_g;
frame[curr_line_addr + x_pos*BYTES_PIXEL + 2] = rgb_r;
}
curr_line_addr += stride;
}
}
/**
* @file lv_port_disp_templ.c
*
*/
/*Copy this file as "lv_port_disp.c" and set this value to "1" to enable content*/
#if 1
/*********************
* INCLUDES
*********************/
#include "xparameters.h"
#include "lv_port_disp_template.h"
#include "../../lvgl.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void disp_init(void);
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
// const lv_area_t * fill_area, lv_color_t color);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
#define MY_DISP_HOR_RES 800
#define MY_DISP_VER_RES 480
#define LV_VER_RES_MAX 800
static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES] __attribute__ ((aligned (64))); /*A screen sized buffer*/
static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES] __attribute__ ((aligned (64))); /*Another screen sized buffer*/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_port_disp_init(void)
{
/*-------------------------
* Initialize your display
* -----------------------*/
disp_init();
/*-----------------------------
* Create a buffer for drawing
*----------------------------*/
/**
* LVGL requires a buffer where it internally draws the widgets.
* Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display.
* The buffer has to be greater than 1 display row
*
* There are 3 buffering configurations:
* 1. Create ONE buffer:
* LVGL will draw the display's content here and writes it to your display
*
* 2. Create TWO buffer:
* LVGL will draw the display's content to a buffer and writes it your display.
* You should use DMA to write the buffer's content to the display.
* It will enable LVGL to draw the next part of the screen to the other buffer while
* the data is being sent form the first buffer. It makes rendering and flushing parallel.
*
* 3. Double buffering
* Set 2 screens sized buffers and set disp_drv.full_refresh = 1.
* This way LVGL will always provide the whole rendered screen in `flush_cb`
* and you only need to change the frame buffer's address.
*/
/* Example for 3) also set disp_drv.full_refresh = 1 below*/
static lv_disp_draw_buf_t draw_buf_dsc_3;
lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2, MY_DISP_VER_RES * LV_VER_RES_MAX); /*Initialize the display buffer*/
/*-----------------------------------
* Register the display in LVGL
*----------------------------------*/
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
/*Set up the functions to access to your display*/
/*Set the resolution of the display*/
disp_drv.hor_res = 800;
disp_drv.ver_res = 480;
/*Used to copy the buffer's content to the display*/
disp_drv.flush_cb = disp_flush;
/*Set a display buffer*/
disp_drv.draw_buf = &draw_buf_dsc_3;
/*Required for Example 3)*/
//disp_drv.full_refresh = 1
/* Fill a memory array with a color if you have GPU.
* Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL.
* But if you have a different GPU you can use with this callback.*/
//disp_drv.gpu_fill_cb = gpu_fill;
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
/*You code here*/
}
/*Flush the content of the internal buffer the specific area on the display
*You can use DMA or any hardware acceleration to do this operation in the background but
*'lv_disp_flush_ready()' has to be called when finished.*/
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
uint32_t frame_buffer_addr = (XPAR_PS7_DDR_0_S_AXI_BASEADDR + 0x6000000);
uint8_t *p_frame=(uint8_t *)frame_buffer_addr;
int32_t x;
int32_t y;
uint32_t stride=800*3;
uint32_t curr_line_addr = area->y1 * stride ;
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
/*Put a pixel to the display. For example:*/
/*put_px(x, y, *color_p)*/
p_frame[curr_line_addr + x*3 + 0] = color_p->ch.blue;
p_frame[curr_line_addr + x*3 + 1] = color_p->ch.green;
p_frame[curr_line_addr + x*3 + 2] = color_p->ch.red;
color_p++;
}
curr_line_addr += stride;
}
xil_printf("x0=%d, x1=%d, y0=%d, y1=%d\r\n", area->x1,area->x2,area->y1,area->y2);
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
/*OPTIONAL: GPU INTERFACE*/
/*If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color*/
//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
// const lv_area_t * fill_area, lv_color_t color)
//{
// /*It's an example code which should be done by your GPU*/
// int32_t x, y;
// dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
//
// for(y = fill_area->y1; y <= fill_area->y2; y++) {
// for(x = fill_area->x1; x <= fill_area->x2; x++) {
// dest_buf[x] = color;
// }
// dest_buf+=dest_width; /*Go to the next line*/
// }
//}
#else /*Enable this file at the top*/
/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif
/**
* @file lv_port_indev_templ.c
*
*/
/*Copy this file as "lv_port_indev.c" and set this value to "1" to enable content*/
#if 1
/*********************
* INCLUDES
*********************/
#include "lv_port_indev_template.h"
#include "../../lvgl.h"
#include "../../../TOUCH/touch.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void touchpad_init(void);
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool touchpad_is_pressed(void);
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y);
/**********************
* STATIC VARIABLES
**********************/
lv_indev_t * indev_touchpad;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_port_indev_init(void)
{
/**
* Here you will find example implementation of input devices supported by LittelvGL:
* - Touchpad
* - Mouse (with cursor support)
* - Keypad (supports GUI usage only with key)
* - Encoder (supports GUI usage only with: left, right, push)
* - Button (external buttons to press points on the screen)
*
* The `..._read()` function are only examples.
* You should shape them according to your hardware
*/
static lv_indev_drv_t indev_drv;
/*------------------
* Touchpad
* -----------------*/
/*Initialize your touchpad if you have*/
touchpad_init();
/*Register a touchpad input device*/
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = touchpad_read;
indev_touchpad = lv_indev_drv_register(&indev_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
/*------------------
* Touchpad
* -----------------*/
/*Initialize your touchpad*/
static void touchpad_init(void)
{
/*Your code comes here*/
}
/*Will be called by the library to read the touchpad*/
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static lv_coord_t last_x = 0;
static lv_coord_t last_y = 0;
/*Save the pressed coordinates and the state*/
if(touchpad_is_pressed()) {
touchpad_get_xy(&last_x, &last_y);
data->state = LV_INDEV_STATE_PR;
} else {
data->state = LV_INDEV_STATE_REL;
}
/*Set the last pressed coordinates*/
xil_printf("touch state=%d, x=%d, y=%d\r\n", data->state, last_x, last_y);
data->point.x = last_x;
data->point.y = last_y;
}
/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
/*Your code comes here*/
tp_dev.scan();
if(tp_dev.sta &0b11111){
return true;
}
return false;
}
/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
/*Your code comes here*/
(*x) = tp_dev.y[0];
(*y) = 480-tp_dev.x[0];
}
#else /*Enable this file at the top*/
/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif
- 触摸和显示效果都非常好
- 用了Xil_MemMap后,跑bench帧率非常高
如果配置lv_conf.h,开启CPU和MEM的Monitor,那么将会在频率的左/右下方的角落里,显示帧率/cpu/mem的实时状态。