【目的】移植lvgl并且运行lvgl的widget示例
在【 HC32F4A0开发板】触摸测试 这篇帖子的基础上,进行移植
1、到lvgl下载官方源码,也可以拷贝原子的8.2源码进行移植,我这里是利用原子的源代码进行移植。
2、在M:\HC32F4A0_DDL_Rev2.1.0的midwares下面新建GUI以及GUI_APP
3、在GUI下面新建lvgl文件夹,建成后将l源码下面的lvgl.h、lvgl_conf_template以及src文件夹、examples下的porting文件夹拷到lvgl文件夹下面。
4、把lvgl_conf_template.h更名为lvgl_conf.h
5、在keil下添如下目录:
6、/lvgl/src/core 分组中添加 core 文件夹下的全部.c 文件,如下图所示:
7、往/lvgl/src/draw 组中添加 draw 文件夹下除 nxp_pxp、nxp_vglite、sdl 和
8、往 /lvgl/src/extra 组中添加 extra 文件夹下除了 lib 文件夹之外的全部.c 文件,如下图所示:
9、往 /lvgl/src/font 组中添加 font 文件夹下的全部.c 文件,如下图所示:
10、往 lvgl/src/gpu 组中添加 draw/stm32_dma2d 和 draw/sdl文件夹下的全部.c文件,如下图所示:
11、往 lvgl/src/hal 组中添加 hal 文件夹下的全部.c 文件,如下图所示:
12、往/lvgl/src/misc 组中添加 misc 文件夹下的全部.c 文件,如下图所示:
13、往 lvgl/src/widgets 组中添加 widgets 文件夹下的全部.c 文件,如下图所示:
14、/lvgl/examples/porting 组添加 /LVGL/GUI/lvgl/examples/porting目录下的 lv_port_disp_template.c 和 lv_port_indev_template.c 文件,如下图所示:
16、将 demos/widgets下的全部C文件加到GUI_APP/widgets下面:
到些文件的拷贝结束。【注意】上面有些是文件夹里有文件夹的,小细心添回,如果后面编译报错,根据报错提示,逐一添加。
17、移植 LVGL 只需要添加关键的头文件路径即可,因为 lvgl.h 文件已经为我们省去了很多包含头文件的操作,添加的头文件路径如下图所示:
18、由于我们前面已经添加了显示、触摸、定时器,所以这一步省略,如果没有的请自行添加。
19、修改工程文件
/**
* @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 "lv_port_disp_template.h"
#include "../../lvgl.h"
#include "ev_hc32f4a0_lqfp176_nt35510.h"
#include "main.h"
/*********************
* DEFINES
*********************/
#define USE_SRAM 0 /* 使用外部 sram 为 1,否则为 0 */
/**********************
* TYPEDEFS
**********************/
#define MY_DISP_HOR_RES (480) /* 屏幕宽度 */
#define MY_DISP_VER_RES (800) /* 屏幕高度 */
/**********************
* 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
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_port_disp_init(void)
{
/*-------------------------
* Initialize your display
* -----------------------*/
disp_init();
/*-----------------------------
* 创建一个绘图缓冲区
*----------------------------*/
/**
* LVGL 需要一个缓冲区用来绘制小部件
* 随后,这个缓冲区的内容会通过显示设备的 flush_cb(显示设备刷新函数) 复制到显示设备上
* 这个缓冲区的大小需要大于显示设备一行的大小
*
* 这里有 3 中缓冲配置:
* 1. 单缓冲区:
* LVGL 会将显示设备的内容绘制到这里,并将他写入显示设备。
*
* 2. 双缓冲区:
* LVGL 会将显示设备的内容绘制到其中一个缓冲区,并将他写入显示设备。
* 需要使用 DMA 将要显示在显示设备的内容写入缓冲区。
* 当数据从第一个缓冲区发送时,它将使 LVGL 能够将屏幕的下一部分绘制到另一个缓冲区。
* 这样使得渲染和刷新可以并行执行。
*
* 3. 全尺寸双缓冲区
* 设置两个屏幕大小的全尺寸缓冲区,并且设置 disp_drv.full_refresh = 1。
* LVGL 将始终以 'flush_cb' 的形式提供整个渲染屏幕,只需更改帧缓冲区的地址。
*/
/* Example for 1) */
//// static lv_disp_draw_buf_t draw_buf_dsc_1;
//// static lv_color_t buf_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
//// lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/
/* Example for 2) */
static lv_disp_draw_buf_t draw_buf_dsc_2;
static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
static lv_color_t buf_2_2[MY_DISP_HOR_RES * 10]; /*An other buffer for 10 rows*/
lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/
/* Example for 3) also set disp_drv.full_refresh = 1 below*/
// static lv_disp_draw_buf_t draw_buf_dsc_3;
// static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*A screen sized buffer*/
// static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*Another screen sized buffer*/
// 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 = MY_DISP_HOR_RES;
disp_drv.ver_res = MY_DISP_VER_RES;
/*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_2;
/*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)
{
BSP_LCD_IO_Init();
BSP_LCD_RSTCmd(EIO_PIN_RESET); /* RST# to low */
DDL_DelayMS(50UL);
BSP_LCD_RSTCmd(EIO_PIN_SET); /* RST# to high */
DDL_DelayMS(50UL);
/* Initialize NT35510 LCD */
BSP_NT35510_Init();
/* Clear LCD screen */
// BSP_NT35510_Clear(LCD_COLOR_BLACK);
/* Turn on LCD backlight */
BSP_LCD_BKLCmd(EIO_PIN_SET);
/* Set LCD cursor */
}
/*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*/
int32_t x;
int32_t y;
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)*/
BSP_NT35510_WritePixel(x, y, color_p->full);
color_p++;
}
}
/* 重要!!!LCD 驱动函数,在指定区域内填充指定颜色块 */
//lcd_color_fill(area->x1,area->y1,area->x2,area->y2,(uint16_t*)color_p);
/*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
4.
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;
static int32_t encoder_diff;
static lv_indev_state_t encoder_state;
/**********************
* 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)
{
/*Save the pressed coordinates and the state*/
if(touchpad_is_pressed()) {
data->state = LV_INDEV_STATE_PR;
}
else {
data->state = LV_INDEV_STATE_REL;
}
/*Set the last pressed coordinates*/
data->point.x = touchdat.stcPoint.u16X;
data->point.y = touchdat.stcPoint.u16Y;
}
/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
TOUCHPAD_Read(&touchdat);
if(touchdat.enPointPress == SET)
{
//DDL_Printf("sta\r\n");
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*/
static uint16_t u16LastX = 0U;
static uint16_t u16LastY = 0U;
/*Save the pressed coordinates and the state*/
if (touchpad_is_pressed()) {
BSP_GT9XX_GetXY(GT9XX_POINT1, &u16LastX, &u16LastY);
}
(*x) = u16LastX;
(*y) = u16LastY;
}
#else /*Enable this file at the top*/
/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif
20、编译测试函数
int32_t main(void)
{
uint8_t show_str[40] = {0};
/* Register write enable for some required peripherals. */
LL_PERIPH_WE(LL_PERIPH_EFM | LL_PERIPH_FCG | LL_PERIPH_GPIO | LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_SRAM);
/* BSP Clock initialize */
BSP_CLK_Init();
/* Expand IO init */
BSP_IO_Init();
/* BSP LED initialize */
BSP_LED_Init();
/* Printf init */
DDL_PrintfInit(BSP_PRINTF_DEVICE, BSP_PRINTF_BAUDRATE, BSP_PRINTF_Preinit);
/* Matrix KEY row init */
/* Initialize LCD touch pad */
/* Initialize NT35510 LCD */
//BSP_NT35510_Init();
lv_init(); /* lvgl 系统初始化 */
lv_port_disp_init(); /* lvgl 显示接口初始化,放在 lv_init()的后面 */
lv_port_indev_init(); /* lvgl 输入接口初始化,放在 lv_init()的后面 */
init_timer0();
/* Register write protected for some required peripherals. */
LL_PERIPH_WP(LL_PERIPH_EFM | LL_PERIPH_FCG | LL_PERIPH_GPIO | LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_SRAM);
lv_demo_widgets(); // 这里是widgets的demo函数
/* Add your code here */
for (;;) {
lv_timer_handler(); /* LVGL 管理函数相当于 RTOS 触发任务调度函数 */
DDL_DelayMS(1UL);
}
}
到这里移植就到一段落了,下面提一些注意事项:
1、要打开字体函数,否则会报下面的错误:
2、小华的有些外设打开需要在hc32f4xx_conf.h里面打开开关,不要会显示文件找不到。
1、修改NT35510的调置块的函数:
/**
* @brief NT35510_SetRegion 设置显示块的坐标
* @param [in] pstcLCD: LCD controller
* @param u16startXpos: Specifies the sartX position.
* @param u16endXpos: Specifies the endX position.
* @param u16startYpos: Specifies the startY position.
* @param u16endYpos: Specifies the endY position.
* @retval None
*/
//设置横坐标指令:0x2A00~0x2A03;
//设置纵坐标指令:0x2B00~0x2B03;
#define NT35110SC 0x2A00
#define NT35110EC 0x2A02
#define NT35110SP 0x2B00
#define NT35110EP 0x2B02
void NT35510_SetRegion(stc_lcd_controller_t *pstcLCD,
uint16_t u16startXpos,
uint16_t u16endXpos,
uint16_t u16startYpos,
uint16_t u16endYpos)
{
/* Set cursor */
NT35510_WriteRegData(pstcLCD, NT35110SC, (u16startXpos >> 8));
NT35510_WriteRegData(pstcLCD, NT35110SC +1U, (u16startXpos & 0xFFU));
NT35510_WriteRegData(pstcLCD, NT35110EC, (u16endXpos >> 8));
NT35510_WriteRegData(pstcLCD, NT35110EC+1U, (u16endXpos & 0xFFU));
NT35510_WriteRegData(pstcLCD,NT35110SP, (u16startYpos >> 8));
NT35510_WriteRegData(pstcLCD,NT35110SP+1U, (u16startYpos & 0xFFU));
NT35510_WriteRegData(pstcLCD,NT35110SP+2U, (u16endYpos >> 8));
NT35510_WriteRegData(pstcLCD,NT35110SP+3U, (u16endYpos & 0xFFU));
}
2、修改lv_port_disp中的显示函数:
/*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*/
int32_t x;
int32_t y;
BSP_NT35510_SetRegion(area->x1,area->x2,area->y1,area->y2);
BSP_NT35510_PrepareWriteRAM();
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)*/
BSP_NT35510_WriteData(color_p->full);
// BSP_NT35510_WritePixel(x,y,color_p->full);
color_p++;
}
}
/* 重要!!!LCD 驱动函数,在指定区域内填充指定颜色块 */
//lcd_color_fill(area->x1,area->y1,area->x2,area->y2,(uint16_t*)color_p);
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
经过这样优化后,就可以流畅的显示了。
楼主啊,我所用的硬件和你一样,我按照你的方法移植为什么屏幕没有被点亮啊