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 image

  • lv_conf.h文件 image image

想跑哪些demo,把相应的宏打开

  • lv_port_disp_template.c文件 image image
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文件 image
  1. 添加打印函数,方便debug
  2. 因为有API函数,所以使用很方便。但需要touch的坐标,与lvgl的失配按图中3的公式。这是经过大约1个小时的测试,找到的,这样才是合适的。

完整的程序

main.c

//****************************************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;
	}
}

lv_port_disp_template.c

/**
 * @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

lv_port_indev_template.c

/**
 * @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帧率非常高 image 7bbce1913a568ec9f866cabc3a0f108

补充说明

如果配置lv_conf.h,开启CPU和MEM的Monitor,那么将会在频率的左/右下方的角落里,显示帧率/cpu/mem的实时状态。 image 168f2d90c78769432fc6f214bfe51ee

⚠️ **GitHub.com Fallback** ⚠️